Skip to content

Commit 42e51d5

Browse files
committed
Merge pull request #217 from dotty-staging/transform/mixin
Transform/mixin
2 parents a9481bb + 83734e1 commit 42e51d5

32 files changed

+681
-146
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,16 @@ class Compiler {
4646
new TailRec),
4747
List(new PatternMatcher,
4848
new ExplicitOuter,
49-
// new LazyValTranformContext().transformer, // disabled, awaiting fixes
5049
new Splitter),
5150
List(new ElimByName,
5251
new InterceptedMethods,
5352
new Literalize,
54-
new GettersSetters),
53+
new Getters,
54+
new ResolveSuper),
5555
List(new Erasure),
56-
List(new CapturedVars,
56+
List(new Mixin,
57+
new Memoize, // TODO: Make LazyVals a part of this phase
58+
new CapturedVars,
5759
new Constructors),
5860
List(new LambdaLift,
5961
new Flatten,

src/dotty/tools/dotc/TypeErasure.scala

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package core
44

55
import Symbols._, Types._, Contexts._, Flags._, Names._, StdNames._, Decorators._, Flags.JavaDefined
66
import dotc.transform.ExplicitOuter._
7+
import typer.Mode
78
import util.DotClass
89

910
/** Erased types are:
@@ -89,7 +90,7 @@ object TypeErasure {
8990

9091
/** The current context with a phase no later than erasure */
9192
private def erasureCtx(implicit ctx: Context) =
92-
if (ctx.erasedTypes) ctx.withPhase(ctx.erasurePhase) else ctx
93+
if (ctx.erasedTypes) ctx.withPhase(ctx.erasurePhase).addMode(Mode.FutureDefsOK) else ctx
9394

9495
def erasure(tp: Type)(implicit ctx: Context): Type = scalaErasureFn(tp)(erasureCtx)
9596
def semiErasure(tp: Type)(implicit ctx: Context): Type = semiErasureFn(tp)(erasureCtx)
@@ -107,6 +108,8 @@ object TypeErasure {
107108
case tp: TermRef =>
108109
assert(tp.symbol.exists, tp)
109110
TermRef(erasedRef(tp.prefix), tp.symbol.asTerm)
111+
case tp: ThisType =>
112+
tp
110113
case tp =>
111114
erasure(tp)
112115
}
@@ -141,7 +144,12 @@ object TypeErasure {
141144
if ((sym eq defn.Any_asInstanceOf) || (sym eq defn.Any_isInstanceOf)) eraseParamBounds(sym.info.asInstanceOf[PolyType])
142145
else if (sym.isAbstractType) TypeAlias(WildcardType)
143146
else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx))
144-
else eraseInfo(tp)(erasureCtx)
147+
else eraseInfo(tp)(erasureCtx) match {
148+
case einfo: MethodType if sym.isGetter && einfo.resultType.isRef(defn.UnitClass) =>
149+
defn.BoxedUnitClass.typeRef
150+
case einfo =>
151+
einfo
152+
}
145153
}
146154

147155
def isUnboundedGeneric(tp: Type)(implicit ctx: Context) = !(
@@ -265,7 +273,7 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
265273
case tp: TermRef =>
266274
this(tp.widen)
267275
case ThisType(_) =>
268-
tp
276+
this(tp.widen)
269277
case SuperType(thistpe, supertpe) =>
270278
SuperType(this(thistpe), this(supertpe))
271279
case ExprType(rt) =>
@@ -319,7 +327,7 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
319327
}
320328

321329
def eraseInfo(tp: Type)(implicit ctx: Context) = tp match {
322-
case ExprType(rt) => MethodType(Nil, Nil, erasure(rt))
330+
case ExprType(rt) => MethodType(Nil, Nil, eraseResult(rt))
323331
case tp => erasure(tp)
324332
}
325333

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import transform.SymUtils._
66
import core._
77
import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
88
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols._
9-
import Denotations._, Decorators._
9+
import Denotations._, Decorators._, DenotTransformers._
1010
import config.Printers._
1111
import typer.Mode
1212
import collection.mutable
@@ -39,8 +39,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
3939
def This(cls: ClassSymbol)(implicit ctx: Context): This =
4040
untpd.This(cls.name).withType(cls.thisType)
4141

42-
def Super(qual: Tree, mix: TypeName, inConstrCall: Boolean)(implicit ctx: Context): Super =
43-
ta.assignType(untpd.Super(qual, mix), qual, inConstrCall)
42+
def Super(qual: Tree, mix: TypeName, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context): Super =
43+
ta.assignType(untpd.Super(qual, mix), qual, inConstrCall, mixinClass)
4444

4545
def Apply(fn: Tree, args: List[Tree])(implicit ctx: Context): Apply =
4646
ta.assignType(untpd.Apply(fn, args), fn, args)
@@ -527,7 +527,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
527527
*/
528528
def changeOwner(from: Symbol, to: Symbol)(implicit ctx: Context): ThisTree = {
529529
def loop(from: Symbol, froms: List[Symbol], tos: List[Symbol]): ThisTree = {
530-
if (from.isWeakOwner) loop(from.owner, from :: froms, to :: tos)
530+
if (from.isWeakOwner && !from.owner.isClass)
531+
loop(from.owner, from :: froms, to :: tos)
531532
else {
532533
//println(i"change owner ${from :: froms}%, % ==> $tos of $tree")
533534
new TreeTypeMap(oldOwners = from :: froms, newOwners = tos).apply(tree)
@@ -536,6 +537,26 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
536537
loop(from, Nil, to :: Nil)
537538
}
538539

540+
/** After phase `trans`, set the owner of every definition in this tree that was formerly
541+
* owner by `from` to `to`.
542+
*/
543+
def changeOwnerAfter(from: Symbol, to: Symbol, trans: DenotTransformer)(implicit ctx: Context): ThisTree = {
544+
assert(ctx.phase == trans.next)
545+
val traverser = new TreeTraverser {
546+
def traverse(tree: Tree) = tree match {
547+
case tree: DefTree =>
548+
val sym = tree.symbol
549+
if (sym.denot(ctx.withPhase(trans)).owner == from)
550+
sym.copySymDenotation(owner = to).installAfter(trans)
551+
if (sym.isWeakOwner) traverseChildren(tree)
552+
case _ =>
553+
traverseChildren(tree)
554+
}
555+
}
556+
traverser.traverse(tree)
557+
tree
558+
}
559+
539560
def select(name: Name)(implicit ctx: Context): Select =
540561
Select(tree, name)
541562

src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,9 @@ class ScalaSettings extends Settings.SettingGroup {
107107
val Xdce = BooleanSetting("-Ydead-code", "Perform dead code elimination.")
108108
val debug = BooleanSetting("-Ydebug", "Increase the quantity of debugging output.")
109109
val debugNames = BooleanSetting("-YdebugNames", "Show name-space indicators when printing names")
110-
val debugTrace = BooleanSetting("-YdebugTrace", "Trace core operations")
111-
val debugFlags = BooleanSetting("-YdebugFlags", "Print all flags of definitions")
110+
val debugTrace = BooleanSetting("-Ydebug-trace", "Trace core operations")
111+
val debugFlags = BooleanSetting("-Ydebug-flags", "Print all flags of definitions")
112+
val debugOwners = BooleanSetting("-Ydebug-owners", "Print all owners of definitions (requires -Yprint-syms)")
112113
//val doc = BooleanSetting ("-Ydoc", "Generate documentation")
113114
val termConflict = ChoiceSetting("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error")
114115
val inline = BooleanSetting("-Yinline", "Perform inlining when possible.")

src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,16 +297,21 @@ object Contexts {
297297
def thisCallArgContext: Context = {
298298
assert(owner.isClassConstructor)
299299
val constrCtx = outersIterator.dropWhile(_.outer.owner == owner).next
300-
var classCtx = outersIterator.dropWhile(!_.isClassDefContext).next
301-
classCtx.superOrThisCallContext(owner, constrCtx.scope).setTyperState(typerState)
300+
superOrThisCallContext(owner, constrCtx.scope).setTyperState(typerState)
302301
}
303302

304303
/** The super= or this-call context with given owner and locals. */
305304
private def superOrThisCallContext(owner: Symbol, locals: Scope): FreshContext = {
306-
assert(isClassDefContext)
307-
outer.fresh.setOwner(owner).setScope(locals).setMode(ctx.mode | Mode.InSuperCall)
305+
var classCtx = outersIterator.dropWhile(!_.isClassDefContext).next
306+
classCtx.outer.fresh.setOwner(owner).setScope(locals).setMode(classCtx.mode | Mode.InSuperCall)
308307
}
309308

309+
/** The context of expression `expr` seen as a member of a statement sequence */
310+
def exprContext(stat: Tree[_ >: Untyped], exprOwner: Symbol) =
311+
if (exprOwner == this.owner) this
312+
else if (untpd.isSuperConstrCall(stat) && this.owner.isClass) superCallContext
313+
else ctx.fresh.setOwner(exprOwner)
314+
310315
/** The current source file; will be derived from current
311316
* compilation unit.
312317
*/

src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ object Denotations {
202202
def requiredClass(name: PreName)(implicit ctx: Context): ClassSymbol =
203203
info.member(name.toTypeName).requiredSymbol(_.isClass).asClass
204204

205-
/** The denotation that has a type matching `targetType` when seen
205+
/** The alternative of this denotation that has a type matching `targetType` when seen
206206
* as a member of type `site`, `NoDenotation` if none exists.
207207
*/
208208
def matchingDenotation(site: Type, targetType: Type)(implicit ctx: Context): SingleDenotation =

src/dotty/tools/dotc/core/NameOps.scala

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,15 @@ object NameOps {
4747
}
4848
}
4949

50-
object SuperAccessorName {
51-
val pre = nme.SUPER_PREFIX
50+
class PrefixNameExtractor(pre: TermName) {
5251
def apply(name: TermName): TermName = pre ++ name
5352
def unapply(name: TermName): Option[TermName] =
5453
if (name startsWith pre) Some(name.drop(pre.length).asTermName) else None
5554
}
5655

56+
object SuperAccessorName extends PrefixNameExtractor(nme.SUPER_PREFIX)
57+
object InitializerName extends PrefixNameExtractor(nme.INITIALIZER_PREFIX)
58+
5759
implicit class NameDecorator[N <: Name](val name: N) extends AnyVal {
5860
import nme._
5961

@@ -68,14 +70,13 @@ object NameOps {
6870
def isProtectedAccessorName = name startsWith PROTECTED_PREFIX
6971
def isReplWrapperName = name containsSlice INTERPRETER_IMPORT_WRAPPER
7072
def isSetterName = name endsWith SETTER_SUFFIX
71-
def isTraitSetterName = isSetterName && (name containsSlice TRAIT_SETTER_PREFIX)
7273
def isSingletonName = name endsWith SINGLETON_SUFFIX
7374
def isModuleClassName = name endsWith MODULE_SUFFIX
7475
def isImportName = name startsWith IMPORT
7576
def isFieldName = name endsWith LOCAL_SUFFIX
7677
def isInheritedName = name.length > 0 && name.head == '(' && name.startsWith(nme.INHERITED)
7778
def isDefaultGetterName = name.isTermName && name.asTermName.defaultGetterIndex >= 0
78-
79+
def isScala2LocalSuffix = name.endsWith(" ")
7980
def isModuleVarName(name: Name): Boolean =
8081
name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX
8182

@@ -224,9 +225,6 @@ object NameOps {
224225
implicit class TermNameDecorator(val name: TermName) extends AnyVal {
225226
import nme._
226227

227-
def traitSetterName: TermName =
228-
nme.TRAIT_SETTER_PREFIX ++ setterName
229-
230228
def setterName: TermName =
231229
if (name.isFieldName) name.fieldToGetter.setterName
232230
else name ++ SETTER_SUFFIX
@@ -240,13 +238,8 @@ object NameOps {
240238
else name ++ LOCAL_SUFFIX
241239

242240
private def setterToGetter: TermName = {
243-
val p = name.indexOfSlice(TRAIT_SETTER_PREFIX)
244-
if (p >= 0)
245-
(name drop (p + TRAIT_SETTER_PREFIX.length)).asTermName.getterName
246-
else {
247-
assert(name.endsWith(SETTER_SUFFIX), name + " is referenced as a setter but has wrong name format")
248-
name.take(name.length - SETTER_SUFFIX.length).asTermName
249-
}
241+
assert(name.endsWith(SETTER_SUFFIX), name + " is referenced as a setter but has wrong name format")
242+
name.take(name.length - SETTER_SUFFIX.length).asTermName
250243
}
251244

252245
def fieldToGetter: TermName = {
@@ -283,6 +276,9 @@ object NameOps {
283276
-1
284277
}
285278

279+
def stripScala2LocalSuffix: TermName =
280+
if (name.isScala2LocalSuffix) name.init.asTermName else name
281+
286282
/** The name of an accessor for protected symbols. */
287283
def protectedAccessorName: TermName =
288284
PROTECTED_PREFIX ++ name.unexpandedName()

src/dotty/tools/dotc/core/Scopes.scala

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import printing.Printer
2020
import util.common._
2121
import util.DotClass
2222
import SymDenotations.NoDenotation
23-
import collection.mutable.ListBuffer
23+
import collection.mutable
2424

2525
object Scopes {
2626

@@ -172,12 +172,27 @@ object Scopes {
172172
*/
173173
private var elemsCache: List[Symbol] = null
174174

175-
def cloneScope(implicit ctx: Context): MutableScope = newScopeWith(this.toList: _*)
175+
/** Clone scope, taking care not to force the denotations of any symbols in the scope.
176+
*/
177+
def cloneScope(implicit ctx: Context): MutableScope = {
178+
val entries = new mutable.ArrayBuffer[ScopeEntry]
179+
var e = lastEntry
180+
while ((e ne null) && e.owner == this) {
181+
entries += e
182+
e = e.prev
183+
}
184+
val scope = newScope
185+
for (i <- entries.length - 1 to 0 by -1) {
186+
val e = entries(i)
187+
scope.newScopeEntry(e.name, e.sym)
188+
}
189+
scope
190+
}
176191

177-
/** create and enter a scope entry */
178-
protected def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry = {
192+
/** create and enter a scope entry with given name and symbol */
193+
protected def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = {
179194
ensureCapacity(if (hashTable ne null) hashTable.length else MinHash)
180-
val e = new ScopeEntry(sym.name, sym, this)
195+
val e = new ScopeEntry(name, sym, this)
181196
e.prev = lastEntry
182197
lastEntry = e
183198
if (hashTable ne null) enterInHash(e)
@@ -186,6 +201,10 @@ object Scopes {
186201
e
187202
}
188203

204+
/** create and enter a scope entry */
205+
protected def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry =
206+
newScopeEntry(sym.name, sym)
207+
189208
private def enterInHash(e: ScopeEntry)(implicit ctx: Context): Unit = {
190209
val idx = e.name.hashCode & (hashTable.length - 1)
191210
e.tail = hashTable(idx)
@@ -325,7 +344,7 @@ object Scopes {
325344
}
326345

327346
override def implicitDecls(implicit ctx: Context): List[TermRef] = {
328-
var irefs = new ListBuffer[TermRef]
347+
var irefs = new mutable.ListBuffer[TermRef]
329348
var e = lastEntry
330349
while (e ne null) {
331350
if (e.sym is Implicit) {

src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ object StdNames {
119119
val SINGLETON_SUFFIX: N = ".type"
120120
val SPECIALIZED_SUFFIX: N = "$sp"
121121
val SUPER_PREFIX: N = "super$"
122-
val TRAIT_SETTER_PREFIX: N = "_setter_$"
123122
val WHILE_PREFIX: N = "while$"
124-
val DEFAULT_EXCEPTION_NAME: N = "ex$"
123+
val DEFAULT_EXCEPTION_NAME: N = "ex$"
124+
val INITIALIZER_PREFIX: N = "initial$"
125125

126126
// value types (and AnyRef) are all used as terms as well
127127
// as (at least) arguments to the @specialize annotation.

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -425,10 +425,14 @@ object SymDenotations {
425425
final def isSourceMethod(implicit ctx: Context) = this is (Method, butNot = Accessor)
426426

427427
/** Is this a setter? */
428-
final def isGetter(implicit ctx: Context) = (this is Accessor) && !originalName.isSetterName
428+
final def isGetter(implicit ctx: Context) =
429+
(this is Accessor) && !originalName.isSetterName && !originalName.isScala2LocalSuffix
429430

430431
/** Is this a setter? */
431-
final def isSetter(implicit ctx: Context) = (this is Accessor) && originalName.isSetterName
432+
final def isSetter(implicit ctx: Context) =
433+
(this is Accessor) &&
434+
originalName.isSetterName &&
435+
info.firstParamTypes.nonEmpty // to avoid being fooled by var x_= : Unit = ...
432436

433437
/** is this the constructor of a class? */
434438
final def isClassConstructor = name == nme.CONSTRUCTOR
@@ -560,7 +564,7 @@ object SymDenotations {
560564
def membersNeedAsSeenFrom(pre: Type)(implicit ctx: Context) =
561565
!( this.isTerm
562566
|| this.isStaticOwner
563-
|| ctx.erasedTypes && symbol != defn.ArrayClass
567+
|| ctx.erasedTypes
564568
|| (pre eq NoPrefix) || (pre eq thisType)
565569
)
566570

0 commit comments

Comments
 (0)