aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/Compiler.scala5
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala4
-rw-r--r--src/dotty/tools/dotc/transform/Constructors.scala36
-rw-r--r--src/dotty/tools/dotc/transform/GettersSetters.scala1
-rw-r--r--src/dotty/tools/dotc/transform/Mixin.scala84
-rw-r--r--src/dotty/tools/dotc/transform/SymUtils.scala9
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala5
-rw-r--r--test/dotc/tests.scala2
-rw-r--r--tests/pos/traits.scala4
9 files changed, 79 insertions, 71 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index f4690df08..62759ba09 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -50,8 +50,9 @@ class Compiler {
new Splitter),
List(new ElimByName,
new InterceptedMethods,
- new Literalize,
- new GettersSetters),
+ new Literalize),
+ List(new Mixin),
+ List(new GettersSetters),
List(new Erasure),
List(new CapturedVars,
new Constructors),
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 74ba79176..8c300c231 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -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)
diff --git a/src/dotty/tools/dotc/transform/Constructors.scala b/src/dotty/tools/dotc/transform/Constructors.scala
index 7bde1ba4f..c966e2678 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,7 +146,7 @@ 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)
@@ -226,10 +200,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/GettersSetters.scala b/src/dotty/tools/dotc/transform/GettersSetters.scala
index b0f6c15c8..b5933cc48 100644
--- a/src/dotty/tools/dotc/transform/GettersSetters.scala
+++ b/src/dotty/tools/dotc/transform/GettersSetters.scala
@@ -105,6 +105,7 @@ import Decorators._
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/Mixin.scala b/src/dotty/tools/dotc/transform/Mixin.scala
index 515ac9c10..8116c723a 100644
--- a/src/dotty/tools/dotc/transform/Mixin.scala
+++ b/src/dotty/tools/dotc/transform/Mixin.scala
@@ -11,7 +11,10 @@ import SymDenotations._
import Types._
import Decorators._
import DenotTransformers._
+import StdNames._
import NameOps._
+import ast.Trees._
+import util.Positions._
import collection.mutable
/** This phase performs the following transformations:
@@ -155,22 +158,21 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
private def superAccessors(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context): List[Tree] =
for (superAcc <- mixin.decls.filter(_ is SuperAccessor).toList)
- yield polyDefDef(implementation(cls, superAcc), forwarder(cls, rebindSuper(cls, superAcc)))
+ yield polyDefDef(implementation(cls, superAcc.asTerm), forwarder(cls, rebindSuper(cls, superAcc)))
private def traitInits(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context): List[Tree] =
for (field <- mixin.decls.filter(fld => fld.isField && !wasDeferred(fld)).toList)
- yield DefDef(implementation(cls, field), ref(field.initializer).withPos(cls.pos))
+ yield ValDef(implementation(cls, field.asTerm), superRef(cls, field.initializer, cls.pos))
private def setters(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context): List[Tree] =
for (setter <- mixin.decls.filter(setr => setr.isSetter && !wasDeferred(setr)).toList)
- yield DefDef(implementation(cls, setter), unitLiteral.withPos(cls.pos))
+ yield DefDef(implementation(cls, setter.asTerm), unitLiteral.withPos(cls.pos))
- private def implementation(cls: ClassSymbol, member: Symbol)(implicit ctx: Context): TermSymbol =
- member.copy(owner = cls, flags = member.flags &~ Deferred)
- .enteredAfter(thisTransform).asTerm
-
- private def constrCall(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context) =
- mixinSuperRef(cls, mixin.primaryConstructor)
+ private def implementation(cls: ClassSymbol, member: TermSymbol)(implicit ctx: Context): TermSymbol =
+ member.copy(
+ owner = cls,
+ name = member.name.stripScala2LocalSuffix,
+ flags = member.flags &~ Deferred).enteredAfter(thisTransform).asTerm
private def methodOverrides(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context): List[Tree] = {
def isOverridden(meth: Symbol) = meth.overridingSymbol(cls).is(Method, butNot = Deferred)
@@ -179,32 +181,66 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
!isOverridden(meth) &&
!meth.allOverriddenSymbols.forall(_ is Deferred)
for (meth <- mixin.decls.toList if needsDisambiguation(meth))
- yield polyDefDef(implementation(cls, meth), forwarder(cls, meth))
+ yield polyDefDef(implementation(cls, meth.asTerm), forwarder(cls, meth))
}
private def wasDeferred(sym: Symbol)(implicit ctx: Context) =
ctx.atPhase(thisTransform) { implicit ctx => sym is Deferred }
- private def mixinSuperRef(cls: ClassSymbol, target: Symbol)(implicit ctx: Context) =
- Super(ref(cls), target.owner.name.asTypeName, inConstrCall = false).select(target)
+ private def superRef(cls: ClassSymbol, target: Symbol, pos: Position)(implicit ctx: Context) = {
+ val inTrait = target.owner is Trait
+ Super(
+ qual = This(cls),
+ mix = if (inTrait) target.owner.name.asTypeName else tpnme.EMPTY,
+ inConstrCall = target.isConstructor && !target.owner.is(Trait),
+ mixinClass = if (inTrait) target.owner else NoSymbol
+ ).select(target)
+ }
private def forwarder(cls: ClassSymbol, target: Symbol)(implicit ctx: Context) =
(targs: List[Type]) => (vrefss: List[List[Tree]]) =>
- mixinSuperRef(cls, target).appliedToTypes(targs).appliedToArgss(vrefss).withPos(cls.pos)
+ superRef(cls, target, cls.pos).appliedToTypes(targs).appliedToArgss(vrefss)
override def transformTemplate(tree: Template)(implicit ctx: Context, info: TransformerInfo) = {
val cls = tree.symbol.owner.asClass
val stats = tree.body
- cpy.Template(tree)(body =
- if (cls is Trait) traitDefs(cls, stats)
- else
- cls.mixins.flatMap { mixin =>
- assert(mixin is Trait)
- traitInits(cls, mixin) :::
- constrCall(cls, mixin) ::
- setters(cls, mixin)
- superAccessors(cls, mixin) :::
- methodOverrides(cls, mixin)
- } ::: stats)
+ val superCls = cls.classInfo.parents.head.symbol
+ val mixins = cls.baseClasses.tail.takeWhile(_ ne superCls)
+
+ // If parent is a constructor call, pull out the call into a separate
+ // supercall constructor, which gets added to `superCalls`, and keep
+ // only the type.
+ val superCalls = new mutable.HashMap[Symbol, Tree]
+ def normalizeParent(tree: Tree) = tree match {
+ case superApp @ Apply(superSel @ Select(New(superType), nme.CONSTRUCTOR), superArgs) =>
+ val constr = superSel.symbol
+ superCalls(constr.owner) = superRef(cls, constr, superSel.pos).appliedToArgs(superArgs)
+ superType
+ case tree: TypeTree => tree
+ }
+ val parentTypeTrees = tree.parents.map(normalizeParent)
+
+ def supCalls(baseCls: Symbol): List[Tree] = superCalls.remove(baseCls) match {
+ case Some(call) => call :: Nil
+ case None =>
+ if (baseCls is Interface) Nil
+ else superRef(cls, baseCls.primaryConstructor, cls.pos).appliedToNone :: Nil
+ }
+
+ cpy.Template(tree)(
+ parents = parentTypeTrees,
+ body =
+ if (cls is Trait) traitDefs(cls, stats)
+ else {
+ val mixInits = mixins.flatMap { mixin =>
+ assert(mixin is Trait)
+ traitInits(cls, mixin) :::
+ supCalls(mixin) :::
+ setters(cls, mixin) :::
+ superAccessors(cls, mixin) :::
+ methodOverrides(cls, mixin)
+ }
+ supCalls(superCls) ::: mixInits ::: stats
+ })
}
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/transform/SymUtils.scala b/src/dotty/tools/dotc/transform/SymUtils.scala
index 06882f1c6..449affb9e 100644
--- a/src/dotty/tools/dotc/transform/SymUtils.scala
+++ b/src/dotty/tools/dotc/transform/SymUtils.scala
@@ -69,15 +69,6 @@ class SymUtils(val self: Symbol) extends AnyVal {
/** `fullName` where `$' is the separator character */
def flatName(implicit ctx: Context): Name = self.fullNameSeparated('$')
- /** The traits mixed into this class in linearization order.
- * These are all inherited traits that are not also inherited by the superclass
- */
- def mixins(implicit ctx: Context): List[ClassSymbol] = {
- val cls = self.asClass
- val superCls = cls.classInfo.parents.head.symbol
- cls.baseClasses.tail.takeWhile(_ ne superCls)
- }
-
def initializer(implicit ctx: Context): TermSymbol =
self.owner.info.decl(InitializerName(self.asTerm.name)).symbol.asTerm
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index bb488bdc5..ed10c7644 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -236,7 +236,7 @@ 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
@@ -249,7 +249,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/test/dotc/tests.scala b/test/dotc/tests.scala
index a52f79abd..2b0d7eb08 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:patternMatcher,mixin,gettersSetters,restoreScopes"
)
val twice = List("#runs", "2", "-YnoDoubleBindings")
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