Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,15 @@ class Compiler {
new Getters,
new ClassTags,
new ElimByName,
new AugmentScala2Traits,
new ResolveSuper),
List(new Erasure),
List(new ElimErasedValueType,
new VCInline,
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),
Expand All @@ -74,7 +76,6 @@ class Compiler {
new ExpandPrivate,
new CollectEntryPoints,
new LabelDefs,
new ElimWildcardIdents,
new TraitConstructors),
List(new GenBCode)
)
Expand Down
9 changes: 9 additions & 0 deletions src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down
54 changes: 45 additions & 9 deletions src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
8 changes: 7 additions & 1 deletion src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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

Expand Down
14 changes: 10 additions & 4 deletions src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
97 changes: 97 additions & 0 deletions src/dotty/tools/dotc/transform/AugmentScala2Traits.scala
Original file line number Diff line number Diff line change
@@ -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 %")
}
}
}
14 changes: 9 additions & 5 deletions src/dotty/tools/dotc/transform/Constructors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 _ =>
}
}
Expand Down
37 changes: 0 additions & 37 deletions src/dotty/tools/dotc/transform/ElimWildcardIdents.scala

This file was deleted.

2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/transform/ExpandSAMs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading