aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/Compiler.scala8
-rw-r--r--src/dotty/tools/dotc/TypeErasure.scala16
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala29
-rw-r--r--src/dotty/tools/dotc/config/ScalaSettings.scala5
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala13
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala2
-rw-r--r--src/dotty/tools/dotc/core/NameOps.scala24
-rw-r--r--src/dotty/tools/dotc/core/Scopes.scala31
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala4
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala10
-rw-r--r--src/dotty/tools/dotc/core/Types.scala31
-rw-r--r--src/dotty/tools/dotc/printing/PlainPrinter.scala4
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala4
-rw-r--r--src/dotty/tools/dotc/transform/Constructors.scala44
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala21
-rw-r--r--src/dotty/tools/dotc/transform/ExplicitOuter.scala14
-rw-r--r--src/dotty/tools/dotc/transform/Getters.scala69
-rw-r--r--src/dotty/tools/dotc/transform/GettersSetters.scala56
-rw-r--r--src/dotty/tools/dotc/transform/MacroTransform.scala3
-rw-r--r--src/dotty/tools/dotc/transform/Memoize.scala86
-rw-r--r--src/dotty/tools/dotc/transform/Mixin.scala176
-rw-r--r--src/dotty/tools/dotc/transform/MixinOps.scala37
-rw-r--r--src/dotty/tools/dotc/transform/ResolveSuper.scala98
-rw-r--r--src/dotty/tools/dotc/transform/SuperAccessors.scala2
-rw-r--r--src/dotty/tools/dotc/transform/SymUtils.scala9
-rw-r--r--src/dotty/tools/dotc/transform/TreeTransform.scala8
-rw-r--r--src/dotty/tools/dotc/typer/ErrorReporting.scala2
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala8
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala5
-rw-r--r--test/dotc/tests.scala2
-rw-r--r--tests/pos/blockescapes.scala2
-rw-r--r--tests/pos/traits.scala4
32 files changed, 681 insertions, 146 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index f4690df08..004a3868c 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -46,14 +46,16 @@ class Compiler {
new TailRec),
List(new PatternMatcher,
new ExplicitOuter,
- // new LazyValTranformContext().transformer, // disabled, awaiting fixes
new Splitter),
List(new ElimByName,
new InterceptedMethods,
new Literalize,
- new GettersSetters),
+ new Getters,
+ new ResolveSuper),
List(new Erasure),
- List(new CapturedVars,
+ List(new Mixin,
+ new Memoize, // TODO: Make LazyVals a part of this phase
+ new CapturedVars,
new Constructors),
List(new LambdaLift,
new Flatten,
diff --git a/src/dotty/tools/dotc/TypeErasure.scala b/src/dotty/tools/dotc/TypeErasure.scala
index 2a55d6732..4a492560f 100644
--- a/src/dotty/tools/dotc/TypeErasure.scala
+++ b/src/dotty/tools/dotc/TypeErasure.scala
@@ -4,6 +4,7 @@ package core
import Symbols._, Types._, Contexts._, Flags._, Names._, StdNames._, Decorators._, Flags.JavaDefined
import dotc.transform.ExplicitOuter._
+import typer.Mode
import util.DotClass
/** Erased types are:
@@ -89,7 +90,7 @@ object TypeErasure {
/** The current context with a phase no later than erasure */
private def erasureCtx(implicit ctx: Context) =
- if (ctx.erasedTypes) ctx.withPhase(ctx.erasurePhase) else ctx
+ if (ctx.erasedTypes) ctx.withPhase(ctx.erasurePhase).addMode(Mode.FutureDefsOK) else ctx
def erasure(tp: Type)(implicit ctx: Context): Type = scalaErasureFn(tp)(erasureCtx)
def semiErasure(tp: Type)(implicit ctx: Context): Type = semiErasureFn(tp)(erasureCtx)
@@ -107,6 +108,8 @@ object TypeErasure {
case tp: TermRef =>
assert(tp.symbol.exists, tp)
TermRef(erasedRef(tp.prefix), tp.symbol.asTerm)
+ case tp: ThisType =>
+ tp
case tp =>
erasure(tp)
}
@@ -141,7 +144,12 @@ object TypeErasure {
if ((sym eq defn.Any_asInstanceOf) || (sym eq defn.Any_isInstanceOf)) eraseParamBounds(sym.info.asInstanceOf[PolyType])
else if (sym.isAbstractType) TypeAlias(WildcardType)
else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx))
- else eraseInfo(tp)(erasureCtx)
+ else eraseInfo(tp)(erasureCtx) match {
+ case einfo: MethodType if sym.isGetter && einfo.resultType.isRef(defn.UnitClass) =>
+ defn.BoxedUnitClass.typeRef
+ case einfo =>
+ einfo
+ }
}
def isUnboundedGeneric(tp: Type)(implicit ctx: Context) = !(
@@ -265,7 +273,7 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
case tp: TermRef =>
this(tp.widen)
case ThisType(_) =>
- tp
+ this(tp.widen)
case SuperType(thistpe, supertpe) =>
SuperType(this(thistpe), this(supertpe))
case ExprType(rt) =>
@@ -319,7 +327,7 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
}
def eraseInfo(tp: Type)(implicit ctx: Context) = tp match {
- case ExprType(rt) => MethodType(Nil, Nil, erasure(rt))
+ case ExprType(rt) => MethodType(Nil, Nil, eraseResult(rt))
case tp => erasure(tp)
}
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 74ba79176..735b218e3 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -6,7 +6,7 @@ import transform.SymUtils._
import core._
import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols._
-import Denotations._, Decorators._
+import Denotations._, Decorators._, DenotTransformers._
import config.Printers._
import typer.Mode
import collection.mutable
@@ -39,8 +39,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def This(cls: ClassSymbol)(implicit ctx: Context): This =
untpd.This(cls.name).withType(cls.thisType)
- def Super(qual: Tree, mix: TypeName, inConstrCall: Boolean)(implicit ctx: Context): Super =
- ta.assignType(untpd.Super(qual, mix), qual, inConstrCall)
+ def Super(qual: Tree, mix: TypeName, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context): Super =
+ ta.assignType(untpd.Super(qual, mix), qual, inConstrCall, mixinClass)
def Apply(fn: Tree, args: List[Tree])(implicit ctx: Context): Apply =
ta.assignType(untpd.Apply(fn, args), fn, args)
@@ -527,7 +527,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
*/
def changeOwner(from: Symbol, to: Symbol)(implicit ctx: Context): ThisTree = {
def loop(from: Symbol, froms: List[Symbol], tos: List[Symbol]): ThisTree = {
- if (from.isWeakOwner) loop(from.owner, from :: froms, to :: tos)
+ if (from.isWeakOwner && !from.owner.isClass)
+ loop(from.owner, from :: froms, to :: tos)
else {
//println(i"change owner ${from :: froms}%, % ==> $tos of $tree")
new TreeTypeMap(oldOwners = from :: froms, newOwners = tos).apply(tree)
@@ -536,6 +537,26 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
loop(from, Nil, to :: Nil)
}
+ /** After phase `trans`, set the owner of every definition in this tree that was formerly
+ * owner by `from` to `to`.
+ */
+ def changeOwnerAfter(from: Symbol, to: Symbol, trans: DenotTransformer)(implicit ctx: Context): ThisTree = {
+ assert(ctx.phase == trans.next)
+ val traverser = new TreeTraverser {
+ def traverse(tree: Tree) = tree match {
+ case tree: DefTree =>
+ val sym = tree.symbol
+ if (sym.denot(ctx.withPhase(trans)).owner == from)
+ sym.copySymDenotation(owner = to).installAfter(trans)
+ if (sym.isWeakOwner) traverseChildren(tree)
+ case _ =>
+ traverseChildren(tree)
+ }
+ }
+ traverser.traverse(tree)
+ tree
+ }
+
def select(name: Name)(implicit ctx: Context): Select =
Select(tree, name)
diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala
index 743925e40..abde6cb53 100644
--- a/src/dotty/tools/dotc/config/ScalaSettings.scala
+++ b/src/dotty/tools/dotc/config/ScalaSettings.scala
@@ -107,8 +107,9 @@ class ScalaSettings extends Settings.SettingGroup {
val Xdce = BooleanSetting("-Ydead-code", "Perform dead code elimination.")
val debug = BooleanSetting("-Ydebug", "Increase the quantity of debugging output.")
val debugNames = BooleanSetting("-YdebugNames", "Show name-space indicators when printing names")
- val debugTrace = BooleanSetting("-YdebugTrace", "Trace core operations")
- val debugFlags = BooleanSetting("-YdebugFlags", "Print all flags of definitions")
+ val debugTrace = BooleanSetting("-Ydebug-trace", "Trace core operations")
+ val debugFlags = BooleanSetting("-Ydebug-flags", "Print all flags of definitions")
+ val debugOwners = BooleanSetting("-Ydebug-owners", "Print all owners of definitions (requires -Yprint-syms)")
//val doc = BooleanSetting ("-Ydoc", "Generate documentation")
val termConflict = ChoiceSetting("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error")
val inline = BooleanSetting("-Yinline", "Perform inlining when possible.")
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index de6b0cabf..6293d18d2 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -297,16 +297,21 @@ object Contexts {
def thisCallArgContext: Context = {
assert(owner.isClassConstructor)
val constrCtx = outersIterator.dropWhile(_.outer.owner == owner).next
- var classCtx = outersIterator.dropWhile(!_.isClassDefContext).next
- classCtx.superOrThisCallContext(owner, constrCtx.scope).setTyperState(typerState)
+ superOrThisCallContext(owner, constrCtx.scope).setTyperState(typerState)
}
/** The super= or this-call context with given owner and locals. */
private def superOrThisCallContext(owner: Symbol, locals: Scope): FreshContext = {
- assert(isClassDefContext)
- outer.fresh.setOwner(owner).setScope(locals).setMode(ctx.mode | Mode.InSuperCall)
+ var classCtx = outersIterator.dropWhile(!_.isClassDefContext).next
+ classCtx.outer.fresh.setOwner(owner).setScope(locals).setMode(classCtx.mode | Mode.InSuperCall)
}
+ /** The context of expression `expr` seen as a member of a statement sequence */
+ def exprContext(stat: Tree[_ >: Untyped], exprOwner: Symbol) =
+ if (exprOwner == this.owner) this
+ else if (untpd.isSuperConstrCall(stat) && this.owner.isClass) superCallContext
+ else ctx.fresh.setOwner(exprOwner)
+
/** The current source file; will be derived from current
* compilation unit.
*/
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 82fd60fa0..ce11759ce 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -202,7 +202,7 @@ object Denotations {
def requiredClass(name: PreName)(implicit ctx: Context): ClassSymbol =
info.member(name.toTypeName).requiredSymbol(_.isClass).asClass
- /** The denotation that has a type matching `targetType` when seen
+ /** The alternative of this denotation that has a type matching `targetType` when seen
* as a member of type `site`, `NoDenotation` if none exists.
*/
def matchingDenotation(site: Type, targetType: Type)(implicit ctx: Context): SingleDenotation =
diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala
index beb3142d3..bc15f6a06 100644
--- a/src/dotty/tools/dotc/core/NameOps.scala
+++ b/src/dotty/tools/dotc/core/NameOps.scala
@@ -47,13 +47,15 @@ object NameOps {
}
}
- object SuperAccessorName {
- val pre = nme.SUPER_PREFIX
+ class PrefixNameExtractor(pre: TermName) {
def apply(name: TermName): TermName = pre ++ name
def unapply(name: TermName): Option[TermName] =
if (name startsWith pre) Some(name.drop(pre.length).asTermName) else None
}
+ object SuperAccessorName extends PrefixNameExtractor(nme.SUPER_PREFIX)
+ object InitializerName extends PrefixNameExtractor(nme.INITIALIZER_PREFIX)
+
implicit class NameDecorator[N <: Name](val name: N) extends AnyVal {
import nme._
@@ -68,14 +70,13 @@ object NameOps {
def isProtectedAccessorName = name startsWith PROTECTED_PREFIX
def isReplWrapperName = name containsSlice INTERPRETER_IMPORT_WRAPPER
def isSetterName = name endsWith SETTER_SUFFIX
- def isTraitSetterName = isSetterName && (name containsSlice TRAIT_SETTER_PREFIX)
def isSingletonName = name endsWith SINGLETON_SUFFIX
def isModuleClassName = name endsWith MODULE_SUFFIX
def isImportName = name startsWith IMPORT
def isFieldName = name endsWith LOCAL_SUFFIX
def isInheritedName = name.length > 0 && name.head == '(' && name.startsWith(nme.INHERITED)
def isDefaultGetterName = name.isTermName && name.asTermName.defaultGetterIndex >= 0
-
+ def isScala2LocalSuffix = name.endsWith(" ")
def isModuleVarName(name: Name): Boolean =
name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX
@@ -224,9 +225,6 @@ object NameOps {
implicit class TermNameDecorator(val name: TermName) extends AnyVal {
import nme._
- def traitSetterName: TermName =
- nme.TRAIT_SETTER_PREFIX ++ setterName
-
def setterName: TermName =
if (name.isFieldName) name.fieldToGetter.setterName
else name ++ SETTER_SUFFIX
@@ -240,13 +238,8 @@ object NameOps {
else name ++ LOCAL_SUFFIX
private def setterToGetter: TermName = {
- val p = name.indexOfSlice(TRAIT_SETTER_PREFIX)
- if (p >= 0)
- (name drop (p + TRAIT_SETTER_PREFIX.length)).asTermName.getterName
- else {
- assert(name.endsWith(SETTER_SUFFIX), name + " is referenced as a setter but has wrong name format")
- name.take(name.length - SETTER_SUFFIX.length).asTermName
- }
+ assert(name.endsWith(SETTER_SUFFIX), name + " is referenced as a setter but has wrong name format")
+ name.take(name.length - SETTER_SUFFIX.length).asTermName
}
def fieldToGetter: TermName = {
@@ -283,6 +276,9 @@ object NameOps {
-1
}
+ def stripScala2LocalSuffix: TermName =
+ if (name.isScala2LocalSuffix) name.init.asTermName else name
+
/** The name of an accessor for protected symbols. */
def protectedAccessorName: TermName =
PROTECTED_PREFIX ++ name.unexpandedName()
diff --git a/src/dotty/tools/dotc/core/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala
index 494a26f7e..09bdca196 100644
--- a/src/dotty/tools/dotc/core/Scopes.scala
+++ b/src/dotty/tools/dotc/core/Scopes.scala
@@ -20,7 +20,7 @@ import printing.Printer
import util.common._
import util.DotClass
import SymDenotations.NoDenotation
-import collection.mutable.ListBuffer
+import collection.mutable
object Scopes {
@@ -172,12 +172,27 @@ object Scopes {
*/
private var elemsCache: List[Symbol] = null
- def cloneScope(implicit ctx: Context): MutableScope = newScopeWith(this.toList: _*)
+ /** Clone scope, taking care not to force the denotations of any symbols in the scope.
+ */
+ def cloneScope(implicit ctx: Context): MutableScope = {
+ val entries = new mutable.ArrayBuffer[ScopeEntry]
+ var e = lastEntry
+ while ((e ne null) && e.owner == this) {
+ entries += e
+ e = e.prev
+ }
+ val scope = newScope
+ for (i <- entries.length - 1 to 0 by -1) {
+ val e = entries(i)
+ scope.newScopeEntry(e.name, e.sym)
+ }
+ scope
+ }
- /** create and enter a scope entry */
- protected def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry = {
+ /** create and enter a scope entry with given name and symbol */
+ protected def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = {
ensureCapacity(if (hashTable ne null) hashTable.length else MinHash)
- val e = new ScopeEntry(sym.name, sym, this)
+ val e = new ScopeEntry(name, sym, this)
e.prev = lastEntry
lastEntry = e
if (hashTable ne null) enterInHash(e)
@@ -186,6 +201,10 @@ object Scopes {
e
}
+ /** create and enter a scope entry */
+ protected def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry =
+ newScopeEntry(sym.name, sym)
+
private def enterInHash(e: ScopeEntry)(implicit ctx: Context): Unit = {
val idx = e.name.hashCode & (hashTable.length - 1)
e.tail = hashTable(idx)
@@ -325,7 +344,7 @@ object Scopes {
}
override def implicitDecls(implicit ctx: Context): List[TermRef] = {
- var irefs = new ListBuffer[TermRef]
+ var irefs = new mutable.ListBuffer[TermRef]
var e = lastEntry
while (e ne null) {
if (e.sym is Implicit) {
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index 99290f084..8393eb56f 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -119,9 +119,9 @@ object StdNames {
val SINGLETON_SUFFIX: N = ".type"
val SPECIALIZED_SUFFIX: N = "$sp"
val SUPER_PREFIX: N = "super$"
- val TRAIT_SETTER_PREFIX: N = "_setter_$"
val WHILE_PREFIX: N = "while$"
- val DEFAULT_EXCEPTION_NAME: N = "ex$"
+ val DEFAULT_EXCEPTION_NAME: N = "ex$"
+ val INITIALIZER_PREFIX: N = "initial$"
// value types (and AnyRef) are all used as terms as well
// as (at least) arguments to the @specialize annotation.
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index ae8fceeb7..dfb58f68b 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -425,10 +425,14 @@ object SymDenotations {
final def isSourceMethod(implicit ctx: Context) = this is (Method, butNot = Accessor)
/** Is this a setter? */
- final def isGetter(implicit ctx: Context) = (this is Accessor) && !originalName.isSetterName
+ final def isGetter(implicit ctx: Context) =
+ (this is Accessor) && !originalName.isSetterName && !originalName.isScala2LocalSuffix
/** Is this a setter? */
- final def isSetter(implicit ctx: Context) = (this is Accessor) && originalName.isSetterName
+ final def isSetter(implicit ctx: Context) =
+ (this is Accessor) &&
+ originalName.isSetterName &&
+ info.firstParamTypes.nonEmpty // to avoid being fooled by var x_= : Unit = ...
/** is this the constructor of a class? */
final def isClassConstructor = name == nme.CONSTRUCTOR
@@ -560,7 +564,7 @@ object SymDenotations {
def membersNeedAsSeenFrom(pre: Type)(implicit ctx: Context) =
!( this.isTerm
|| this.isStaticOwner
- || ctx.erasedTypes && symbol != defn.ArrayClass
+ || ctx.erasedTypes
|| (pre eq NoPrefix) || (pre eq thisType)
)
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index d0ddfdd28..5228c077e 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -1173,8 +1173,19 @@ object Types {
if (newd.exists) newd else d.staleSymbolError
}
case d =>
- if (d.validFor.runId == ctx.period.runId) d.current
- else loadDenot
+ if (d.validFor.runId != ctx.period.runId)
+ loadDenot
+ // The following branch was used to avoid an assertErased error.
+ // It's idea was to void keeping non-sym denotations after erasure
+ // since they violate the assertErased contract. But the problem is
+ // that when seen again in an earlier phase the denotation is
+ // still seen as a SymDenotation, whereas it should be a SingleDenotation.
+ // That's why the branch is disabled.
+ //
+ // else if (ctx.erasedTypes && lastSymbol != null)
+ // denotOfSym(lastSymbol)
+ else
+ d.current
}
if (ctx.typerState.ephemeral) record("ephemeral cache miss: loadDenot")
else if (d.exists) {
@@ -1505,7 +1516,7 @@ object Types {
* signature, if denotation is not yet completed.
*/
def apply(prefix: Type, name: TermName, denot: Denotation)(implicit ctx: Context): TermRef = {
- if ((prefix eq NoPrefix) || denot.symbol.isFresh)
+ if ((prefix eq NoPrefix) || denot.symbol.isFresh || ctx.erasedTypes)
apply(prefix, denot.symbol.asTerm)
else denot match {
case denot: SymDenotation if denot.isCompleted => withSig(prefix, name, denot.signature)
@@ -1527,7 +1538,7 @@ object Types {
* (2) The name in the term ref need not be the same as the name of the Symbol.
*/
def withSymAndName(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef =
- if ((prefix eq NoPrefix) || sym.isFresh)
+ if ((prefix eq NoPrefix) || sym.isFresh || ctx.erasedTypes)
withFixedSym(prefix, name, sym)
else if (sym.defRunId != NoRunId && sym.isCompleted)
withSig(prefix, name, sym.signature) withSym (sym, sym.signature)
@@ -1538,7 +1549,7 @@ object Types {
* (which must be completed).
*/
def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef =
- if ((prefix eq NoPrefix) || sym.isFresh) withFixedSym(prefix, sym.name, sym)
+ if ((prefix eq NoPrefix) || sym.isFresh || ctx.erasedTypes) withFixedSym(prefix, sym.name, sym)
else withSig(prefix, sym.name, sym.signature).withSym(sym, sym.signature)
/** Create a term ref with given prefix, name and signature */
@@ -1547,7 +1558,7 @@ object Types {
/** Create a term ref with given prefix, name, signature, and initial denotation */
def withSigAndDenot(prefix: Type, name: TermName, sig: Signature, denot: Denotation)(implicit ctx: Context): TermRef = {
- if ((prefix eq NoPrefix) || denot.symbol.isFresh)
+ if ((prefix eq NoPrefix) || denot.symbol.isFresh || ctx.erasedTypes)
withFixedSym(prefix, denot.symbol.asTerm.name, denot.symbol.asTerm)
else
withSig(prefix, name, sig)
@@ -1623,8 +1634,10 @@ object Types {
final class CachedSuperType(thistpe: Type, supertpe: Type) extends SuperType(thistpe, supertpe)
object SuperType {
- def apply(thistpe: Type, supertpe: Type)(implicit ctx: Context): Type =
+ def apply(thistpe: Type, supertpe: Type)(implicit ctx: Context): Type = {
+ assert(thistpe != NoPrefix)
unique(new CachedSuperType(thistpe, supertpe))
+ }
}
/** A constant type with single `value`. */
@@ -1817,7 +1830,7 @@ object Types {
}
catch {
case ex: AssertionError =>
- println(i"failure while taking result signture of $resultType")
+ println(i"failure while taking result signture of $this: $resultType")
throw ex
}
@@ -1837,7 +1850,7 @@ object Types {
extends CachedGroundType with BindingType with TermType with MethodOrPoly with NarrowCached { thisMethodType =>
override val resultType = resultTypeExp(this)
- assert(resultType != NoType)
+ assert(resultType.exists)
def isJava = false
def isImplicit = false
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala
index 9fba7ec09..78ee32b98 100644
--- a/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -288,7 +288,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
else if (flags is Mutable) "variable"
else if (sym.isClassConstructor && sym.isPrimaryConstructor) "primary constructor"
else if (sym.isClassConstructor) "constructor"
- else if (sym.isSourceMethod) "method"
+ else if (sym.is(Method)) "method"
else if (sym.isTerm) "value"
else ""
}
@@ -303,7 +303,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
else if (flags is Mutable) "var"
else if (flags is Package) "package"
else if (flags is Module) "object"
- else if (sym.isSourceMethod) "def"
+ else if (sym is Method) "def"
else if (sym.isTerm && (!(flags is Param))) "val"
else ""
}
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index e43aaa24f..50b73a357 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -205,7 +205,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}
def dclTextOr(treeText: => Text) =
- if (useSymbol) annotsText(tree.symbol) ~~ dclText(tree.symbol)
+ if (useSymbol)
+ annotsText(tree.symbol) ~~ dclText(tree.symbol) ~
+ ( " <in " ~ toText(tree.symbol.owner) ~ ">" provided ctx.settings.debugOwners.value)
else treeText
def idText(tree: untpd.Tree): Text = {
diff --git a/src/dotty/tools/dotc/transform/Constructors.scala b/src/dotty/tools/dotc/transform/Constructors.scala
index 7bde1ba4f..9420ce2c0 100644
--- a/src/dotty/tools/dotc/transform/Constructors.scala
+++ b/src/dotty/tools/dotc/transform/Constructors.scala
@@ -109,32 +109,6 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
}
}
- val superCalls = new mutable.ListBuffer[Tree]
-
- // If parent is a constructor call, pull out the call into a separate
- // supercall constructor, which gets appended to `superCalls`, and keep
- // only the type.
- def normalizeParent(tree: Tree) = tree match {
- case superApp @ Apply(
- superSel @ Select(
- superNew @ New(superType),
- nme.CONSTRUCTOR),
- superArgs) =>
- val toClass = !superType.symbol.is(Trait)
- val mappedArgs = superArgs.map(intoConstr(_, inSuperCall = toClass))
- val receiver =
- if (toClass) Super(This(cls), tpnme.EMPTY, inConstrCall = true)
- else This(cls)
- superCalls +=
- cpy.Apply(superApp)(
- receiver.withPos(superNew.pos)
- .select(superSel.symbol).withPos(superSel.pos),
- mappedArgs)
- superType
- case tree: TypeTree => tree
- }
- val parentTypeTrees = tree.parents.map(normalizeParent)
-
// Collect all private parameter accessors and value definitions that need
// to be retained. There are several reasons why a parameter accessor or
// definition might need to be retained:
@@ -172,16 +146,12 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
traverse(stat)
}
}
- usage.collect(superCalls.toList ++ tree.body)
+ usage.collect(tree.body)
def isRetained(acc: Symbol) = !mightBeDropped(acc) || usage.retained(acc)
val constrStats, clsStats = new mutable.ListBuffer[Tree]
- def assign(vble: Symbol, rhs: Tree): Tree =
- if (cls is Trait) ref(vble.setter).appliedTo(rhs)
- else Assign(ref(vble), rhs)
-
// Split class body into statements that go into constructor and
// definitions that are kept as members of the class.
def splitStats(stats: List[Tree]): Unit = stats match {
@@ -191,7 +161,7 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
val sym = stat.symbol
if (isRetained(sym)) {
if (!rhs.isEmpty && !isWildcardArg(rhs))
- constrStats += assign(sym, intoConstr(rhs)).withPos(stat.pos)
+ constrStats += Assign(ref(sym), intoConstr(rhs)).withPos(stat.pos)
clsStats += cpy.ValDef(stat)(rhs = EmptyTree)
}
else if (!rhs.isEmpty) {
@@ -215,7 +185,7 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
// The initializers for the retained accessors */
val copyParams = accessorFields.filter(isRetained).map(acc =>
- assign(acc, ref(acc.subst(accessors, paramSyms))).withPos(tree.pos))
+ Assign(ref(acc), ref(acc.subst(accessors, paramSyms))).withPos(tree.pos))
// Drop accessors that are not retained from class scope
val dropped = usage.dropped
@@ -226,10 +196,14 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
decls = clsInfo.decls.filteredScope(!dropped.contains(_))))
}
+ val (superCalls, followConstrStats) = constrStats.toList match {
+ case (sc: Apply) :: rest if sc.symbol.isConstructor => (sc :: Nil, rest)
+ case stats => (Nil, stats)
+ }
+
cpy.Template(tree)(
constr = cpy.DefDef(constr)(
- rhs = Block(superCalls.toList ::: copyParams ::: constrStats.toList, unitLiteral)),
- parents = parentTypeTrees,
+ rhs = Block(superCalls ::: copyParams ::: followConstrStats, unitLiteral)),
body = clsStats.toList)
}
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index 9f381bb8e..0a34b9e7c 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -94,7 +94,8 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
if (ctx.mode.isExpr)
tree.tpe match {
case ref: TermRef =>
- assert(ref.denot.isInstanceOf[SymDenotation],
+ assert(ref.denot.isInstanceOf[SymDenotation] ||
+ ref.denot.isInstanceOf[UniqueRefDenotation],
i"non-sym type $ref of class ${ref.getClass} with denot of class ${ref.denot.getClass} of $tree")
case _ =>
}
@@ -247,6 +248,10 @@ object Erasure extends TypeTestsCasts{
tree.withType(erased)
}
+ override def typedLiteral(tree: untpd.Literal)(implicit ctc: Context): Literal =
+ if (tree.typeOpt.isRef(defn.UnitClass)) tree.withType(tree.typeOpt)
+ else super.typedLiteral(tree)
+
/** Type check select nodes, applying the following rewritings exhaustively
* on selections `e.m`, where `OT` is the type of the owner of `m` and `ET`
* is the erased type of the selection's original qualifier expression.
@@ -277,7 +282,7 @@ object Erasure extends TypeTestsCasts{
case _ => sym.name
}
untpd.cpy.Select(tree)(qual, sym.name)
- .withType(NamedType.withSymAndName(qual.tpe, sym, name))
+ .withType(NamedType.withFixedSym(qual.tpe, sym))
}
def selectArrayMember(qual: Tree, erasedPre: Type): Tree =
@@ -369,12 +374,20 @@ object Erasure extends TypeTestsCasts{
}
}
+ override def typedValDef(vdef: untpd.ValDef, sym: Symbol)(implicit ctx: Context): ValDef =
+ super.typedValDef(untpd.cpy.ValDef(vdef)(
+ tpt = untpd.TypedSplice(TypeTree(sym.info).withPos(vdef.tpt.pos))), sym)
+
override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = {
+ val restpe = sym.info.resultType
val ddef1 = untpd.cpy.DefDef(ddef)(
tparams = Nil,
vparamss = ddef.vparamss.flatten :: Nil,
- tpt = // keep UnitTypes intact in result position
- untpd.TypedSplice(TypeTree(eraseResult(ddef.tpt.typeOpt)).withPos(ddef.tpt.pos)))
+ tpt = untpd.TypedSplice(TypeTree(restpe).withPos(ddef.tpt.pos)),
+ rhs = ddef.rhs match {
+ case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe))
+ case _ => ddef.rhs
+ })
super.typedDefDef(ddef1, sym)
}
diff --git a/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/src/dotty/tools/dotc/transform/ExplicitOuter.scala
index d056d7e35..28d742b5e 100644
--- a/src/dotty/tools/dotc/transform/ExplicitOuter.scala
+++ b/src/dotty/tools/dotc/transform/ExplicitOuter.scala
@@ -187,6 +187,10 @@ object ExplicitOuter {
private def hasOuter(cls: ClassSymbol)(implicit ctx: Context): Boolean =
needsOuterIfReferenced(cls) && outerAccessor(cls).exists
+ /** Class constructor takes an outer argument. Can be called only after phase ExplicitOuter. */
+ private def hasOuterParam(cls: ClassSymbol)(implicit ctx: Context): Boolean =
+ !cls.is(Trait) && needsOuterIfReferenced(cls) && outerAccessor(cls).exists
+
/** Tree references a an outer class of `cls` which is not a static owner.
*/
def referencesOuter(cls: Symbol, tree: Tree)(implicit ctx: Context): Boolean = {
@@ -248,7 +252,7 @@ object ExplicitOuter {
/** If `cls` has an outer parameter add one to the method type `tp`. */
def addParam(cls: ClassSymbol, tp: Type): Type =
- if (hasOuter(cls)) {
+ if (hasOuterParam(cls)) {
val mt @ MethodType(pnames, ptypes) = tp
mt.derivedMethodType(
nme.OUTER :: pnames, cls.owner.enclosingClass.typeRef :: ptypes, mt.resultType)
@@ -261,14 +265,14 @@ object ExplicitOuter {
if (fun.symbol.isConstructor) {
val cls = fun.symbol.owner.asClass
def outerArg(receiver: Tree): Tree = receiver match {
- case New(tpt) =>
- singleton(outerPrefix(tpt.tpe))
+ case New(_) | Super(_, _) =>
+ singleton(outerPrefix(receiver.tpe))
case This(_) =>
- ref(outerParamAccessor(cls)) // will be rewried to outer argument of secondary constructor in phase Constructors
+ ref(outerParamAccessor(cls)) // will be rewired to outer argument of secondary constructor in phase Constructors
case TypeApply(Select(r, nme.asInstanceOf_), args) =>
outerArg(r) // cast was inserted, skip
}
- if (hasOuter(cls))
+ if (hasOuterParam(cls))
methPart(fun) match {
case Select(receiver, _) => outerArg(receiver).withPos(fun.pos) :: Nil
}
diff --git a/src/dotty/tools/dotc/transform/Getters.scala b/src/dotty/tools/dotc/transform/Getters.scala
new file mode 100644
index 000000000..4ea9d2c6b
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/Getters.scala
@@ -0,0 +1,69 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import DenotTransformers.SymTransformer
+import Contexts.Context
+import SymDenotations.SymDenotation
+import Types._
+import Symbols._
+import SymUtils._
+import Constants._
+import TreeTransforms._
+import Flags._
+import Decorators._
+
+/** Performs the following rewritings for fields of a class:
+ *
+ * <mods> val x: T = e
+ * --> <mods> <stable> def x: T = e
+ * <mods> var x: T = e
+ * --> <mods> def x: T = e
+ *
+ * <mods> val x: T
+ * --> <mods> <stable> def x: T
+ *
+ * <mods> var x: T
+ * --> <mods> def x: T
+ *
+ * Omitted from the rewritings are
+ *
+ * - private[this] fields in non-trait classes
+ * - fields generated for static modules (TODO: needed?)
+ * - parameters, static fields, and fields coming from Java
+ *
+ * Furthermore, assignements to mutable vars are replaced by setter calls
+ *
+ * p.x = e
+ * --> p.x_=(e)
+ *
+ * No fields are generated yet. This is done later in phase Memoize.
+ */
+class Getters extends MiniPhaseTransform with SymTransformer { thisTransform =>
+ import ast.tpd._
+
+ override def phaseName = "getters"
+ override def treeTransformPhase = thisTransform.next
+
+ override def transformSym(d: SymDenotation)(implicit ctx: Context): SymDenotation = {
+ def noGetterNeeded =
+ d.is(NoGetterNeeded) ||
+ d.initial.asInstanceOf[SymDenotation].is(PrivateLocal) && !d.owner.is(Trait) ||
+ d.is(Module) && d.isStatic ||
+ d.isSelfSym
+ if (d.isTerm && d.owner.isClass && d.info.isValueType && !noGetterNeeded) {
+ val maybeStable = if (d.isStable) Stable else EmptyFlags
+ d.copySymDenotation(
+ initFlags = d.flags | maybeStable | AccessorCreationFlags,
+ info = ExprType(d.info))
+ }
+ else d
+ }
+ private val NoGetterNeeded = Method | Param | JavaDefined | JavaStatic
+
+ override def transformValDef(tree: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree =
+ if (tree.symbol is Method) DefDef(tree.symbol.asTerm, tree.rhs) else tree
+
+ override def transformAssign(tree: Assign)(implicit ctx: Context, info: TransformerInfo): Tree =
+ if (tree.lhs.symbol is Method) tree.lhs.becomes(tree.rhs) else tree
+}
diff --git a/src/dotty/tools/dotc/transform/GettersSetters.scala b/src/dotty/tools/dotc/transform/GettersSetters.scala
index 772a63e52..b5933cc48 100644
--- a/src/dotty/tools/dotc/transform/GettersSetters.scala
+++ b/src/dotty/tools/dotc/transform/GettersSetters.scala
@@ -16,27 +16,39 @@ import NameOps._
import Flags._
import Decorators._
-/** Performs the following rewritings:
+/** Performs the following rewritings on fields of classes, where `x_L` is the "local name" of `x`:
*
* val x: T = e
* --> private val x_L: T = e
- * <stable> def x: T = x_L (if in class)
- * --> private notJavaPrivate var x_L: T = e
* <stable> def x: T = x_L
- * private notJavaPrivate def x_=(x: T): Unit = x_L = x (if in trait)
+ *
* var x: T = e
+ * def x_=(y: T) = ()
* --> private var x_L: T = e
* def x: T = x_L
* def x_=(x: T): Unit = x_L = x (if in class or trait)
+ *
* lazy val x: T = e
- * --> lazy def x = e
+ * --> def x: T = e
+ *
+ * val x: T
+ * --> <stable> def x: T
+ *
+ * var x: T
+ * --> def x: T
+ *
+ * Omitted from the rewritings are
+ *
+ * - private[this] fields in non-trait classes
+ * - fields generated for static modules (TODO: needed?)
+ * - parameters, static fields, and fields coming from Java
*
* Furthermore, assignements to mutable vars are replaced by setter calls
*
* p.x = e
* --> p.x_=(e)
*/
-class GettersSetters extends MiniPhaseTransform with SymTransformer { thisTransform =>
+ class GettersSetters extends MiniPhaseTransform with SymTransformer { thisTransform =>
import ast.tpd._
override def phaseName = "gettersSetters"
@@ -45,38 +57,34 @@ class GettersSetters extends MiniPhaseTransform with SymTransformer { thisTransf
override def transformSym(d: SymDenotation)(implicit ctx: Context): SymDenotation = {
def noGetterNeeded =
- d.is(Method | Param | JavaDefined) ||
+ d.is(NoGetterNeeded) ||
d.initial.asInstanceOf[SymDenotation].is(PrivateLocal) && !d.owner.is(Trait) ||
d.is(Module) && d.isStatic ||
d.isSelfSym
- if (d.isTerm && (d.owner.isClass || d.is(Lazy)) && d.info.isValueType && !noGetterNeeded) {
+ if (d.isTerm && d.owner.isClass && d.info.isValueType && !noGetterNeeded) {
val maybeStable = if (d.isStable) Stable else EmptyFlags
- if (d.name.toString == "_") println(i"make accessor $d in ${d.owner} ${d.symbol.id}")
+ //if (d.name.toString == "_") println(i"make accessor $d in ${d.owner} ${d.symbol.id}")
d.copySymDenotation(
initFlags = d.flags | maybeStable | AccessorCreationFlags,
info = ExprType(d.info))
}
else d
}
+ private val NoGetterNeeded = Method | Param | JavaDefined | JavaStatic
+ private val NoFieldNeeded = Lazy | Deferred | ParamAccessor
override def transformValDef(tree: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
if (tree.symbol is Method) {
val getter = tree.symbol.asTerm
assert(getter is Accessor)
- if (getter.is(Lazy | Deferred | ParamAccessor)) DefDef(getter, tree.rhs)
+ if (getter is NoFieldNeeded)
+ DefDef(getter, tree.rhs)
else {
val inTrait = getter.owner.is(Trait)
- val maybePrivate =
- if (inTrait) Private | NotJavaPrivate
- else if (getter.owner.isClass) Private
- else EmptyFlags
- val maybeMutable =
- if (inTrait || getter.is(Mutable)) Mutable
- else EmptyFlags
val field = ctx.newSymbol(
owner = ctx.owner,
name = getter.name.fieldName,
- flags = maybePrivate | maybeMutable,
+ flags = Private | (getter.flags & Mutable),
info = getter.info.resultType).enteredAfter(thisTransform)
assert(tree.rhs.tpe.exists, tree.show)
val fieldDef =
@@ -88,16 +96,7 @@ class GettersSetters extends MiniPhaseTransform with SymTransformer { thisTransf
val rhs = ref(field)
assert(rhs.hasType)
val getterDef = DefDef(getter, rhs.ensureConforms(getter.info.widen))
- if (!getter.is(Mutable) && inTrait) { // add a setter anyway, will be needed for mixin
- val setter = ctx.newSymbol(
- owner = ctx.owner,
- name = getter.name.traitSetterName,
- flags = (getter.flags & AccessFlags) | Accessor | maybePrivate,
- info = MethodType(field.info :: Nil, defn.UnitType)).enteredAfter(thisTransform)
- val setterDef = DefDef(setter.asTerm, vrefss => Assign(ref(field), vrefss.head.head))
- Thicket(fieldDef, getterDef, setterDef)
- }
- else Thicket(fieldDef, getterDef)
+ Thicket(fieldDef, getterDef)
}
}
else tree
@@ -106,6 +105,7 @@ class GettersSetters extends MiniPhaseTransform with SymTransformer { thisTransf
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree =
if (tree.symbol.isSetter && !tree.symbol.is(Deferred | ParamAccessor)) {
val Literal(Constant(())) = tree.rhs
+ assert(tree.symbol.field.exists, i"no field for ${tree.symbol.showLocated}")
val initializer = Assign(ref(tree.symbol.field), ref(tree.vparamss.head.head.symbol))
assert(initializer.hasType)
cpy.DefDef(tree)(rhs = initializer)
diff --git a/src/dotty/tools/dotc/transform/MacroTransform.scala b/src/dotty/tools/dotc/transform/MacroTransform.scala
index 47ffaafb3..3a8bcc920 100644
--- a/src/dotty/tools/dotc/transform/MacroTransform.scala
+++ b/src/dotty/tools/dotc/transform/MacroTransform.scala
@@ -44,11 +44,10 @@ abstract class MacroTransform extends Phase {
def currentClass(implicit ctx: Context): ClassSymbol = ctx.owner.enclosingClass.asClass
def transformStats(trees: List[Tree], exprOwner: Symbol)(implicit ctx: Context): List[Tree] = {
- val exprCtx = ctx.withOwner(exprOwner)
def transformStat(stat: Tree): Tree = stat match {
case _: Import | _: DefTree => transform(stat)
case Thicket(stats) => cpy.Thicket(stat)(stats mapConserve transformStat)
- case _ => transform(stat)(exprCtx)
+ case _ => transform(stat)(ctx.exprContext(stat, exprOwner))
}
flatten(trees.mapconserve(transformStat(_)))
}
diff --git a/src/dotty/tools/dotc/transform/Memoize.scala b/src/dotty/tools/dotc/transform/Memoize.scala
new file mode 100644
index 000000000..ef70b9ecf
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/Memoize.scala
@@ -0,0 +1,86 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import DenotTransformers._
+import Phases.Phase
+import Contexts.Context
+import SymDenotations.SymDenotation
+import Types._
+import Symbols._
+import SymUtils._
+import Constants._
+import ast.Trees._
+import TreeTransforms._
+import NameOps._
+import Flags._
+import Decorators._
+
+/** Provides the implementations of all getters and setters, introducing
+ * fields to hold the value accessed by them.
+ * TODO: Make LazyVals a part of this phase?
+ *
+ * <accessor> <stable> <mods> def x(): T = e
+ * --> private val x: T = e
+ * <accessor> <stable> <mods> def x(): T = x
+ *
+ * <accessor> <mods> def x(): T = e
+ * --> private var x: T = e
+ * <accessor> <mods> def x(): T = x
+ *
+ * <accessor> <mods> def x_=(y: T): Unit = ()
+ * --> <accessor> <mods> def x_=(y: T): Unit = x = y
+ */
+ class Memoize extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
+ import ast.tpd._
+
+ override def phaseName = "memoize"
+ override def treeTransformPhase = thisTransform.next
+
+ /** Should to run after mixin so that fields get generated in the
+ * class that contains the concrete getter rather than the trait
+ * that defines it.
+ */
+ override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Mixin])
+
+ override def prepareForDefDef(tree: DefDef)(implicit ctx: Context) = {
+ val sym = tree.symbol
+ if (sym.isGetter && !sym.is(NoFieldNeeded)) {
+ // allocate field early so that initializer has the right owner for subsequeny phases in
+ // the group.
+ val maybeMutable = if (sym is Stable) EmptyFlags else Mutable
+ val field = ctx.newSymbol(
+ owner = ctx.owner,
+ name = sym.name.asTermName.fieldName,
+ flags = Private | maybeMutable,
+ info = sym.info.resultType,
+ coord = tree.pos).enteredAfter(thisTransform)
+ tree.rhs.changeOwnerAfter(sym, field, thisTransform)
+ }
+ this
+ }
+
+ override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ val sym = tree.symbol
+ def field = {
+ val field = sym.field.asTerm
+ assert(field.exists, i"no field for ${sym.showLocated} in ${sym.owner.info.decls.toList.map{_.showDcl}}%; %")
+ field
+ }
+ if (sym.is(Accessor, butNot = NoFieldNeeded))
+ if (sym.isGetter) {
+ val fieldDef = transformFollowing(ValDef(field, tree.rhs))
+ val getterDef = cpy.DefDef(tree)(rhs = transformFollowingDeep(ref(field)))
+ Thicket(fieldDef, getterDef)
+ }
+ else if (sym.isSetter) {
+ val Literal(Constant(())) = tree.rhs
+ val initializer = Assign(ref(field), ref(tree.vparamss.head.head.symbol))
+ cpy.DefDef(tree)(rhs = transformFollowingDeep(initializer))
+ }
+ else tree // curiously, some accessors from Scala2 have ' ' suffixes. They count as
+ // neither getters nor setters
+ else tree
+ }
+ private val NoFieldNeeded = Lazy | Deferred | ParamAccessor
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/transform/Mixin.scala b/src/dotty/tools/dotc/transform/Mixin.scala
new file mode 100644
index 000000000..1d342404a
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/Mixin.scala
@@ -0,0 +1,176 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import TreeTransforms._
+import Contexts.Context
+import Flags._
+import SymUtils._
+import Symbols._
+import SymDenotations._
+import Types._
+import Decorators._
+import DenotTransformers._
+import StdNames._
+import NameOps._
+import Phases._
+import ast.Trees._
+import collection.mutable
+
+/** This phase performs the following transformations:
+ *
+ * 1. (done in `traitDefs`) Map every concrete trait getter
+ *
+ * <mods> def x(): T = expr
+ *
+ * to the pair of definitions:
+ *
+ * <mods> def x(): T
+ * protected def initial$x(): T = { stats; expr }
+ *
+ * where `stats` comprises all statements between either the start of the trait
+ * or the previous field definition which are not definitions (i.e. are executed for
+ * their side effects).
+ *
+ * 2. (done in `traitDefs`) Make every concrete trait setter
+ *
+ * <mods> def x_=(y: T) = ()
+ *
+ * deferred by maping it to
+ *
+ * <mods> def x_=(y: T)
+ *
+ * 3. For a non-trait class C:
+ *
+ * For every trait M directly implemented by the class (see SymUtils.mixin), in
+ * reverse linearization order, add the following definitions to C:
+ *
+ * 3.1 (done in `traitInits`) For every concrete trait getter `<mods> def x(): T` in M,
+ * in order of textual occurrence:
+ *
+ * <mods> def x(): T = super[M].initial$x()
+ *
+ * 3.2 (done in `superCallOpt`) The call:
+ *
+ * super[M].<init>
+ *
+ * 3.3 (done in `setters`) For every concrete setter `<mods> def x_=(y: T)` in M:
+ *
+ * <mods> def x_=(y: T) = ()
+ *
+ * Conceptually, this is the second half of the previous mixin phase. It needs to run
+ * after erasure because it copies references to possibly private inner classes and objects
+ * into enclosing classes where they are not visible. This can only be done if all references
+ * are symbolic.
+ */
+class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
+ import ast.tpd._
+
+ override def phaseName: String = "mixin"
+ override def treeTransformPhase = thisTransform.next
+
+ override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Erasure])
+
+ override def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation =
+ if (sym.is(Accessor, butNot = Deferred) && sym.owner.is(Trait))
+ sym.copySymDenotation(initFlags = sym.flags | Deferred)
+ else
+ sym
+
+ private def initializer(sym: Symbol)(implicit ctx: Context): TermSymbol = {
+ val initName = InitializerName(sym.name.asTermName)
+ sym.owner.info.decl(initName).symbol
+ .orElse(
+ ctx.newSymbol(
+ sym.owner,
+ initName,
+ Protected | Synthetic | Method,
+ sym.info,
+ coord = sym.symbol.coord).enteredAfter(thisTransform))
+ .asTerm
+ }
+
+ override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = {
+ val cls = impl.symbol.owner.asClass
+ val ops = new MixinOps(cls, thisTransform)
+ import ops._
+
+ def traitDefs(stats: List[Tree]): List[Tree] = {
+ val initBuf = new mutable.ListBuffer[Tree]
+ stats flatMap {
+ case stat: DefDef if stat.symbol.isGetter && !stat.rhs.isEmpty =>
+ val vsym = stat.symbol
+ val isym = initializer(vsym)
+ val rhs = Block(
+ initBuf.toList.map(_.changeOwner(impl.symbol, isym)),
+ stat.rhs.changeOwner(vsym, isym))
+ initBuf.clear()
+ List(
+ cpy.DefDef(stat)(mods = stat.mods | Deferred, rhs = EmptyTree),
+ DefDef(isym, rhs))
+ case stat: DefDef if stat.symbol.isSetter =>
+ List(cpy.DefDef(stat)(
+ mods = stat.mods | Deferred,
+ rhs = EmptyTree))
+ case stat: DefTree =>
+ List(stat)
+ case stat =>
+ initBuf += stat
+ Nil
+ }
+ }
+
+ def transformSuper(tree: Tree): Tree = {
+ val Apply(sel @ Select(New(_), nme.CONSTRUCTOR), args) = tree
+ superRef(tree.symbol, tree.pos).appliedToArgs(args)
+ }
+
+ val superCalls = (
+ for (p <- impl.parents if p.symbol.isConstructor)
+ yield p.symbol.owner -> transformSuper(p)
+ ).toMap
+
+ def superCallOpt(baseCls: Symbol): List[Tree] = superCalls.get(baseCls) match {
+ case Some(call) =>
+ if (defn.PhantomClasses.contains(baseCls)) Nil else call :: Nil
+ case None =>
+ if (baseCls.is(Interface) || defn.PhantomClasses.contains(baseCls)) Nil
+ else {
+ //println(i"synth super call ${baseCls.primaryConstructor}: ${baseCls.primaryConstructor.info}")
+ superRef(baseCls.primaryConstructor).appliedToNone :: Nil
+/* constr.tpe.widen match {
+ case tpe: PolyType =>
+ val targs = cls.thisType.baseTypeWithArgs(baseCls).argTypes
+ constr = constr.appliedToTypes(targs)
+ case _ =>
+ }
+ constr.ensureApplied :: Nil
+*/
+ }
+ }
+
+ def wasDeferred(sym: Symbol) =
+ ctx.atPhase(thisTransform) { implicit ctx => sym is Deferred }
+
+ def traitInits(mixin: ClassSymbol): List[Tree] =
+ for (getter <- mixin.decls.filter(getr => getr.isGetter && !wasDeferred(getr)).toList)
+ yield {
+ DefDef(implementation(getter.asTerm), superRef(initializer(getter)).appliedToNone)
+ }
+
+ def setters(mixin: ClassSymbol): List[Tree] =
+ for (setter <- mixin.decls.filter(setr => setr.isSetter && !wasDeferred(setr)).toList)
+ yield DefDef(implementation(setter.asTerm), unitLiteral.withPos(cls.pos))
+
+ cpy.Template(impl)(
+ parents = impl.parents.map(p => TypeTree(p.tpe).withPos(p.pos)),
+ body =
+ if (cls is Trait) traitDefs(impl.body)
+ else {
+ val mixInits = mixins.flatMap { mixin =>
+ traitInits(mixin) ::: superCallOpt(mixin) ::: setters(mixin)
+ }
+ superCallOpt(superCls) ::: mixInits ::: impl.body
+ })
+ }
+}
diff --git a/src/dotty/tools/dotc/transform/MixinOps.scala b/src/dotty/tools/dotc/transform/MixinOps.scala
new file mode 100644
index 000000000..de15b045f
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/MixinOps.scala
@@ -0,0 +1,37 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import Symbols._, Types._, Contexts._, SymDenotations._, DenotTransformers._, Flags._
+import util.Positions._
+import StdNames._, NameOps._
+
+class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx: Context) {
+ import ast.tpd._
+
+ val superCls: Symbol = cls.classInfo.parents.head.symbol
+ val mixins: List[ClassSymbol] =
+ if (cls is Trait) Nil
+ else cls.baseClasses.tail.takeWhile(_ ne superCls).reverse
+
+ def implementation(member: TermSymbol): TermSymbol =
+ member.copy(
+ owner = cls,
+ name = member.name.stripScala2LocalSuffix,
+ flags = member.flags &~ Deferred &~ Module,
+ info = cls.thisType.memberInfo(member)).enteredAfter(thisTransform).asTerm
+
+ def superRef(target: Symbol, pos: Position = cls.pos): Tree = {
+ val sup = if (target.isConstructor && !target.owner.is(Trait))
+ Super(This(cls), tpnme.EMPTY, true)
+ else
+ Super(This(cls), target.owner.name.asTypeName, false, target.owner)
+ //println(i"super ref $target on $sup")
+ ast.untpd.Select(sup.withPos(pos), target.name)
+ .withType(NamedType.withFixedSym(sup.tpe, target))
+ //sup.select(target)
+ }
+
+ def forwarder(target: Symbol) = (targs: List[Type]) => (vrefss: List[List[Tree]]) =>
+ superRef(target).appliedToTypes(targs).appliedToArgss(vrefss)
+}
diff --git a/src/dotty/tools/dotc/transform/ResolveSuper.scala b/src/dotty/tools/dotc/transform/ResolveSuper.scala
new file mode 100644
index 000000000..23ff45a7c
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/ResolveSuper.scala
@@ -0,0 +1,98 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import TreeTransforms._
+import Contexts.Context
+import Flags._
+import SymUtils._
+import Symbols._
+import SymDenotations._
+import Types._
+import Decorators._
+import DenotTransformers._
+import StdNames._
+import NameOps._
+import ast.Trees._
+import util.Positions._
+import Names._
+import collection.mutable
+
+/** This phase adds super accessors and method overrides where
+ * linearization differs from Java's rule for default methods in interfaces.
+ * In particular:
+ *
+ * For every trait M directly implemented by the class (see SymUtils.mixin), in
+ * reverse linearization order, add the following definitions to C:
+ *
+ * 3.1 (done in `superAccessors`) For every superAccessor
+ * `<mods> def super$f[Ts](ps1)...(psN): U` in M:
+ *
+ * <mods> def super$f[Ts](ps1)...(psN): U = super[S].f[Ts](ps1)...(psN)
+ *
+ * where `S` is the superclass of `M` in the linearization of `C`.
+ *
+ * 3.2 (done in `methodOverrides`) For every method
+ * `<mods> def f[Ts](ps1)...(psN): U` in M` that needs to be disambiguated:
+ *
+ * <mods> def f[Ts](ps1)...(psN): U = super[M].f[Ts](ps1)...(psN)
+ *
+ * A method in M needs to be disambiguated if it is concrete, not overridden in C,
+ * and if it overrides another concrete method.
+ *
+ * This is the first part of what was the mixin phase. It is complemented by
+ * Mixin, which runs after erasure.
+ */
+class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
+ import ast.tpd._
+
+ override def phaseName: String = "resolveSuper"
+
+ override def treeTransformPhase = thisTransform.next
+
+ override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = {
+ val cls = impl.symbol.owner.asClass
+ val ops = new MixinOps(cls, thisTransform)
+ import ops._
+
+ /** Returns the symbol that is accessed by a super-accessor in a mixin composition.
+ *
+ * @param base The class in which everything is mixed together
+ * @param member The symbol statically referred to by the superaccessor in the trait
+ */
+ def rebindSuper(base: Symbol, acc: Symbol): Symbol = {
+ var bcs = cls.info.baseClasses.dropWhile(acc.owner != _).tail
+ var sym: Symbol = NoSymbol
+ val SuperAccessorName(memberName) = acc.name: Name // dotty deviation: ": Name" needed otherwise pattern type is neither a subtype nor a supertype of selector type
+ ctx.debuglog(i"starting rebindsuper from $cls of ${acc.showLocated}: ${acc.info} in $bcs, name = $memberName")
+ while (bcs.nonEmpty && sym == NoSymbol) {
+ val other = bcs.head.info.nonPrivateDecl(memberName)
+ if (ctx.settings.debug.value)
+ ctx.log(i"rebindsuper ${bcs.head} $other deferred = ${other.symbol.is(Deferred)}")
+ sym = other.matchingDenotation(cls.thisType, cls.thisType.memberInfo(acc)).symbol
+ bcs = bcs.tail
+ }
+ assert(sym.exists)
+ sym
+ }
+
+ def superAccessors(mixin: ClassSymbol): List[Tree] =
+ for (superAcc <- mixin.decls.filter(_ is SuperAccessor).toList)
+ yield polyDefDef(implementation(superAcc.asTerm), forwarder(rebindSuper(cls, superAcc)))
+
+ def methodOverrides(mixin: ClassSymbol): List[Tree] = {
+ def isOverridden(meth: Symbol) = meth.overridingSymbol(cls).is(Method, butNot = Deferred)
+ def needsDisambiguation(meth: Symbol): Boolean =
+ meth.is(Method, butNot = PrivateOrDeferred) &&
+ !isOverridden(meth) &&
+ !meth.allOverriddenSymbols.forall(_ is Deferred)
+ for (meth <- mixin.decls.toList if needsDisambiguation(meth))
+ yield polyDefDef(implementation(meth.asTerm), forwarder(meth))
+ }
+
+ val overrides = mixins.flatMap(mixin => superAccessors(mixin) ::: methodOverrides(mixin))
+
+ cpy.Template(impl)(body = overrides ::: impl.body)
+ }
+ private val PrivateOrDeferred = Private | Deferred
+}
diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala
index b11658efb..537c8c0c6 100644
--- a/src/dotty/tools/dotc/transform/SuperAccessors.scala
+++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala
@@ -90,7 +90,7 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this
val superAcc = clazz.info.decl(supername).suchThat(_.signature == sym.signature).symbol orElse {
ctx.debuglog(s"add super acc ${sym.showLocated} to $clazz")
val acc = ctx.newSymbol(
- clazz, supername, SuperAccessor | Private | Artifact,
+ clazz, supername, SuperAccessor | Private | Artifact | Method,
ensureMethodic(sel.tpe.widenSingleton), coord = sym.coord).enteredAfter(thisTransformer)
// Diagnostic for SI-7091
if (!accDefs.contains(clazz))
diff --git a/src/dotty/tools/dotc/transform/SymUtils.scala b/src/dotty/tools/dotc/transform/SymUtils.scala
index ba45d3f04..449affb9e 100644
--- a/src/dotty/tools/dotc/transform/SymUtils.scala
+++ b/src/dotty/tools/dotc/transform/SymUtils.scala
@@ -61,12 +61,17 @@ class SymUtils(val self: Symbol) extends AnyVal {
def setter(implicit ctx: Context): Symbol =
if (self.isSetter) self
- else accessorNamed(self.asTerm.name.setterName) orElse
- accessorNamed(self.asTerm.name.traitSetterName)
+ else accessorNamed(self.asTerm.name.setterName)
def field(implicit ctx: Context): Symbol =
self.owner.info.decl(self.asTerm.name.fieldName).suchThat(!_.is(Method)).symbol
/** `fullName` where `$' is the separator character */
def flatName(implicit ctx: Context): Name = self.fullNameSeparated('$')
+
+ def initializer(implicit ctx: Context): TermSymbol =
+ self.owner.info.decl(InitializerName(self.asTerm.name)).symbol.asTerm
+
+ def isField(implicit ctx: Context): Boolean =
+ self.isTerm && !self.is(Method)
}
diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala
index 588a13fc9..850563a48 100644
--- a/src/dotty/tools/dotc/transform/TreeTransform.scala
+++ b/src/dotty/tools/dotc/transform/TreeTransform.scala
@@ -905,7 +905,7 @@ object TreeTransforms {
case tree: UnApply => goUnApply(tree, info.nx.nxTransUnApply(cur))
case tree: Template => goTemplate(tree, info.nx.nxTransTemplate(cur))
case tree: PackageDef => goPackageDef(tree, info.nx.nxTransPackageDef(cur))
- case Thicket(trees) => cpy.Thicket(tree)(transformTrees(trees, info, cur))
+ case Thicket(trees) => tree
case tree => goOther(tree, info.nx.nxTransOther(cur))
}
@@ -1164,7 +1164,8 @@ object TreeTransforms {
val stats = transformStats(tree.stats, tree.symbol, mutatedInfo, cur)(nestedCtx)
goPackageDef(cpy.PackageDef(tree)(pid, stats), mutatedInfo.nx.nxTransPackageDef(cur))
}
- case Thicket(trees) => cpy.Thicket(tree)(transformTrees(trees, info, cur))
+ case Thicket(trees) =>
+ cpy.Thicket(tree)(transformTrees(trees, info, cur))
case tree =>
implicit val originalInfo: TransformerInfo = info
goOther(tree, info.nx.nxTransOther(cur))
@@ -1200,11 +1201,10 @@ object TreeTransforms {
def transformStats(trees: List[Tree], exprOwner: Symbol, info: TransformerInfo, current: Int)(implicit ctx: Context): List[Tree] = {
val newInfo = mutateTransformers(info, prepForStats, info.nx.nxPrepStats, trees, current)
- val exprCtx = ctx.withOwner(exprOwner)
def transformStat(stat: Tree): Tree = stat match {
case _: Import | _: DefTree => transform(stat, newInfo, current)
case Thicket(stats) => cpy.Thicket(stat)(stats mapConserve transformStat)
- case _ => transform(stat, newInfo, current)(exprCtx)
+ case _ => transform(stat, newInfo, current)(ctx.exprContext(stat, exprOwner))
}
val newTrees = flatten(trees.mapconserve(transformStat))
goStats(newTrees, newInfo.nx.nxTransStats(current))(ctx, newInfo)
diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala
index e96e04b1a..8e8cf58f9 100644
--- a/src/dotty/tools/dotc/typer/ErrorReporting.scala
+++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala
@@ -35,7 +35,7 @@ object ErrorReporting {
// See test pending/pos/boundspropagation.scala
val treeSym = ctx.symOfContextTree(tree)
if (treeSym.exists && treeSym.name == cycleSym.name && treeSym.owner == cycleSym.owner) {
- val result = if (cycleSym.isSourceMethod) " result" else ""
+ val result = if (cycleSym is Method) " result" else ""
d"overloaded or recursive $cycleSym needs$result type"
}
else errorMsg(msg, cx.outer)
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index bb488bdc5..765c6bea7 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -236,9 +236,10 @@ trait TypeAssigner {
tree.withType(cls.thisType)
}
- def assignType(tree: untpd.Super, qual: Tree, inConstrCall: Boolean)(implicit ctx: Context) = {
+ def assignType(tree: untpd.Super, qual: Tree, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context) = {
val mix = tree.mix
- val cls = qual.tpe.widen.typeSymbol
+ val qtype @ ThisType(_) = qual.tpe
+ val cls = qtype.cls
def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix) match {
case p :: Nil =>
@@ -249,7 +250,8 @@ trait TypeAssigner {
errorType("ambiguous parent class qualifier", tree.pos)
}
val owntype =
- if (!mix.isEmpty) findMixinSuper(cls.info)
+ if (mixinClass.exists) mixinClass.typeRef
+ else if (!mix.isEmpty) findMixinSuper(cls.info)
else if (inConstrCall || ctx.erasedTypes) cls.info.firstParent
else {
val ps = cls.info.parents
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 3c36a1f25..a5396d445 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -1042,8 +1042,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case Thicket(stats) :: rest =>
traverse(stats ++ rest)
case stat :: rest =>
- val nestedCtx = if (exprOwner == ctx.owner) ctx else ctx.fresh.setOwner(exprOwner)
- buf += typed(stat)(nestedCtx)
+ buf += typed(stat)(ctx.exprContext(stat, exprOwner))
traverse(rest)
case nil =>
buf.toList
@@ -1246,6 +1245,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
typed(etaExpand(tree, wtp, arity), pt)
else if (wtp.paramTypes.isEmpty)
adaptInterpolated(tpd.Apply(tree, Nil), pt, EmptyTree)
+ else if (wtp.isImplicit)
+ err.typeMismatch(tree, pt)
else
errorTree(tree,
d"""missing arguments for $methodStr
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index ae648693a..aafd5e924 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -15,7 +15,7 @@ class tests extends CompilerTest {
implicit val defaultOptions = noCheckOptions ++ List(
"-Yno-deep-subtypes",
- "-Ycheck:patternMatcher,gettersSetters,restoreScopes"
+ "-Ycheck:resolveSuper,mixin,restoreScopes"
)
val twice = List("#runs", "2", "-YnoDoubleBindings")
diff --git a/tests/pos/blockescapes.scala b/tests/pos/blockescapes.scala
index 35d40974b..68ce37ed3 100644
--- a/tests/pos/blockescapes.scala
+++ b/tests/pos/blockescapes.scala
@@ -3,7 +3,7 @@ object blockescapes {
{ val x = 0; () }
val x0 = { class Foo; new Foo }
val x1 = {}
- val x2 = { val z = 0 }
+ var x2 = { val z = 0 }
val m1 = { val x = 2; x }
trait T
diff --git a/tests/pos/traits.scala b/tests/pos/traits.scala
index 15310d5a4..db611eeb5 100644
--- a/tests/pos/traits.scala
+++ b/tests/pos/traits.scala
@@ -1,10 +1,10 @@
-trait B {
+trait B extends Object {
val z: Int
}
-trait T {
+trait T extends B {
var x = 2