Skip to content

Commit 4b76327

Browse files
authored
Merge pull request #2282 from dotty-staging/changle-elimbyname
Rework ElimByName and combine with new phase HoistSuperArgs
2 parents e0e9ddf + b14969c commit 4b76327

22 files changed

+356
-108
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ class Compiler {
5555
new ExtensionMethods, // Expand methods of value classes with extension methods
5656
new ExpandSAMs, // Expand single abstract method closures to anonymous classes
5757
new TailRec, // Rewrite tail recursion to loops
58+
new ByNameClosures, // Expand arguments to by-name parameters to closures
5859
new LiftTry, // Put try expressions that might execute on non-empty stacks into their own methods
60+
new HoistSuperArgs, // Hoist complex arguments of supercalls to enclosing scope
5961
new ClassOf), // Expand `Predef.classOf` calls.
6062
List(new TryCatchPatterns, // Compile cases in try/catch
6163
new PatternMatcher, // Compile pattern matches
@@ -69,7 +71,7 @@ class Compiler {
6971
new SeqLiterals, // Express vararg arguments as arrays
7072
new InterceptedMethods, // Special handling of `==`, `|=`, `getClass` methods
7173
new Getters, // Replace non-private vals and vars with getter defs (fields are added later)
72-
new ElimByName, // Expand by-name parameters and arguments
74+
new ElimByName, // Expand by-name parameter references
7375
new AugmentScala2Traits, // Expand traits defined in Scala 2.11 to simulate old-style rewritings
7476
new ResolveSuper, // Implement super accessors and add forwarders to trait methods
7577
new PrimitiveForwarders, // Add forwarders to trait methods that have a mismatch between generic and primitives

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
629629
case tree: DefTree =>
630630
val sym = tree.symbol
631631
val prevDenot = sym.denot(ctx.withPhase(trans))
632-
if (prevDenot.owner == from) {
632+
if (prevDenot.effectiveOwner == from.skipWeakOwner) {
633633
val d = sym.copySymDenotation(owner = to)
634634
d.installAfter(trans)
635635
d.transformAfter(trans, d => if (d.owner eq from) d.copySymDenotation(owner = to) else d)

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,11 @@ class Definitions {
280280
def ObjectMethods = List(Object_eq, Object_ne, Object_synchronized, Object_clone,
281281
Object_finalize, Object_notify, Object_notifyAll, Object_wait, Object_waitL, Object_waitLI)
282282

283-
/** Dummy method needed by elimByName */
284-
lazy val dummyApply = enterPolyMethod(
285-
OpsPackageClass, nme.dummyApply, 1,
283+
/** Marker method to indicate an argument to a call-by-name parameter.
284+
* Created by byNameClosures and elimByName, eliminated by Erasure,
285+
*/
286+
lazy val cbnArg = enterPolyMethod(
287+
OpsPackageClass, nme.cbnArg, 1,
286288
pt => MethodType(List(FunctionOf(Nil, TypeParamRef(pt, 0))), TypeParamRef(pt, 0)))
287289

288290
/** Method representing a throw */

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,6 @@ object Flags {
372372
/** Symbol always defines a fresh named type */
373373
final val Fresh = commonFlag(45, "<fresh>")
374374

375-
/** Symbol is defined in a super call */
376-
final val InSuperCall = commonFlag(46, "<in supercall>")
377-
378375
/** Denotation is in train of being loaded and completed, used to catch cyclic dependencies */
379376
final val Touched = commonFlag(48, "<touched>")
380377

@@ -451,7 +448,7 @@ object Flags {
451448
/** Flags guaranteed to be set upon symbol creation */
452449
final val FromStartFlags =
453450
Module | Package | Deferred | MethodOrHKCommon | Param | ParamAccessor |
454-
Scala2ExistentialCommon | Mutable.toCommonFlags | InSuperCall | Touched | JavaStatic |
451+
Scala2ExistentialCommon | Mutable.toCommonFlags | Touched | JavaStatic |
455452
CovariantOrOuter | ContravariantOrLabel | CaseAccessorOrBaseTypeArg |
456453
Fresh | Frozen | Erroneous | ImplicitCommon | Permanent | Synthetic |
457454
SuperAccessorOrScala2x | Inline
@@ -511,8 +508,7 @@ object Flags {
511508
Accessor | AbsOverride | Stable | Captured | Synchronized
512509

513510
/** Flags that can apply to a module class */
514-
final val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags |
515-
InSuperCall | ImplClass
511+
final val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags | ImplClass
516512

517513
/** Packages and package classes always have these flags set */
518514
final val PackageCreationFlags =

compiler/src/dotty/tools/dotc/core/NameKinds.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ object NameKinds {
221221
val ExceptionBinderName = new UniqueNameKind("ex")
222222
val SkolemName = new UniqueNameKind("?")
223223
val LiftedTreeName = new UniqueNameKind("liftedTree")
224+
val SuperArgName = new UniqueNameKind("$superArg$")
224225

225226
val UniqueExtMethName = new UniqueNameKind("$extension") {
226227
override def unmangle(name: SimpleTermName): TermName = {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ object StdNames {
379379
val build : N = "build"
380380
val bytes: N = "bytes"
381381
val canEqual_ : N = "canEqual"
382+
val cbnArg: N = "<cbn-arg>"
382383
val checkInitialized: N = "checkInitialized"
383384
val ClassManifestFactory: N = "ClassManifestFactory"
384385
val classOf: N = "classOf"
@@ -392,7 +393,6 @@ object StdNames {
392393
val delayedInitArg: N = "delayedInit$body"
393394
val drop: N = "drop"
394395
val dynamics: N = "dynamics"
395-
val dummyApply: N = "<dummy-apply>"
396396
val elem: N = "elem"
397397
val emptyValDef: N = "emptyValDef"
398398
val ensureAccessible : N = "ensureAccessible"

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ object SymDenotations {
851851

852852
/** The class containing this denotation.
853853
* If this denotation is already a class, return itself
854-
* Definitions flagged with InSuperCall are treated specially.
854+
* Definitions flagged with JavaStatic are treated specially.
855855
* Their enclosing class is not the lexically enclosing class,
856856
* but in turn the enclosing class of the latter. This reflects
857857
* the context created by `Context#superCallContext`, `Context#thisCallArgContext`
@@ -862,7 +862,7 @@ object SymDenotations {
862862
*/
863863
final def enclosingClass(implicit ctx: Context): Symbol = {
864864
def enclClass(sym: Symbol, skip: Boolean): Symbol = {
865-
def newSkip = sym.is(InSuperCall) || sym.is(JavaStaticTerm)
865+
def newSkip = sym.is(JavaStaticTerm)
866866
if (!sym.exists)
867867
NoSymbol
868868
else if (sym.isClass)

compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,6 @@ Standard-Section: "ASTs" TopLevelStat*
186186
CONTRAVARIANT // type param marked “-”
187187
SCALA2X // Imported from Scala2.x
188188
DEFAULTparameterized // Method with default params
189-
INSUPERCALL // defined in the argument of a constructor supercall
190189
STABLE // Method that is assumed to be stable
191190
Annotation
192191
Annotation = ANNOTATION Length tycon_Type fullAnnotation_Term
@@ -278,8 +277,7 @@ object TastyFormat {
278277
final val CONTRAVARIANT = 28
279278
final val SCALA2X = 29
280279
final val DEFAULTparameterized = 30
281-
final val INSUPERCALL = 31
282-
final val STABLE = 32
280+
final val STABLE = 31
283281

284282
final val SHARED = 64
285283
final val TERMREFdirect = 65
@@ -403,7 +401,6 @@ object TastyFormat {
403401
| CONTRAVARIANT
404402
| SCALA2X
405403
| DEFAULTparameterized
406-
| INSUPERCALL
407404
| STABLE
408405
| ANNOTATION
409406
| PRIVATEqualified
@@ -469,7 +466,6 @@ object TastyFormat {
469466
case CONTRAVARIANT => "CONTRAVARIANT"
470467
case SCALA2X => "SCALA2X"
471468
case DEFAULTparameterized => "DEFAULTparameterized"
472-
case INSUPERCALL => "INSUPERCALL"
473469
case STABLE => "STABLE"
474470

475471
case SHARED => "SHARED"

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,6 @@ class TreePickler(pickler: TastyPickler) {
577577
if (flags is Synthetic) writeByte(SYNTHETIC)
578578
if (flags is Artifact) writeByte(ARTIFACT)
579579
if (flags is Scala2x) writeByte(SCALA2X)
580-
if (flags is InSuperCall) writeByte(INSUPERCALL)
581580
if (sym.isTerm) {
582581
if (flags is Implicit) writeByte(IMPLICIT)
583582
if ((flags is Lazy) && !(sym is Module)) writeByte(LAZY)

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,6 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
510510
case CONTRAVARIANT => addFlag(Contravariant)
511511
case SCALA2X => addFlag(Scala2x)
512512
case DEFAULTparameterized => addFlag(DefaultParameterized)
513-
case INSUPERCALL => addFlag(InSuperCall)
514513
case STABLE => addFlag(Stable)
515514
case PRIVATEqualified =>
516515
readByte()
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import TreeTransforms._
5+
import core._
6+
import Symbols._
7+
import SymDenotations._
8+
import Contexts._
9+
import Types._
10+
import Flags._
11+
import Decorators._
12+
import DenotTransformers.IdentityDenotTransformer
13+
import core.StdNames.nme
14+
15+
/** This phase translates arguments to call-by-name parameters, using the rules
16+
*
17+
* x ==> x if x is a => parameter
18+
* e.apply() ==> <cbn-arg>(e) if e is pure
19+
* e ==> <cbn-arg>(() => e) for all other arguments
20+
*
21+
* where
22+
*
23+
* <cbn-arg>: [T](() => T): T
24+
*
25+
* is a synthetic method defined in Definitions. Erasure will later strip the <cbn-arg> wrappers.
26+
*/
27+
class ByNameClosures extends TransformByNameApply with IdentityDenotTransformer { thisTransformer =>
28+
import ast.tpd._
29+
30+
override def phaseName: String = "byNameClosures"
31+
32+
override def mkByNameClosure(arg: Tree, argType: Type)(implicit ctx: Context): Tree = {
33+
val meth = ctx.newSymbol(
34+
ctx.owner, nme.ANON_FUN, Synthetic | Method, MethodType(Nil, Nil, argType))
35+
Closure(meth, _ => arg.changeOwnerAfter(ctx.owner, meth, thisTransformer))
36+
}
37+
}

compiler/src/dotty/tools/dotc/transform/Constructors.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ class Constructors extends MiniPhaseTransform with IdentityDenotTransformer { th
3030
import tpd._
3131

3232
override def phaseName: String = "constructors"
33-
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Memoize])
34-
33+
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Memoize], classOf[HoistSuperArgs])
3534

3635
// Collect all private parameter accessors and value definitions that need
3736
// to be retained. There are several reasons why a parameter accessor or
@@ -103,7 +102,7 @@ class Constructors extends MiniPhaseTransform with IdentityDenotTransformer { th
103102
* outer link, so no parameter accessors need to be rewired to parameters
104103
*/
105104
private def noDirectRefsFrom(tree: Tree)(implicit ctx: Context) =
106-
tree.isDef && tree.symbol.isClass && !tree.symbol.is(InSuperCall)
105+
tree.isDef && tree.symbol.isClass
107106

108107
/** Class members that can be eliminated if referenced only from their own
109108
* constructor.

compiler/src/dotty/tools/dotc/transform/ElimByName.scala

Lines changed: 9 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package transform
33

44
import TreeTransforms._
55
import core._
6-
import DenotTransformers._
6+
import DenotTransformers.InfoTransformer
77
import Symbols._
88
import SymDenotations._
99
import Contexts._
@@ -15,32 +15,16 @@ import util.Attachment
1515
import core.StdNames.nme
1616
import ast.Trees._
1717

18-
/** This phase eliminates ExprTypes `=> T` as types of function parameters, and replaces them by
18+
/** This phase eliminates ExprTypes `=> T` as types of method parameter references, and replaces them b
1919
* nullary function types. More precisely:
2020
*
2121
* For the types of parameter symbols:
2222
*
23-
* => T ==> () => T
23+
* => T ==> () => T
2424
*
25-
* Note that `=> T` types are not eliminated in MethodTypes. This is done later at erasure.
26-
* Terms are rewritten as follows:
25+
* For cbn parameter values
2726
*
28-
* x ==> x.apply() if x is a parameter that had type => T
29-
*
30-
* Arguments to call-by-name parameters are translated as follows. First, the argument is
31-
* rewritten by the rules
32-
*
33-
* e.apply() ==> e if e.apply() is an argument to a call-by-name parameter
34-
* expr ==> () => expr if other expr is an argument to a call-by-name parameter
35-
*
36-
* This makes the argument compatible with a parameter type of () => T, which will be the
37-
* formal parameter type at erasure. But to be -Ycheckable until then, any argument
38-
* ARG rewritten by the rules above is again wrapped in an application DummyApply(ARG)
39-
* where
40-
*
41-
* DummyApply: [T](() => T): T
42-
*
43-
* is a synthetic method defined in Definitions. Erasure will later strip these DummyApply wrappers.
27+
* x ==> x()
4428
*
4529
* Note: This scheme to have inconsistent types between method types (whose formal types are still
4630
* ExprTypes and parameter valdefs (which are now FunctionTypes) is not pretty. There are two
@@ -53,61 +37,18 @@ import ast.Trees._
5337
* Option 2: Merge ElimByName with erasure, or have it run immediately before. This has not been
5438
* tried yet.
5539
*/
56-
class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransformer =>
40+
class ElimByName extends TransformByNameApply with InfoTransformer { thisTransformer =>
5741
import ast.tpd._
5842

5943
override def phaseName: String = "elimByName"
6044

6145
override def runsAfterGroupsOf = Set(classOf[Splitter])
62-
// assumes idents and selects have symbols; interferes with splitter distribution
63-
// that's why it's "after group".
64-
65-
/** The info of the tree's symbol at phase Nullarify (i.e. before transformation) */
66-
private def originalDenotation(tree: Tree)(implicit ctx: Context) =
67-
tree.symbol.denot(ctx.withPhase(thisTransformer))
68-
69-
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
70-
ctx.traceIndented(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) {
71-
72-
def transformArg(arg: Tree, formal: Type): Tree = formal.dealias match {
73-
case formalExpr: ExprType =>
74-
var argType = arg.tpe.widenIfUnstable
75-
if (defn.isBottomType(argType)) argType = formal.widenExpr
76-
val argFun = arg match {
77-
case Apply(Select(qual, nme.apply), Nil)
78-
if qual.tpe.derivesFrom(defn.FunctionClass(0)) && isPureExpr(qual) =>
79-
qual
80-
case _ =>
81-
val inSuper = if (ctx.mode.is(Mode.InSuperCall)) InSuperCall else EmptyFlags
82-
val meth = ctx.newSymbol(
83-
ctx.owner, nme.ANON_FUN, Synthetic | Method | inSuper, MethodType(Nil, Nil, argType))
84-
Closure(meth, _ =>
85-
atGroupEnd { implicit ctx: Context =>
86-
arg.changeOwner(ctx.owner, meth)
87-
}
88-
)
89-
}
90-
ref(defn.dummyApply).appliedToType(argType).appliedTo(argFun)
91-
case _ =>
92-
arg
93-
}
94-
95-
val mt @ MethodType(_) = tree.fun.tpe.widen
96-
val args1 = tree.args.zipWithConserve(mt.paramInfos)(transformArg)
97-
cpy.Apply(tree)(tree.fun, args1)
98-
}
99-
100-
/** If denotation had an ExprType before, it now gets a function type */
101-
private def exprBecomesFunction(symd: SymDenotation)(implicit ctx: Context) =
102-
(symd is Param) || (symd is (ParamAccessor, butNot = Method))
46+
// I got errors running this phase in an earlier group, but I did not track them down.
10347

10448
/** Map `tree` to `tree.apply()` is `ftree` was of ExprType and becomes now a function */
105-
private def applyIfFunction(tree: Tree, ftree: Tree)(implicit ctx: Context) = {
106-
val origDenot = originalDenotation(ftree)
107-
if (exprBecomesFunction(origDenot) && (origDenot.info.isInstanceOf[ExprType]))
108-
tree.select(defn.Function0_apply).appliedToNone
49+
private def applyIfFunction(tree: Tree, ftree: Tree)(implicit ctx: Context) =
50+
if (isByNameRef(ftree)) tree.select(defn.Function0_apply).appliedToNone
10951
else tree
110-
}
11152

11253
override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree =
11354
applyIfFunction(tree, tree)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ object Erasure extends TypeTestsCasts{
452452
*/
453453
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
454454
val Apply(fun, args) = tree
455-
if (fun.symbol == defn.dummyApply)
455+
if (fun.symbol == defn.cbnArg)
456456
typedUnadapted(args.head, pt)
457457
else typedExpr(fun, FunProto(args, pt, this)) match {
458458
case fun1: Apply => // arguments passed in prototype were already passed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class ExplicitOuter extends MiniPhaseTransform with InfoTransformer { thisTransf
4646
/** List of names of phases that should have finished their processing of all compilation units
4747
* before this phase starts
4848
*/
49-
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[PatternMatcher])
49+
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[PatternMatcher], classOf[HoistSuperArgs])
5050

5151
/** Add outer accessors if a class always needs an outer pointer */
5252
override def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context) = tp match {

0 commit comments

Comments
 (0)