@@ -2,32 +2,50 @@ package dotty.tools.dotc
2
2
package transform
3
3
4
4
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 ._
12
13
import SymUtils ._
14
+ import util .Attachment
13
15
import core .StdNames .nme
14
16
import ast .Trees ._
15
17
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
17
23
* nullary function types. More precisely:
18
24
*
19
- * For parameter types:
25
+ * For the types of parameter symbols :
20
26
*
21
27
* => T ==> () => T
22
28
*
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:
24
31
*
25
32
* 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
+ *
26
37
* e.apply() ==> e if e.apply() is an argument to a call-by-name parameter
27
38
* 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.
28
45
*/
29
46
class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransformer =>
30
47
import ast .tpd ._
48
+ import ElimByName ._
31
49
32
50
override def phaseName : String = " elimByName"
33
51
@@ -44,34 +62,24 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform
44
62
override def transformApply (tree : Apply )(implicit ctx : Context , info : TransformerInfo ): Tree =
45
63
ctx.traceIndented(s " transforming ${tree.show} at phase ${ctx.phase}" , show = true ) {
46
64
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 {
50
68
case Apply (Select (qual, nme.apply), Nil ) if qual.tpe derivesFrom defn.FunctionClass (0 ) =>
51
69
qual
52
70
case _ =>
53
71
val meth = ctx.newSymbol(
54
72
ctx.owner, nme.ANON_FUN , Synthetic | Method , MethodType (Nil , Nil , arg.tpe.widen))
55
73
Closure (meth, _ => arg.changeOwner(ctx.owner, meth))
56
74
}
75
+ val argApplied = argFun.select(defn.Function0_apply ).appliedToNone
76
+ argApplied.putAttachment(ByNameArg , ())
77
+ argApplied
57
78
case _ =>
58
79
arg
59
80
}
60
81
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
75
83
val args1 = tree.args.zipWithConserve(formals)(transformArg)
76
84
cpy.Apply (tree)(tree.fun, args1)
77
85
}
@@ -99,22 +107,13 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform
99
107
case _ => tree
100
108
}
101
109
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
111
114
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)
114
117
case _ => tp
115
118
}
116
-
117
- def transformInfo (tp : Type , sym : Symbol )(implicit ctx : Context ): Type =
118
- if (exprBecomesFunction(sym)) transformParamInfo(tp)
119
- else elimByNameParams(tp)
120
119
}
0 commit comments