@@ -5,8 +5,11 @@ package typer
5
5
import dotty .tools .dotc .ast .Trees .ApplyKind
6
6
import dotty .tools .dotc .ast .tpd
7
7
import dotty .tools .dotc .ast .untpd
8
+ import dotty .tools .dotc .ast .TreeInfo
8
9
import dotty .tools .dotc .core .Contexts .Context
9
10
import dotty .tools .dotc .core .Names .Name
11
+ import dotty .tools .dotc .core .NameKinds .TempResultName
12
+
10
13
import core .Symbols .defn
11
14
12
15
/** A function computing the assignment of a lvalue.
@@ -25,6 +28,39 @@ private[typer] final class PartialAssignment[+T <: LValue](val lhs: T)(
25
28
26
29
end PartialAssignment
27
30
31
+ /** The expression of a pure value or a synthetic val definition binding a value whose evaluation
32
+ * must be hoisted.
33
+ *
34
+ * Use this type to represent a part of a lvalue that must be evaluated before the lvalue gets
35
+ * used for updating a value.
36
+ */
37
+ private [typer] opaque type PossiblyHoistedValue = tpd.Tree
38
+
39
+ extension (self : PossiblyHoistedValue )
40
+
41
+ /** Returns a tree representing the value of `self`. */
42
+ def value (using Context ): tpd.Tree =
43
+ self.definition.map((d) => tpd.Ident (d.namedType)).getOrElse(self)
44
+
45
+ /** Returns the synthetic val defining `self` if it is hoisted. */
46
+ def definition : Option [tpd.ValDef ] =
47
+ self match
48
+ case d : tpd.ValDef => Some (d)
49
+ case _ => None
50
+
51
+ /** Returns a tree representing the value of `self` along with its hoisted definition, if any. */
52
+ def valueAndDefinition (using Context ): (tpd.Tree , Option [tpd.ValDef ]) =
53
+ self.definition
54
+ .map((d) => (tpd.Ident (d.namedType), Some (d)))
55
+ .getOrElse((self, None ))
56
+
57
+ object PossiblyHoistedValue :
58
+
59
+ /** Creates a value representing the `e`'s evaluation. */
60
+ def apply (e : tpd.Tree )(using Context ): PossiblyHoistedValue =
61
+ if tpd.exprPurity(e) >= TreeInfo .Pure then e else
62
+ tpd.SyntheticValDef (TempResultName .fresh(), e)
63
+
28
64
/** The left-hand side of an assignment. */
29
65
private [typer] sealed abstract class LValue :
30
66
@@ -34,23 +70,8 @@ private[typer] sealed abstract class LValue:
34
70
/** Returns a tree computing the assignment of `rhs` to this lvalue. */
35
71
def formAssignment (rhs : untpd.Tree )(using Context ): untpd.Tree
36
72
37
- /** Returns the value of `t`, which may be an expression or a local `val` definition. */
38
- protected final def read (t : tpd.Tree )(using Context ): tpd.Tree =
39
- t match
40
- case d : tpd.ValDef => tpd.Ident (d.namedType)
41
- case e => e
42
-
43
73
end LValue
44
74
45
- private [typer] final case class UnappliedSetter (
46
- expression : untpd.Tree , locals : List [tpd.ValDef ]
47
- ) extends LValue :
48
-
49
- def formAssignment (rhs : untpd.Tree )(using Context ): untpd.Tree =
50
- untpd.Apply (expression, List (rhs))
51
-
52
- end UnappliedSetter
53
-
54
75
/** A simple expression, typically valid on left-hand side of an `Assign` tree.
55
76
*
56
77
* Use this class to represent an assignment that translates to an `Assign` tree or to wrap an
@@ -75,43 +96,52 @@ end SimpleLValue
75
96
* @param arguments The arguments of the partial application.
76
97
*/
77
98
private [typer] final case class ApplyLValue (
78
- function : tpd. Tree ,
79
- arguments : List [tpd. Tree ]
99
+ function : ApplyLValue . Callee ,
100
+ arguments : List [PossiblyHoistedValue ]
80
101
) extends LValue :
81
102
82
103
val locals : List [tpd.ValDef ] =
83
- ( function +: arguments) .collect { case d : tpd.ValDef => d }
104
+ function.locals ++ ( arguments.collect { case d : tpd.ValDef => d })
84
105
85
106
def formAssignment (rhs : untpd.Tree )(using Context ): untpd.Tree =
86
- val s = untpd. TypedSplice (read( function))
87
- val t = arguments.map((a) => untpd.TypedSplice (read(a) )) :+ rhs
107
+ val s = function.expanded
108
+ val t = arguments.map((a) => untpd.TypedSplice (a.value )) :+ rhs
88
109
untpd.Apply (s, t)
89
110
90
- end ApplyLValue
111
+ object ApplyLValue :
91
112
92
- /** A lvalue represeted by the application of a partially applied method.
93
- *
94
- * @param receiver The receiver of the partially applied method.
95
- * @param member The name of the partially applied method.
96
- * @param arguments The arguments of the partial application.
97
- */
98
- private [typer] final case class SelectLValue (
99
- receiver : tpd.Tree ,
100
- member : Name ,
101
- arguments : List [tpd.Tree ] = List ()
102
- ) extends LValue :
113
+ /** The callee of a lvalue represented by a partial application. */
114
+ sealed abstract class Callee :
103
115
104
- def expandReceiver ()(using Context ): tpd.Tree =
105
- receiver match
106
- case d : tpd.ValDef => d.rhs
107
- case r => r
116
+ def expanded (using Context ): untpd.Tree
108
117
109
- val locals : List [tpd. ValDef ] =
110
- (receiver +: arguments).collect { case d : tpd.ValDef => d }
118
+ /** Returns the local ` val` definitions composing this lvalue. */
119
+ def locals : List [ tpd.ValDef ]
111
120
112
- def formAssignment (rhs : untpd.Tree )(using Context ): untpd.Tree =
113
- val s = untpd.Select (untpd.TypedSplice (read(receiver)), member)
114
- val t = arguments.map((a) => untpd.TypedSplice (read(a))) :+ rhs
115
- untpd.Apply (s, t)
121
+ object Callee :
122
+
123
+ def apply (receiver : tpd.Tree )(using Context ): Typed =
124
+ Typed (PossiblyHoistedValue (receiver), None )
125
+
126
+ def apply (receiver : tpd.Tree , member : Name )(using Context ): Typed =
127
+ Typed (PossiblyHoistedValue (receiver), Some (member))
116
128
117
- end SelectLValue
129
+ /** A function representing a lvalue. */
130
+ final case class Typed (receiver : PossiblyHoistedValue , member : Option [Name ]) extends Callee :
131
+
132
+ def expanded (using Context ): untpd.Tree =
133
+ val s = untpd.TypedSplice (receiver.value)
134
+ member.map((m) => untpd.Select (s, m)).getOrElse(s)
135
+
136
+ def locals : List [tpd.ValDef ] =
137
+ receiver.definition.toList
138
+
139
+ /** The untyped expression of a function representing a lvalue along with its captures. */
140
+ final case class Untyped (value : untpd.Tree , locals : List [tpd.ValDef ]) extends Callee :
141
+
142
+ def expanded (using Context ): untpd.Tree =
143
+ value
144
+
145
+ end Callee
146
+
147
+ end ApplyLValue
0 commit comments