Skip to content

Commit e9128e4

Browse files
committed
Integration with HoistSuperArgs
Do the necessary changes to combine HoistSuperArgs and ByNameClosures. Also, polishings.
1 parent 9cb36d8 commit e9128e4

File tree

9 files changed

+40
-33
lines changed

9 files changed

+40
-33
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ 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), List( // Expand by-name arguments
58+
new ByNameClosures, // Expand arguments to by-name parameters to closures
5959
new LiftTry, // Put try expressions that might execute on non-empty stacks into their own methods
6060
new HoistSuperArgs, // Hoist complex arguments of supercalls to enclosing scope
6161
new ClassOf), // Expand `Predef.classOf` calls.
@@ -71,7 +71,7 @@ class Compiler {
7171
new SeqLiterals, // Express vararg arguments as arrays
7272
new InterceptedMethods, // Special handling of `==`, `|=`, `getClass` methods
7373
new Getters, // Replace non-private vals and vars with getter defs (fields are added later)
74-
new ElimByName, // Expand by-name parameters
74+
new ElimByName, // Expand by-name parameter references
7575
new AugmentScala2Traits, // Expand traits defined in Scala 2.11 to simulate old-style rewritings
7676
new ResolveSuper, // Implement super accessors and add forwarders to trait methods
7777
new PrimitiveForwarders, // Add forwarders to trait methods that have a mismatch between generic and primitives

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/StdNames.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ object StdNames {
378378
val build : N = "build"
379379
val bytes: N = "bytes"
380380
val canEqual_ : N = "canEqual"
381+
val cbnArg: N = "<cbn-arg>"
381382
val checkInitialized: N = "checkInitialized"
382383
val ClassManifestFactory: N = "ClassManifestFactory"
383384
val classOf: N = "classOf"
@@ -391,7 +392,6 @@ object StdNames {
391392
val delayedInitArg: N = "delayedInit$body"
392393
val drop: N = "drop"
393394
val dynamics: N = "dynamics"
394-
val dummyApply: N = "<dummy-apply>"
395395
val elem: N = "elem"
396396
val emptyValDef: N = "emptyValDef"
397397
val ensureAccessible : N = "ensureAccessible"

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,23 @@ import core.StdNames.nme
1515
/** This phase translates arguments to call-by-name parameters, using the rules
1616
*
1717
* x ==> x if x is a => parameter
18-
* e.apply() ==> DummyApply(e) if e is pure
19-
* e ==> DummyApply(() => e) for all other arguments
18+
* e.apply() ==> <cbn-arg>(e) if e is pure
19+
* e ==> <cbn-arg>(() => e) for all other arguments
2020
*
2121
* where
2222
*
23-
* DummyApply: [T](() => T): T
23+
* <cbn-arg>: [T](() => T): T
2424
*
25-
* is a synthetic method defined in Definitions. Erasure will later strip these DummyApply wrappers.
25+
* is a synthetic method defined in Definitions. Erasure will later strip the <cbn-arg> wrappers.
2626
*/
2727
class ByNameClosures extends TransformByNameApply with IdentityDenotTransformer { thisTransformer =>
2828
import ast.tpd._
2929

30-
override def phaseName: String = "bynameClosures"
30+
override def phaseName: String = "byNameClosures"
3131

3232
override def mkClosure(arg: Tree, argType: Type)(implicit ctx: Context): Tree = {
33-
val inSuper = if (ctx.mode.is(Mode.InSuperCall)) InSuperCall else EmptyFlags
3433
val meth = ctx.newSymbol(
35-
ctx.owner, nme.ANON_FUN, Synthetic | Method | inSuper, MethodType(Nil, Nil, argType))
34+
ctx.owner, nme.ANON_FUN, Synthetic | Method, MethodType(Nil, Nil, argType))
3635
Closure(meth, _ => arg.changeOwnerAfter(ctx.owner, meth, thisTransformer))
3736
}
3837
}

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ 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:
@@ -25,7 +25,6 @@ import ast.Trees._
2525
* For cbn parameter values
2626
*
2727
* x ==> x()
28-
* CbnArg(x) ==> DummyApply(x)
2928
*
3029
* Note: This scheme to have inconsistent types between method types (whose formal types are still
3130
* ExprTypes and parameter valdefs (which are now FunctionTypes) is not pretty. There are two
@@ -43,10 +42,8 @@ class ElimByName extends TransformByNameApply with InfoTransformer { thisTransfo
4342

4443
override def phaseName: String = "elimByName"
4544

46-
override def runsAfter = Set(classOf[HoistSuperArgs])
4745
override def runsAfterGroupsOf = Set(classOf[Splitter])
48-
// assumes idents and selects have symbols; interferes with splitter distribution
49-
// that's why it's "after group".
46+
// I got errors running this phase in an earlier group, but I did not track them down.
5047

5148
/** Map `tree` to `tree.apply()` is `ftree` was of ExprType and becomes now a function */
5249
private def applyIfFunction(tree: Tree, ftree: Tree)(implicit ctx: Context) =

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/HoistSuperArgs.scala

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ class HoistSuperArgs extends MiniPhaseTransform with IdentityDenotTransformer {
4242

4343
def phaseName = "hoistSuperArgs"
4444

45+
override def runsAfter = Set(classOf[ByNameClosures])
46+
// By name closures need to be introduced first in order to be hoisted out here.
47+
// There's an interaction with by name closures in that the <cbn-arg> marker
48+
// application should not be hoisted, but be left at the point of call.
49+
4550
/** Hoist complex arguments in super call `parent` out of the class.
4651
* @return A pair consisting of the transformed super call and a list of super argument
4752
* defininitions.
@@ -81,16 +86,18 @@ class HoistSuperArgs extends MiniPhaseTransform with IdentityDenotTransformer {
8186
if (methOwner.isClass) meth.enteredAfter(thisTransform) else meth
8287
}
8388

89+
def refNeedsHoist(tp: Type): Boolean = tp match {
90+
case tp: ThisType => !tp.cls.isStaticOwner && tp.cls != cls
91+
case tp: TermRef => refNeedsHoist(tp.prefix)
92+
case _ => false
93+
}
94+
8495
/** Super call argument is complex, needs to be hoisted */
8596
def needsHoist(tree: Tree) = tree match {
8697
case _: DefDef => true
8798
case _: Template => true
88-
case _: This => !tree.symbol.isStaticOwner
8999
case _: New => !tree.tpe.typeSymbol.isStatic
90-
case _: RefTree =>
91-
var owner = tree.symbol.effectiveOwner
92-
if (owner.isLocalDummy) owner = owner.owner
93-
tree.isTerm && !owner.isStaticOwner && owner != cls
100+
case _: RefTree | _: This => refNeedsHoist(tree.tpe)
94101
case _ => false
95102
}
96103

@@ -99,8 +106,10 @@ class HoistSuperArgs extends MiniPhaseTransform with IdentityDenotTransformer {
99106
* @return The argument after possible hoisting
100107
* Might append a method definition to `superArgs` as a side effect.
101108
*/
102-
def hoistSuperArg(arg: Tree) =
103-
if (arg.existsSubTree(needsHoist)) {
109+
def hoistSuperArg(arg: Tree): Tree = arg match {
110+
case Apply(fn, arg1 :: Nil) if fn.symbol == defn.cbnArg =>
111+
cpy.Apply(arg)(fn, hoistSuperArg(arg1) :: Nil)
112+
case _ if (arg.existsSubTree(needsHoist)) =>
104113
val superMeth = newSuperArgMethod(arg.tpe)
105114
val superArgDef = polyDefDef(superMeth, trefs => vrefss => {
106115
val paramSyms = trefs.map(_.typeSymbol) ::: vrefss.flatten.map(_.symbol)
@@ -139,8 +148,8 @@ class HoistSuperArgs extends MiniPhaseTransform with IdentityDenotTransformer {
139148
.appliedToArgss(termParamRefs(constr.info))
140149
ctx.log(i"hoist $arg, cls = $cls = $res")
141150
res
142-
}
143-
else arg
151+
case _ => arg
152+
}
144153

145154
def recur(tree: Tree): Tree = tree match {
146155
case Apply(fn, args) => cpy.Apply(tree)(recur(fn), args.mapconserve(hoistSuperArg))

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import DenotTransformers._
1313
import core.StdNames.nme
1414
import ast.Trees._
1515

16-
/** Abstract base class of ByNameClosures and ELimByName, factoring out the
16+
/** Abstract base class of ByNameClosures and ElimByName, factoring out the
1717
* common functionality to transform arguments of by-name parameters.
1818
*/
1919
abstract class TransformByNameApply extends MiniPhaseTransform { thisTransformer: DenotTransformer =>
@@ -32,7 +32,7 @@ abstract class TransformByNameApply extends MiniPhaseTransform { thisTransformer
3232
origDenot.info.isInstanceOf[ExprType] && exprBecomesFunction(origDenot)
3333
}
3434

35-
def mkClosure(arg: Tree, argType: Type)(implicit ctx: Context): Tree = unsupported("mkClosure")
35+
def mkClosure(arg: Tree, argType: Type)(implicit ctx: Context): Tree = unsupported(i"mkClosure($arg)")
3636

3737
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
3838
ctx.traceIndented(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) {
@@ -41,13 +41,13 @@ abstract class TransformByNameApply extends MiniPhaseTransform { thisTransformer
4141
case formalExpr: ExprType =>
4242
var argType = arg.tpe.widenIfUnstable
4343
if (defn.isBottomType(argType)) argType = formal.widenExpr
44-
def wrap(arg: Tree) = ref(defn.dummyApply).appliedToType(argType).appliedTo(arg)
44+
def wrap(arg: Tree) = ref(defn.cbnArg).appliedToType(argType).appliedTo(arg)
4545
arg match {
4646
case Apply(Select(qual, nme.apply), Nil)
4747
if qual.tpe.derivesFrom(defn.FunctionClass(0)) && isPureExpr(qual) =>
4848
wrap(qual)
4949
case _ =>
50-
if (isByNameRef(arg) || arg.symbol == defn.dummyApply) arg
50+
if (isByNameRef(arg) || arg.symbol == defn.cbnArg) arg
5151
else wrap(mkClosure(arg, argType))
5252
}
5353
case _ =>

tests/neg/tailcall/t1672b.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ object Test1772B {
4646
else 1 + (try {
4747
throw new RuntimeException
4848
} catch {
49-
case _: Throwable => bar(i - 1) // error
49+
case _: Throwable => bar(i - 1) // old error
5050
})
5151
}
5252
}

0 commit comments

Comments
 (0)