aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/ast/TreeInfo.scala26
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala2
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala9
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala2
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala28
-rw-r--r--src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala2
-rw-r--r--src/dotty/tools/dotc/transform/ExpandSAMs.scala17
-rw-r--r--src/dotty/tools/dotc/transform/NormalizeFlags.scala5
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala3
-rw-r--r--tests/run/Course-2002-10.check (renamed from tests/pending/run/Course-2002-10.check)0
-rw-r--r--tests/run/Course-2002-10.scala (renamed from tests/pending/run/Course-2002-10.scala)0
11 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)))
}
}
diff --git a/tests/pending/run/Course-2002-10.check b/tests/run/Course-2002-10.check
index 207b671f0..207b671f0 100644
--- a/tests/pending/run/Course-2002-10.check
+++ b/tests/run/Course-2002-10.check
diff --git a/tests/pending/run/Course-2002-10.scala b/tests/run/Course-2002-10.scala
index 4cfa1deb0..4cfa1deb0 100644
--- a/tests/pending/run/Course-2002-10.scala
+++ b/tests/run/Course-2002-10.scala