Skip to content

Commit 9f508df

Browse files
committed
Merge pull request #199 from dotty-staging/transform/lambdalift
Transform/lambdalift
2 parents e992cf9 + 1070499 commit 9f508df

29 files changed

+302
-125
lines changed

src/dotty/tools/dotc/Compiler.scala

+3-2
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ class Compiler {
5353
new Literalize,
5454
new GettersSetters),
5555
List(new Erasure),
56-
List(new CapturedVars, new Constructors)/*,
57-
List(new LambdaLift)*/
56+
List(new CapturedVars,
57+
new Constructors),
58+
List(new LambdaLift)
5859
)
5960

6061
var runId = 1

src/dotty/tools/dotc/TypeErasure.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,10 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
258258
else this(parent)
259259
case tp: TermRef =>
260260
this(tp.widen)
261-
case ThisType(_) | SuperType(_, _) =>
261+
case ThisType(_) =>
262262
tp
263+
case SuperType(thistpe, supertpe) =>
264+
SuperType(this(thistpe), this(supertpe))
263265
case ExprType(rt) =>
264266
MethodType(Nil, Nil, this(rt))
265267
case tp: TypeProxy =>

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

+25-10
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,13 @@ final class TreeTypeMap(
7979

8080
override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = treeMap(tree) match {
8181
case impl @ Template(constr, parents, self, body) =>
82-
val tmap = withMappedSyms(impl.symbol :: impl.constr.symbol :: Nil)
83-
val parents1 = parents mapconserve transform
84-
val (_, constr1 :: self1 :: Nil) = transformDefs(constr :: self :: Nil)
85-
val body1 = tmap.transformStats(body)
86-
updateDecls(constr :: body, constr1 :: body1)
82+
val tmap = withMappedSyms(localSyms(impl :: self :: Nil))
8783
cpy.Template(impl)(
88-
constr1.asInstanceOf[DefDef], parents1, self1.asInstanceOf[ValDef], body1)
89-
.withType(tmap.mapType(impl.tpe))
84+
constr = tmap.transformSub(constr),
85+
parents = parents mapconserve transform,
86+
self = tmap.transformSub(self),
87+
body = body mapconserve tmap.transform
88+
).withType(tmap.mapType(impl.tpe))
9089
case tree1 =>
9190
tree1.withType(mapType(tree1.tpe)) match {
9291
case id: Ident if tpd.needsSelect(id.tpe) =>
@@ -160,8 +159,24 @@ final class TreeTypeMap(
160159
* and return a treemap that contains the substitution
161160
* between original and mapped symbols.
162161
*/
163-
def withMappedSyms(syms: List[Symbol]): TreeTypeMap = {
164-
val mapped = ctx.mapSymbols(syms, this)
165-
withSubstitution(syms, mapped)
162+
def withMappedSyms(syms: List[Symbol], mapAlways: Boolean = false): TreeTypeMap =
163+
withMappedSyms(syms, ctx.mapSymbols(syms, this, mapAlways))
164+
165+
/** The tree map with the substitution between originals `syms`
166+
* and mapped symbols `mapped`. Also goes into mapped classes
167+
* and substitutes their declarations.
168+
*/
169+
def withMappedSyms(syms: List[Symbol], mapped: List[Symbol]): TreeTypeMap = {
170+
val symsChanged = syms ne mapped
171+
val substMap = withSubstitution(syms, mapped)
172+
val fullMap = (substMap /: mapped.filter(_.isClass)) { (tmap, cls) =>
173+
val origDcls = cls.decls.toList
174+
val mappedDcls = ctx.mapSymbols(origDcls, tmap)
175+
val tmap1 = tmap.withMappedSyms(origDcls, mappedDcls)
176+
if (symsChanged) (origDcls, mappedDcls).zipped.foreach(cls.asClass.replace)
177+
tmap1
178+
}
179+
if (symsChanged || (fullMap eq substMap)) fullMap
180+
else withMappedSyms(syms, mapAlways = true)
166181
}
167182
}

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

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols.
99
import Denotations._, Decorators._
1010
import config.Printers._
1111
import typer.Mode
12+
import collection.mutable
1213
import typer.ErrorReporting._
1314

1415
import scala.annotation.tailrec
@@ -620,6 +621,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
620621
}
621622
acc(false, tree)
622623
}
624+
625+
def filterSubTrees(f: Tree => Boolean): List[Tree] = {
626+
val buf = new mutable.ListBuffer[Tree]
627+
foreachSubTree { tree => if (f(tree)) buf += tree }
628+
buf.toList
629+
}
623630
}
624631

625632
implicit class ListOfTreeDecorator(val xs: List[tpd.Tree]) extends AnyVal {

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

+2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ object Printers {
44

55
class Printer {
66
def println(msg: => String): Unit = System.out.println(msg)
7+
def echo[T](msg: => String, value: T): T = { println(msg + value); value }
78
}
89

910
object noPrinter extends Printer {
1011
override def println(msg: => String): Unit = ()
12+
override def echo[T](msg: => String, value: T): T = value
1113
}
1214

1315
val default: Printer = new Printer

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

+5
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ object Decorators {
100100
else x1 :: xs1
101101
}
102102

103+
def foldRightBN[U](z: => U)(op: (T, => U) => U): U = xs match {
104+
case Nil => z
105+
case x :: xs1 => op(x, xs1.foldRightBN(z)(op))
106+
}
107+
103108
final def hasSameLengthAs[U](ys: List[U]): Boolean = {
104109
@tailrec def loop(xs: List[T], ys: List[U]): Boolean =
105110
if (xs.isEmpty) ys.isEmpty

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

+8-6
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,9 @@ object Flags {
331331
final val JavaDefined = commonFlag(30, "<java>")
332332

333333
/** Symbol is implemented as a Java static */
334-
final val Static = commonFlag(31, "<static>")
334+
final val JavaStatic = commonFlag(31, "<static>")
335+
final val JavaStaticTerm = JavaStatic.toTermFlags
336+
final val JavaStaticType = JavaStatic.toTypeFlags
335337

336338
/** Variable is accessed from nested function. */
337339
final val Captured = termFlag(32, "<captured>")
@@ -421,7 +423,7 @@ object Flags {
421423
/** Flags representing source modifiers */
422424
final val SourceModifierFlags =
423425
commonFlags(Private, Protected, Abstract, Final,
424-
Sealed, Case, Implicit, Override, AbsOverride, Lazy, Static)
426+
Sealed, Case, Implicit, Override, AbsOverride, Lazy, JavaStatic)
425427

426428
/** Flags representing modifiers that can appear in trees */
427429
final val ModifierFlags =
@@ -436,7 +438,7 @@ object Flags {
436438
/** Flags guaranteed to be set upon symbol creation */
437439
final val FromStartFlags =
438440
AccessFlags | Module | Package | Deferred | MethodOrHKCommon | Param | ParamAccessor | Scala2ExistentialCommon |
439-
InSuperCall | Touched | Static | CovariantOrOuter | ContravariantOrLabel | ExpandedName | AccessorOrSealed |
441+
InSuperCall | Touched | JavaStatic | CovariantOrOuter | ContravariantOrLabel | ExpandedName | AccessorOrSealed |
440442
CaseAccessorOrTypeArgument | Fresh | Frozen | Erroneous | ImplicitCommon | Permanent |
441443
SelfNameOrImplClass
442444

@@ -473,7 +475,7 @@ object Flags {
473475
*/
474476
final val RetainedModuleValAndClassFlags: FlagSet =
475477
AccessFlags | Package | Case |
476-
Synthetic | ExpandedName | JavaDefined | Static | Artifact |
478+
Synthetic | ExpandedName | JavaDefined | JavaStatic | Artifact |
477479
Erroneous | Lifted | MixedIn | Specialized
478480

479481
/** Flags that can apply to a module val */
@@ -487,7 +489,7 @@ object Flags {
487489

488490
/** Packages and package classes always have these flags set */
489491
final val PackageCreationFlags =
490-
Module | Package | Final | JavaDefined | Static
492+
Module | Package | Final | JavaDefined
491493

492494
/** These flags are pickled */
493495
final val PickledFlags = flagRange(FirstFlag, FirstNotPickledFlag)
@@ -562,7 +564,7 @@ object Flags {
562564
final val ProtectedLocal = allOf(Protected, Local)
563565

564566
/** Java symbol which is `protected` and `static` */
565-
final val StaticProtected = allOf(JavaDefined, Protected, Static)
567+
final val StaticProtected = allOf(JavaDefined, Protected, JavaStatic)
566568

567569
final val AbstractFinal = allOf(Abstract, Final)
568570
final val AbstractSealed = allOf(Abstract, Sealed)

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

+1
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ object Scopes {
278278
if (e.sym == prev) e.sym = replacement
279279
e = lookupNextEntry(e)
280280
}
281+
elemsCache = null
281282
}
282283

283284
/** Lookup a symbol entry matching given name.

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

+12-6
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ object SymDenotations {
390390

391391
/** Is this denotation static (i.e. with no outer instance)? */
392392
final def isStatic(implicit ctx: Context) =
393-
(this is Static) || this.exists && owner.isStaticOwner
393+
(this is JavaStatic) || this.exists && owner.isStaticOwner
394394

395395
/** Is this a package class or module class that defines static symbols? */
396396
final def isStaticOwner(implicit ctx: Context): Boolean =
@@ -666,10 +666,16 @@ object SymDenotations {
666666
* for these definitions.
667667
*/
668668
final def enclosingClass(implicit ctx: Context): Symbol = {
669-
def enclClass(d: SymDenotation): Symbol =
670-
if (d.isClass || !d.exists) d.symbol else enclClass(d.owner)
671-
val cls = enclClass(this)
672-
if (this is InSuperCall) cls.owner.enclosingClass else cls
669+
def enclClass(sym: Symbol, skip: Boolean): Symbol = {
670+
def newSkip = sym.is(InSuperCall) || sym.is(JavaStaticTerm)
671+
if (!sym.exists)
672+
NoSymbol
673+
else if (sym.isClass)
674+
if (skip) enclClass(sym.owner, newSkip) else sym
675+
else
676+
enclClass(sym.owner, skip || newSkip)
677+
}
678+
enclClass(symbol, false)
673679
}
674680

675681
final def isEffectivelyFinal(implicit ctx: Context): Boolean = {
@@ -976,7 +982,7 @@ object SymDenotations {
976982
/** The type parameters of this class */
977983
override final def typeParams(implicit ctx: Context): List[TypeSymbol] = {
978984
def computeTypeParams = {
979-
if (ctx.erasedTypes && (symbol ne defn.ArrayClass)) Nil
985+
if (ctx.erasedTypes || is(Module)) Nil // fast return for modules to avoid scanning package decls
980986
else if (this ne initial) initial.asSymDenotation.typeParams
981987
else decls.filter(sym =>
982988
(sym is TypeParam) && sym.owner == symbol).asInstanceOf[List[TypeSymbol]]

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,10 @@ trait Symbols { this: Context =>
267267
* Cross symbol references are brought over from originals to copies.
268268
* Do not copy any symbols if all attributes of all symbols stay the same.
269269
*/
270-
def mapSymbols(originals: List[Symbol], ttmap: TreeTypeMap) =
271-
if (originals forall (sym =>
270+
def mapSymbols(originals: List[Symbol], ttmap: TreeTypeMap, mapAlways: Boolean = false): List[Symbol] =
271+
if (originals.forall(sym =>
272272
(ttmap.mapType(sym.info) eq sym.info) &&
273-
!(ttmap.oldOwners contains sym.owner)))
273+
!(ttmap.oldOwners contains sym.owner)) && !mapAlways)
274274
originals
275275
else {
276276
val copies: List[Symbol] = for (original <- originals) yield

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

+8
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,14 @@ class TypeComparer(initctx: Context) extends DotClass {
515515
case _ =>
516516
secondTry(tp1, tp2)
517517
}
518+
case tp2: SuperType =>
519+
tp1 match {
520+
case tp1: SuperType =>
521+
isSubType(tp1.thistpe, tp2.thistpe) &&
522+
isSameType(tp1.supertpe, tp2.supertpe)
523+
case _ =>
524+
secondTry(tp1, tp2)
525+
}
518526
case AndType(tp21, tp22) =>
519527
isSubType(tp1, tp21) && isSubType(tp1, tp22)
520528
case ErrorType =>

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

+4
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ object Types {
116116
tp.tp1.derivesFrom(cls) || tp.tp2.derivesFrom(cls)
117117
case tp: OrType =>
118118
tp.tp1.derivesFrom(cls) && tp.tp2.derivesFrom(cls)
119+
case tp: JavaArrayType =>
120+
cls == defn.ObjectClass
119121
case _ =>
120122
false
121123
}
@@ -408,6 +410,8 @@ object Types {
408410
goAnd(l, r)
409411
case OrType(l, r) =>
410412
goOr(l, r)
413+
case tp: JavaArrayType =>
414+
defn.ObjectType.findMember(name, pre, excluded)
411415
case ErrorType =>
412416
ctx.newErrorSymbol(pre.classSymbol orElse defn.RootClass, name)
413417
case _ =>

src/dotty/tools/dotc/core/pickling/ClassfileConstants.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ object ClassfileConstants {
343343
case JAVA_ACC_PROTECTED => Protected
344344
case JAVA_ACC_FINAL => Final
345345
case JAVA_ACC_SYNTHETIC => Synthetic
346-
case JAVA_ACC_STATIC => Static
346+
case JAVA_ACC_STATIC => JavaStatic
347347
case JAVA_ACC_ABSTRACT => if (isAnnotation) EmptyFlags else if (isClass) Abstract else Deferred
348348
case JAVA_ACC_INTERFACE => if (isAnnotation) EmptyFlags else JavaInterface
349349
case _ => EmptyFlags

src/dotty/tools/dotc/core/pickling/PickleBuffer.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ object PickleBuffer {
236236
JAVA -> JavaDefined,
237237
SYNTHETIC -> Synthetic,
238238
STABLE -> Stable,
239-
STATIC -> Static,
239+
STATIC -> JavaStatic,
240240
CASEACCESSOR -> CaseAccessor,
241241
DEFAULTPARAM -> (DefaultParameterized, Trait),
242242
BRIDGE -> Bridge,

src/dotty/tools/dotc/transform/Erasure.scala

+5-6
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
101101
}
102102

103103
def assertErased(tp: Type, tree: tpd.Tree = tpd.EmptyTree)(implicit ctx: Context): Unit =
104-
assert(isErasedType(tp), i"The type $tp - ${tp.toString} of class ${tp.getClass} of tree $tree / ${tree.getClass} is illegal after erasure, phase = ${ctx.phase}")
104+
assert(isErasedType(tp), i"The type $tp - ${tp.toString} of class ${tp.getClass} of tree $tree : ${tree.tpe} / ${tree.getClass} is illegal after erasure, phase = ${ctx.phase}")
105105
}
106106

107107
object Erasure extends TypeTestsCasts{
@@ -183,6 +183,7 @@ object Erasure extends TypeTestsCasts{
183183
}
184184

185185
/** Generate a synthetic cast operation from tree.tpe to pt.
186+
* Does not do any boxing/unboxing (this is handled upstream).
186187
*/
187188
def cast(tree: Tree, pt: Type)(implicit ctx: Context): Tree = {
188189
// TODO: The commented out assertion fails for tailcall/t6574.scala
@@ -315,7 +316,7 @@ object Erasure extends TypeTestsCasts{
315316
override def typedThis(tree: untpd.This)(implicit ctx: Context): Tree =
316317
if (tree.symbol == ctx.owner.enclosingClass || tree.symbol.isStaticOwner) promote(tree)
317318
else {
318-
ctx.log(i"computing outer path from ${ctx.owner.ownersIterator.toList}%, % to ${tree.symbol}")
319+
ctx.log(i"computing outer path from ${ctx.owner.ownersIterator.toList}%, % to ${tree.symbol}, encl class = ${ctx.owner.enclosingClass}")
319320
outer.path(tree.symbol)
320321
}
321322

@@ -377,10 +378,8 @@ object Erasure extends TypeTestsCasts{
377378
EmptyTree
378379

379380
override def typedStats(stats: List[untpd.Tree], exprOwner: Symbol)(implicit ctx: Context): List[Tree] = {
380-
val statsFlatten = Trees.flatten(stats)
381-
val stats1 = super.typedStats(statsFlatten, exprOwner)
382-
383-
if (ctx.owner.isClass) stats1:::addBridges(statsFlatten, stats1)(ctx) else stats1
381+
val stats1 = Trees.flatten(super.typedStats(stats, exprOwner))
382+
if (ctx.owner.isClass) stats1 ::: addBridges(stats, stats1)(ctx) else stats1
384383
}
385384

386385
// this implementation doesn't check for bridge clashes with value types!

src/dotty/tools/dotc/transform/ExplicitOuter.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ object ExplicitOuter {
179179
* definitions in the class to find the one with the OuterAccessor flag.
180180
*/
181181
def outerAccessor(cls: ClassSymbol)(implicit ctx: Context): Symbol =
182-
cls.info.member(outerAccName(cls)).suchThat(_ is OuterAccessor).symbol orElse
182+
if (cls.isStatic) NoSymbol // fast return to avoid scanning package decls
183+
else cls.info.member(outerAccName(cls)).suchThat(_ is OuterAccessor).symbol orElse
183184
cls.info.decls.find(_ is OuterAccessor).getOrElse(NoSymbol)
184185

185186
/** Class has an outer accessor. Can be called only after phase ExplicitOuter. */

src/dotty/tools/dotc/transform/FirstTransform.scala

+22-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import Types._
1010
import Constants.Constant
1111
import Contexts.Context
1212
import Symbols._
13+
import SymDenotations._
14+
import Decorators._
1315
import scala.collection.mutable
1416
import DenotTransformers._
1517
import typer.Checking
@@ -21,6 +23,7 @@ import NameOps._
2123
* - ensures there are companion objects for all classes except module classes
2224
* - eliminates some kinds of trees: Imports, NamedArgs, all TypTrees other than TypeTree
2325
* - converts Select/Ident/SelectFromTypeTree nodes that refer to types to TypeTrees.
26+
* - inserts `.package` for selections of package object members
2427
* - checks the bounds of AppliedTypeTrees
2528
* - stubs out native methods
2629
*/
@@ -29,6 +32,15 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer {
2932

3033
override def phaseName = "companions"
3134

35+
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = tree match {
36+
case Select(qual, _) if tree.symbol.exists =>
37+
assert(qual.tpe derivesFrom tree.symbol.owner, i"non member selection of ${tree.symbol.showLocated} from ${qual.tpe}")
38+
case _: TypeTree =>
39+
case _: Import | _: NamedArg | _: TypTree =>
40+
assert(false, i"illegal tree: $tree")
41+
case _ =>
42+
}
43+
3244
/** Reorder statements so that module classes always come after their companion classes, add missing companion classes */
3345
private def reorderAndComplete(stats: List[Tree])(implicit ctx: Context): List[Tree] = {
3446
val moduleClassDefs, singleClassDefs = mutable.Map[Name, Tree]()
@@ -96,14 +108,22 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer {
96108
}
97109

98110
override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) =
99-
normalizeType(tree)
111+
normalizeType {
112+
val qual = tree.qualifier
113+
qual.symbol.moduleClass.denot match {
114+
case pkg: PackageClassDenotation if tree.symbol.maybeOwner.isPackageObject =>
115+
cpy.Select(tree)(qual select pkg.packageObj.symbol, tree.name)
116+
case _ =>
117+
tree
118+
}
119+
}
100120

101121
override def transformSelectFromTypeTree(tree: SelectFromTypeTree)(implicit ctx: Context, info: TransformerInfo) =
102122
normalizeType(tree)
103123

104124
override def transformOther(tree: Tree)(implicit ctx: Context, info: TransformerInfo) = tree match {
105125
case tree: Import => EmptyTree
106-
case tree: NamedArg => tree.arg
126+
case tree: NamedArg => transform(tree.arg)
107127
case AppliedTypeTree(tycon, args) =>
108128
val tparams = tycon.tpe.typeSymbol.typeParams
109129
Checking.checkBounds(

0 commit comments

Comments
 (0)