Skip to content

Commit b84d17d

Browse files
committed
Check baseclasses when determining purity of class
A class is pure for the purpose of reducing projections in inlinig if none of its baseclasses has an initializer. To make this robust wrt compilation order, we need to move computation of NoInits flags from Typer to the class completer. # Conflicts: # compiler/src/dotty/tools/dotc/typer/Inliner.scala
1 parent 42698ae commit b84d17d

File tree

5 files changed

+22
-15
lines changed

5 files changed

+22
-15
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,17 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
240240
case y => y
241241
}
242242

243+
/** The largest subset of {NoInits, PureInterface} that a
244+
* trait enclosing this statement can have as flags.
245+
*/
246+
def defKind(tree: Tree): FlagSet = unsplice(tree) match {
247+
case EmptyTree | _: Import => NoInitsInterface
248+
case tree: TypeDef => if (tree.isClassDef) NoInits else NoInitsInterface
249+
case tree: DefDef => if (tree.unforcedRhs == EmptyTree) NoInitsInterface else NoInits
250+
case tree: ValDef => if (tree.unforcedRhs == EmptyTree) NoInitsInterface else EmptyFlags
251+
case _ => EmptyFlags
252+
}
253+
243254
/** Checks whether predicate `p` is true for all result parts of this expression,
244255
* where we zoom into Ifs, Matches, and Blocks.
245256
*/
@@ -623,17 +634,6 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
623634
accum(Nil, root)
624635
}
625636

626-
/** The largest subset of {NoInits, PureInterface} that a
627-
* trait enclosing this statement can have as flags.
628-
*/
629-
def defKind(tree: Tree): FlagSet = unsplice(tree) match {
630-
case EmptyTree | _: Import => NoInitsInterface
631-
case tree: TypeDef => if (tree.isClassDef) NoInits else NoInitsInterface
632-
case tree: DefDef => if (tree.unforcedRhs == EmptyTree) NoInitsInterface else NoInits
633-
case tree: ValDef => if (tree.unforcedRhs == EmptyTree) NoInitsInterface else EmptyFlags
634-
case _ => EmptyFlags
635-
}
636-
637637
/** The top level classes in this tree, including only those module classes that
638638
* are not a linked class of some other class in the result.
639639
*/

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ class Definitions {
5555
ctx.newSymbol(owner, name, flags | Permanent, info)
5656

5757
private def newClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, infoFn: ClassSymbol => Type) =
58-
ctx.newClassSymbol(owner, name, flags | Permanent, infoFn)
58+
ctx.newClassSymbol(owner, name, flags | Permanent | NoInits, infoFn)
5959

6060
private def enterCompleteClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, parents: List[TypeRef], decls: Scope = newScope) =
61-
ctx.newCompleteClassSymbol(owner, name, flags | Permanent, parents, decls).entered
61+
ctx.newCompleteClassSymbol(owner, name, flags | Permanent | NoInits, parents, decls).entered
6262

6363
private def enterTypeField(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
6464
scope.enter(newSymbol(cls, name, flags, TypeBounds.empty))
@@ -275,6 +275,7 @@ class Definitions {
275275
val cls = ctx.requiredClass("java.lang.Object")
276276
assert(!cls.isCompleted, "race for completing java.lang.Object")
277277
cls.info = ClassInfo(cls.owner.thisType, cls, AnyClass.typeRef :: Nil, newScope)
278+
cls.setFlag(NoInits)
278279

279280
// The companion object doesn't really exist, `NoType` is the general
280281
// technique to do that. Here we need to set it before completing

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,12 @@ object SymDenotations {
599599
final def isStable(implicit ctx: Context) =
600600
isType || !is(Erased) && (is(Stable) || !(is(UnstableValue) || info.isInstanceOf[ExprType]))
601601

602+
/** Is this a denotation of a class that does not have - either direct or inherited -
603+
* initaliazion code?
604+
*/
605+
def isNoInitsClass(implicit ctx: Context) =
606+
isClass && asClass.baseClasses.forall(_.is(NoInits))
607+
602608
/** Is this a "real" method? A real method is a method which is:
603609
* - not an accessor
604610
* - not a label

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,8 @@ class Namer { typer: Typer =>
991991
if (isDerivedValueClass(cls)) cls.setFlag(Final)
992992
cls.info = avoidPrivateLeaks(cls, cls.pos)
993993
cls.baseClasses.foreach(_.invalidateBaseTypeCache()) // we might have looked before and found nothing
994+
cls.setNoInitsFlags((NoInitsInterface /: impl.body) ((fs, stat) => fs & untpd.defKind(stat)))
995+
if (cls.isNoInitsClass) cls.primaryConstructor.setFlag(Stable)
994996
}
995997
}
996998

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,8 +1534,6 @@ class Typer extends Namer
15341534
val dummy = localDummy(cls, impl)
15351535
val body1 = addAccessorDefs(cls,
15361536
typedStats(impl.body, dummy)(ctx.inClassContext(self1.symbol)))
1537-
if (!ctx.isAfterTyper)
1538-
cls.setNoInitsFlags((NoInitsInterface /: body1) ((fs, stat) => fs & defKind(stat)))
15391537

15401538
// Expand comments and type usecases if `-Ycook-comments` is set.
15411539
if (ctx.settings.YcookComments.value) {

0 commit comments

Comments
 (0)