diff options
Diffstat (limited to 'src/dotty')
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeInfo.scala | 26 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Flags.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 9 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Symbols.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 28 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/ExpandSAMs.scala | 17 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/NormalizeFlags.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 3 |
9 files changed, 55 insertions, 39 deletions
diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index 6401c01c1..c9a22f09e 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -8,6 +8,7 @@ import Names._, StdNames._, NameOps._, Decorators._, Symbols._ import util.HashSet trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => + import TreeInfo._ // Note: the <: Type constraint looks necessary (and is needed to make the file compile in dotc). // But Scalac accepts the program happily without it. Need to find out why. @@ -24,12 +25,16 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => case _ => false } - /** Does tree contain an initialization part when seen as a member of a class or trait? + /** The largest subset of {NoInits, PureInterface} that a + * trait enclosing this statement can have as flags. + * Does tree contain an initialization part when seen as a member of a class or trait? */ - def isNoInitMember(tree: Tree): Boolean = unsplice(tree) match { - case EmptyTree | Import(_, _) | TypeDef(_, _) | DefDef(_, _, _, _, _) => true - case tree: ValDef => tree.unforcedRhs == EmptyTree - case _ => false + def defKind(tree: Tree): FlagSet = unsplice(tree) match { + case EmptyTree | _: Import => NoInitsInterface + case tree: TypeDef => if (tree.isClassDef) NoInits else NoInitsInterface + case tree: DefDef => if (tree.unforcedRhs == EmptyTree) NoInitsInterface else NoInits + case tree: ValDef => if (tree.unforcedRhs == EmptyTree) NoInitsInterface else EmptyFlags + case _ => EmptyFlags } def isOpAssign(tree: Tree) = unsplice(tree) match { @@ -272,6 +277,7 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] } trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => + import TreeInfo._ /** The purity level of this statement. * @return pure if statement has no side effects @@ -510,15 +516,17 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => case nil => Nil } +} - private class PurityLevel(val x: Int) { +object TreeInfo { + class PurityLevel(val x: Int) extends AnyVal { def >= (that: PurityLevel) = x >= that.x def min(that: PurityLevel) = new PurityLevel(x min that.x) } - private val Pure = new PurityLevel(2) - private val Idempotent = new PurityLevel(1) - private val Impure = new PurityLevel(0) + val Pure = new PurityLevel(2) + val Idempotent = new PurityLevel(1) + val Impure = new PurityLevel(0) } /** a Match(Typed(_, tpt), _) must be translated into a switch if isSwitchAnnotation(tpt.tpe) diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index 3efadcb00..759dff0d4 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -467,6 +467,8 @@ object Flags { /** Pure interfaces always have these flags */ final val PureInterfaceCreationFlags = Trait | NoInits | PureInterface + final val NoInitsInterface = NoInits | PureInterface + /** The flags of the self symbol */ final val SelfSymFlags = Private | Local | Deferred diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 17d80eb03..9db75ee94 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -40,7 +40,7 @@ trait SymDenotations { this: Context => } def stillValid(denot: SymDenotation): Boolean = - if (denot is ValidForever) true + if (denot.is(ValidForever) || denot.isRefinementClass) true else { val initial = denot.initial if (initial ne denot) @@ -49,6 +49,7 @@ trait SymDenotations { this: Context => val owner = denot.owner.denot stillValid(owner) && ( !owner.isClass + || owner.isRefinementClass || (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol) || denot.isSelfSym) } catch { @@ -115,6 +116,12 @@ object SymDenotations { /** Unset given flags(s) of this denotation */ final def resetFlag(flags: FlagSet): Unit = { myFlags &~= flags } + /** Set applicable flags from `flags` which is a subset of {NoInits, PureInterface} */ + final def setApplicableFlags(flags: FlagSet): Unit = { + val mask = if (myFlags.is(Trait)) NoInitsInterface else NoInits + setFlag(flags & mask) + } + /** Has this denotation one of the flags in `fs` set? */ final def is(fs: FlagSet)(implicit ctx: Context) = { (if (fs <= FromStartFlags) myFlags else flags) is fs diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index 0478b1b7b..602bdba80 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -408,7 +408,7 @@ object Symbols { /** Subclass tests and casts */ final def isTerm(implicit ctx: Context): Boolean = (if(isDefinedInCurrentRun) lastDenot else denot).isTerm - + final def isType(implicit ctx: Context): Boolean = (if(isDefinedInCurrentRun) lastDenot else denot).isType diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index d4260e679..683b3be22 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -6,7 +6,7 @@ package tasty import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._ import StdNames._, Denotations._, Flags._, Constants._, Annotations._ import util.Positions._ -import dotty.tools.dotc.ast.{tpd, Trees, untpd} +import ast.{tpd, Trees, untpd} import Trees._ import Decorators._ import TastyUnpickler._, TastyBuffer._, PositionPickler._ @@ -352,9 +352,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { } /** Create symbol of definition node and enter in symAtAddr map - * @return true iff the definition does not contain initialization code + * @return the largest subset of {NoInits, PureInterface} that a + * trait owning this symbol can have as flags. */ - def createSymbol()(implicit ctx: Context): Boolean = { + def createSymbol()(implicit ctx: Context): FlagSet = { val start = currentAddr val tag = readByte() val end = readEnd() @@ -410,7 +411,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { sym.completer.withDecls(newScope) forkAt(templateStart).indexTemplateParams()(localContext(sym)) } - tag != VALDEF || rhsIsEmpty + if (isClass) NoInits + else if (sym.isType || sym.isConstructor || flags.is(Deferred)) NoInitsInterface + else if (tag == VALDEF) EmptyFlags + else NoInits } /** Read modifier list into triplet of flags, annotations and a privateWithin @@ -474,25 +478,26 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { /** Create symbols for a definitions in statement sequence between * current address and `end`. - * @return true iff none of the statements contains initialization code + * @return the largest subset of {NoInits, PureInterface} that a + * trait owning the indexed statements can have as flags. */ - def indexStats(end: Addr)(implicit ctx: Context): Boolean = { - val noInitss = + def indexStats(end: Addr)(implicit ctx: Context): FlagSet = { + val flagss = until(end) { nextByte match { case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM => createSymbol() case IMPORT => skipTree() - true + NoInitsInterface case PACKAGE => processPackage { (pid, end) => implicit ctx => indexStats(end) } case _ => skipTree() - false + EmptyFlags } } - noInitss.forall(_ == true) + (NoInitsInterface /: flagss)(_ & _) } /** Process package with given operation `op`. The operation takes as arguments @@ -633,8 +638,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { } else EmptyValDef setClsInfo(parentRefs, if (self.isEmpty) NoType else self.tpt.tpe) - val noInits = fork.indexStats(end) - if (noInits) cls.setFlag(NoInits) + cls.setApplicableFlags(fork.indexStats(end)) val constr = readIndexedDef().asInstanceOf[DefDef] def mergeTypeParamsAndAliases(tparams: List[TypeDef], stats: List[Tree]): (List[Tree], List[Tree]) = diff --git a/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala b/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala index aa1fd9a90..b080a97b6 100644 --- a/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala +++ b/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala @@ -220,7 +220,7 @@ object PickleBuffer { DEFERRED_PKL -> Deferred, FINAL_PKL -> Final, METHOD_PKL -> Method, - INTERFACE_PKL -> PureInterface, + INTERFACE_PKL -> NoInitsInterface, MODULE_PKL -> Module, IMPLICIT_PKL -> Implicit, SEALED_PKL -> Sealed, diff --git a/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 2416e4624..1650a244d 100644 --- a/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -25,20 +25,19 @@ class ExpandSAMs extends MiniPhaseTransform { thisTransformer => import ast.tpd._ - def noJvmSam(cls: ClassSymbol)(implicit ctx: Context): Boolean = - !cls.is(Trait) || - cls.superClass != defn.ObjectClass || - !cls.is(NoInits) || - !cls.directlyInheritedTraits.forall(_.is(NoInits)) || - ExplicitOuter.needsOuterIfReferenced(cls) || - cls.typeRef.fields.nonEmpty // Superaccessors already show up as abstract methods here, so no test necessary - + /** Is SAMType `cls` also a SAM under the rules of the JVM? */ + def isJvmSam(cls: ClassSymbol)(implicit ctx: Context): Boolean = + cls.is(NoInitsTrait) && + cls.superClass == defn.ObjectClass && + cls.directlyInheritedTraits.forall(_.is(NoInits)) && + !ExplicitOuter.needsOuterIfReferenced(cls) && + cls.typeRef.fields.isEmpty // Superaccessors already show up as abstract methods here, so no test necessary override def transformBlock(tree: Block)(implicit ctx: Context, info: TransformerInfo): Tree = tree match { case Block(stats @ (fn: DefDef) :: Nil, Closure(_, fnRef, tpt)) if fnRef.symbol == fn.symbol => tpt.tpe match { case NoType => tree // it's a plain function - case tpe @ SAMType(_) if !noJvmSam(tpe.classSymbol.asClass) => + case tpe @ SAMType(_) if isJvmSam(tpe.classSymbol.asClass) => if (tpe isRef defn.PartialFunctionClass) toPartialFunction(tree) else tree case tpe => diff --git a/src/dotty/tools/dotc/transform/NormalizeFlags.scala b/src/dotty/tools/dotc/transform/NormalizeFlags.scala index 2f5907b75..755846904 100644 --- a/src/dotty/tools/dotc/transform/NormalizeFlags.scala +++ b/src/dotty/tools/dotc/transform/NormalizeFlags.scala @@ -19,12 +19,7 @@ class NormalizeFlags extends MiniPhaseTransform with SymTransformer { thisTransf 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 2e76d3171..c81857e6f 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -563,7 +563,8 @@ 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) + cls.setApplicableFlags( + (NoInitsInterface /: impl.body)((fs, stat) => fs & defKind(stat))) } } |