Skip to content

Refactor class parents handling #11475

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1539,7 +1539,7 @@ object SymDenotations {
info2 match {
case info2: ClassInfo =>
info1 match {
case info1: ClassInfo => info1.classParents ne info2.classParents
case info1: ClassInfo => info1.declaredParents ne info2.declaredParents
case _ => completersMatter
}
case _ => completersMatter
Expand Down Expand Up @@ -1730,16 +1730,16 @@ object SymDenotations {
super.info_=(tp)
}

def classParents(using Context): List[Type] = info match {
case classInfo: ClassInfo => classInfo.parents
/** The symbols of the parent classes. */
def parentSyms(using Context): List[Symbol] = info match {
case classInfo: ClassInfo => classInfo.declaredParents.map(_.classSymbol)
case _ => Nil
}

/** The symbol of the superclass, NoSymbol if no superclass exists */
def superClass(using Context): Symbol = classParents match {
def superClass(using Context): Symbol = parentSyms match {
case parent :: _ =>
val cls = parent.classSymbol
if (cls.is(Trait)) NoSymbol else cls
if (parent.is(Trait)) NoSymbol else parent
case _ =>
NoSymbol
}
Expand Down Expand Up @@ -1799,19 +1799,20 @@ object SymDenotations {
def computeBaseData(implicit onBehalf: BaseData, ctx: Context): (List[ClassSymbol], BaseClassSet) = {
def emptyParentsExpected =
is(Package) || (symbol == defn.AnyClass) || ctx.erasedTypes && (symbol == defn.ObjectClass)
if (classParents.isEmpty && !emptyParentsExpected)
val psyms = parentSyms
if (psyms.isEmpty && !emptyParentsExpected)
onBehalf.signalProvisional()
val builder = new BaseDataBuilder
def traverse(parents: List[Type]): Unit = parents match {
def traverse(parents: List[Symbol]): Unit = parents match {
case p :: parents1 =>
p.classSymbol match {
p match {
case pcls: ClassSymbol => builder.addAll(pcls.baseClasses)
case _ => assert(isRefinementClass || p.isError || ctx.mode.is(Mode.Interactive), s"$this has non-class parent: $p")
}
traverse(parents1)
case nil =>
}
traverse(classParents)
traverse(psyms)
(classSymbol :: builder.baseClasses, builder.baseClassSet)
}

Expand Down Expand Up @@ -1959,7 +1960,7 @@ object SymDenotations {
denots1
case nil => denots
if name.isConstructorName then ownDenots
else collect(ownDenots, classParents)
else collect(ownDenots, info.parents)

override final def findMember(name: Name, pre: Type, required: FlagSet, excluded: FlagSet)(using Context): Denotation =
val raw = if excluded.is(Private) then nonPrivateMembersNamed(name) else membersNamed(name)
Expand Down Expand Up @@ -2028,7 +2029,7 @@ object SymDenotations {
else if (isOwnThis)
if (clsd.baseClassSet.contains(symbol))
if (symbol.isStatic && symbol.typeParams.isEmpty) symbol.typeRef
else foldGlb(NoType, clsd.classParents)
else foldGlb(NoType, clsd.info.parents)
else NoType
else
recur(clsd.typeRef).asSeenFrom(prefix, clsd.owner)
Expand Down Expand Up @@ -2134,8 +2135,8 @@ object SymDenotations {
var names = Set[Name]()
def maybeAdd(name: Name) = if (keepOnly(thisType, name)) names += name
try {
for (p <- classParents if p.classSymbol.isClass)
for (name <- p.classSymbol.asClass.memberNames(keepOnly))
for (p <- parentSyms if p.isClass)
for (name <- p.asClass.memberNames(keepOnly))
maybeAdd(name)
val ownSyms =
if (keepOnly eq implicitFilter)
Expand Down
55 changes: 28 additions & 27 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4528,20 +4528,21 @@ object Types {
type TypeOrSymbol = Type | Symbol

/** Roughly: the info of a class during a period.
* @param prefix The prefix on which parents, decls, and selfType need to be rebased.
* @param cls The class symbol.
* @param classParents The parent types of this class.
* These are all normalized to be TypeRefs by moving any refinements
* to be member definitions of the class itself.
* @param decls The symbols defined directly in this class.
* @param selfInfo The type of `this` in this class, if explicitly given,
* NoType otherwise. If class is compiled from source, can also
* be a reference to the self symbol containing the type.
* @param prefix The prefix on which parents, decls, and selfType need to be rebased.
* @param cls The class symbol.
* @param declaredParents The parent types of this class.
* These are all normalized to be TypeRefs by moving any refinements
* to be member definitions of the class itself.
* Unlike `parents`, the types are not seen as seen from `prefix`.
* @param decls The symbols defined directly in this class.
* @param selfInfo The type of `this` in this class, if explicitly given,
* NoType otherwise. If class is compiled from source, can also
* be a reference to the self symbol containing the type.
*/
abstract case class ClassInfo(
prefix: Type,
cls: ClassSymbol,
classParents: List[Type],
declaredParents: List[Type],
decls: Scope,
selfInfo: TypeOrSymbol) extends CachedGroundType with TypeType {

Expand Down Expand Up @@ -4577,20 +4578,20 @@ object Types {

override def parents(using Context): List[Type] = {
if (parentsCache == null)
parentsCache = classParents.mapConserve(_.asSeenFrom(prefix, cls.owner))
parentsCache = declaredParents.mapConserve(_.asSeenFrom(prefix, cls.owner))
parentsCache
}

protected def newLikeThis(prefix: Type, classParents: List[Type], decls: Scope, selfInfo: TypeOrSymbol)(using Context): ClassInfo =
ClassInfo(prefix, cls, classParents, decls, selfInfo)
protected def newLikeThis(prefix: Type, declaredParents: List[Type], decls: Scope, selfInfo: TypeOrSymbol)(using Context): ClassInfo =
ClassInfo(prefix, cls, declaredParents, decls, selfInfo)

def derivedClassInfo(prefix: Type)(using Context): ClassInfo =
if (prefix eq this.prefix) this
else newLikeThis(prefix, classParents, decls, selfInfo)
else newLikeThis(prefix, declaredParents, decls, selfInfo)

def derivedClassInfo(prefix: Type = this.prefix, classParents: List[Type] = this.classParents, decls: Scope = this.decls, selfInfo: TypeOrSymbol = this.selfInfo)(using Context): ClassInfo =
if ((prefix eq this.prefix) && (classParents eq this.classParents) && (decls eq this.decls) && (selfInfo eq this.selfInfo)) this
else newLikeThis(prefix, classParents, decls, selfInfo)
def derivedClassInfo(prefix: Type = this.prefix, declaredParents: List[Type] = this.declaredParents, decls: Scope = this.decls, selfInfo: TypeOrSymbol = this.selfInfo)(using Context): ClassInfo =
if ((prefix eq this.prefix) && (declaredParents eq this.declaredParents) && (decls eq this.decls) && (selfInfo eq this.selfInfo)) this
else newLikeThis(prefix, declaredParents, decls, selfInfo)

/** If this class has opaque type alias members, a new class info
* with their aliases added as refinements to the self type of the class.
Expand Down Expand Up @@ -4626,13 +4627,13 @@ object Types {
}

override def computeHash(bs: Binders): Int = doHash(bs, cls, prefix)
override def hashIsStable: Boolean = prefix.hashIsStable && classParents.hashIsStable
override def hashIsStable: Boolean = prefix.hashIsStable && declaredParents.hashIsStable

override def eql(that: Type): Boolean = that match {
case that: ClassInfo =>
prefix.eq(that.prefix) &&
cls.eq(that.cls) &&
classParents.eqElements(that.classParents) &&
declaredParents.eqElements(that.declaredParents) &&
decls.eq(that.decls) &&
selfInfo.eq(that.selfInfo)
case _ => false
Expand All @@ -4644,17 +4645,17 @@ object Types {
case that: ClassInfo =>
prefix.equals(that.prefix, bs) &&
cls.eq(that.cls) &&
classParents.equalElements(that.classParents, bs) &&
declaredParents.equalElements(that.declaredParents, bs) &&
decls.eq(that.decls) &&
selfInfo.eq(that.selfInfo)
case _ => false
}

override def toString: String = s"ClassInfo($prefix, $cls, $classParents)"
override def toString: String = s"ClassInfo($prefix, $cls, $declaredParents)"
}

class CachedClassInfo(prefix: Type, cls: ClassSymbol, classParents: List[Type], decls: Scope, selfInfo: TypeOrSymbol)
extends ClassInfo(prefix, cls, classParents, decls, selfInfo)
class CachedClassInfo(prefix: Type, cls: ClassSymbol, declaredParents: List[Type], decls: Scope, selfInfo: TypeOrSymbol)
extends ClassInfo(prefix, cls, declaredParents, decls, selfInfo)

/** A class for temporary class infos where `parents` are not yet known */
final class TempClassInfo(prefix: Type, cls: ClassSymbol, decls: Scope, selfInfo: TypeOrSymbol)
Expand All @@ -4664,15 +4665,15 @@ object Types {
def finalized(parents: List[Type])(using Context): ClassInfo =
ClassInfo(prefix, cls, parents, decls, selfInfo)

override def newLikeThis(prefix: Type, classParents: List[Type], decls: Scope, selfInfo: TypeOrSymbol)(using Context): ClassInfo =
override def newLikeThis(prefix: Type, declaredParents: List[Type], decls: Scope, selfInfo: TypeOrSymbol)(using Context): ClassInfo =
TempClassInfo(prefix, cls, decls, selfInfo)

override def toString: String = s"TempClassInfo($prefix, $cls)"
}

object ClassInfo {
def apply(prefix: Type, cls: ClassSymbol, classParents: List[Type], decls: Scope, selfInfo: TypeOrSymbol = NoType)(using Context): ClassInfo =
unique(new CachedClassInfo(prefix, cls, classParents, decls, selfInfo))
def apply(prefix: Type, cls: ClassSymbol, declaredParents: List[Type], decls: Scope, selfInfo: TypeOrSymbol = NoType)(using Context): ClassInfo =
unique(new CachedClassInfo(prefix, cls, declaredParents, decls, selfInfo))
}

/** Type bounds >: lo <: hi */
Expand Down Expand Up @@ -5276,7 +5277,7 @@ object Types {
protected def mapFullClassInfo(tp: ClassInfo): ClassInfo =
tp.derivedClassInfo(
prefix = this(tp.prefix),
classParents = tp.classParents.mapConserve(this),
declaredParents = tp.declaredParents.mapConserve(this),
selfInfo = tp.selfInfo match {
case tp: Type => this(tp)
case sym => sym
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ object PickledQuotes {
class ReplaceSplicedTyped extends TypeMap() {
override def apply(tp: Type): Type = tp match {
case tp: ClassInfo =>
tp.derivedClassInfo(classParents = tp.classParents.map(apply))
tp.derivedClassInfo(declaredParents = tp.declaredParents.map(apply))
case tp: TypeRef =>
typeSpliceMap.get(tp.symbol) match
case Some(t) if tp.typeSymbol.hasAnnotation(defn.QuotedRuntime_SplicedTypeAnnot) => mapOver(t)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ object FromSymbol {
newSymbol(cls, nme.CONSTRUCTOR, EmptyFlags, NoType)
)
val constr = tpd.DefDef(constrSym.asTerm)
val parents = cls.classParents.map(tpd.TypeTree(_))
val parents = cls.info.parents.map(tpd.TypeTree(_))
val body = cls.unforcedDecls.filter(!_.isPrimaryConstructor).map(s => definitionFromSym(s))
tpd.ClassDefWithParents(cls, constr, parents, body)
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ class CheckReentrant extends MiniPhase {
scanning(sym) {
sym.info.widenExpr.classSymbols.foreach(addVars)
}
for (parent <- cls.classInfo.classParents)
addVars(parent.classSymbol.asClass)
for (parent <- cls.parentSyms)
addVars(parent.asClass)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ class ElimPolyFunction extends MiniPhase with DenotTransformer {
case ref: ClassDenotation if ref.symbol != defn.PolyFunctionClass && ref.derivesFrom(defn.PolyFunctionClass) =>
val cinfo = ref.classInfo
val newParent = functionTypeOfPoly(cinfo)
val newParents = cinfo.classParents.map(parent =>
val newParents = cinfo.declaredParents.map(parent =>
if (parent.typeSymbol == defn.PolyFunctionClass)
newParent
else
parent
)
ref.copySymDenotation(info = cinfo.derivedClassInfo(classParents = newParents))
ref.copySymDenotation(info = cinfo.derivedClassInfo(declaredParents = newParents))
case _ =>
ref
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ class PickleQuotes extends MacroTransform {
apply(tp.dealias)
case tp @ TypeRef(pre, _) if pre == NoPrefix || pre.termSymbol.isLocal =>
val hiBound = tp.typeSymbol.info match
case info @ ClassInfo(_, _, classParents, _, _) => classParents.reduce(_ & _)
case info: ClassInfo => info.parents.reduce(_ & _)
case info => info.hiBound
apply(hiBound)
case tp =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
lazy val accessors =
if (isDerivedValueClass(clazz)) clazz.paramAccessors.take(1) // Tail parameters can only be `erased`
else clazz.caseAccessors
val isEnumValue = clazz.isAnonymousClass && clazz.classParents.head.classSymbol.is(Enum)
val isEnumValue = clazz.isAnonymousClass && clazz.info.parents.head.classSymbol.is(Enum)
val isSimpleEnumValue = isEnumValue && !clazz.owner.isAllOf(EnumCase)
val isJavaEnumValue = isEnumValue && clazz.derivesFrom(defn.JavaEnumClass)
val isNonJavaEnumValue = isEnumValue && !isJavaEnumValue
Expand Down Expand Up @@ -428,7 +428,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {

/** Is this an anonymous class deriving from an enum definition? */
extension (cls: ClassSymbol) private def isEnumValueImplementation(using Context): Boolean =
cls.isAnonymousClass && cls.classParents.head.typeSymbol.is(Enum) // asserted in Typer
cls.isAnonymousClass && cls.info.parents.head.typeSymbol.is(Enum) // asserted in Typer

/** If this is the class backing a serializable singleton enum value with base class `MyEnum`,
* and not deriving from `java.lang.Enum` add the method:
Expand Down Expand Up @@ -546,7 +546,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
newParents = newParents :+ TypeTree(parent)
val oldClassInfo = clazz.classInfo
val newClassInfo = oldClassInfo.derivedClassInfo(
classParents = oldClassInfo.classParents :+ parent)
declaredParents = oldClassInfo.declaredParents :+ parent)
clazz.copySymDenotation(info = newClassInfo).installAfter(thisPhase)
}
def addMethod(name: TermName, info: Type, cls: Symbol, body: (Symbol, Tree) => Context ?=> Tree): Unit = {
Expand Down
15 changes: 6 additions & 9 deletions compiler/src/dotty/tools/dotc/transform/init/Summarization.scala
Original file line number Diff line number Diff line change
Expand Up @@ -335,16 +335,13 @@ object Summarization {
}

if (cls.defTree.isEmpty)
cls.info match {
case cinfo: ClassInfo =>
val source = {
implicit val ctx2: Context = theCtx.withSource(cls.source(using theCtx))
TypeTree(cls.typeRef).withSpan(cls.span)
}
val source = {
implicit val ctx2: Context = theCtx.withSource(cls.source(using theCtx))
TypeTree(cls.typeRef).withSpan(cls.span)
}

val parentOuter = cinfo.classParents.map { extractParentOuters(_, source) }.toMap
ClassSummary(cls, parentOuter)
}
val parentOuter = cls.info.parents.map { extractParentOuters(_, source) }.toMap
ClassSummary(cls, parentOuter)
else {
val tpl = cls.defTree.asInstanceOf[TypeDef]
val parents = tpl.rhs.asInstanceOf[Template].parents
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ class PrepJSInterop extends MacroTransform with IdentityDenotTransformer { thisP

/** Performs checks and rewrites specific to classes / objects extending `js.Any`. */
private def transformJSClassDef(classDef: TypeDef)(using Context): Tree = {
val sym = classDef.symbol
val sym = classDef.symbol.asClass
val isJSNative = sym.hasAnnotation(jsdefn.JSNativeAnnot)

sym.addAnnotation(jsdefn.JSTypeAnnot)
Expand All @@ -315,8 +315,8 @@ class PrepJSInterop extends MacroTransform with IdentityDenotTransformer { thisP
}

// Check the parents
for (parent <- sym.info.parents) {
parent.typeSymbol match {
for (parentSym <- sym.parentSyms) {
parentSym match {
case parentSym if parentSym == defn.ObjectClass =>
// AnyRef is valid, except for non-native JS classes and objects
if (!isJSNative && !sym.is(Trait)) {
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -576,8 +576,8 @@ object Checking {
}
tp.derivedClassInfo(
prefix = apply(tp.prefix),
classParents =
tp.parents.map(p => transformedParent(apply(p)))
declaredParents =
tp.declaredParents.map(p => transformedParent(apply(p)))
)
case _ =>
mapOver(tp)
Expand Down Expand Up @@ -1180,7 +1180,7 @@ trait Checking {
report.error(i"enum case does not extend its enum $enumCls", enumCase.srcPos)
cls.info match
case info: ClassInfo =>
cls.info = info.derivedClassInfo(classParents = enumCls.typeRefApplied :: info.classParents)
cls.info = info.derivedClassInfo(declaredParents = enumCls.typeRefApplied :: info.declaredParents)
case _ =>

val enumCase =
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ class Namer { typer: Typer =>
alt != denot.symbol && alt.info.matchesLoosely(denot.info))

def inheritsConcreteMember =
denot.owner.asClass.classParents.exists(parent =>
denot.owner.asClass.info.parents.exists(parent =>
parent.member(denot.name).hasAltWith(sd =>
!sd.symbol.is(Deferred) && sd.matches(denot)))

Expand Down Expand Up @@ -809,7 +809,7 @@ class Namer { typer: Typer =>

if denot.isClass && !sym.isEnumAnonymClass && !sym.isRefinementClass then
val child = if (denot.is(Module)) denot.sourceModule else denot.symbol
denot.asClass.classParents.foreach { parent => register(child, parent.classSymbol.asClass) }
denot.info.parents.foreach { parent => register(child, parent.classSymbol.asClass) }
else if denot.is(CaseVal, butNot = Method | Module) then
assert(denot.is(Enum), denot)
denot.info.classSymbols.foreach { parent => register(denot.symbol, parent) }
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,14 @@ object RefChecks {
report.error(DoesNotConformToSelfType(category, cinfo.selfType, cls, otherSelf, relation, other),
cls.srcPos)
}
val parents = cinfo.classParents
for (parent <- parents)
checkSelfConforms(parent.classSymbol.asClass, "illegal inheritance", "parent")
val psyms = cls.asClass.parentSyms
for (psym <- psyms)
checkSelfConforms(psym.asClass, "illegal inheritance", "parent")
for (reqd <- cinfo.cls.givenSelfType.classSymbols)
checkSelfConforms(reqd, "missing requirement", "required")

def isClassExtendingJavaEnum =
!cls.isOneOf(Enum | Trait) && parents.exists(_.classSymbol == defn.JavaEnumClass)
!cls.isOneOf(Enum | Trait) && psyms.contains(defn.JavaEnumClass)

// Prevent wrong `extends` of java.lang.Enum
if isClassExtendingJavaEnum then
Expand Down
Loading