diff options
author | Martin Odersky <odersky@gmail.com> | 2015-03-05 13:22:00 +0100 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2015-03-18 11:14:15 +0100 |
commit | 321563940dee1716c19600efd57acb9ed83a7687 (patch) | |
tree | 9053dfcff007d16ceb6dbaa7256889455a7a07a7 /src/dotty/tools | |
parent | 7fd242f2f1b1d2f536e73ec0fdb92a34b27b2a89 (diff) | |
download | dotty-321563940dee1716c19600efd57acb9ed83a7687.tar.gz dotty-321563940dee1716c19600efd57acb9ed83a7687.tar.bz2 dotty-321563940dee1716c19600efd57acb9ed83a7687.zip |
Compute PureInterface flag after pickling.
ElimLocals becomes a slightly less trivial transform: NormalizeFlags.
It also computes PureInterface flag, thus relieving Namer and Unpickler
from doing the same in two different ways. Besides, the computation in
Namer/TreeInfo was flawed because it did not take into account that
nested non-static classes are not allowed in an interface (only static
classes are, but these would not be members of the interface in the Scala
sense).
Diffstat (limited to 'src/dotty/tools')
-rw-r--r-- | src/dotty/tools/dotc/Compiler.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeInfo.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala | 27 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/ElimLocals.scala | 22 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/NormalizeFlags.scala | 30 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 6 |
6 files changed, 46 insertions, 52 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index dea619a52..e051e16c8 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -44,7 +44,7 @@ class Compiler { List(new Pickler), // Pickler needs to come last in a group since it should not pickle trees generated later List(new RefChecks, new ElimRepeated, - new ElimLocals, + new NormalizeFlags, new ExtensionMethods), List(new TailRec), // TailRec needs to be in its own group for now. // Otherwise it produces -Ycheck incorrect code for diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index 5338297e8..0abd25f51 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -24,19 +24,14 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => case _ => false } - /** Is tree legal as a member definition of an interface? + /** Does tree contain an initialization part when seen as a member of a class or trait? */ - def isPureInterfaceMember(tree: Tree): Boolean = unsplice(tree) match { + def isNoInitMember(tree: Tree): Boolean = unsplice(tree) match { case EmptyTree | Import(_, _) | TypeDef(_, _) => true - case defn: ValOrDefDef => defn.unforcedRhs == EmptyTree + case tree: ValDef => tree.unforcedRhs == EmptyTree case _ => false } - /** Is tree legal as a member definition of a no-init trait? - */ - def isNoInitMember(tree: Tree): Boolean = - isPureInterfaceMember(tree) || unsplice(tree).isInstanceOf[DefDef] - def isOpAssign(tree: Tree) = unsplice(tree) match { case Apply(fn, _ :: Nil) => unsplice(fn) match { diff --git a/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala b/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala index 4890e14ef..7b2a8fdc4 100644 --- a/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala @@ -286,9 +286,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, roots: Set[ } /** Create symbol of definition node and enter in symAtAddr map - * @return flag set over PureInterface | NoInits according to form of definition + * @return true iff the definition does not contain initialization code */ - def createSymbol()(implicit ctx: Context): FlagSet = { + def createSymbol()(implicit ctx: Context): Boolean = { val start = currentAddr val tag = readByte() val end = readEnd() @@ -340,11 +340,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, roots: Set[ completer.withDecls(newScope) forkAt(templateStart).indexTemplateParams()(localContext(sym)) } - - var resultFlags: FlagSet = EmptyFlags - if (tag != VALDEF || rhsIsEmpty) resultFlags |= NoInits - if (tag != VALDEF && tag != DEFDEF || rhsIsEmpty) resultFlags |= PureInterface - resultFlags + tag != VALDEF || rhsIsEmpty } /** Read modifier list into triplet of flags, annotations and a privateWithin @@ -409,18 +405,18 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, roots: Set[ /** Create symbols for a definitions in statement sequence between * current address and `end`. - * @return flag set over PureInterface | NoInits according to forms of statements + * @return true iff none of the statements contains initialization code */ - def indexStats(end: Addr)(implicit ctx: Context): FlagSet = { - val statFlags = + def indexStats(end: Addr)(implicit ctx: Context): Boolean = { + val noInitss = until(end) { nextByte match { case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM => createSymbol() - case EMPTYTREE | IMPORT => skipTree(); PureInterface | NoInits - case _ => skipTree(); EmptyFlags + case EMPTYTREE | IMPORT => skipTree(); true + case _ => skipTree(); false } } - ((PureInterface | NoInits) /: statFlags) (_ & _) + noInitss.forall(_ == true) } /** Create symbols the longest consecutive sequence of parameters with given @@ -506,7 +502,6 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, roots: Set[ setClsInfo( ctx.normalizeToClassRefs(impl.parents.map(_.tpe), cls, cls.unforcedDecls), if (impl.self.isEmpty) NoType else impl.self.tpt.tpe) - if (!cls.is(Trait)) cls.resetFlag(PureInterface) ta.assignType(untpd.TypeDef(sym.name.asTypeName, impl), sym) } else { @@ -549,8 +544,8 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, roots: Set[ untpd.ValDef(readName(), readTpt(), EmptyTree).withType(NoType) } else EmptyValDef - val additionalFlags = fork.indexStats(end) // PureInterface or NoInits - cls.setFlag(additionalFlags) // PureInterface will be reset later if cls is not a trait + val noInits = fork.indexStats(end) + if (noInits) cls.setFlag(NoInits) val constr = readIndexedDef().asInstanceOf[DefDef] def mergeTypeParamsAndAliases(tparams: List[TypeDef], stats: List[Tree]): (List[Tree], List[Tree]) = diff --git a/src/dotty/tools/dotc/transform/ElimLocals.scala b/src/dotty/tools/dotc/transform/ElimLocals.scala deleted file mode 100644 index d18ad0288..000000000 --- a/src/dotty/tools/dotc/transform/ElimLocals.scala +++ /dev/null @@ -1,22 +0,0 @@ -package dotty.tools.dotc -package transform - -import core._ -import DenotTransformers.SymTransformer -import Phases.Phase -import Contexts.Context -import SymDenotations.SymDenotation -import TreeTransforms.MiniPhaseTransform -import Flags.Local - -/** Widens all private[this] and protected[this] qualifiers to just private/protected */ -class ElimLocals extends MiniPhaseTransform with SymTransformer { thisTransformer => - override def phaseName = "elimLocals" - - def transformSym(ref: SymDenotation)(implicit ctx: Context) = - dropLocal(ref) - - private def dropLocal(ref: SymDenotation)(implicit ctx: Context) = - if (ref.flags is Local) ref.copySymDenotation(initFlags = ref.flags &~ Local) - else ref -} diff --git a/src/dotty/tools/dotc/transform/NormalizeFlags.scala b/src/dotty/tools/dotc/transform/NormalizeFlags.scala new file mode 100644 index 000000000..fce2c3317 --- /dev/null +++ b/src/dotty/tools/dotc/transform/NormalizeFlags.scala @@ -0,0 +1,30 @@ +package dotty.tools.dotc +package transform + +import core._ +import DenotTransformers.SymTransformer +import Phases.Phase +import Contexts.Context +import SymDenotations.SymDenotation +import TreeTransforms.MiniPhaseTransform +import Flags._, Symbols._ + +/** 1. Widens all private[this] and protected[this] qualifiers to just private/protected + * 2. Sets PureInterface flag for traits that only have pure interface members and that + * do not have initialization code. A pure interface member is either an abstract + * or alias type definition or a deferred val or def. + */ +class NormalizeFlags extends MiniPhaseTransform with SymTransformer { thisTransformer => + override def phaseName = "elimLocals" + + def transformSym(ref: SymDenotation)(implicit ctx: Context) = { + var newFlags = ref.flags &~ Local + if (ref.is(NoInitsTrait) && ref.info.decls.forall(isPureInterfaceMember)) + newFlags |= PureInterface + if (newFlags != ref.flags) ref.copySymDenotation(initFlags = newFlags) + else ref + } + + private def isPureInterfaceMember(sym: Symbol)(implicit ctx: Context) = + if (sym.isTerm) sym.is(Deferred) else !sym.isClass +} diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 04f648c00..708fb06c1 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -523,11 +523,7 @@ class Namer { typer: Typer => index(rest)(inClassContext(selfInfo)) denot.info = ClassInfo(cls.owner.thisType, cls, parentRefs, decls, selfInfo) - if (impl.body forall isNoInitMember) { - cls.setFlag(NoInits) - if (cls.is(Trait) && impl.body.forall(isPureInterfaceMember)) - cls.setFlag(PureInterface) - } + if (impl.body forall isNoInitMember) cls.setFlag(NoInits) } } |