Skip to content

Commit 09d5673

Browse files
committed
Merge commits '474b2ae' and '46eb5ea' from #201 into umaster
2 parents 97a3732 + 474b2ae commit 09d5673

File tree

6 files changed

+77
-51
lines changed

6 files changed

+77
-51
lines changed

src/dotty/tools/dotc/TypeErasure.scala

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ object TypeErasure {
111111
erasure(tp)
112112
}
113113

114+
/** The erasure of a symbol's info. This is different of `erasure` in the way `ExprType`s are
115+
* treated. `eraseInfo` maps them them to nullary method types, whereas `erasure` maps them
116+
* to `Function0`.
117+
*/
118+
def eraseInfo(tp: Type)(implicit ctx: Context): Type = scalaErasureFn.eraseInfo(tp)(erasureCtx)
119+
114120
/** The erasure of a function result type. Differs from normal erasure in that
115121
* Unit is kept instead of being mapped to BoxedUnit.
116122
*/
@@ -135,7 +141,7 @@ object TypeErasure {
135141
if ((sym eq defn.Any_asInstanceOf) || (sym eq defn.Any_isInstanceOf)) eraseParamBounds(sym.info.asInstanceOf[PolyType])
136142
else if (sym.isAbstractType) TypeAlias(WildcardType)
137143
else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx))
138-
else erase(tp)(erasureCtx)
144+
else eraseInfo(tp)(erasureCtx)
139145
}
140146

141147
def isUnboundedGeneric(tp: Type)(implicit ctx: Context) = !(
@@ -263,7 +269,7 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
263269
case SuperType(thistpe, supertpe) =>
264270
SuperType(this(thistpe), this(supertpe))
265271
case ExprType(rt) =>
266-
MethodType(Nil, Nil, this(rt))
272+
defn.FunctionClass(0).typeRef
267273
case tp: TypeProxy =>
268274
this(tp.underlying)
269275
case AndType(tp1, tp2) =>
@@ -312,6 +318,11 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
312318
else JavaArrayType(this(elemtp))
313319
}
314320

321+
def eraseInfo(tp: Type)(implicit ctx: Context) = tp match {
322+
case ExprType(rt) => MethodType(Nil, Nil, erasure(rt))
323+
case tp => erasure(tp)
324+
}
325+
315326
private def eraseDerivedValueClassRef(tref: TypeRef)(implicit ctx: Context): Type =
316327
unsupported("eraseDerivedValueClass")
317328

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

Lines changed: 41 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,50 @@ package dotty.tools.dotc
22
package transform
33

44
import TreeTransforms._
5-
import core.DenotTransformers._
6-
import core.Symbols._
7-
import core.SymDenotations._
8-
import core.Contexts._
9-
import core.Types._
10-
import core.Flags._
11-
import core.Decorators._
5+
import core._
6+
import DenotTransformers._
7+
import Symbols._
8+
import SymDenotations._
9+
import Contexts._
10+
import Types._
11+
import Flags._
12+
import Decorators._
1213
import SymUtils._
14+
import util.Attachment
1315
import core.StdNames.nme
1416
import ast.Trees._
1517

16-
/** This phase eliminates ExprTypes `=> T` and replaces them by
18+
object ElimByName {
19+
val ByNameArg = new Attachment.Key[Unit]
20+
}
21+
22+
/** This phase eliminates ExprTypes `=> T` as types of function parameters, and replaces them by
1723
* nullary function types. More precisely:
1824
*
19-
* For parameter types:
25+
* For the types of parameter symbols:
2026
*
2127
* => T ==> () => T
2228
*
23-
* For terms:
29+
* Note that `=> T` types are not eliminated in MnethodTypes. This is done later at erasure.
30+
* Terms are rewritten as follows:
2431
*
2532
* x ==> x.apply() if x is a parameter that had type => T
33+
*
34+
* Arguments to call-by-name parameters are translated as follows. First, the argument is
35+
* rewritten by the rules
36+
*
2637
* e.apply() ==> e if e.apply() is an argument to a call-by-name parameter
2738
* expr ==> () => expr if other expr is an argument to a call-by-name parameter
39+
*
40+
* This makes the argument compatible with a parameter type of () => T, which will be the
41+
* formal parameter type at erasure. But to be -Ycheckable until then, any argument
42+
* ARG rewritten by the rules above is again wrapped in an application ARG.apply(),
43+
* labelled with a `ByNameParam` attachment. Erasure will later strip wrapped
44+
* `.apply()` calls with ByNameParam attachments.
2845
*/
2946
class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransformer =>
3047
import ast.tpd._
48+
import ElimByName._
3149

3250
override def phaseName: String = "elimByName"
3351

@@ -44,34 +62,24 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform
4462
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
4563
ctx.traceIndented(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) {
4664

47-
def transformArg(arg: Tree, formal: Type): Tree = formal match {
48-
case _: ExprType =>
49-
arg match {
65+
def transformArg(arg: Tree, formal: Type): Tree = formal.dealias match {
66+
case formalExpr: ExprType =>
67+
val argFun = arg match {
5068
case Apply(Select(qual, nme.apply), Nil) if qual.tpe derivesFrom defn.FunctionClass(0) =>
5169
qual
5270
case _ =>
5371
val meth = ctx.newSymbol(
5472
ctx.owner, nme.ANON_FUN, Synthetic | Method, MethodType(Nil, Nil, arg.tpe.widen))
5573
Closure(meth, _ => arg.changeOwner(ctx.owner, meth))
5674
}
75+
val argApplied = argFun.select(defn.Function0_apply).appliedToNone
76+
argApplied.putAttachment(ByNameArg, ())
77+
argApplied
5778
case _ =>
5879
arg
5980
}
6081

61-
/** Given that `info` is the possibly curried) method type of the
62-
* tree's symbol, the method type that corresponds to the current application.
63-
*/
64-
def matchingMethType(info: Type, tree: Tree): Type = tree match {
65-
case Apply(fn, _) => matchingMethType(info.resultType, fn)
66-
case _ => info
67-
}
68-
69-
val origMethType = originalDenotation(tree.fun).info match {
70-
case pt: PolyType => pt.resultType
71-
case mt => mt
72-
}
73-
74-
val MethodType(_, formals) = matchingMethType(origMethType, tree.fun)
82+
val MethodType(_, formals) = tree.fun.tpe.widen
7583
val args1 = tree.args.zipWithConserve(formals)(transformArg)
7684
cpy.Apply(tree)(tree.fun, args1)
7785
}
@@ -99,22 +107,13 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform
99107
case _ => tree
100108
}
101109

102-
def elimByNameParams(tp: Type)(implicit ctx: Context): Type = tp match {
103-
case tp: PolyType =>
104-
tp.derivedPolyType(tp.paramNames, tp.paramBounds, elimByNameParams(tp.resultType))
105-
case tp: MethodType =>
106-
tp.derivedMethodType(tp.paramNames, tp.paramTypes mapConserve transformParamInfo,
107-
elimByNameParams(tp.resultType))
108-
case _ =>
109-
tp
110-
}
110+
override def transformValDef(tree: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree =
111+
if (exprBecomesFunction(tree.symbol))
112+
cpy.ValDef(tree)(tpt = tree.tpt.withType(tree.symbol.info))
113+
else tree
111114

112-
def transformParamInfo(tp: Type)(implicit ctx: Context) = tp match {
113-
case ExprType(rt) => defn.FunctionType(Nil, rt)
115+
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp match {
116+
case ExprType(rt) if exprBecomesFunction(sym) => defn.FunctionType(Nil, rt)
114117
case _ => tp
115118
}
116-
117-
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
118-
if (exprBecomesFunction(sym)) transformParamInfo(tp)
119-
else elimByNameParams(tp)
120119
}

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
6262
}
6363
}
6464
case ref =>
65-
ref.derivedSingleDenotation(ref.symbol, erasure(ref.info))
65+
ref.derivedSingleDenotation(ref.symbol, eraseInfo(ref.info))
6666
}
6767

6868
val eraser = new Erasure.Typer
@@ -350,7 +350,11 @@ object Erasure extends TypeTestsCasts{
350350

351351
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
352352
val Apply(fun, args) = tree
353-
typedExpr(fun, FunProto(args, pt, this)) match {
353+
if (tree.removeAttachment(ElimByName.ByNameArg).isDefined) {
354+
val Select(qual, nme.apply) = fun
355+
typedUnadapted(qual, pt)
356+
}
357+
else typedExpr(fun, FunProto(args, pt, this)) match {
354358
case fun1: Apply => // arguments passed in prototype were already passed
355359
fun1
356360
case fun1 =>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ class TreeChecker {
198198
!pt.isInstanceOf[FunProto])
199199
assert(tree.tpe <:< pt,
200200
s"error at ${sourcePos(tree.pos)}\n" +
201-
err.typeMismatchStr(tree.tpe, pt) + "tree = " + tree)
201+
err.typeMismatchStr(tree.tpe, pt) + "\ntree = " + tree)
202202
tree
203203
}
204204
}

test/dotc/tests.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,7 @@ class tests extends CompilerTest {
105105
@Test def dotc_config = compileDir(dotcDir + "tools/dotc/config", twice)
106106
@Test def dotc_core = compileDir(dotcDir + "tools/dotc/core", twice)(allowDeepSubtypes)
107107
@Test def dotc_core_pickling = compileDir(dotcDir + "tools/dotc/core/pickling", twice)(allowDeepSubtypes)
108-
109-
@Test def dotc_transform = compileDir(dotcDir + "tools/dotc/transform", twice)(defaultOptions ++ List("-Ycheck:pat,era,lam"))
110-
//disabled, awaiting fix for call-by-name function types.
111-
108+
@Test def dotc_transform = compileDir(dotcDir + "tools/dotc/transform", twice)
112109
@Test def dotc_parsing = compileDir(dotcDir + "tools/dotc/parsing", twice)
113110
@Test def dotc_printing = compileDir(dotcDir + "tools/dotc/printing", twice)
114111
@Test def dotc_reporting = compileDir(dotcDir + "tools/dotc/reporting", twice)

tests/pos/bynamefuns.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
object Test {
2+
3+
type LF = (=> Int) => Int
4+
5+
def f(x: => Int) = x * x
6+
7+
val x: LF = f
8+
9+
def g = 3
10+
11+
f(11)
12+
x(g)
13+
x(11)
14+
15+
}

0 commit comments

Comments
 (0)