@@ -2,32 +2,52 @@ 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 an `ByNameParam` attachment.
44
+ *
45
+ * Erasure will later strip wrapped `.apply()` calls with ByNameParam attachments.
46
+ *
28
47
*/
29
48
class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransformer =>
30
49
import ast .tpd ._
50
+ import ElimByName ._
31
51
32
52
override def phaseName : String = " elimByName"
33
53
@@ -44,34 +64,24 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform
44
64
override def transformApply (tree : Apply )(implicit ctx : Context , info : TransformerInfo ): Tree =
45
65
ctx.traceIndented(s " transforming ${tree.show} at phase ${ctx.phase}" , show = true ) {
46
66
47
- def transformArg (arg : Tree , formal : Type ): Tree = formal match {
48
- case _ : ExprType =>
49
- arg match {
67
+ def transformArg (arg : Tree , formal : Type ): Tree = formal.dealias match {
68
+ case formalExpr : ExprType =>
69
+ val argFun = arg match {
50
70
case Apply (Select (qual, nme.apply), Nil ) if qual.tpe derivesFrom defn.FunctionClass (0 ) =>
51
71
qual
52
72
case _ =>
53
73
val meth = ctx.newSymbol(
54
74
ctx.owner, nme.ANON_FUN , Synthetic | Method , MethodType (Nil , Nil , arg.tpe.widen))
55
75
Closure (meth, _ => arg.changeOwner(ctx.owner, meth))
56
76
}
77
+ val argApplied = argFun.select(defn.Function0_apply ).appliedToNone
78
+ argApplied.putAttachment(ByNameArg , ())
79
+ argApplied
57
80
case _ =>
58
81
arg
59
82
}
60
83
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)
84
+ val MethodType (_, formals) = tree.fun.tpe.widen
75
85
val args1 = tree.args.zipWithConserve(formals)(transformArg)
76
86
cpy.Apply (tree)(tree.fun, args1)
77
87
}
@@ -99,22 +109,13 @@ class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransform
99
109
case _ => tree
100
110
}
101
111
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
- }
112
+ override def transformValDef (tree : ValDef )(implicit ctx : Context , info : TransformerInfo ): Tree =
113
+ if (exprBecomesFunction(tree.symbol))
114
+ cpy.ValDef (tree)(tpt = tree.tpt.withType(tree.symbol.info))
115
+ else tree
111
116
112
- def transformParamInfo (tp : Type )(implicit ctx : Context ) = tp match {
113
- case ExprType (rt) => defn.FunctionType (Nil , rt)
117
+ def transformInfo (tp : Type , sym : Symbol )(implicit ctx : Context ): Type = tp match {
118
+ case ExprType (rt) if exprBecomesFunction(sym) => defn.FunctionType (Nil , rt)
114
119
case _ => tp
115
120
}
116
-
117
- def transformInfo (tp : Type , sym : Symbol )(implicit ctx : Context ): Type =
118
- if (exprBecomesFunction(sym)) transformParamInfo(tp)
119
- else elimByNameParams(tp)
120
121
}
0 commit comments