aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorodersky <odersky@gmail.com>2015-06-06 11:00:59 +0200
committerodersky <odersky@gmail.com>2015-06-06 11:00:59 +0200
commit6ca52b0f23f0c3425d054d0918a149e0e7afb765 (patch)
tree2feaae75dc15cde118cc7fafc5912fa50247d3bd /src
parentc0770edba1f5ba85b5a48f2c2ce68704dbe00087 (diff)
parent0cdb29904affbf55d5f08a005e8b96acfd73aa81 (diff)
downloaddotty-6ca52b0f23f0c3425d054d0918a149e0e7afb765.tar.gz
dotty-6ca52b0f23f0c3425d054d0918a149e0e7afb765.tar.bz2
dotty-6ca52b0f23f0c3425d054d0918a149e0e7afb765.zip
Merge pull request #622 from dotty-staging/add/implement-scala2-traits
Implement Scala2 traits
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/Compiler.scala3
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala9
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala54
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala8
-rw-r--r--src/dotty/tools/dotc/core/NameOps.scala14
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala1
-rw-r--r--src/dotty/tools/dotc/core/TypeErasure.scala2
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala2
-rw-r--r--src/dotty/tools/dotc/transform/AugmentScala2Traits.scala97
-rw-r--r--src/dotty/tools/dotc/transform/Constructors.scala14
-rw-r--r--src/dotty/tools/dotc/transform/ElimWildcardIdents.scala37
-rw-r--r--src/dotty/tools/dotc/transform/ExpandSAMs.scala2
-rw-r--r--src/dotty/tools/dotc/transform/FullParameterization.scala13
-rw-r--r--src/dotty/tools/dotc/transform/LazyVals.scala12
-rw-r--r--src/dotty/tools/dotc/transform/LinkScala2ImplClasses.scala58
-rw-r--r--src/dotty/tools/dotc/transform/Memoize.scala11
-rw-r--r--src/dotty/tools/dotc/transform/Mixin.scala48
-rw-r--r--src/dotty/tools/dotc/transform/MixinOps.scala12
-rw-r--r--src/dotty/tools/dotc/transform/PatternMatcher.scala2
-rw-r--r--src/dotty/tools/dotc/transform/ResolveSuper.scala13
-rw-r--r--src/dotty/tools/dotc/transform/SymUtils.scala6
-rw-r--r--src/dotty/tools/dotc/transform/SyntheticMethods.scala3
-rw-r--r--src/dotty/tools/dotc/transform/TraitConstructors.scala3
-rw-r--r--src/dotty/tools/dotc/transform/TypeUtils.scala2
24 files changed, 310 insertions, 116 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index d7ef44144..386f976cf 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -56,6 +56,7 @@ class Compiler {
new Getters,
new ClassTags,
new ElimByName,
+ new AugmentScala2Traits,
new ResolveSuper),
List(new Erasure),
List(new ElimErasedValueType,
@@ -63,6 +64,7 @@ class Compiler {
new Mixin,
new LazyVals,
new Memoize,
+ new LinkScala2ImplClasses,
new CapturedVars, // capturedVars has a transformUnit: no phases should introduce local mutable vars here
new Constructors,
new FunctionalInterfaces),
@@ -74,7 +76,6 @@ class Compiler {
new ExpandPrivate,
new CollectEntryPoints,
new LabelDefs,
- new ElimWildcardIdents,
new TraitConstructors),
List(new GenBCode)
)
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index a38a238c8..e38de458a 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -418,6 +418,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
Thicket(valdef, clsdef)
}
+ /** A `_' with given type */
+ def Underscore(tp: Type)(implicit ctx: Context) = untpd.Ident(nme.WILDCARD).withType(tp)
+
def defaultValue(tpe: Types.Type)(implicit ctx: Context) = {
val tpw = tpe.widen
@@ -720,6 +723,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def ensureConforms(tp: Type)(implicit ctx: Context): Tree =
if (tree.tpe <:< tp) tree else asInstance(tp)
+ /** If inititializer tree is `_', the default value of its type,
+ * otherwise the tree itself.
+ */
+ def wildcardToDefault(implicit ctx: Context) =
+ if (isWildcardArg(tree)) defaultValue(tree.tpe) else tree
+
/** `this && that`, for boolean trees `this`, `that` */
def and(that: Tree)(implicit ctx: Context): Tree =
tree.select(defn.Boolean_&&).appliedTo(that)
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 6ac15dbca..4d475fe2b 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -227,16 +227,36 @@ object Denotations {
else
asSingleDenotation
- /** Form a denotation by conjoining with denotation `that` */
+ /** Form a denotation by conjoining with denotation `that`.
+ *
+ * NoDenotations are dropped. MultiDenotations are handled by merging
+ * parts with same signatures. SingleDenotations with equal signatures
+ * are joined as follows:
+ *
+ * In a first step, consider only those denotations which have symbols
+ * that are accessible from prefix `pre`.
+ *
+ * If there are several such denotations, try to pick one by applying the following
+ * three precedence rules in decreasing order of priority:
+ *
+ * 1. Prefer denotations with more specific infos.
+ * 2. If infos are equally specific, prefer denotations with concrete symbols over denotations
+ * with abstract symbols.
+ * 3. If infos are equally specific and symbols are equally concrete,
+ * prefer denotations with symbols defined in subclasses
+ * over denotations with symbols defined in proper superclasses.
+ *
+ * If there is exactly one (preferred) accessible denotation, return it.
+ *
+ * If there is no preferred accessible denotation, return a JointRefDenotation
+ * with one of the operand symbols (unspecified which one), and an info which
+ * is intersection (&) of the infos of the operand denotations.
+ *
+ * If SingleDenotations with different signatures are joined, return NoDenotation.
+ */
def & (that: Denotation, pre: Type)(implicit ctx: Context): Denotation = {
- /** Try to merge denot1 and denot2 without adding a new signature.
- * Prefer denotations with more specific types, provided the symbol stays accessible
- * Prefer denotations with accessible symbols over denotations with
- * existing, but inaccessible symbols.
- * If there's no preference, produce a JointRefDenotation with the intersection of both infos.
- * If unsuccessful, return NoDenotation.
- */
+ /** Try to merge denot1 and denot2 without adding a new signature. */
def mergeDenot(denot1: Denotation, denot2: SingleDenotation): Denotation = denot1 match {
case denot1 @ MultiDenotation(denot11, denot12) =>
val d1 = mergeDenot(denot11, denot2)
@@ -254,8 +274,24 @@ object Denotations {
val sym1 = denot1.symbol
val sym2 = denot2.symbol
val sym2Accessible = sym2.isAccessibleFrom(pre)
+ def shadows(sym1: Symbol, sym2: Symbol) = {
+ val owner1 = sym1.owner
+ val owner2 = sym2.owner
+ owner1.derivesFrom(owner2) && owner1.ne(owner2)
+ }
+ /** Preference according to order (overrides, isAsConcrete, shadows)*/
def prefer(info1: Type, sym1: Symbol, info2: Type, sym2: Symbol) =
- info1.overrides(info2) && (sym1.isAsConcrete(sym2) || !info2.overrides(info1))
+ info1.overrides(info2) && (
+ // non-standard ordering of tests for efficiency -
+ // overrides is costlier to compute than the others, so its 2nd test comes last.
+ sym1.isAsConcrete(sym2) && (
+ !sym2.isAsConcrete(sym1)
+ ||
+ shadows(sym1, sym2)
+ )
+ ||
+ !info2.overrides(info1)
+ )
if (sym2Accessible && prefer(info2, sym2, info1, sym1)) denot2
else {
val sym1Accessible = sym1.isAccessibleFrom(pre)
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index cfa0faef9..3efadcb00 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -427,7 +427,7 @@ object Flags {
/** Flags representing modifiers that can appear in trees */
final val ModifierFlags =
- SourceModifierFlags | Module | Param | Synthetic | Package | Local
+ SourceModifierFlags | Module | Param | Synthetic | Package | Local | commonFlags(Mutable)
// | Trait is subsumed by commonFlags(Lazy) from SourceModifierFlags
assert(ModifierFlags.isTermFlags && ModifierFlags.isTypeFlags)
@@ -520,12 +520,18 @@ object Flags {
/** A private method */
final val PrivateMethod = allOf(Private, Method)
+ /** A private accessor */
+ final val PrivateAccessor = allOf(Private, Accessor)
+
/** A type parameter with synthesized name */
final val ExpandedTypeParam = allOf(ExpandedName, TypeParam)
/** A parameter or parameter accessor */
final val ParamOrAccessor = Param | ParamAccessor
+ /** A lazy or deferred value */
+ final val LazyOrDeferred = Lazy | Deferred
+
/** A type parameter or type parameter accessor */
final val TypeParamOrAccessor = TypeParam | TypeParamAccessor
diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala
index bf5e219cf..dc94f6db1 100644
--- a/src/dotty/tools/dotc/core/NameOps.scala
+++ b/src/dotty/tools/dotc/core/NameOps.scala
@@ -155,13 +155,17 @@ object NameOps {
/** The expanded name of `name` relative to given class `base`.
*/
- def expandedName(base: Symbol)(implicit ctx: Context): N =
- expandedName(if (base is Flags.ExpandedName) base.name else base.fullNameSeparated("$"))
+ def expandedName(base: Symbol, separator: Name)(implicit ctx: Context): N =
+ expandedName(if (base is Flags.ExpandedName) base.name else base.fullNameSeparated("$"), separator)
+
+ def expandedName(base: Symbol)(implicit ctx: Context): N = expandedName(base, nme.EXPAND_SEPARATOR)
/** The expanded name of `name` relative to `basename` with given `separator`
*/
- def expandedName(prefix: Name): N =
- name.fromName(prefix ++ nme.EXPAND_SEPARATOR ++ name).asInstanceOf[N]
+ def expandedName(prefix: Name, separator: Name = nme.EXPAND_SEPARATOR): N =
+ name.fromName(prefix ++ separator ++ name).asInstanceOf[N]
+
+ def expandedName(prefix: Name): N = expandedName(prefix, nme.EXPAND_SEPARATOR)
def unexpandedName: N = {
val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR)
@@ -178,6 +182,8 @@ object NameOps {
def revertShadowed: N = likeTyped(name.drop(nme.SHADOWED.length))
+ def implClassName: N = likeTyped(name ++ tpnme.IMPL_CLASS_SUFFIX)
+
/** Translate a name into a list of simple TypeNames and TermNames.
* In all segments before the last, type/term is determined by whether
* the following separator char is '.' or '#'. The last segment
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index 6273612c7..eaf4ce1e2 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -126,6 +126,7 @@ object StdNames {
val INITIALIZER_PREFIX: N = "initial$"
val COMPANION_MODULE_METHOD: N = "companion$module"
val COMPANION_CLASS_METHOD: N = "companion$class"
+ val TRAIT_SETTER_SEPARATOR: N = "$_setter_$"
// 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/TypeErasure.scala b/src/dotty/tools/dotc/core/TypeErasure.scala
index fac795ef8..92e32d4b1 100644
--- a/src/dotty/tools/dotc/core/TypeErasure.scala
+++ b/src/dotty/tools/dotc/core/TypeErasure.scala
@@ -164,7 +164,7 @@ object TypeErasure {
else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx))
else erase.eraseInfo(tp, sym)(erasureCtx) match {
case einfo: MethodType if sym.isGetter && einfo.resultType.isRef(defn.UnitClass) =>
- MethodType(Nil, Nil, defn.BoxedUnitClass.typeRef)
+ MethodType(Nil, defn.BoxedUnitClass.typeRef)
case einfo =>
einfo
}
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index cc8f0bef8..fa238f32c 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -172,7 +172,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
* parent { type Apply = body; argBindings? }
*
* split it into
-
+ *
* - the `parent`
* - the simplified `body`
* - the bindings HK$ members, if there are any
diff --git a/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala b/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala
new file mode 100644
index 000000000..c3e205f83
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala
@@ -0,0 +1,97 @@
+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._
+
+/** This phase augments Scala2 traits with implementation classes and with additional members
+ * needed for mixin composition.
+ * These symbols would have been added between Unpickling and Mixin in the Scala2 pipeline.
+ * Specifcally, it adds
+ *
+ * - an implementation class which defines a trait constructor and trait method implementations
+ * - trait setters for vals defined in traits
+ *
+ * Furthermore, it expands the names of all private getters and setters in the trait and makes
+ * them not-private.
+ */
+class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransformer with FullParameterization { thisTransform =>
+ import ast.tpd._
+
+ override def phaseName: String = "augmentScala2Traits"
+
+ override def rewiredTarget(referenced: Symbol, derived: Symbol)(implicit ctx: Context) = NoSymbol
+
+ override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = {
+ val cls = impl.symbol.owner.asClass
+ for (mixin <- cls.mixins)
+ if (mixin.is(Scala2x))
+ augmentScala2Trait(mixin, cls)
+ impl
+ }
+
+ private def augmentScala2Trait(mixin: ClassSymbol, cls: ClassSymbol)(implicit ctx: Context): Unit = {
+ if (mixin.implClass.is(Scala2x)) () // nothing to do, mixin was already augmented
+ else {
+ //println(i"creating new implclass for $mixin ${mixin.implClass}")
+ val ops = new MixinOps(cls, thisTransform)
+ import ops._
+
+ val implClass = ctx.newCompleteClassSymbol(
+ owner = mixin.owner,
+ name = mixin.name.implClassName,
+ flags = Abstract | Scala2x,
+ parents = defn.ObjectClass.typeRef :: Nil,
+ assocFile = mixin.assocFile).enteredAfter(thisTransform)
+
+ def implMethod(meth: TermSymbol): Symbol = {
+ val mold =
+ if (meth.isConstructor)
+ meth.copySymDenotation(
+ name = nme.IMPLCLASS_CONSTRUCTOR,
+ info = MethodType(Nil, defn.UnitType))
+ else meth.ensureNotPrivate
+ meth.copy(
+ owner = implClass,
+ name = mold.name.asTermName,
+ flags = Method | JavaStatic | mold.flags & ExpandedName,
+ info = fullyParameterizedType(mold.info, mixin))
+ }
+
+ def traitSetter(getter: TermSymbol) = {
+ val separator = if (getter.is(Private)) nme.EXPAND_SEPARATOR else nme.TRAIT_SETTER_SEPARATOR
+ val expandedGetterName =
+ if (getter.is(ExpandedName)) getter.name
+ else getter.name.expandedName(getter.owner, separator)
+ getter.copy(
+ name = expandedGetterName.setterName,
+ flags = Method | Accessor | ExpandedName,
+ info = MethodType(getter.info.resultType :: Nil, defn.UnitType))
+ }
+
+ for (sym <- mixin.info.decls) {
+ if (needsForwarder(sym) || sym.isConstructor || sym.isGetter && sym.is(Lazy))
+ implClass.enter(implMethod(sym.asTerm))
+ if (sym.isGetter && !sym.is(LazyOrDeferred) &&
+ !sym.setter.exists && !sym.info.resultType.isInstanceOf[ConstantType])
+ traitSetter(sym.asTerm).enteredAfter(thisTransform)
+ if (sym.is(PrivateAccessor, butNot = ExpandedName) &&
+ (sym.isGetter || sym.isSetter)) // strangely, Scala 2 fields are also methods that have Accessor set.
+ sym.ensureNotPrivate.installAfter(thisTransform)
+ }
+ ctx.log(i"Scala2x trait decls of $mixin = ${mixin.info.decls.toList.map(_.showDcl)}%\n %")
+ ctx.log(i"Scala2x impl decls of $mixin = ${implClass.info.decls.toList.map(_.showDcl)}%\n %")
+ }
+ }
+}
diff --git a/src/dotty/tools/dotc/transform/Constructors.scala b/src/dotty/tools/dotc/transform/Constructors.scala
index fa60ad277..100e9ff21 100644
--- a/src/dotty/tools/dotc/transform/Constructors.scala
+++ b/src/dotty/tools/dotc/transform/Constructors.scala
@@ -30,15 +30,19 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
import tpd._
override def phaseName: String = "constructors"
- override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Erasure])
+ override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Memoize])
- /** All initializers should be moved into constructor
- */
+ /** All initializers for non-lazy fields should be moved into constructor.
+ * All non-abstract methods should be implemented (this is assured for constructors
+ * in this phase and for other methods in memoize).
+ */
override def checkPostCondition(tree: tpd.Tree)(implicit ctx: Context): Unit = {
tree match {
- case t: ValDef if ((t.rhs ne EmptyTree) && !(t.symbol is Flags.Lazy) && t.symbol.owner.isClass) =>
- assert(false, i"$t initializers should be moved to constructors")
+ case tree: ValDef if tree.symbol.exists && tree.symbol.owner.isClass && !tree.symbol.is(Lazy) =>
+ assert(tree.rhs.isEmpty, i"$tree: initializer should be moved to constructors")
+ case tree: DefDef if !tree.symbol.is(LazyOrDeferred) =>
+ assert(!tree.rhs.isEmpty, i"unimplemented: $tree")
case _ =>
}
}
diff --git a/src/dotty/tools/dotc/transform/ElimWildcardIdents.scala b/src/dotty/tools/dotc/transform/ElimWildcardIdents.scala
deleted file mode 100644
index 29194d235..000000000
--- a/src/dotty/tools/dotc/transform/ElimWildcardIdents.scala
+++ /dev/null
@@ -1,37 +0,0 @@
-package dotty.tools.dotc
-package transform
-
-import TreeTransforms.{MiniPhaseTransform, TransformerInfo}
-import ast.tpd
-import ast.Trees._
-import core._
-import Contexts.Context
-import Symbols._
-import Types._
-import StdNames._
-
-/**
- * Replace Ident("_") in tree with default values of corresponding type:
- * numerics: `0`
- * booleans: `false`
- * classes: `null`
- */
-class ElimWildcardIdents extends MiniPhaseTransform {
- import ast.tpd._
- def phaseName: String = "elimWildcardIdents"
-
- def wildcardToDefaultValue(tree: Tree)(implicit ctx: Context) = {
- def recur(x: Tree): Tree = x match {
- case x: Ident if x.name == nme.WILDCARD && x.symbol.isClass => defaultValue(tree.tpe)
- case Block(Nil, y) => recur(y)
- case _ => tree
- }
- recur(tree)
- }
-
- override def transformValDef(tree: tpd.ValDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree =
- cpy.ValDef(tree)(rhs = wildcardToDefaultValue(tree.rhs))
-
- override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree =
- cpy.DefDef(tree)(rhs = wildcardToDefaultValue(tree.rhs))
-}
diff --git a/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/src/dotty/tools/dotc/transform/ExpandSAMs.scala
index bba42f403..2416e4624 100644
--- a/src/dotty/tools/dotc/transform/ExpandSAMs.scala
+++ b/src/dotty/tools/dotc/transform/ExpandSAMs.scala
@@ -74,7 +74,7 @@ class ExpandSAMs extends MiniPhaseTransform { thisTransformer =>
val defaultSym = ctx.newSymbol(isDefinedAtFn, nme.WILDCARD, Synthetic, selector.tpe.widen)
val defaultCase =
CaseDef(
- Bind(defaultSym, untpd.Ident(nme.WILDCARD).withType(selector.tpe.widen)),
+ Bind(defaultSym, Underscore(selector.tpe.widen)),
EmptyTree,
Literal(Constant(false)))
cpy.Match(applyRhs)(paramRef, cases.map(translateCase) :+ defaultCase)
diff --git a/src/dotty/tools/dotc/transform/FullParameterization.scala b/src/dotty/tools/dotc/transform/FullParameterization.scala
index 87d492062..e9057e885 100644
--- a/src/dotty/tools/dotc/transform/FullParameterization.scala
+++ b/src/dotty/tools/dotc/transform/FullParameterization.scala
@@ -86,6 +86,7 @@ trait FullParameterization {
* }
*
* If a self type is present, $this has this self type as its type.
+ * @param abstractOverClass if true, include the type parameters of the class in the method's list of type parameters.
*/
def fullyParameterizedType(info: Type, clazz: ClassSymbol, abstractOverClass: Boolean = true)(implicit ctx: Context): Type = {
val (mtparamCount, origResult) = info match {
@@ -225,12 +226,18 @@ trait FullParameterization {
}
object FullParameterization {
+
/** Assuming `info` is a result of a `fullyParameterizedType` call, the signature of the
* original method type `X` such that `info = fullyParameterizedType(X, ...)`.
*/
def memberSignature(info: Type)(implicit ctx: Context): Signature = info match {
- case info: PolyType => memberSignature(info.resultType)
- case info @ MethodType(nme.SELF :: Nil, _) => info.resultType.ensureMethodic.signature
- case _ => Signature.NotAMethod
+ case info: PolyType =>
+ memberSignature(info.resultType)
+ case info @ MethodType(nme.SELF :: Nil, _) =>
+ info.resultType.ensureMethodic.signature
+ case info @ MethodType(nme.SELF :: otherNames, thisType :: otherTypes) =>
+ info.derivedMethodType(otherNames, otherTypes, info.resultType).signature
+ case _ =>
+ Signature.NotAMethod
}
}
diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala
index 5b146a785..e52e2537c 100644
--- a/src/dotty/tools/dotc/transform/LazyVals.scala
+++ b/src/dotty/tools/dotc/transform/LazyVals.scala
@@ -146,8 +146,8 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer {
def mkNonThreadSafeDef(target: Tree, flag: Tree, rhs: Tree)(implicit ctx: Context) = {
val setFlag = flag.becomes(Literal(Constants.Constant(true)))
- val setTarget = target.becomes(rhs)
- val init = Block(List(setFlag, setTarget), target.ensureApplied)
+ val setTargets = if (isWildcardArg(rhs)) Nil else target.becomes(rhs) :: Nil
+ val init = Block(setFlag :: setTargets, target.ensureApplied)
If(flag.ensureApplied, target.ensureApplied, init)
}
@@ -175,7 +175,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer {
val containerSymbol = ctx.newSymbol(claz, containerName,
x.symbol.flags &~ containerFlagsMask | containerFlags | Flags.Private,
tpe, coord = x.symbol.coord
- ).entered
+ ).enteredAfter(this)
val containerTree = ValDef(containerSymbol, defaultValue(tpe))
if (x.tpe.isNotNull && tpe <:< defn.ObjectType) { // can use 'null' value instead of flag
@@ -184,7 +184,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer {
}
else {
val flagName = ctx.freshName(x.name ++ StdNames.nme.BITMAP_PREFIX).toTermName
- val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags | Flags.Private, defn.BooleanType).entered
+ val flagSymbol = ctx.newSymbol(x.symbol.owner, flagName, containerFlags | Flags.Private, defn.BooleanType).enteredAfter(this)
val flag = ValDef(flagSymbol, Literal(Constants.Constant(false)))
val slowPath = DefDef(x.symbol.asTerm, mkNonThreadSafeDef(ref(containerSymbol), ref(flagSymbol), x.rhs))
Thicket(List(containerTree, flag, slowPath))
@@ -278,7 +278,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer {
CaseDef(computedState, EmptyTree, body)
}
- val default = CaseDef(untpd.Ident(nme.WILDCARD).withType(defn.LongType), EmptyTree, Literal(Constant(())))
+ val default = CaseDef(Underscore(defn.LongType), EmptyTree, Literal(Constant(())))
val cases = Match(stateMask.appliedTo(ref(flagSymbol), Literal(Constant(ord))),
List(compute, waitFirst, waitSecond, computed, default)) //todo: annotate with @switch
@@ -331,7 +331,7 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer {
}
val containerName = ctx.freshName(x.name ++ StdNames.nme.LAZY_LOCAL).toTermName
- val containerSymbol = ctx.newSymbol(claz, containerName, (x.mods &~ containerFlagsMask | containerFlags).flags, tpe, coord = x.symbol.coord).entered
+ val containerSymbol = ctx.newSymbol(claz, containerName, (x.mods &~ containerFlagsMask | containerFlags).flags, tpe, coord = x.symbol.coord).enteredAfter(this)
val containerTree = ValDef(containerSymbol, defaultValue(tpe))
val offset = ref(companion).ensureApplied.select(offsetSymbol)
diff --git a/src/dotty/tools/dotc/transform/LinkScala2ImplClasses.scala b/src/dotty/tools/dotc/transform/LinkScala2ImplClasses.scala
new file mode 100644
index 000000000..8c247130a
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/LinkScala2ImplClasses.scala
@@ -0,0 +1,58 @@
+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.untpd
+import ast.Trees._
+import collection.mutable
+
+/** Rewrite calls
+ *
+ * super[M].f(args)
+ *
+ * where M is a Scala2 trait implemented by the current class to
+ *
+ * M$class.f(this, args)
+ *
+ * provided the implementation class M$class defines a corresponding function `f`.
+ */
+class LinkScala2ImplClasses extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
+ import ast.tpd._
+
+ override def phaseName: String = "linkScala2ImplClasses"
+
+ override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Mixin])
+
+ override def transformApply(app: Apply)(implicit ctx: Context, info: TransformerInfo) = {
+ def currentClass = ctx.owner.enclosingClass.asClass
+ app match {
+ case Apply(sel @ Select(Super(_, _), _), args)
+ if sel.symbol.owner.is(Scala2xTrait) && currentClass.mixins.contains(sel.symbol.owner) =>
+ val impl = implMethod(sel.symbol)
+ if (impl.exists) Apply(ref(impl), This(currentClass) :: args).withPos(app.pos)
+ else app // could have been an abstract method in a trait linked to from a super constructor
+ case _ =>
+ app
+ }
+ }
+
+ private def implMethod(meth: Symbol)(implicit ctx: Context): Symbol =
+ meth.owner.implClass.info
+ .decl(if (meth.isConstructor) nme.IMPLCLASS_CONSTRUCTOR else meth.name)
+ .suchThat(c => FullParameterization.memberSignature(c.info) == meth.signature)
+ .symbol
+
+ private val Scala2xTrait = allOf(Scala2x, Trait)
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/transform/Memoize.scala b/src/dotty/tools/dotc/transform/Memoize.scala
index cbde1ef8a..6b19b6d13 100644
--- a/src/dotty/tools/dotc/transform/Memoize.scala
+++ b/src/dotty/tools/dotc/transform/Memoize.scala
@@ -42,12 +42,6 @@ import Decorators._
*/
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Mixin])
- override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = tree match {
- case tree: DefDef if !tree.symbol.is(Lazy | Deferred) =>
- assert(!tree.rhs.isEmpty, i"unimplemented: $tree")
- case _ =>
- }
-
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
val sym = tree.symbol
@@ -61,8 +55,9 @@ import Decorators._
lazy val field = sym.field.orElse(newField).asTerm
if (sym.is(Accessor, butNot = NoFieldNeeded))
if (sym.isGetter) {
- tree.rhs.changeOwnerAfter(sym, field, thisTransform)
- val fieldDef = transformFollowing(ValDef(field, tree.rhs))
+ var rhs = tree.rhs.changeOwnerAfter(sym, field, thisTransform)
+ if (isWildcardArg(rhs)) rhs = EmptyTree
+ val fieldDef = transformFollowing(ValDef(field, rhs))
val getterDef = cpy.DefDef(tree)(rhs = transformFollowingDeep(ref(field)))
Thicket(fieldDef, getterDef)
}
diff --git a/src/dotty/tools/dotc/transform/Mixin.scala b/src/dotty/tools/dotc/transform/Mixin.scala
index d2e7943f8..63e680414 100644
--- a/src/dotty/tools/dotc/transform/Mixin.scala
+++ b/src/dotty/tools/dotc/transform/Mixin.scala
@@ -14,6 +14,7 @@ import DenotTransformers._
import StdNames._
import NameOps._
import Phases._
+import ast.untpd
import ast.Trees._
import collection.mutable
@@ -46,10 +47,23 @@ import collection.mutable
* 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:
+ * in order of textual occurrence, produce the following:
+ *
+ * 3.1.1 If `x` is also a member of `C`, and M is a Dotty trait:
*
* <mods> def x(): T = super[M].initial$x()
*
+ * 3.1.2 If `x` is also a member of `C`, and M is a Scala 2.x trait:
+ *
+ * <mods> def x(): T = _
+ *
+ * 3.1.3 If `x` is not a member of `C`, and M is a Dotty trait:
+ *
+ * super[M].initial$x()
+ *
+ * 3.1.4 If `x` is not a member of `C`, and M is a Scala2.x trait, nothing gets added.
+ *
+ *
* 3.2 (done in `superCallOpt`) The call:
*
* super[M].<init>
@@ -104,7 +118,7 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
val isym = initializer(vsym)
val rhs = Block(
initBuf.toList.map(_.changeOwner(impl.symbol, isym)),
- stat.rhs.changeOwner(vsym, isym))
+ stat.rhs.changeOwner(vsym, isym).wildcardToDefault)
initBuf.clear()
cpy.DefDef(stat)(rhs = EmptyTree) :: DefDef(isym, rhs) :: Nil
case stat: DefDef if stat.symbol.isSetter =>
@@ -134,15 +148,7 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
if (baseCls.is(NoInitsTrait) || 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
-*/
+ transformFollowingDeep(superRef(baseCls.primaryConstructor).appliedToNone) :: Nil
}
}
@@ -150,16 +156,16 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
ctx.atPhase(thisTransform) { implicit ctx => sym is Deferred }
def traitInits(mixin: ClassSymbol): List[Tree] =
- for (getter <- mixin.info.decls.filter(getr => getr.isGetter && !wasDeferred(getr)).toList)
- yield {
- // transformFollowing call is needed to make memoize & lazy vals run
- val rhs = transformFollowing(superRef(initializer(getter)).appliedToNone)
- // isCurrent: getter is a member of implementing class
- val isCurrent = getter.is(ExpandedName) || ctx.atPhase(thisTransform) { implicit ctx =>
- cls.info.member(getter.name).suchThat(_.isGetter).symbol == getter
- }
- if (isCurrent) transformFollowing(DefDef(implementation(getter.asTerm), rhs))
- else rhs
+ for (getter <- mixin.info.decls.filter(getr => getr.isGetter && !wasDeferred(getr)).toList) yield {
+ val isScala2x = mixin.is(Scala2x)
+ def default = Underscore(getter.info.resultType)
+ def initial = transformFollowing(superRef(initializer(getter)).appliedToNone)
+ if (isCurrent(getter) || getter.is(ExpandedName))
+ // transformFollowing call is needed to make memoize & lazy vals run
+ transformFollowing(
+ DefDef(implementation(getter.asTerm), if (isScala2x) default else initial))
+ else if (isScala2x) EmptyTree
+ else initial
}
def setters(mixin: ClassSymbol): List[Tree] =
diff --git a/src/dotty/tools/dotc/transform/MixinOps.scala b/src/dotty/tools/dotc/transform/MixinOps.scala
index 1dce85eaa..64f0edfb8 100644
--- a/src/dotty/tools/dotc/transform/MixinOps.scala
+++ b/src/dotty/tools/dotc/transform/MixinOps.scala
@@ -31,6 +31,18 @@ class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx:
//sup.select(target)
}
+ /** Is `sym` a member of implementing class `cls`? */
+ def isCurrent(sym: Symbol) = cls.info.member(sym.name).hasAltWith(_.symbol == sym)
+
+ def needsForwarder(meth: Symbol): Boolean = {
+ def needsDisambiguation = !meth.allOverriddenSymbols.forall(_ is Deferred)
+ meth.is(Method, butNot = PrivateOrAccessorOrDeferred) &&
+ isCurrent(meth) &&
+ (needsDisambiguation || meth.owner.is(Scala2x))
+ }
+
+ final val PrivateOrAccessorOrDeferred = Private | Accessor | Deferred
+
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/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala
index 507dbb0ce..5fa17921f 100644
--- a/src/dotty/tools/dotc/transform/PatternMatcher.scala
+++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala
@@ -60,7 +60,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
val sel = Ident(selector.termRef).withPos(tree.pos)
val rethrow = tpd.CaseDef(EmptyTree, EmptyTree, Throw(ref(selector)))
val newCases = tpd.CaseDef(
- Bind(selector,untpd.Ident(nme.WILDCARD).withPos(tree.pos).withType(selector.info)),
+ Bind(selector, Underscore(selector.info).withPos(tree.pos)),
EmptyTree,
transformMatch(tpd.Match(sel, tree.cases ::: rethrow :: Nil)))
cpy.Try(tree)(tree.expr, newCases :: Nil, tree.finalizer)
diff --git a/src/dotty/tools/dotc/transform/ResolveSuper.scala b/src/dotty/tools/dotc/transform/ResolveSuper.scala
index 0f1c448d9..27387bca4 100644
--- a/src/dotty/tools/dotc/transform/ResolveSuper.scala
+++ b/src/dotty/tools/dotc/transform/ResolveSuper.scala
@@ -48,7 +48,8 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th
override def phaseName: String = "resolveSuper"
- override def runsAfter = Set(classOf[ElimByName]) // verified empirically, need to figure out what the reason is.
+ override def runsAfter = Set(classOf[ElimByName], // verified empirically, need to figure out what the reason is.
+ classOf[AugmentScala2Traits])
/** Returns the symbol that is accessed by a super-accessor in a mixin composition.
*
@@ -80,15 +81,9 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th
for (superAcc <- mixin.info.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 = PrivateOrAccessorOrDeferred) &&
- !isOverridden(meth) &&
- !meth.allOverriddenSymbols.forall(_ is Deferred)
- for (meth <- mixin.info.decls.toList if needsDisambiguation(meth))
+ def methodOverrides(mixin: ClassSymbol): List[Tree] =
+ for (meth <- mixin.info.decls.toList if needsForwarder(meth))
yield polyDefDef(implementation(meth.asTerm), forwarder(meth))
- }
val overrides = mixins.flatMap(mixin => superAccessors(mixin) ::: methodOverrides(mixin))
diff --git a/src/dotty/tools/dotc/transform/SymUtils.scala b/src/dotty/tools/dotc/transform/SymUtils.scala
index df3b183a9..d3e029a74 100644
--- a/src/dotty/tools/dotc/transform/SymUtils.scala
+++ b/src/dotty/tools/dotc/transform/SymUtils.scala
@@ -85,9 +85,9 @@ class SymUtils(val self: Symbol) extends AnyVal {
def field(implicit ctx: Context): Symbol =
self.owner.info.decl(self.asTerm.name.fieldName).suchThat(!_.is(Method)).symbol
- 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)
+
+ def implClass(implicit ctx: Context): Symbol =
+ self.owner.info.decl(self.name.implClassName).symbol
}
diff --git a/src/dotty/tools/dotc/transform/SyntheticMethods.scala b/src/dotty/tools/dotc/transform/SyntheticMethods.scala
index 9d0aebe45..b33bbd6a4 100644
--- a/src/dotty/tools/dotc/transform/SyntheticMethods.scala
+++ b/src/dotty/tools/dotc/transform/SyntheticMethods.scala
@@ -105,8 +105,7 @@ class SyntheticMethods(thisTransformer: DenotTransformer) {
*/
def equalsBody(that: Tree)(implicit ctx: Context): Tree = {
val thatAsClazz = ctx.newSymbol(ctx.owner, nme.x_0, Synthetic, clazzType, coord = ctx.owner.pos) // x$0
- def wildcardAscription(tp: Type) =
- Typed(untpd.Ident(nme.WILDCARD).withType(tp), TypeTree(tp))
+ def wildcardAscription(tp: Type) = Typed(Underscore(tp), TypeTree(tp))
val pattern = Bind(thatAsClazz, wildcardAscription(clazzType)) // x$0 @ (_: C)
val comparisons = accessors map (accessor =>
This(clazz).select(accessor).select(defn.Any_==).appliedTo(ref(thatAsClazz).select(accessor)))
diff --git a/src/dotty/tools/dotc/transform/TraitConstructors.scala b/src/dotty/tools/dotc/transform/TraitConstructors.scala
index 32c4b9da4..9fea468da 100644
--- a/src/dotty/tools/dotc/transform/TraitConstructors.scala
+++ b/src/dotty/tools/dotc/transform/TraitConstructors.scala
@@ -22,8 +22,7 @@ class TraitConstructors extends MiniPhaseTransform with SymTransformer {
def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = {
if (sym.isPrimaryConstructor && (sym.owner is Flags.Trait))
- // TODO: Someone needs to carefully check if name clashes are possible with this mangling scheme
- sym.copySymDenotation(name = nme.INITIALIZER_PREFIX ++ sym.owner.fullNameSeparated("$"))
+ sym.copySymDenotation(name = nme.IMPLCLASS_CONSTRUCTOR)
else sym
}
diff --git a/src/dotty/tools/dotc/transform/TypeUtils.scala b/src/dotty/tools/dotc/transform/TypeUtils.scala
index c01b6478c..d474c77b4 100644
--- a/src/dotty/tools/dotc/transform/TypeUtils.scala
+++ b/src/dotty/tools/dotc/transform/TypeUtils.scala
@@ -29,6 +29,6 @@ class TypeUtils(val self: Type) extends AnyVal {
def ensureMethodic(implicit ctx: Context): Type = self match {
case self: MethodicType => self
- case _ => ExprType(self)
+ case _ => if (ctx.erasedTypes) MethodType(Nil, self) else ExprType(self)
}
}