OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// A library to help transform compounds and null-aware accessors into | 5 /// A library to help transform compounds and null-aware accessors into |
6 /// let expressions. | 6 /// let expressions. |
7 | 7 |
8 import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart' | 8 import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart' |
9 show | 9 show |
10 KernelArguments, | 10 KernelArguments, |
11 KernelComplexAssign, | 11 KernelComplexAssignment, |
12 KernelConditionalExpression, | 12 KernelConditionalExpression, |
13 KernelMethodInvocation, | 13 KernelMethodInvocation, |
14 KernelPropertyGet, | 14 KernelPropertyGet, |
15 KernelPropertySet, | 15 KernelPropertySet, |
16 KernelVariableDeclaration, | 16 KernelVariableDeclaration, |
17 KernelVariableGet, | 17 KernelVariableGet, |
18 KernelVariableSet; | 18 KernelVariableSet; |
19 | 19 |
20 import 'package:front_end/src/fasta/kernel/utils.dart' show offsetForToken; | 20 import 'package:front_end/src/fasta/kernel/utils.dart' show offsetForToken; |
21 | 21 |
(...skipping 21 matching lines...) Expand all Loading... |
43 /// [Accessor] object. Later, after `= b` is parsed, [buildAssignment] will be | 43 /// [Accessor] object. Later, after `= b` is parsed, [buildAssignment] will be |
44 /// called. | 44 /// called. |
45 abstract class Accessor { | 45 abstract class Accessor { |
46 final BuilderHelper helper; | 46 final BuilderHelper helper; |
47 final Token token; | 47 final Token token; |
48 | 48 |
49 Accessor(this.helper, this.token); | 49 Accessor(this.helper, this.token); |
50 | 50 |
51 /// Builds an [Expression] representing a read from the accessor. | 51 /// Builds an [Expression] representing a read from the accessor. |
52 Expression buildSimpleRead() { | 52 Expression buildSimpleRead() { |
53 return _finish(_makeSimpleRead()); | 53 return _finish(_makeSimpleRead(), null); |
54 } | 54 } |
55 | 55 |
56 /// Builds an [Expression] representing an assignment with the accessor on | 56 /// Builds an [Expression] representing an assignment with the accessor on |
57 /// the LHS and [value] on the RHS. | 57 /// the LHS and [value] on the RHS. |
58 /// | 58 /// |
59 /// The returned expression evaluates to the assigned value, unless | 59 /// The returned expression evaluates to the assigned value, unless |
60 /// [voidContext] is true, in which case it may evaluate to anything. | 60 /// [voidContext] is true, in which case it may evaluate to anything. |
61 Expression buildAssignment(Expression value, {bool voidContext: false}) { | 61 Expression buildAssignment(Expression value, {bool voidContext: false}) { |
62 return _finish(_makeSimpleWrite(value, voidContext)); | 62 var complexAssignment = startComplexAssignment(value); |
| 63 return _finish(_makeSimpleWrite(value, voidContext, complexAssignment), |
| 64 complexAssignment); |
63 } | 65 } |
64 | 66 |
65 /// Returns an [Expression] representing a null-aware assignment (`??=`) with | 67 /// Returns an [Expression] representing a null-aware assignment (`??=`) with |
66 /// the accessor on the LHS and [value] on the RHS. | 68 /// the accessor on the LHS and [value] on the RHS. |
67 /// | 69 /// |
68 /// The returned expression evaluates to the assigned value, unless | 70 /// The returned expression evaluates to the assigned value, unless |
69 /// [voidContext] is true, in which case it may evaluate to anything. | 71 /// [voidContext] is true, in which case it may evaluate to anything. |
70 /// | 72 /// |
71 /// [type] is the static type of the RHS. | 73 /// [type] is the static type of the RHS. |
72 Expression buildNullAwareAssignment(Expression value, DartType type, | 74 Expression buildNullAwareAssignment(Expression value, DartType type, |
73 {bool voidContext: false}) { | 75 {bool voidContext: false}) { |
| 76 var complexAssignment = startComplexAssignment(value); |
74 if (voidContext) { | 77 if (voidContext) { |
75 return _finish(new KernelConditionalExpression( | 78 var nullAwareCombiner = new KernelConditionalExpression( |
76 buildIsNull(_makeRead()), _makeWrite(value, false), new NullLiteral(), | 79 buildIsNull(_makeRead(complexAssignment)), |
77 isNullAwareCombiner: true)); | 80 _makeWrite(value, false, complexAssignment), |
| 81 new NullLiteral()); |
| 82 complexAssignment?.nullAwareCombiner = nullAwareCombiner; |
| 83 return _finish(nullAwareCombiner, complexAssignment); |
78 } | 84 } |
79 var tmp = new VariableDeclaration.forValue(_makeRead()); | 85 var tmp = new VariableDeclaration.forValue(_makeRead(complexAssignment)); |
80 return _finish(makeLet( | 86 var nullAwareCombiner = new KernelConditionalExpression( |
81 tmp, | 87 buildIsNull(new VariableGet(tmp)), |
82 new KernelConditionalExpression(buildIsNull(new VariableGet(tmp)), | 88 _makeWrite(value, false, complexAssignment), |
83 _makeWrite(value, false), new VariableGet(tmp), | 89 new VariableGet(tmp)); |
84 isNullAwareCombiner: true))); | 90 complexAssignment?.nullAwareCombiner = nullAwareCombiner; |
| 91 return _finish(makeLet(tmp, nullAwareCombiner), complexAssignment); |
85 } | 92 } |
86 | 93 |
87 /// Returns an [Expression] representing a compound assignment (e.g. `+=`) | 94 /// Returns an [Expression] representing a compound assignment (e.g. `+=`) |
88 /// with the accessor on the LHS and [value] on the RHS. | 95 /// with the accessor on the LHS and [value] on the RHS. |
89 Expression buildCompoundAssignment(Name binaryOperator, Expression value, | 96 Expression buildCompoundAssignment(Name binaryOperator, Expression value, |
90 {int offset: TreeNode.noOffset, | 97 {int offset: TreeNode.noOffset, |
91 bool voidContext: false, | 98 bool voidContext: false, |
92 Procedure interfaceTarget}) { | 99 Procedure interfaceTarget}) { |
93 return _finish(_makeWrite( | 100 var complexAssignment = startComplexAssignment(value); |
94 makeBinary(_makeRead(), binaryOperator, interfaceTarget, value, | 101 var combiner = makeBinary( |
95 offset: offset, isCombiner: true), | 102 _makeRead(complexAssignment), binaryOperator, interfaceTarget, value, |
96 voidContext)); | 103 offset: offset); |
| 104 complexAssignment?.combiner = combiner; |
| 105 return _finish(_makeWrite(combiner, voidContext, complexAssignment), |
| 106 complexAssignment); |
97 } | 107 } |
98 | 108 |
99 /// Returns an [Expression] representing a pre-increment or pre-decrement | 109 /// Returns an [Expression] representing a pre-increment or pre-decrement |
100 /// of the accessor. | 110 /// of the accessor. |
101 Expression buildPrefixIncrement(Name binaryOperator, | 111 Expression buildPrefixIncrement(Name binaryOperator, |
102 {int offset: TreeNode.noOffset, | 112 {int offset: TreeNode.noOffset, |
103 bool voidContext: false, | 113 bool voidContext: false, |
104 Procedure interfaceTarget}) { | 114 Procedure interfaceTarget}) { |
105 return buildCompoundAssignment(binaryOperator, new IntLiteral(1), | 115 return buildCompoundAssignment(binaryOperator, new IntLiteral(1), |
106 offset: offset, | 116 offset: offset, |
107 voidContext: voidContext, | 117 voidContext: voidContext, |
108 interfaceTarget: interfaceTarget); | 118 interfaceTarget: interfaceTarget); |
109 } | 119 } |
110 | 120 |
111 /// Returns an [Expression] representing a post-increment or post-decrement | 121 /// Returns an [Expression] representing a post-increment or post-decrement |
112 /// of the accessor. | 122 /// of the accessor. |
113 Expression buildPostfixIncrement(Name binaryOperator, | 123 Expression buildPostfixIncrement(Name binaryOperator, |
114 {int offset: TreeNode.noOffset, | 124 {int offset: TreeNode.noOffset, |
115 bool voidContext: false, | 125 bool voidContext: false, |
116 Procedure interfaceTarget}) { | 126 Procedure interfaceTarget}) { |
117 if (voidContext) { | 127 if (voidContext) { |
118 return buildPrefixIncrement(binaryOperator, | 128 return buildPrefixIncrement(binaryOperator, |
119 offset: offset, voidContext: true, interfaceTarget: interfaceTarget); | 129 offset: offset, voidContext: true, interfaceTarget: interfaceTarget); |
120 } | 130 } |
121 var value = new VariableDeclaration.forValue(_makeRead()); | 131 var rhs = new IntLiteral(1); |
| 132 var complexAssignment = startComplexAssignment(rhs); |
| 133 var value = new VariableDeclaration.forValue(_makeRead(complexAssignment)); |
122 valueAccess() => new VariableGet(value); | 134 valueAccess() => new VariableGet(value); |
| 135 var combiner = makeBinary( |
| 136 valueAccess(), binaryOperator, interfaceTarget, rhs, |
| 137 offset: offset); |
| 138 complexAssignment?.combiner = combiner; |
| 139 complexAssignment?.isPostIncDec = true; |
123 var dummy = new KernelVariableDeclaration.forValue( | 140 var dummy = new KernelVariableDeclaration.forValue( |
124 _makeWrite( | 141 _makeWrite(combiner, true, complexAssignment), |
125 makeBinary(valueAccess(), binaryOperator, interfaceTarget, | 142 helper.functionNestingLevel); |
126 new IntLiteral(1), | 143 return _finish( |
127 offset: offset, isCombiner: true), | 144 makeLet(value, makeLet(dummy, valueAccess())), complexAssignment); |
128 true), | |
129 helper.functionNestingLevel, | |
130 isDiscarding: true); | |
131 return _finish(makeLet(value, makeLet(dummy, valueAccess()))); | |
132 } | 145 } |
133 | 146 |
134 Expression _makeSimpleRead() => _makeRead(); | 147 Expression _makeSimpleRead() => _makeRead(null); |
135 | 148 |
136 Expression _makeSimpleWrite(Expression value, bool voidContext) { | 149 Expression _makeSimpleWrite(Expression value, bool voidContext, |
137 return _makeWrite(value, voidContext); | 150 KernelComplexAssignment complexAssignment) { |
| 151 return _makeWrite(value, voidContext, complexAssignment); |
138 } | 152 } |
139 | 153 |
140 Expression _makeRead(); | 154 Expression _makeRead(KernelComplexAssignment complexAssignment); |
141 | 155 |
142 Expression _makeWrite(Expression value, bool voidContext); | 156 Expression _makeWrite(Expression value, bool voidContext, |
| 157 KernelComplexAssignment complexAssignment); |
143 | 158 |
144 Expression _finish(Expression body) => body; | 159 Expression _finish( |
| 160 Expression body, KernelComplexAssignment complexAssignment) => |
| 161 body; |
145 | 162 |
146 /// Returns an [Expression] representing a compile-time error. | 163 /// Returns an [Expression] representing a compile-time error. |
147 /// | 164 /// |
148 /// At runtime, an exception will be thrown. | 165 /// At runtime, an exception will be thrown. |
149 makeInvalidRead() { | 166 makeInvalidRead() { |
150 return internalError( | 167 return internalError( |
151 "Unhandled compile-time error.", null, offsetForToken(token)); | 168 "Unhandled compile-time error.", null, offsetForToken(token)); |
152 } | 169 } |
153 | 170 |
154 /// Returns an [Expression] representing a compile-time error wrapping | 171 /// Returns an [Expression] representing a compile-time error wrapping |
155 /// [value]. | 172 /// [value]. |
156 /// | 173 /// |
157 /// At runtime, [value] will be evaluated before throwing an exception. | 174 /// At runtime, [value] will be evaluated before throwing an exception. |
158 makeInvalidWrite(Expression value) { | 175 makeInvalidWrite(Expression value) { |
159 return internalError( | 176 return internalError( |
160 "Unhandled compile-time error.", null, offsetForToken(token)); | 177 "Unhandled compile-time error.", null, offsetForToken(token)); |
161 } | 178 } |
| 179 |
| 180 /// Creates a data structure for tracking the desugaring of a complex |
| 181 /// assignment expression whose right hand side is [rhs], if necessary, or |
| 182 /// returns `null` if not necessary. |
| 183 KernelComplexAssignment startComplexAssignment(Expression rhs) => null; |
162 } | 184 } |
163 | 185 |
164 abstract class VariableAccessor extends Accessor { | 186 abstract class VariableAccessor extends Accessor { |
165 VariableDeclaration variable; | 187 VariableDeclaration variable; |
166 DartType promotedType; | 188 DartType promotedType; |
167 | 189 |
168 VariableAccessor( | 190 VariableAccessor( |
169 BuilderHelper helper, this.variable, this.promotedType, Token token) | 191 BuilderHelper helper, this.variable, this.promotedType, Token token) |
170 : super(helper, token); | 192 : super(helper, token); |
171 | 193 |
172 Expression _makeRead() { | 194 Expression _makeRead(KernelComplexAssignment complexAssignment) { |
173 var fact = helper.typePromoter | 195 var fact = helper.typePromoter |
174 .getFactForAccess(variable, helper.functionNestingLevel); | 196 .getFactForAccess(variable, helper.functionNestingLevel); |
175 var scope = helper.typePromoter.currentScope; | 197 var scope = helper.typePromoter.currentScope; |
176 return new KernelVariableGet(variable, fact, scope) | 198 return new KernelVariableGet(variable, fact, scope) |
177 ..fileOffset = offsetForToken(token); | 199 ..fileOffset = offsetForToken(token); |
178 } | 200 } |
179 | 201 |
180 Expression _makeWrite(Expression value, bool voidContext) { | 202 Expression _makeWrite(Expression value, bool voidContext, |
| 203 KernelComplexAssignment complexAssignment) { |
181 helper.typePromoter.mutateVariable(variable, helper.functionNestingLevel); | 204 helper.typePromoter.mutateVariable(variable, helper.functionNestingLevel); |
182 return variable.isFinal || variable.isConst | 205 return variable.isFinal || variable.isConst |
183 ? makeInvalidWrite(value) | 206 ? makeInvalidWrite(value) |
184 : new KernelVariableSet(variable, value) | 207 : new KernelVariableSet(variable, value) |
185 ..fileOffset = offsetForToken(token); | 208 ..fileOffset = offsetForToken(token); |
186 } | 209 } |
187 } | 210 } |
188 | 211 |
189 class PropertyAccessor extends Accessor { | 212 class PropertyAccessor extends Accessor { |
190 VariableDeclaration _receiverVariable; | 213 VariableDeclaration _receiverVariable; |
(...skipping 12 matching lines...) Expand all Loading... |
203 } | 226 } |
204 } | 227 } |
205 | 228 |
206 PropertyAccessor.internal(BuilderHelper helper, this.receiver, this.name, | 229 PropertyAccessor.internal(BuilderHelper helper, this.receiver, this.name, |
207 this.getter, this.setter, Token token) | 230 this.getter, this.setter, Token token) |
208 : super(helper, token); | 231 : super(helper, token); |
209 | 232 |
210 Expression _makeSimpleRead() => new KernelPropertyGet(receiver, name, getter) | 233 Expression _makeSimpleRead() => new KernelPropertyGet(receiver, name, getter) |
211 ..fileOffset = offsetForToken(token); | 234 ..fileOffset = offsetForToken(token); |
212 | 235 |
213 Expression _makeSimpleWrite(Expression value, bool voidContext) { | 236 Expression _makeSimpleWrite(Expression value, bool voidContext, |
| 237 KernelComplexAssignment complexAssignment) { |
214 return new KernelPropertySet(receiver, name, value, setter) | 238 return new KernelPropertySet(receiver, name, value, setter) |
215 ..fileOffset = offsetForToken(token); | 239 ..fileOffset = offsetForToken(token); |
216 } | 240 } |
217 | 241 |
218 receiverAccess() { | 242 receiverAccess() { |
219 _receiverVariable ??= new VariableDeclaration.forValue(receiver); | 243 _receiverVariable ??= new VariableDeclaration.forValue(receiver); |
220 return new VariableGet(_receiverVariable) | 244 return new VariableGet(_receiverVariable) |
221 ..fileOffset = offsetForToken(token); | 245 ..fileOffset = offsetForToken(token); |
222 } | 246 } |
223 | 247 |
224 Expression _makeRead() => | 248 Expression _makeRead(KernelComplexAssignment complexAssignment) => |
225 new KernelPropertyGet(receiverAccess(), name, getter) | 249 new KernelPropertyGet(receiverAccess(), name, getter) |
226 ..fileOffset = offsetForToken(token); | 250 ..fileOffset = offsetForToken(token); |
227 | 251 |
228 Expression _makeWrite(Expression value, bool voidContext) { | 252 Expression _makeWrite(Expression value, bool voidContext, |
| 253 KernelComplexAssignment complexAssignment) { |
229 return new KernelPropertySet(receiverAccess(), name, value, setter) | 254 return new KernelPropertySet(receiverAccess(), name, value, setter) |
230 ..fileOffset = offsetForToken(token); | 255 ..fileOffset = offsetForToken(token); |
231 } | 256 } |
232 | 257 |
233 Expression _finish(Expression body) => makeLet(_receiverVariable, body); | 258 Expression _finish( |
| 259 Expression body, KernelComplexAssignment complexAssignment) => |
| 260 makeLet(_receiverVariable, body); |
234 } | 261 } |
235 | 262 |
236 /// Special case of [PropertyAccessor] to avoid creating an indirect access to | 263 /// Special case of [PropertyAccessor] to avoid creating an indirect access to |
237 /// 'this'. | 264 /// 'this'. |
238 class ThisPropertyAccessor extends Accessor { | 265 class ThisPropertyAccessor extends Accessor { |
239 Name name; | 266 Name name; |
240 Member getter, setter; | 267 Member getter, setter; |
241 | 268 |
242 ThisPropertyAccessor( | 269 ThisPropertyAccessor( |
243 BuilderHelper helper, this.name, this.getter, this.setter, Token token) | 270 BuilderHelper helper, this.name, this.getter, this.setter, Token token) |
244 : super(helper, token); | 271 : super(helper, token); |
245 | 272 |
246 Expression _makeRead() => | 273 Expression _makeRead(KernelComplexAssignment complexAssignment) => |
247 new KernelPropertyGet(new ThisExpression(), name, getter) | 274 new KernelPropertyGet(new ThisExpression(), name, getter) |
248 ..fileOffset = offsetForToken(token); | 275 ..fileOffset = offsetForToken(token); |
249 | 276 |
250 Expression _makeWrite(Expression value, bool voidContext) { | 277 Expression _makeWrite(Expression value, bool voidContext, |
| 278 KernelComplexAssignment complexAssignment) { |
251 return new KernelPropertySet(new ThisExpression(), name, value, setter) | 279 return new KernelPropertySet(new ThisExpression(), name, value, setter) |
252 ..fileOffset = offsetForToken(token); | 280 ..fileOffset = offsetForToken(token); |
253 } | 281 } |
254 } | 282 } |
255 | 283 |
256 class NullAwarePropertyAccessor extends Accessor { | 284 class NullAwarePropertyAccessor extends Accessor { |
257 VariableDeclaration receiver; | 285 VariableDeclaration receiver; |
258 Name name; | 286 Name name; |
259 Member getter, setter; | 287 Member getter, setter; |
260 DartType type; | 288 DartType type; |
261 | 289 |
262 NullAwarePropertyAccessor(BuilderHelper helper, Expression receiver, | 290 NullAwarePropertyAccessor(BuilderHelper helper, Expression receiver, |
263 this.name, this.getter, this.setter, this.type, Token token) | 291 this.name, this.getter, this.setter, this.type, Token token) |
264 : this.receiver = makeOrReuseVariable(receiver), | 292 : this.receiver = makeOrReuseVariable(receiver), |
265 super(helper, token); | 293 super(helper, token); |
266 | 294 |
267 receiverAccess() => new VariableGet(receiver); | 295 receiverAccess() => new VariableGet(receiver); |
268 | 296 |
269 Expression _makeRead() => | 297 Expression _makeRead(KernelComplexAssignment complexAssignment) => |
270 new KernelPropertyGet(receiverAccess(), name, getter); | 298 new KernelPropertyGet(receiverAccess(), name, getter); |
271 | 299 |
272 Expression _makeWrite(Expression value, bool voidContext) { | 300 Expression _makeWrite(Expression value, bool voidContext, |
| 301 KernelComplexAssignment complexAssignment) { |
273 return new KernelPropertySet(receiverAccess(), name, value, setter); | 302 return new KernelPropertySet(receiverAccess(), name, value, setter); |
274 } | 303 } |
275 | 304 |
276 Expression _finish(Expression body) => makeLet( | 305 Expression _finish( |
277 receiver, | 306 Expression body, KernelComplexAssignment complexAssignment) => |
278 new KernelConditionalExpression( | 307 makeLet( |
279 buildIsNull(receiverAccess()), new NullLiteral(), body)); | 308 receiver, |
| 309 new KernelConditionalExpression( |
| 310 buildIsNull(receiverAccess()), new NullLiteral(), body)); |
280 } | 311 } |
281 | 312 |
282 class SuperPropertyAccessor extends Accessor { | 313 class SuperPropertyAccessor extends Accessor { |
283 Name name; | 314 Name name; |
284 Member getter, setter; | 315 Member getter, setter; |
285 | 316 |
286 SuperPropertyAccessor( | 317 SuperPropertyAccessor( |
287 BuilderHelper helper, this.name, this.getter, this.setter, Token token) | 318 BuilderHelper helper, this.name, this.getter, this.setter, Token token) |
288 : super(helper, token); | 319 : super(helper, token); |
289 | 320 |
290 Expression _makeRead() { | 321 Expression _makeRead(KernelComplexAssignment complexAssignment) { |
291 if (getter == null) return makeInvalidRead(); | 322 if (getter == null) return makeInvalidRead(); |
292 // TODO(ahe): Use [DirectPropertyGet] when possible. | 323 // TODO(ahe): Use [DirectPropertyGet] when possible. |
293 return new SuperPropertyGet(name, getter) | 324 return new SuperPropertyGet(name, getter) |
294 ..fileOffset = offsetForToken(token); | 325 ..fileOffset = offsetForToken(token); |
295 } | 326 } |
296 | 327 |
297 Expression _makeWrite(Expression value, bool voidContext) { | 328 Expression _makeWrite(Expression value, bool voidContext, |
| 329 KernelComplexAssignment complexAssignment) { |
298 if (setter == null) return makeInvalidWrite(value); | 330 if (setter == null) return makeInvalidWrite(value); |
299 // TODO(ahe): Use [DirectPropertySet] when possible. | 331 // TODO(ahe): Use [DirectPropertySet] when possible. |
300 return new SuperPropertySet(name, value, setter) | 332 return new SuperPropertySet(name, value, setter) |
301 ..fileOffset = offsetForToken(token); | 333 ..fileOffset = offsetForToken(token); |
302 } | 334 } |
303 } | 335 } |
304 | 336 |
305 class IndexAccessor extends Accessor { | 337 class IndexAccessor extends Accessor { |
306 Expression receiver; | 338 Expression receiver; |
307 Expression index; | 339 Expression index; |
308 VariableDeclaration receiverVariable; | 340 VariableDeclaration receiverVariable; |
309 VariableDeclaration indexVariable; | 341 VariableDeclaration indexVariable; |
310 Procedure getter, setter; | 342 Procedure getter, setter; |
311 | 343 |
312 static Accessor make(BuilderHelper helper, Expression receiver, | 344 static Accessor make(BuilderHelper helper, Expression receiver, |
313 Expression index, Procedure getter, Procedure setter, | 345 Expression index, Procedure getter, Procedure setter, |
314 {Token token}) { | 346 {Token token}) { |
315 if (receiver is ThisExpression) { | 347 if (receiver is ThisExpression) { |
316 return new ThisIndexAccessor(helper, index, getter, setter, token); | 348 return new ThisIndexAccessor(helper, index, getter, setter, token); |
317 } else { | 349 } else { |
318 return new IndexAccessor.internal( | 350 return new IndexAccessor.internal( |
319 helper, receiver, index, getter, setter, token); | 351 helper, receiver, index, getter, setter, token); |
320 } | 352 } |
321 } | 353 } |
322 | 354 |
323 IndexAccessor.internal(BuilderHelper helper, this.receiver, this.index, | 355 IndexAccessor.internal(BuilderHelper helper, this.receiver, this.index, |
324 this.getter, this.setter, Token token) | 356 this.getter, this.setter, Token token) |
325 : super(helper, token); | 357 : super(helper, token); |
326 | 358 |
327 Expression _makeSimpleRead() => new KernelMethodInvocation( | 359 Expression _makeSimpleRead() { |
328 receiver, indexGetName, new KernelArguments(<Expression>[index]), | 360 var read = new KernelMethodInvocation( |
329 interfaceTarget: getter) | 361 receiver, indexGetName, new KernelArguments(<Expression>[index]), |
330 ..fileOffset = offsetForToken(token); | 362 interfaceTarget: getter) |
| 363 ..fileOffset = offsetForToken(token); |
| 364 return read; |
| 365 } |
331 | 366 |
332 Expression _makeSimpleWrite(Expression value, bool voidContext) { | 367 Expression _makeSimpleWrite(Expression value, bool voidContext, |
333 if (!voidContext) return _makeWriteAndReturn(value); | 368 KernelComplexAssignment complexAssignment) { |
334 return new KernelMethodInvocation( | 369 if (!voidContext) return _makeWriteAndReturn(value, complexAssignment); |
| 370 var write = new KernelMethodInvocation( |
335 receiver, indexSetName, new KernelArguments(<Expression>[index, value]), | 371 receiver, indexSetName, new KernelArguments(<Expression>[index, value]), |
336 interfaceTarget: setter) | 372 interfaceTarget: setter) |
337 ..fileOffset = offsetForToken(token); | 373 ..fileOffset = offsetForToken(token); |
| 374 complexAssignment?.write = write; |
| 375 return write; |
338 } | 376 } |
339 | 377 |
340 receiverAccess() { | 378 receiverAccess() { |
341 // We cannot reuse the receiver if it is a variable since it might be | 379 // We cannot reuse the receiver if it is a variable since it might be |
342 // reassigned in the index expression. | 380 // reassigned in the index expression. |
343 receiverVariable ??= new VariableDeclaration.forValue(receiver); | 381 receiverVariable ??= new VariableDeclaration.forValue(receiver); |
344 return new VariableGet(receiverVariable) | 382 return new VariableGet(receiverVariable) |
345 ..fileOffset = offsetForToken(token); | 383 ..fileOffset = offsetForToken(token); |
346 } | 384 } |
347 | 385 |
348 indexAccess() { | 386 indexAccess() { |
349 indexVariable ??= new VariableDeclaration.forValue(index); | 387 indexVariable ??= new VariableDeclaration.forValue(index); |
350 return new VariableGet(indexVariable)..fileOffset = offsetForToken(token); | 388 return new VariableGet(indexVariable)..fileOffset = offsetForToken(token); |
351 } | 389 } |
352 | 390 |
353 Expression _makeRead() { | 391 Expression _makeRead(KernelComplexAssignment complexAssignment) { |
354 return new KernelMethodInvocation(receiverAccess(), indexGetName, | 392 var read = new KernelMethodInvocation(receiverAccess(), indexGetName, |
355 new KernelArguments(<Expression>[indexAccess()]), | 393 new KernelArguments(<Expression>[indexAccess()]), |
356 interfaceTarget: getter) | 394 interfaceTarget: getter) |
357 ..fileOffset = offsetForToken(token); | 395 ..fileOffset = offsetForToken(token); |
| 396 complexAssignment?.read = read; |
| 397 return read; |
358 } | 398 } |
359 | 399 |
360 Expression _makeWrite(Expression value, bool voidContext) { | 400 Expression _makeWrite(Expression value, bool voidContext, |
361 if (!voidContext) return _makeWriteAndReturn(value); | 401 KernelComplexAssignment complexAssignment) { |
362 return new KernelMethodInvocation(receiverAccess(), indexSetName, | 402 if (!voidContext) return _makeWriteAndReturn(value, complexAssignment); |
| 403 var write = new KernelMethodInvocation(receiverAccess(), indexSetName, |
363 new KernelArguments(<Expression>[indexAccess(), value]), | 404 new KernelArguments(<Expression>[indexAccess(), value]), |
364 interfaceTarget: setter) | 405 interfaceTarget: setter) |
365 ..fileOffset = offsetForToken(token); | 406 ..fileOffset = offsetForToken(token); |
| 407 complexAssignment?.write = write; |
| 408 return write; |
366 } | 409 } |
367 | 410 |
368 // TODO(dmitryas): remove this method after the "[]=" operator of the Context | 411 // TODO(dmitryas): remove this method after the "[]=" operator of the Context |
369 // class is made to return a value. | 412 // class is made to return a value. |
370 _makeWriteAndReturn(Expression value) { | 413 _makeWriteAndReturn( |
| 414 Expression value, KernelComplexAssignment complexAssignment) { |
371 // The call to []= does not return the value like direct-style assignments | 415 // The call to []= does not return the value like direct-style assignments |
372 // do. We need to bind the value in a let. | 416 // do. We need to bind the value in a let. |
373 var valueVariable = new VariableDeclaration.forValue(value); | 417 var valueVariable = new VariableDeclaration.forValue(value); |
| 418 var write = new KernelMethodInvocation( |
| 419 receiverAccess(), |
| 420 indexSetName, |
| 421 new KernelArguments( |
| 422 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
| 423 interfaceTarget: setter) |
| 424 ..fileOffset = offsetForToken(token); |
| 425 complexAssignment?.write = write; |
374 var dummy = new KernelVariableDeclaration.forValue( | 426 var dummy = new KernelVariableDeclaration.forValue( |
375 new KernelMethodInvocation( | 427 write, helper.functionNestingLevel); |
376 receiverAccess(), | |
377 indexSetName, | |
378 new KernelArguments( | |
379 <Expression>[indexAccess(), new VariableGet(valueVariable)]), | |
380 interfaceTarget: setter) | |
381 ..fileOffset = offsetForToken(token), | |
382 helper.functionNestingLevel, | |
383 isDiscarding: true); | |
384 return makeLet( | 428 return makeLet( |
385 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); | 429 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
386 } | 430 } |
387 | 431 |
388 Expression _finish(Expression body) { | 432 Expression _finish( |
389 if (receiverVariable == null) { | 433 Expression body, KernelComplexAssignment complexAssignment) { |
390 assert(indexVariable == null); | 434 Expression desugared = |
391 return body; | 435 makeLet(receiverVariable, makeLet(indexVariable, body)); |
| 436 if (complexAssignment != null) { |
| 437 complexAssignment.desugared = desugared; |
| 438 return complexAssignment; |
392 } else { | 439 } else { |
393 return new KernelComplexAssign( | 440 return desugared; |
394 receiverVariable, makeLet(indexVariable, body)); | |
395 } | 441 } |
396 } | 442 } |
397 } | 443 } |
398 | 444 |
399 /// Special case of [IndexAccessor] to avoid creating an indirect access to | 445 /// Special case of [IndexAccessor] to avoid creating an indirect access to |
400 /// 'this'. | 446 /// 'this'. |
401 class ThisIndexAccessor extends Accessor { | 447 class ThisIndexAccessor extends Accessor { |
402 Expression index; | 448 Expression index; |
403 VariableDeclaration indexVariable; | 449 VariableDeclaration indexVariable; |
404 Procedure getter, setter; | 450 Procedure getter, setter; |
405 | 451 |
406 ThisIndexAccessor( | 452 ThisIndexAccessor( |
407 BuilderHelper helper, this.index, this.getter, this.setter, Token token) | 453 BuilderHelper helper, this.index, this.getter, this.setter, Token token) |
408 : super(helper, token); | 454 : super(helper, token); |
409 | 455 |
410 Expression _makeSimpleRead() { | 456 Expression _makeSimpleRead() { |
411 return new KernelMethodInvocation(new ThisExpression(), indexGetName, | 457 return new KernelMethodInvocation(new ThisExpression(), indexGetName, |
412 new KernelArguments(<Expression>[index]), | 458 new KernelArguments(<Expression>[index]), |
413 interfaceTarget: getter); | 459 interfaceTarget: getter); |
414 } | 460 } |
415 | 461 |
416 Expression _makeSimpleWrite(Expression value, bool voidContext) { | 462 Expression _makeSimpleWrite(Expression value, bool voidContext, |
| 463 KernelComplexAssignment complexAssignment) { |
417 if (!voidContext) return _makeWriteAndReturn(value); | 464 if (!voidContext) return _makeWriteAndReturn(value); |
418 return new KernelMethodInvocation(new ThisExpression(), indexSetName, | 465 return new KernelMethodInvocation(new ThisExpression(), indexSetName, |
419 new KernelArguments(<Expression>[index, value]), | 466 new KernelArguments(<Expression>[index, value]), |
420 interfaceTarget: setter); | 467 interfaceTarget: setter); |
421 } | 468 } |
422 | 469 |
423 indexAccess() { | 470 indexAccess() { |
424 indexVariable ??= new VariableDeclaration.forValue(index); | 471 indexVariable ??= new VariableDeclaration.forValue(index); |
425 return new VariableGet(indexVariable); | 472 return new VariableGet(indexVariable); |
426 } | 473 } |
427 | 474 |
428 Expression _makeRead() => new KernelMethodInvocation(new ThisExpression(), | 475 Expression _makeRead(KernelComplexAssignment complexAssignment) => |
429 indexGetName, new KernelArguments(<Expression>[indexAccess()]), | 476 new KernelMethodInvocation(new ThisExpression(), indexGetName, |
430 interfaceTarget: getter); | 477 new KernelArguments(<Expression>[indexAccess()]), |
| 478 interfaceTarget: getter); |
431 | 479 |
432 Expression _makeWrite(Expression value, bool voidContext) { | 480 Expression _makeWrite(Expression value, bool voidContext, |
| 481 KernelComplexAssignment complexAssignment) { |
433 if (!voidContext) return _makeWriteAndReturn(value); | 482 if (!voidContext) return _makeWriteAndReturn(value); |
434 return new KernelMethodInvocation(new ThisExpression(), indexSetName, | 483 return new KernelMethodInvocation(new ThisExpression(), indexSetName, |
435 new KernelArguments(<Expression>[indexAccess(), value]), | 484 new KernelArguments(<Expression>[indexAccess(), value]), |
436 interfaceTarget: setter); | 485 interfaceTarget: setter); |
437 } | 486 } |
438 | 487 |
439 _makeWriteAndReturn(Expression value) { | 488 _makeWriteAndReturn(Expression value) { |
440 var valueVariable = new VariableDeclaration.forValue(value); | 489 var valueVariable = new VariableDeclaration.forValue(value); |
441 var dummy = new VariableDeclaration.forValue(new KernelMethodInvocation( | 490 var dummy = new VariableDeclaration.forValue(new KernelMethodInvocation( |
442 new ThisExpression(), | 491 new ThisExpression(), |
443 indexSetName, | 492 indexSetName, |
444 new KernelArguments( | 493 new KernelArguments( |
445 <Expression>[indexAccess(), new VariableGet(valueVariable)]), | 494 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
446 interfaceTarget: setter)); | 495 interfaceTarget: setter)); |
447 return makeLet( | 496 return makeLet( |
448 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); | 497 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
449 } | 498 } |
450 | 499 |
451 Expression _finish(Expression body) => makeLet(indexVariable, body); | 500 Expression _finish( |
| 501 Expression body, KernelComplexAssignment complexAssignment) => |
| 502 makeLet(indexVariable, body); |
452 } | 503 } |
453 | 504 |
454 class SuperIndexAccessor extends Accessor { | 505 class SuperIndexAccessor extends Accessor { |
455 Expression index; | 506 Expression index; |
456 VariableDeclaration indexVariable; | 507 VariableDeclaration indexVariable; |
457 Member getter, setter; | 508 Member getter, setter; |
458 | 509 |
459 SuperIndexAccessor( | 510 SuperIndexAccessor( |
460 BuilderHelper helper, this.index, this.getter, this.setter, Token token) | 511 BuilderHelper helper, this.index, this.getter, this.setter, Token token) |
461 : super(helper, token); | 512 : super(helper, token); |
462 | 513 |
463 indexAccess() { | 514 indexAccess() { |
464 indexVariable ??= new VariableDeclaration.forValue(index); | 515 indexVariable ??= new VariableDeclaration.forValue(index); |
465 return new VariableGet(indexVariable); | 516 return new VariableGet(indexVariable); |
466 } | 517 } |
467 | 518 |
468 Expression _makeSimpleRead() => new SuperMethodInvocation( | 519 Expression _makeSimpleRead() => new SuperMethodInvocation( |
469 indexGetName, new KernelArguments(<Expression>[index]), getter); | 520 indexGetName, new KernelArguments(<Expression>[index]), getter); |
470 | 521 |
471 Expression _makeSimpleWrite(Expression value, bool voidContext) { | 522 Expression _makeSimpleWrite(Expression value, bool voidContext, |
| 523 KernelComplexAssignment complexAssignment) { |
472 if (!voidContext) return _makeWriteAndReturn(value); | 524 if (!voidContext) return _makeWriteAndReturn(value); |
473 return new SuperMethodInvocation( | 525 return new SuperMethodInvocation( |
474 indexSetName, new KernelArguments(<Expression>[index, value]), setter); | 526 indexSetName, new KernelArguments(<Expression>[index, value]), setter); |
475 } | 527 } |
476 | 528 |
477 Expression _makeRead() { | 529 Expression _makeRead(KernelComplexAssignment complexAssignment) { |
478 return new SuperMethodInvocation( | 530 return new SuperMethodInvocation( |
479 indexGetName, new KernelArguments(<Expression>[indexAccess()]), getter); | 531 indexGetName, new KernelArguments(<Expression>[indexAccess()]), getter); |
480 } | 532 } |
481 | 533 |
482 Expression _makeWrite(Expression value, bool voidContext) { | 534 Expression _makeWrite(Expression value, bool voidContext, |
| 535 KernelComplexAssignment complexAssignment) { |
483 if (!voidContext) return _makeWriteAndReturn(value); | 536 if (!voidContext) return _makeWriteAndReturn(value); |
484 return new SuperMethodInvocation(indexSetName, | 537 return new SuperMethodInvocation(indexSetName, |
485 new KernelArguments(<Expression>[indexAccess(), value]), setter); | 538 new KernelArguments(<Expression>[indexAccess(), value]), setter); |
486 } | 539 } |
487 | 540 |
488 _makeWriteAndReturn(Expression value) { | 541 _makeWriteAndReturn(Expression value) { |
489 var valueVariable = new VariableDeclaration.forValue(value); | 542 var valueVariable = new VariableDeclaration.forValue(value); |
490 var dummy = new VariableDeclaration.forValue(new SuperMethodInvocation( | 543 var dummy = new VariableDeclaration.forValue(new SuperMethodInvocation( |
491 indexSetName, | 544 indexSetName, |
492 new KernelArguments( | 545 new KernelArguments( |
493 <Expression>[indexAccess(), new VariableGet(valueVariable)]), | 546 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
494 setter)); | 547 setter)); |
495 return makeLet( | 548 return makeLet( |
496 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); | 549 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
497 } | 550 } |
498 | 551 |
499 Expression _finish(Expression body) { | 552 Expression _finish( |
| 553 Expression body, KernelComplexAssignment complexAssignment) { |
500 return makeLet(indexVariable, body); | 554 return makeLet(indexVariable, body); |
501 } | 555 } |
502 } | 556 } |
503 | 557 |
504 class StaticAccessor extends Accessor { | 558 class StaticAccessor extends Accessor { |
505 Member readTarget; | 559 Member readTarget; |
506 Member writeTarget; | 560 Member writeTarget; |
507 | 561 |
508 StaticAccessor( | 562 StaticAccessor( |
509 BuilderHelper helper, this.readTarget, this.writeTarget, Token token) | 563 BuilderHelper helper, this.readTarget, this.writeTarget, Token token) |
510 : super(helper, token); | 564 : super(helper, token); |
511 | 565 |
512 Expression _makeRead() => readTarget == null | 566 Expression _makeRead(KernelComplexAssignment complexAssignment) => |
513 ? makeInvalidRead() | 567 readTarget == null |
514 : helper.makeStaticGet(readTarget, token); | 568 ? makeInvalidRead() |
| 569 : helper.makeStaticGet(readTarget, token); |
515 | 570 |
516 Expression _makeWrite(Expression value, bool voidContext) { | 571 Expression _makeWrite(Expression value, bool voidContext, |
| 572 KernelComplexAssignment complexAssignment) { |
517 return writeTarget == null | 573 return writeTarget == null |
518 ? makeInvalidWrite(value) | 574 ? makeInvalidWrite(value) |
519 : new StaticSet(writeTarget, value) | 575 : new StaticSet(writeTarget, value) |
520 ..fileOffset = offsetForToken(token); | 576 ..fileOffset = offsetForToken(token); |
521 } | 577 } |
522 } | 578 } |
523 | 579 |
524 class ReadOnlyAccessor extends Accessor { | 580 class ReadOnlyAccessor extends Accessor { |
525 Expression expression; | 581 Expression expression; |
526 VariableDeclaration value; | 582 VariableDeclaration value; |
527 | 583 |
528 ReadOnlyAccessor(BuilderHelper helper, this.expression, Token token) | 584 ReadOnlyAccessor(BuilderHelper helper, this.expression, Token token) |
529 : super(helper, token); | 585 : super(helper, token); |
530 | 586 |
531 Expression _makeSimpleRead() => expression; | 587 Expression _makeSimpleRead() => expression; |
532 | 588 |
533 Expression _makeRead() { | 589 Expression _makeRead(KernelComplexAssignment complexAssignment) { |
534 value ??= new VariableDeclaration.forValue(expression); | 590 value ??= new VariableDeclaration.forValue(expression); |
535 return new VariableGet(value); | 591 return new VariableGet(value); |
536 } | 592 } |
537 | 593 |
538 Expression _makeWrite(Expression value, bool voidContext) => | 594 Expression _makeWrite(Expression value, bool voidContext, |
| 595 KernelComplexAssignment complexAssignment) => |
539 makeInvalidWrite(value); | 596 makeInvalidWrite(value); |
540 | 597 |
541 Expression _finish(Expression body) => makeLet(value, body); | 598 Expression _finish( |
| 599 Expression body, KernelComplexAssignment complexAssignment) => |
| 600 makeLet(value, body); |
542 } | 601 } |
543 | 602 |
544 Expression makeLet(VariableDeclaration variable, Expression body) { | 603 Expression makeLet(VariableDeclaration variable, Expression body) { |
545 if (variable == null) return body; | 604 if (variable == null) return body; |
546 return new Let(variable, body); | 605 return new Let(variable, body); |
547 } | 606 } |
548 | 607 |
549 Expression makeBinary( | 608 Expression makeBinary( |
550 Expression left, Name operator, Procedure interfaceTarget, Expression right, | 609 Expression left, Name operator, Procedure interfaceTarget, Expression right, |
551 {int offset: TreeNode.noOffset, bool isCombiner: false}) { | 610 {int offset: TreeNode.noOffset}) { |
552 return new KernelMethodInvocation( | 611 return new KernelMethodInvocation( |
553 left, operator, new KernelArguments(<Expression>[right]), | 612 left, operator, new KernelArguments(<Expression>[right]), |
554 interfaceTarget: interfaceTarget, isCombiner: isCombiner) | 613 interfaceTarget: interfaceTarget) |
555 ..fileOffset = offset; | 614 ..fileOffset = offset; |
556 } | 615 } |
557 | 616 |
558 Expression buildIsNull(Expression value, {int offset: TreeNode.noOffset}) { | 617 Expression buildIsNull(Expression value, {int offset: TreeNode.noOffset}) { |
559 return makeBinary(value, equalsName, null, new NullLiteral(), offset: offset); | 618 return makeBinary(value, equalsName, null, new NullLiteral(), offset: offset); |
560 } | 619 } |
561 | 620 |
562 VariableDeclaration makeOrReuseVariable(Expression value) { | 621 VariableDeclaration makeOrReuseVariable(Expression value) { |
563 // TODO: Devise a way to remember if a variable declaration was reused | 622 // TODO: Devise a way to remember if a variable declaration was reused |
564 // or is fresh (hence needs a let binding). | 623 // or is fresh (hence needs a let binding). |
565 return new VariableDeclaration.forValue(value); | 624 return new VariableDeclaration.forValue(value); |
566 } | 625 } |
OLD | NEW |