Skip to content

Commit 4eb1072

Browse files
committed
Produce PureInterface flag together with NoInits flag
The previous stale symbol was discovered because NormalizeFlags looks at all declarations of a MoInits trait in the SymTransformer. I.e it does this for all no-init traits, whether loaded from a classfile or currently compiled. This is wasteful because it forces too many definitions. The new scheme drops the scan in favor of producing PureInterface together with NoInits. PureInterface is already read as a flag from Java snd Scala2 classfiles. For source and Tasty it is now generated as members are indexed.
1 parent d25497a commit 4eb1072

File tree

5 files changed

+45
-24
lines changed

5 files changed

+45
-24
lines changed

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

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Names._, StdNames._, NameOps._, Decorators._, Symbols._
88
import util.HashSet
99

1010
trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
11+
import TreeInfo._
1112

1213
// Note: the <: Type constraint looks necessary (and is needed to make the file compile in dotc).
1314
// But Scalac accepts the program happily without it. Need to find out why.
@@ -26,10 +27,12 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
2627

2728
/** Does tree contain an initialization part when seen as a member of a class or trait?
2829
*/
29-
def isNoInitMember(tree: Tree): Boolean = unsplice(tree) match {
30-
case EmptyTree | Import(_, _) | TypeDef(_, _) | DefDef(_, _, _, _, _) => true
31-
case tree: ValDef => tree.unforcedRhs == EmptyTree
32-
case _ => false
30+
def defKind(tree: Tree): DefKind = unsplice(tree) match {
31+
case EmptyTree | _: Import => InterfaceDef
32+
case tree: TypeDef => if (tree.isClassDef) NoInitDef else InterfaceDef
33+
case tree: DefDef => if (tree.unforcedRhs == EmptyTree) InterfaceDef else NoInitDef
34+
case tree: ValDef => if (tree.unforcedRhs == EmptyTree) InterfaceDef else GeneralDef
35+
case _ => GeneralDef
3336
}
3437

3538
def isOpAssign(tree: Tree) = unsplice(tree) match {
@@ -272,6 +275,7 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
272275
}
273276

274277
trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
278+
import TreeInfo._
275279

276280
/** The purity level of this statement.
277281
* @return pure if statement has no side effects
@@ -510,15 +514,27 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
510514
case nil =>
511515
Nil
512516
}
517+
}
518+
519+
object TreeInfo {
513520

514-
private class PurityLevel(val x: Int) {
521+
class PurityLevel(val x: Int) extends AnyVal {
515522
def >= (that: PurityLevel) = x >= that.x
516523
def min(that: PurityLevel) = new PurityLevel(x min that.x)
517524
}
518525

519-
private val Pure = new PurityLevel(2)
520-
private val Idempotent = new PurityLevel(1)
521-
private val Impure = new PurityLevel(0)
526+
val Pure = new PurityLevel(2)
527+
val Idempotent = new PurityLevel(1)
528+
val Impure = new PurityLevel(0)
529+
530+
case class DefKind(val x: Int) extends AnyVal {
531+
def >= (that: DefKind) = x >= that.x
532+
def min(that: DefKind) = new DefKind(x min that.x)
533+
}
534+
535+
val InterfaceDef = new DefKind(2)
536+
val NoInitDef = new DefKind(1)
537+
val GeneralDef = new DefKind(0)
522538
}
523539

524540
/** a Match(Typed(_, tpt), _) must be translated into a switch if isSwitchAnnotation(tpt.tpe)

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ object SymDenotations {
115115
/** Unset given flags(s) of this denotation */
116116
final def resetFlag(flags: FlagSet): Unit = { myFlags &~= flags }
117117

118+
final def setFlagsFromDefKind(kind: TreeInfo.DefKind): Unit =
119+
if (kind >= TreeInfo.NoInitDef) {
120+
setFlag(NoInits)
121+
if (kind == TreeInfo.InterfaceDef && myFlags.is(Trait)) setFlag(PureInterface)
122+
}
123+
118124
/** Has this denotation one of the flags in `fs` set? */
119125
final def is(fs: FlagSet)(implicit ctx: Context) = {
120126
(if (fs <= FromStartFlags) myFlags else flags) is fs

src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ package tasty
66
import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._
77
import StdNames._, Denotations._, Flags._, Constants._, Annotations._
88
import util.Positions._
9-
import dotty.tools.dotc.ast.{tpd, Trees, untpd}
9+
import ast.{tpd, Trees, untpd}
10+
import ast.TreeInfo._
1011
import Trees._
1112
import Decorators._
1213
import TastyUnpickler._, TastyBuffer._, PositionPickler._
@@ -352,7 +353,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
352353
/** Create symbol of definition node and enter in symAtAddr map
353354
* @return true iff the definition does not contain initialization code
354355
*/
355-
def createSymbol()(implicit ctx: Context): Boolean = {
356+
def createSymbol()(implicit ctx: Context): DefKind = {
356357
val start = currentAddr
357358
val tag = readByte()
358359
val end = readEnd()
@@ -408,7 +409,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
408409
sym.completer.withDecls(newScope)
409410
forkAt(templateStart).indexTemplateParams()(localContext(sym))
410411
}
411-
tag != VALDEF || rhsIsEmpty
412+
if (isClass) NoInitDef
413+
else if (sym.isType || sym.isConstructor || flags.is(Deferred)) InterfaceDef
414+
else if (tag == VALDEF) GeneralDef
415+
else NoInitDef
412416
}
413417

414418
/** Read modifier list into triplet of flags, annotations and a privateWithin
@@ -474,23 +478,23 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
474478
* current address and `end`.
475479
* @return true iff none of the statements contains initialization code
476480
*/
477-
def indexStats(end: Addr)(implicit ctx: Context): Boolean = {
478-
val noInitss =
481+
def indexStats(end: Addr)(implicit ctx: Context): DefKind = {
482+
val defKinds =
479483
until(end) {
480484
nextByte match {
481485
case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM =>
482486
createSymbol()
483487
case IMPORT =>
484488
skipTree()
485-
true
489+
InterfaceDef
486490
case PACKAGE =>
487491
processPackage { (pid, end) => implicit ctx => indexStats(end) }
488492
case _ =>
489493
skipTree()
490-
false
494+
GeneralDef
491495
}
492496
}
493-
noInitss.forall(_ == true)
497+
(InterfaceDef /: defKinds)(_ min _)
494498
}
495499

496500
/** Process package with given operation `op`. The operation takes as arguments
@@ -631,8 +635,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
631635
}
632636
else EmptyValDef
633637
setClsInfo(parentRefs, if (self.isEmpty) NoType else self.tpt.tpe)
634-
val noInits = fork.indexStats(end)
635-
if (noInits) cls.setFlag(NoInits)
638+
cls.setFlagsFromDefKind(fork.indexStats(end))
636639
val constr = readIndexedDef().asInstanceOf[DefDef]
637640

638641
def mergeTypeParamsAndAliases(tparams: List[TypeDef], stats: List[Tree]): (List[Tree], List[Tree]) =

src/dotty/tools/dotc/transform/NormalizeFlags.scala

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,7 @@ class NormalizeFlags extends MiniPhaseTransform with SymTransformer { thisTransf
1919

2020
def transformSym(ref: SymDenotation)(implicit ctx: Context) = {
2121
var newFlags = ref.flags &~ Local
22-
if (ref.is(NoInitsTrait) && ref.info.decls.forall(isPureInterfaceMember))
23-
newFlags |= PureInterface
2422
if (newFlags != ref.flags) ref.copySymDenotation(initFlags = newFlags)
2523
else ref
2624
}
27-
28-
private def isPureInterfaceMember(sym: Symbol)(implicit ctx: Context) =
29-
if (sym.isTerm) sym.is(Deferred) else !sym.isClass
3025
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,8 @@ class Namer { typer: Typer =>
563563

564564
index(rest)(inClassContext(selfInfo))
565565
denot.info = ClassInfo(cls.owner.thisType, cls, parentRefs, decls, selfInfo)
566-
if (impl.body forall isNoInitMember) cls.setFlag(NoInits)
566+
cls.setFlagsFromDefKind(
567+
(TreeInfo.InterfaceDef /: impl.body)((kind, stat) => kind min defKind(stat)))
567568
}
568569
}
569570

0 commit comments

Comments
 (0)