OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'package:js_runtime/shared/embedded_names.dart'; | |
6 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
7 | 6 |
8 import '../closure.dart'; | 7 import '../closure.dart'; |
9 import '../common.dart'; | 8 import '../common.dart'; |
10 import '../common/names.dart'; | |
11 import '../constants/constructors.dart'; | |
12 import '../constants/expressions.dart'; | |
13 import '../constants/values.dart'; | 9 import '../constants/values.dart'; |
14 import '../common_elements.dart'; | 10 import '../common_elements.dart'; |
15 import '../elements/entities.dart'; | 11 import '../elements/entities.dart'; |
16 import '../elements/jumps.dart'; | 12 import '../elements/jumps.dart'; |
17 import '../elements/names.dart'; | 13 import '../elements/names.dart'; |
18 import '../elements/operators.dart'; | |
19 import '../elements/types.dart'; | 14 import '../elements/types.dart'; |
20 import '../js/js.dart' as js; | 15 import '../js/js.dart' as js; |
21 import '../js_backend/backend.dart' show JavaScriptBackend; | |
22 import '../js_backend/namer.dart'; | 16 import '../js_backend/namer.dart'; |
23 import '../js_emitter/code_emitter_task.dart'; | 17 import '../js_emitter/code_emitter_task.dart'; |
24 import '../native/native.dart' as native; | 18 import '../native/native.dart' as native; |
25 import '../types/types.dart'; | 19 import '../types/types.dart'; |
26 import '../universe/call_structure.dart'; | 20 import '../universe/call_structure.dart'; |
27 import '../universe/selector.dart'; | 21 import '../universe/selector.dart'; |
28 import '../world.dart'; | 22 import '../world.dart'; |
29 import 'kernel_debug.dart'; | |
30 | 23 |
31 /// Interface that translates between Kernel IR nodes and entities. | 24 /// Interface that translates between Kernel IR nodes and entities. |
32 abstract class KernelToElementMap { | 25 abstract class KernelToElementMap { |
33 /// Access to the commonly used elements and types. | 26 /// Access to the commonly used elements and types. |
34 CommonElements get commonElements; | 27 CommonElements get commonElements; |
35 | 28 |
36 /// Returns the [DartType] corresponding to [type]. | 29 /// Returns the [DartType] corresponding to [type]. |
37 DartType getDartType(ir.DartType type); | 30 DartType getDartType(ir.DartType type); |
38 | 31 |
| 32 /// Returns the [InterfaceType] corresponding to [type]. |
| 33 InterfaceType getInterfaceType(ir.InterfaceType type); |
| 34 |
| 35 /// Returns the [FunctionType] of the [node]. |
| 36 FunctionType getFunctionType(ir.FunctionNode node); |
| 37 |
39 /// Return the [InterfaceType] corresponding to the [cls] with the given | 38 /// Return the [InterfaceType] corresponding to the [cls] with the given |
40 /// [typeArguments]. | 39 /// [typeArguments]. |
41 InterfaceType createInterfaceType( | 40 InterfaceType createInterfaceType( |
42 ir.Class cls, List<ir.DartType> typeArguments); | 41 ir.Class cls, List<ir.DartType> typeArguments); |
43 | 42 |
| 43 /// Returns the [CallStructure] corresponding to the [arguments]. |
| 44 CallStructure getCallStructure(ir.Arguments arguments); |
| 45 |
44 /// Returns the [Selector] corresponding to the invocation or getter/setter | 46 /// Returns the [Selector] corresponding to the invocation or getter/setter |
45 /// access of [node]. | 47 /// access of [node]. |
46 Selector getSelector(ir.Expression node); | 48 Selector getSelector(ir.Expression node); |
47 | 49 |
48 /// Returns the [MemberEntity] corresponding to the member [node]. | 50 /// Returns the [MemberEntity] corresponding to the member [node]. |
49 MemberEntity getMember(ir.Member node); | 51 MemberEntity getMember(ir.Member node); |
50 | 52 |
51 /// Returns the [FunctionEntity] corresponding to the procedure [node]. | 53 /// Returns the [FunctionEntity] corresponding to the procedure [node]. |
52 FunctionEntity getMethod(ir.Procedure node); | 54 FunctionEntity getMethod(ir.Procedure node); |
53 | 55 |
54 /// Returns the [ConstructorEntity] corresponding to the generative or factory | 56 /// Returns the [ConstructorEntity] corresponding to the generative or factory |
55 /// constructor [node]. | 57 /// constructor [node]. |
56 ConstructorEntity getConstructor(ir.Member node); | 58 ConstructorEntity getConstructor(ir.Member node); |
57 | 59 |
58 /// Returns the [FieldEntity] corresponding to the field [node]. | 60 /// Returns the [FieldEntity] corresponding to the field [node]. |
59 FieldEntity getField(ir.Field node); | 61 FieldEntity getField(ir.Field node); |
60 | 62 |
| 63 /// Returns the [ClassEntity] corresponding to the class [node]. |
| 64 ClassEntity getClass(ir.Class node); |
| 65 |
61 /// Returns the [Local] corresponding to the [node]. The node must be either | 66 /// Returns the [Local] corresponding to the [node]. The node must be either |
62 /// a [ir.FunctionDeclaration] or [ir.FunctionExpression]. | 67 /// a [ir.FunctionDeclaration] or [ir.FunctionExpression]. |
63 Local getLocalFunction(ir.TreeNode node); | 68 Local getLocalFunction(ir.TreeNode node); |
64 | 69 |
65 /// Returns the super [MemberEntity] for a super invocation, get or set of | 70 /// Returns the super [MemberEntity] for a super invocation, get or set of |
66 /// [name] from the member [context]. | 71 /// [name] from the member [context]. |
67 /// | 72 /// |
68 /// The IR doesn't always resolve super accesses to the corresponding | 73 /// The IR doesn't always resolve super accesses to the corresponding |
69 /// [target]. If not, the target is computed using [name] and [setter] from | 74 /// [target]. If not, the target is computed using [name] and [setter] from |
70 /// the enclosing class of [context]. | 75 /// the enclosing class of [context]. |
(...skipping 25 matching lines...) Expand all Loading... |
96 /// Computes the [ConstantValue] for the constant [expression]. | 101 /// Computes the [ConstantValue] for the constant [expression]. |
97 // TODO(johnniwinther): Move to [KernelToElementMapForBuilding]. This is only | 102 // TODO(johnniwinther): Move to [KernelToElementMapForBuilding]. This is only |
98 // used in impact builder for symbol constants. | 103 // used in impact builder for symbol constants. |
99 ConstantValue getConstantValue(ir.Expression expression, | 104 ConstantValue getConstantValue(ir.Expression expression, |
100 {bool requireConstant: true, bool implicitNull: false}); | 105 {bool requireConstant: true, bool implicitNull: false}); |
101 } | 106 } |
102 | 107 |
103 /// Interface that translates between Kernel IR nodes and entities used for | 108 /// Interface that translates between Kernel IR nodes and entities used for |
104 /// computing the [WorldImpact] for members. | 109 /// computing the [WorldImpact] for members. |
105 abstract class KernelToElementMapForImpact extends KernelToElementMap { | 110 abstract class KernelToElementMapForImpact extends KernelToElementMap { |
106 /// Returns the [CallStructure] corresponding to the [arguments]. | |
107 CallStructure getCallStructure(ir.Arguments arguments); | |
108 | |
109 /// Returns the [ConstructorEntity] corresponding to a super initializer in | 111 /// Returns the [ConstructorEntity] corresponding to a super initializer in |
110 /// [constructor]. | 112 /// [constructor]. |
111 /// | 113 /// |
112 /// The IR resolves super initializers to a [target] up in the type hierarchy. | 114 /// The IR resolves super initializers to a [target] up in the type hierarchy. |
113 /// Most of the time, the result of this function will be the entity | 115 /// Most of the time, the result of this function will be the entity |
114 /// corresponding to that target. In the presence of unnamed mixins, this | 116 /// corresponding to that target. In the presence of unnamed mixins, this |
115 /// function returns an entity for an intermediate synthetic constructor that | 117 /// function returns an entity for an intermediate synthetic constructor that |
116 /// kernel doesn't explicitly represent. | 118 /// kernel doesn't explicitly represent. |
117 /// | 119 /// |
118 /// For example: | 120 /// For example: |
(...skipping 27 matching lines...) Expand all Loading... |
146 /// [JS_INTERCEPTOR_CONSTANT] function, if any. | 148 /// [JS_INTERCEPTOR_CONSTANT] function, if any. |
147 InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node); | 149 InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node); |
148 } | 150 } |
149 | 151 |
150 /// Interface that translates between Kernel IR nodes and entities used for | 152 /// Interface that translates between Kernel IR nodes and entities used for |
151 /// global type inference and building the SSA graph for members. | 153 /// global type inference and building the SSA graph for members. |
152 abstract class KernelToElementMapForBuilding implements KernelToElementMap { | 154 abstract class KernelToElementMapForBuilding implements KernelToElementMap { |
153 /// [ElementEnvironment] for library, class and member lookup. | 155 /// [ElementEnvironment] for library, class and member lookup. |
154 ElementEnvironment get elementEnvironment; | 156 ElementEnvironment get elementEnvironment; |
155 | 157 |
156 /// Returns the [FunctionType] of the [node]. | |
157 FunctionType getFunctionType(ir.FunctionNode node); | |
158 | |
159 /// Returns the list of [DartType]s corresponding to [types]. | 158 /// Returns the list of [DartType]s corresponding to [types]. |
160 List<DartType> getDartTypes(List<ir.DartType> types); | 159 List<DartType> getDartTypes(List<ir.DartType> types); |
161 | 160 |
162 /// Returns the [InterfaceType] corresponding to [type]. | |
163 InterfaceType getInterfaceType(ir.InterfaceType type); | |
164 | |
165 /// Returns the kernel IR node that defines the [member]. | 161 /// Returns the kernel IR node that defines the [member]. |
166 ir.Node getMemberNode(covariant MemberEntity member); | 162 ir.Node getMemberNode(covariant MemberEntity member); |
167 | 163 |
168 /// Returns the [ClassEntity] corresponding to the class [node]. | |
169 ClassEntity getClass(ir.Class node); | |
170 | |
171 /// Returns the [LibraryEntity] corresponding to the library [node]. | 164 /// Returns the [LibraryEntity] corresponding to the library [node]. |
172 LibraryEntity getLibrary(ir.Library node); | 165 LibraryEntity getLibrary(ir.Library node); |
173 | 166 |
174 /// Returns the [js.Template] for the `JsBuiltin` [constant] value. | 167 /// Returns the [js.Template] for the `JsBuiltin` [constant] value. |
175 js.Template getJsBuiltinTemplate( | 168 js.Template getJsBuiltinTemplate( |
176 ConstantValue constant, CodeEmitterTask emitter); | 169 ConstantValue constant, CodeEmitterTask emitter); |
177 | 170 |
178 /// Return the [ConstantValue] the initial value of [field] or `null` if | 171 /// Return the [ConstantValue] the initial value of [field] or `null` if |
179 /// the initializer is not a constant expression. | 172 /// the initializer is not a constant expression. |
180 ConstantValue getFieldConstantValue(ir.Field field); | 173 ConstantValue getFieldConstantValue(ir.Field field); |
181 | 174 |
182 /// Returns the `noSuchMethod` [FunctionEntity] call from a | 175 /// Returns the `noSuchMethod` [FunctionEntity] call from a |
183 /// `super.noSuchMethod` invocation within [cls]. | 176 /// `super.noSuchMethod` invocation within [cls]. |
184 FunctionEntity getSuperNoSuchMethod(ClassEntity cls); | 177 FunctionEntity getSuperNoSuchMethod(ClassEntity cls); |
185 | 178 |
186 /// Returns a [Spannable] for a message pointing to the IR [node] in the | 179 /// Returns a [Spannable] for a message pointing to the IR [node] in the |
187 /// context of [member]. | 180 /// context of [member]. |
188 Spannable getSpannable(MemberEntity member, ir.Node node); | 181 Spannable getSpannable(MemberEntity member, ir.Node node); |
189 } | 182 } |
190 | 183 |
191 /// Kinds of foreign functions. | 184 /// Kinds of foreign functions. |
192 enum ForeignKind { | 185 enum ForeignKind { |
193 JS, | 186 JS, |
194 JS_BUILTIN, | 187 JS_BUILTIN, |
195 JS_EMBEDDED_GLOBAL, | 188 JS_EMBEDDED_GLOBAL, |
196 JS_INTERCEPTOR_CONSTANT, | 189 JS_INTERCEPTOR_CONSTANT, |
197 NONE, | 190 NONE, |
198 } | 191 } |
199 | 192 |
200 abstract class KernelToElementMapMixin | |
201 implements KernelToElementMapForBuilding { | |
202 DiagnosticReporter get reporter; | |
203 native.BehaviorBuilder get nativeBehaviorBuilder; | |
204 ConstantValue computeConstantValue(ConstantExpression constant, | |
205 {bool requireConstant: true}); | |
206 | |
207 @override | |
208 Name getName(ir.Name name) { | |
209 return new Name( | |
210 name.name, name.isPrivate ? getLibrary(name.library) : null); | |
211 } | |
212 | |
213 CallStructure getCallStructure(ir.Arguments arguments) { | |
214 int argumentCount = arguments.positional.length + arguments.named.length; | |
215 List<String> namedArguments = arguments.named.map((e) => e.name).toList(); | |
216 return new CallStructure(argumentCount, namedArguments); | |
217 } | |
218 | |
219 @override | |
220 Selector getSelector(ir.Expression node) { | |
221 // TODO(efortuna): This is screaming for a common interface between | |
222 // PropertyGet and SuperPropertyGet (and same for *Get). Talk to kernel | |
223 // folks. | |
224 if (node is ir.PropertyGet) { | |
225 return getGetterSelector(node.name); | |
226 } | |
227 if (node is ir.SuperPropertyGet) { | |
228 return getGetterSelector(node.name); | |
229 } | |
230 if (node is ir.PropertySet) { | |
231 return getSetterSelector(node.name); | |
232 } | |
233 if (node is ir.SuperPropertySet) { | |
234 return getSetterSelector(node.name); | |
235 } | |
236 if (node is ir.InvocationExpression) { | |
237 return getInvocationSelector(node); | |
238 } | |
239 throw new SpannableAssertionFailure( | |
240 CURRENT_ELEMENT_SPANNABLE, | |
241 "Can only get the selector for a property get or an invocation: " | |
242 "${node}"); | |
243 } | |
244 | |
245 Selector getInvocationSelector(ir.InvocationExpression invocation) { | |
246 Name name = getName(invocation.name); | |
247 SelectorKind kind; | |
248 if (Selector.isOperatorName(name.text)) { | |
249 if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) { | |
250 kind = SelectorKind.INDEX; | |
251 } else { | |
252 kind = SelectorKind.OPERATOR; | |
253 } | |
254 } else { | |
255 kind = SelectorKind.CALL; | |
256 } | |
257 | |
258 CallStructure callStructure = getCallStructure(invocation.arguments); | |
259 return new Selector(kind, name, callStructure); | |
260 } | |
261 | |
262 Selector getGetterSelector(ir.Name irName) { | |
263 Name name = new Name( | |
264 irName.name, irName.isPrivate ? getLibrary(irName.library) : null); | |
265 return new Selector.getter(name); | |
266 } | |
267 | |
268 Selector getSetterSelector(ir.Name irName) { | |
269 Name name = new Name( | |
270 irName.name, irName.isPrivate ? getLibrary(irName.library) : null); | |
271 return new Selector.setter(name); | |
272 } | |
273 | |
274 ConstantValue getConstantValue(ir.Expression node, | |
275 {bool requireConstant: true, bool implicitNull: false}) { | |
276 ConstantExpression constant; | |
277 if (node == null) { | |
278 if (!implicitNull) { | |
279 throw new SpannableAssertionFailure( | |
280 CURRENT_ELEMENT_SPANNABLE, 'No expression for constant.'); | |
281 } | |
282 constant = new NullConstantExpression(); | |
283 } else { | |
284 constant = | |
285 new Constantifier(this, requireConstant: requireConstant).visit(node); | |
286 } | |
287 if (constant == null) { | |
288 if (requireConstant) { | |
289 throw new UnsupportedError( | |
290 'No constant for ${DebugPrinter.prettyPrint(node)}'); | |
291 } | |
292 return null; | |
293 } | |
294 return computeConstantValue(constant, requireConstant: requireConstant); | |
295 } | |
296 | |
297 /// Converts [annotations] into a list of [ConstantValue]s. | |
298 List<ConstantValue> getMetadata(List<ir.Expression> annotations) { | |
299 if (annotations.isEmpty) return const <ConstantValue>[]; | |
300 List<ConstantValue> metadata = <ConstantValue>[]; | |
301 annotations.forEach((ir.Expression node) { | |
302 metadata.add(getConstantValue(node)); | |
303 }); | |
304 return metadata; | |
305 } | |
306 | |
307 /// Returns `true` is [node] has a `@Native(...)` annotation. | |
308 // TODO(johnniwinther): Cache this for later use. | |
309 bool isNativeClass(ir.Class node) { | |
310 for (ir.Expression annotation in node.annotations) { | |
311 if (annotation is ir.ConstructorInvocation) { | |
312 FunctionEntity target = getConstructor(annotation.target); | |
313 if (target.enclosingClass == commonElements.nativeAnnotationClass) { | |
314 return true; | |
315 } | |
316 } | |
317 } | |
318 return false; | |
319 } | |
320 | |
321 /// Compute the kind of foreign helper function called by [node], if any. | |
322 ForeignKind getForeignKind(ir.StaticInvocation node) { | |
323 if (isForeignLibrary(node.target.enclosingLibrary)) { | |
324 switch (node.target.name.name) { | |
325 case JavaScriptBackend.JS: | |
326 return ForeignKind.JS; | |
327 case JavaScriptBackend.JS_BUILTIN: | |
328 return ForeignKind.JS_BUILTIN; | |
329 case JavaScriptBackend.JS_EMBEDDED_GLOBAL: | |
330 return ForeignKind.JS_EMBEDDED_GLOBAL; | |
331 case JavaScriptBackend.JS_INTERCEPTOR_CONSTANT: | |
332 return ForeignKind.JS_INTERCEPTOR_CONSTANT; | |
333 } | |
334 } | |
335 return ForeignKind.NONE; | |
336 } | |
337 | |
338 /// Return `true` if [node] is the `dart:_foreign_helper` library. | |
339 bool isForeignLibrary(ir.Library node) { | |
340 return node.importUri == Uris.dart__foreign_helper; | |
341 } | |
342 | |
343 /// Looks up [typeName] for use in the spec-string of a `JS` called. | |
344 // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling | |
345 // the `ForeignResolver`. | |
346 // TODO(johnniwinther): Cache the result to avoid redundant lookups? | |
347 native.TypeLookup typeLookup({bool resolveAsRaw: true}) { | |
348 DartType lookup(String typeName, {bool required}) { | |
349 DartType findIn(Uri uri) { | |
350 LibraryEntity library = elementEnvironment.lookupLibrary(uri); | |
351 if (library != null) { | |
352 ClassEntity cls = elementEnvironment.lookupClass(library, typeName); | |
353 if (cls != null) { | |
354 // TODO(johnniwinther): Align semantics. | |
355 return resolveAsRaw | |
356 ? elementEnvironment.getRawType(cls) | |
357 : elementEnvironment.getThisType(cls); | |
358 } | |
359 } | |
360 return null; | |
361 } | |
362 | |
363 // TODO(johnniwinther): Narrow the set of lookups base on the depending | |
364 // library. | |
365 DartType type = findIn(Uris.dart_core); | |
366 type ??= findIn(Uris.dart__js_helper); | |
367 type ??= findIn(Uris.dart__interceptors); | |
368 type ??= findIn(Uris.dart__isolate_helper); | |
369 type ??= findIn(Uris.dart__native_typed_data); | |
370 type ??= findIn(Uris.dart_collection); | |
371 type ??= findIn(Uris.dart_math); | |
372 type ??= findIn(Uris.dart_html); | |
373 type ??= findIn(Uris.dart_html_common); | |
374 type ??= findIn(Uris.dart_svg); | |
375 type ??= findIn(Uris.dart_web_audio); | |
376 type ??= findIn(Uris.dart_web_gl); | |
377 type ??= findIn(Uris.dart_web_sql); | |
378 type ??= findIn(Uris.dart_indexed_db); | |
379 type ??= findIn(Uris.dart_typed_data); | |
380 if (type == null && required) { | |
381 reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE, | |
382 MessageKind.GENERIC, {'text': "Type '$typeName' not found."}); | |
383 } | |
384 return type; | |
385 } | |
386 | |
387 return lookup; | |
388 } | |
389 | |
390 String _getStringArgument(ir.StaticInvocation node, int index) { | |
391 return node.arguments.positional[index].accept(new Stringifier()); | |
392 } | |
393 | |
394 /// Computes the [native.NativeBehavior] for a call to the [JS] function. | |
395 // TODO(johnniwinther): Cache this for later use. | |
396 native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) { | |
397 if (node.arguments.positional.length < 2 || | |
398 node.arguments.named.isNotEmpty) { | |
399 reporter.reportErrorMessage( | |
400 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS); | |
401 return new native.NativeBehavior(); | |
402 } | |
403 String specString = _getStringArgument(node, 0); | |
404 if (specString == null) { | |
405 reporter.reportErrorMessage( | |
406 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST); | |
407 return new native.NativeBehavior(); | |
408 } | |
409 | |
410 String codeString = _getStringArgument(node, 1); | |
411 if (codeString == null) { | |
412 reporter.reportErrorMessage( | |
413 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND); | |
414 return new native.NativeBehavior(); | |
415 } | |
416 | |
417 return native.NativeBehavior.ofJsCall( | |
418 specString, | |
419 codeString, | |
420 typeLookup(resolveAsRaw: true), | |
421 CURRENT_ELEMENT_SPANNABLE, | |
422 reporter, | |
423 commonElements); | |
424 } | |
425 | |
426 /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN] | |
427 /// function. | |
428 // TODO(johnniwinther): Cache this for later use. | |
429 native.NativeBehavior getNativeBehaviorForJsBuiltinCall( | |
430 ir.StaticInvocation node) { | |
431 if (node.arguments.positional.length < 1) { | |
432 reporter.internalError( | |
433 CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type."); | |
434 return new native.NativeBehavior(); | |
435 } | |
436 if (node.arguments.positional.length < 2) { | |
437 reporter.internalError( | |
438 CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name."); | |
439 return new native.NativeBehavior(); | |
440 } | |
441 String specString = _getStringArgument(node, 0); | |
442 if (specString == null) { | |
443 reporter.internalError( | |
444 CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument."); | |
445 return new native.NativeBehavior(); | |
446 } | |
447 return native.NativeBehavior.ofJsBuiltinCall( | |
448 specString, | |
449 typeLookup(resolveAsRaw: true), | |
450 CURRENT_ELEMENT_SPANNABLE, | |
451 reporter, | |
452 commonElements); | |
453 } | |
454 | |
455 /// Computes the [native.NativeBehavior] for a call to the | |
456 /// [JS_EMBEDDED_GLOBAL] function. | |
457 // TODO(johnniwinther): Cache this for later use. | |
458 native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall( | |
459 ir.StaticInvocation node) { | |
460 if (node.arguments.positional.length < 1) { | |
461 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | |
462 "JS embedded global expression has no type."); | |
463 return new native.NativeBehavior(); | |
464 } | |
465 if (node.arguments.positional.length < 2) { | |
466 reporter.internalError( | |
467 CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name."); | |
468 return new native.NativeBehavior(); | |
469 } | |
470 if (node.arguments.positional.length > 2 || | |
471 node.arguments.named.isNotEmpty) { | |
472 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | |
473 "JS embedded global has more than 2 arguments."); | |
474 return new native.NativeBehavior(); | |
475 } | |
476 String specString = _getStringArgument(node, 0); | |
477 if (specString == null) { | |
478 reporter.internalError( | |
479 CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument."); | |
480 return new native.NativeBehavior(); | |
481 } | |
482 return native.NativeBehavior.ofJsEmbeddedGlobalCall( | |
483 specString, | |
484 typeLookup(resolveAsRaw: true), | |
485 CURRENT_ELEMENT_SPANNABLE, | |
486 reporter, | |
487 commonElements); | |
488 } | |
489 | |
490 /// Computes the [InterfaceType] referenced by a call to the | |
491 /// [JS_INTERCEPTOR_CONSTANT] function, if any. | |
492 InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node) { | |
493 if (node.arguments.positional.length != 1 || | |
494 node.arguments.named.isNotEmpty) { | |
495 reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE, | |
496 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); | |
497 } | |
498 ir.Node argument = node.arguments.positional.first; | |
499 if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) { | |
500 return getInterfaceType(argument.type); | |
501 } | |
502 return null; | |
503 } | |
504 | |
505 /// Computes the native behavior for reading the native [field]. | |
506 // TODO(johnniwinther): Cache this for later use. | |
507 native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field, | |
508 {bool isJsInterop}) { | |
509 DartType type = getDartType(field.type); | |
510 List<ConstantValue> metadata = getMetadata(field.annotations); | |
511 return nativeBehaviorBuilder.buildFieldLoadBehavior( | |
512 type, metadata, typeLookup(resolveAsRaw: false), | |
513 isJsInterop: isJsInterop); | |
514 } | |
515 | |
516 /// Computes the native behavior for writing to the native [field]. | |
517 // TODO(johnniwinther): Cache this for later use. | |
518 native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) { | |
519 DartType type = getDartType(field.type); | |
520 return nativeBehaviorBuilder.buildFieldStoreBehavior(type); | |
521 } | |
522 | |
523 /// Computes the native behavior for calling [procedure]. | |
524 // TODO(johnniwinther): Cache this for later use. | |
525 native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure, | |
526 {bool isJsInterop}) { | |
527 DartType type = getFunctionType(procedure.function); | |
528 List<ConstantValue> metadata = getMetadata(procedure.annotations); | |
529 return nativeBehaviorBuilder.buildMethodBehavior( | |
530 type, metadata, typeLookup(resolveAsRaw: false), | |
531 isJsInterop: isJsInterop); | |
532 } | |
533 | |
534 @override | |
535 FunctionEntity getSuperNoSuchMethod(ClassEntity cls) { | |
536 while (cls != null) { | |
537 cls = elementEnvironment.getSuperClass(cls); | |
538 MemberEntity member = | |
539 elementEnvironment.lookupClassMember(cls, Identifiers.noSuchMethod_); | |
540 if (member != null) { | |
541 if (member.isFunction) { | |
542 FunctionEntity function = member; | |
543 if (function.parameterStructure.positionalParameters >= 1) { | |
544 return function; | |
545 } | |
546 } | |
547 // If [member] is not a valid `noSuchMethod` the target is | |
548 // `Object.superNoSuchMethod`. | |
549 break; | |
550 } | |
551 } | |
552 FunctionEntity function = elementEnvironment.lookupClassMember( | |
553 commonElements.objectClass, Identifiers.noSuchMethod_); | |
554 assert(function != null, | |
555 failedAt(cls, "No super noSuchMethod found for class $cls.")); | |
556 return function; | |
557 } | |
558 | |
559 js.Name getNameForJsGetName(ConstantValue constant, Namer namer) { | |
560 int index = _extractEnumIndexFromConstantValue( | |
561 constant, commonElements.jsGetNameEnum); | |
562 if (index == null) return null; | |
563 return namer.getNameForJsGetName( | |
564 CURRENT_ELEMENT_SPANNABLE, JsGetName.values[index]); | |
565 } | |
566 | |
567 js.Template getJsBuiltinTemplate( | |
568 ConstantValue constant, CodeEmitterTask emitter) { | |
569 int index = _extractEnumIndexFromConstantValue( | |
570 constant, commonElements.jsBuiltinEnum); | |
571 if (index == null) return null; | |
572 return emitter.builtinTemplateFor(JsBuiltin.values[index]); | |
573 } | |
574 | |
575 int _extractEnumIndexFromConstantValue( | |
576 ConstantValue constant, ClassEntity classElement) { | |
577 if (constant is ConstructedConstantValue) { | |
578 if (constant.type.element == classElement) { | |
579 assert(constant.fields.length == 1 || constant.fields.length == 2); | |
580 ConstantValue indexConstant = constant.fields.values.first; | |
581 if (indexConstant is IntConstantValue) { | |
582 return indexConstant.primitiveValue; | |
583 } | |
584 } | |
585 } | |
586 return null; | |
587 } | |
588 } | |
589 | |
590 /// Visitor that converts string literals and concatenations of string literals | |
591 /// into the string value. | |
592 class Stringifier extends ir.ExpressionVisitor<String> { | |
593 @override | |
594 String visitStringLiteral(ir.StringLiteral node) => node.value; | |
595 | |
596 @override | |
597 String visitStringConcatenation(ir.StringConcatenation node) { | |
598 StringBuffer sb = new StringBuffer(); | |
599 for (ir.Expression expression in node.expressions) { | |
600 String value = expression.accept(this); | |
601 if (value == null) return null; | |
602 sb.write(value); | |
603 } | |
604 return sb.toString(); | |
605 } | |
606 } | |
607 | |
608 /// Visitor that converts a kernel constant expression into a | |
609 /// [ConstantExpression]. | |
610 class Constantifier extends ir.ExpressionVisitor<ConstantExpression> { | |
611 final bool requireConstant; | |
612 final KernelToElementMapMixin elementAdapter; | |
613 | |
614 Constantifier(this.elementAdapter, {this.requireConstant: true}); | |
615 | |
616 CommonElements get _commonElements => elementAdapter.commonElements; | |
617 | |
618 ConstantExpression visit(ir.Expression node) { | |
619 ConstantExpression constant = node.accept(this); | |
620 if (constant == null && requireConstant) { | |
621 throw new UnsupportedError( | |
622 "No constant computed for $node (${node.runtimeType})"); | |
623 } | |
624 return constant; | |
625 } | |
626 | |
627 ConstantExpression defaultExpression(ir.Expression node) { | |
628 if (requireConstant) { | |
629 throw new UnimplementedError( | |
630 'Unimplemented constant expression $node (${node.runtimeType})'); | |
631 } | |
632 return null; | |
633 } | |
634 | |
635 List<ConstantExpression> _computeList(List<ir.Expression> expressions) { | |
636 List<ConstantExpression> list = <ConstantExpression>[]; | |
637 for (ir.Expression expression in expressions) { | |
638 ConstantExpression constant = visit(expression); | |
639 if (constant == null) return null; | |
640 list.add(constant); | |
641 } | |
642 return list; | |
643 } | |
644 | |
645 List<ConstantExpression> _computeArguments(ir.Arguments node) { | |
646 List<ConstantExpression> arguments = <ConstantExpression>[]; | |
647 for (ir.Expression argument in node.positional) { | |
648 ConstantExpression constant = visit(argument); | |
649 if (constant == null) return null; | |
650 arguments.add(constant); | |
651 } | |
652 for (ir.NamedExpression argument in node.named) { | |
653 ConstantExpression constant = visit(argument.value); | |
654 if (constant == null) return null; | |
655 arguments.add(constant); | |
656 } | |
657 return arguments; | |
658 } | |
659 | |
660 ConstructedConstantExpression _computeConstructorInvocation( | |
661 ir.Constructor target, ir.Arguments arguments) { | |
662 List<ConstantExpression> expressions = _computeArguments(arguments); | |
663 if (expressions == null) return null; | |
664 return new ConstructedConstantExpression( | |
665 elementAdapter.createInterfaceType( | |
666 target.enclosingClass, arguments.types), | |
667 elementAdapter.getConstructor(target), | |
668 elementAdapter.getCallStructure(arguments), | |
669 expressions); | |
670 } | |
671 | |
672 @override | |
673 ConstantExpression visitConstructorInvocation(ir.ConstructorInvocation node) { | |
674 return _computeConstructorInvocation(node.target, node.arguments); | |
675 } | |
676 | |
677 @override | |
678 ConstantExpression visitVariableGet(ir.VariableGet node) { | |
679 if (node.variable.parent is ir.FunctionNode) { | |
680 ir.FunctionNode function = node.variable.parent; | |
681 int index = function.positionalParameters.indexOf(node.variable); | |
682 if (index != -1) { | |
683 return new PositionalArgumentReference(index); | |
684 } else { | |
685 assert(function.namedParameters.contains(node.variable)); | |
686 return new NamedArgumentReference(node.variable.name); | |
687 } | |
688 } else if (node.variable.isConst) { | |
689 return visit(node.variable.initializer); | |
690 } | |
691 return defaultExpression(node); | |
692 } | |
693 | |
694 @override | |
695 ConstantExpression visitStaticGet(ir.StaticGet node) { | |
696 ir.Member target = node.target; | |
697 if (target is ir.Field && target.isConst) { | |
698 return new FieldConstantExpression(elementAdapter.getField(node.target)); | |
699 } else if (node.target is ir.Procedure) { | |
700 FunctionEntity function = elementAdapter.getMethod(node.target); | |
701 DartType type = elementAdapter.getFunctionType(node.target.function); | |
702 return new FunctionConstantExpression(function, type); | |
703 } | |
704 return defaultExpression(node); | |
705 } | |
706 | |
707 @override | |
708 ConstantExpression visitNullLiteral(ir.NullLiteral node) { | |
709 return new NullConstantExpression(); | |
710 } | |
711 | |
712 @override | |
713 ConstantExpression visitBoolLiteral(ir.BoolLiteral node) { | |
714 return new BoolConstantExpression(node.value); | |
715 } | |
716 | |
717 @override | |
718 ConstantExpression visitIntLiteral(ir.IntLiteral node) { | |
719 return new IntConstantExpression(node.value); | |
720 } | |
721 | |
722 @override | |
723 ConstantExpression visitDoubleLiteral(ir.DoubleLiteral node) { | |
724 return new DoubleConstantExpression(node.value); | |
725 } | |
726 | |
727 @override | |
728 ConstantExpression visitStringLiteral(ir.StringLiteral node) { | |
729 return new StringConstantExpression(node.value); | |
730 } | |
731 | |
732 @override | |
733 ConstantExpression visitSymbolLiteral(ir.SymbolLiteral node) { | |
734 return new SymbolConstantExpression(node.value); | |
735 } | |
736 | |
737 @override | |
738 ConstantExpression visitStringConcatenation(ir.StringConcatenation node) { | |
739 List<ConstantExpression> expressions = _computeList(node.expressions); | |
740 if (expressions == null) return null; | |
741 return new ConcatenateConstantExpression(expressions); | |
742 } | |
743 | |
744 @override | |
745 ConstantExpression visitMapLiteral(ir.MapLiteral node) { | |
746 if (!node.isConst) { | |
747 return defaultExpression(node); | |
748 } | |
749 DartType keyType = elementAdapter.getDartType(node.keyType); | |
750 DartType valueType = elementAdapter.getDartType(node.valueType); | |
751 List<ConstantExpression> keys = <ConstantExpression>[]; | |
752 List<ConstantExpression> values = <ConstantExpression>[]; | |
753 for (ir.MapEntry entry in node.entries) { | |
754 ConstantExpression key = visit(entry.key); | |
755 if (key == null) return null; | |
756 keys.add(key); | |
757 ConstantExpression value = visit(entry.value); | |
758 if (value == null) return null; | |
759 values.add(value); | |
760 } | |
761 return new MapConstantExpression( | |
762 _commonElements.mapType(keyType, valueType), keys, values); | |
763 } | |
764 | |
765 @override | |
766 ConstantExpression visitListLiteral(ir.ListLiteral node) { | |
767 if (!node.isConst) { | |
768 return defaultExpression(node); | |
769 } | |
770 DartType elementType = elementAdapter.getDartType(node.typeArgument); | |
771 List<ConstantExpression> values = <ConstantExpression>[]; | |
772 for (ir.Expression expression in node.expressions) { | |
773 ConstantExpression value = visit(expression); | |
774 if (value == null) return null; | |
775 values.add(value); | |
776 } | |
777 return new ListConstantExpression( | |
778 _commonElements.listType(elementType), values); | |
779 } | |
780 | |
781 @override | |
782 ConstantExpression visitTypeLiteral(ir.TypeLiteral node) { | |
783 DartType type = elementAdapter.getDartType(node.type); | |
784 String name; | |
785 if (type.isDynamic) { | |
786 name = 'dynamic'; | |
787 } else if (type is InterfaceType) { | |
788 name = type.element.name; | |
789 } else if (type.isFunctionType || type.isTypedef) { | |
790 // TODO(johnniwinther): Compute a name for the type literal? It is only | |
791 // used in error messages in the old SSA builder. | |
792 name = '?'; | |
793 } else { | |
794 return defaultExpression(node); | |
795 } | |
796 return new TypeConstantExpression(type, name); | |
797 } | |
798 | |
799 @override | |
800 ConstantExpression visitNot(ir.Not node) { | |
801 ConstantExpression expression = visit(node.operand); | |
802 if (expression == null) return null; | |
803 return new UnaryConstantExpression(UnaryOperator.NOT, expression); | |
804 } | |
805 | |
806 @override | |
807 ConstantExpression visitConditionalExpression(ir.ConditionalExpression node) { | |
808 ConstantExpression condition = visit(node.condition); | |
809 if (condition == null) return null; | |
810 ConstantExpression trueExp = visit(node.then); | |
811 if (trueExp == null) return null; | |
812 ConstantExpression falseExp = visit(node.otherwise); | |
813 if (falseExp == null) return null; | |
814 return new ConditionalConstantExpression(condition, trueExp, falseExp); | |
815 } | |
816 | |
817 @override | |
818 ConstantExpression visitPropertyGet(ir.PropertyGet node) { | |
819 if (node.name.name != 'length') { | |
820 throw new UnimplementedError( | |
821 'Unexpected constant expression $node (${node.runtimeType})'); | |
822 } | |
823 ConstantExpression receiver = visit(node.receiver); | |
824 if (receiver == null) return null; | |
825 return new StringLengthConstantExpression(receiver); | |
826 } | |
827 | |
828 @override | |
829 ConstantExpression visitMethodInvocation(ir.MethodInvocation node) { | |
830 // Method invocations are generally not constant expressions but unary | |
831 // and binary expressions are encoded as method invocations in kernel. | |
832 if (node.arguments.named.isNotEmpty) { | |
833 return defaultExpression(node); | |
834 } | |
835 if (node.arguments.positional.length == 0) { | |
836 UnaryOperator operator; | |
837 if (node.name.name == UnaryOperator.NEGATE.selectorName) { | |
838 operator = UnaryOperator.NEGATE; | |
839 } else { | |
840 operator = UnaryOperator.parse(node.name.name); | |
841 } | |
842 if (operator != null) { | |
843 ConstantExpression expression = visit(node.receiver); | |
844 if (expression == null) return null; | |
845 return new UnaryConstantExpression(operator, expression); | |
846 } | |
847 } | |
848 if (node.arguments.positional.length == 1) { | |
849 BinaryOperator operator = BinaryOperator.parse(node.name.name); | |
850 if (operator != null) { | |
851 ConstantExpression left = visit(node.receiver); | |
852 if (left == null) return null; | |
853 ConstantExpression right = visit(node.arguments.positional.single); | |
854 if (right == null) return null; | |
855 return new BinaryConstantExpression(left, operator, right); | |
856 } | |
857 } | |
858 return defaultExpression(node); | |
859 } | |
860 | |
861 @override | |
862 ConstantExpression visitStaticInvocation(ir.StaticInvocation node) { | |
863 MemberEntity member = elementAdapter.getMember(node.target); | |
864 if (member == _commonElements.identicalFunction) { | |
865 if (node.arguments.positional.length == 2 && | |
866 node.arguments.named.isEmpty) { | |
867 ConstantExpression left = visit(node.arguments.positional[0]); | |
868 if (left == null) return null; | |
869 ConstantExpression right = visit(node.arguments.positional[1]); | |
870 if (right == null) return null; | |
871 return new IdenticalConstantExpression(left, right); | |
872 } | |
873 } else if (member.name == 'fromEnvironment' && | |
874 node.arguments.positional.length == 1) { | |
875 ConstantExpression name = visit(node.arguments.positional.single); | |
876 if (name == null) return null; | |
877 ConstantExpression defaultValue; | |
878 if (node.arguments.named.length == 1) { | |
879 if (node.arguments.named.single.name != 'defaultValue') { | |
880 return defaultExpression(node); | |
881 } | |
882 defaultValue = visit(node.arguments.named.single.value); | |
883 if (defaultValue == null) return null; | |
884 } | |
885 if (member.enclosingClass == _commonElements.boolClass) { | |
886 return new BoolFromEnvironmentConstantExpression(name, defaultValue); | |
887 } else if (member.enclosingClass == _commonElements.intClass) { | |
888 return new IntFromEnvironmentConstantExpression(name, defaultValue); | |
889 } else if (member.enclosingClass == _commonElements.stringClass) { | |
890 return new StringFromEnvironmentConstantExpression(name, defaultValue); | |
891 } | |
892 } | |
893 return defaultExpression(node); | |
894 } | |
895 | |
896 @override | |
897 ConstantExpression visitLogicalExpression(ir.LogicalExpression node) { | |
898 BinaryOperator operator = BinaryOperator.parse(node.operator); | |
899 if (operator != null) { | |
900 ConstantExpression left = visit(node.left); | |
901 if (left == null) return null; | |
902 ConstantExpression right = visit(node.right); | |
903 if (right == null) return null; | |
904 return new BinaryConstantExpression(left, operator, right); | |
905 } | |
906 return defaultExpression(node); | |
907 } | |
908 | |
909 @override | |
910 ConstantExpression visitLet(ir.Let node) { | |
911 ir.Expression body = node.body; | |
912 if (body is ir.ConditionalExpression) { | |
913 ir.Expression condition = body.condition; | |
914 if (condition is ir.MethodInvocation) { | |
915 ir.Expression receiver = condition.receiver; | |
916 ir.Expression otherwise = body.otherwise; | |
917 if (condition.name.name == BinaryOperator.EQ.name && | |
918 receiver is ir.VariableGet && | |
919 condition.arguments.positional.single is ir.NullLiteral && | |
920 otherwise is ir.VariableGet) { | |
921 if (receiver.variable == node.variable && | |
922 otherwise.variable == node.variable) { | |
923 // We have <left> ?? <right> encoded as: | |
924 // let #1 = <left> in #1 == null ? <right> : #1 | |
925 ConstantExpression left = visit(node.variable.initializer); | |
926 if (left == null) return null; | |
927 ConstantExpression right = visit(body.then); | |
928 if (right == null) return null; | |
929 // TODO(johnniwinther): Remove [IF_NULL] binary constant expression | |
930 // when the resolver is removed; then we no longer need the | |
931 // expressions to be structurally equivalence for equivalence | |
932 // testing. | |
933 return new BinaryConstantExpression( | |
934 left, BinaryOperator.IF_NULL, right); | |
935 } | |
936 } | |
937 } | |
938 } | |
939 return defaultExpression(node); | |
940 } | |
941 | |
942 /// Compute the [ConstantConstructor] corresponding to the const constructor | |
943 /// [node]. | |
944 ConstantConstructor computeConstantConstructor(ir.Constructor node) { | |
945 assert(node.isConst); | |
946 ir.Class cls = node.enclosingClass; | |
947 InterfaceType type = elementAdapter.elementEnvironment | |
948 .getThisType(elementAdapter.getClass(cls)); | |
949 | |
950 Map<dynamic, ConstantExpression> defaultValues = | |
951 <dynamic, ConstantExpression>{}; | |
952 int parameterIndex = 0; | |
953 for (ir.VariableDeclaration parameter | |
954 in node.function.positionalParameters) { | |
955 if (parameterIndex >= node.function.requiredParameterCount) { | |
956 ConstantExpression defaultValue; | |
957 if (parameter.initializer != null) { | |
958 defaultValue = parameter.initializer.accept(this); | |
959 } else { | |
960 defaultValue = new NullConstantExpression(); | |
961 } | |
962 if (defaultValue == null) return null; | |
963 defaultValues[parameterIndex] = defaultValue; | |
964 } | |
965 parameterIndex++; | |
966 } | |
967 for (ir.VariableDeclaration parameter in node.function.namedParameters) { | |
968 ConstantExpression defaultValue = parameter.initializer.accept(this); | |
969 if (defaultValue == null) return null; | |
970 defaultValues[parameter.name] = defaultValue; | |
971 } | |
972 | |
973 bool isRedirecting = node.initializers.length == 1 && | |
974 node.initializers.single is ir.RedirectingInitializer; | |
975 | |
976 Map<FieldEntity, ConstantExpression> fieldMap = | |
977 <FieldEntity, ConstantExpression>{}; | |
978 | |
979 void registerField(ir.Field field, ConstantExpression constant) { | |
980 fieldMap[elementAdapter.getField(field)] = constant; | |
981 } | |
982 | |
983 if (!isRedirecting) { | |
984 for (ir.Field field in cls.fields) { | |
985 if (field.isStatic) continue; | |
986 if (field.initializer != null) { | |
987 registerField(field, field.initializer.accept(this)); | |
988 } | |
989 } | |
990 } | |
991 | |
992 ConstructedConstantExpression superConstructorInvocation; | |
993 for (ir.Initializer initializer in node.initializers) { | |
994 if (initializer is ir.FieldInitializer) { | |
995 registerField(initializer.field, initializer.value.accept(this)); | |
996 } else if (initializer is ir.SuperInitializer) { | |
997 superConstructorInvocation = _computeConstructorInvocation( | |
998 initializer.target, initializer.arguments); | |
999 } else if (initializer is ir.RedirectingInitializer) { | |
1000 superConstructorInvocation = _computeConstructorInvocation( | |
1001 initializer.target, initializer.arguments); | |
1002 } else { | |
1003 throw new UnsupportedError( | |
1004 'Unexpected initializer $node (${node.runtimeType})'); | |
1005 } | |
1006 } | |
1007 if (isRedirecting) { | |
1008 return new RedirectingGenerativeConstantConstructor( | |
1009 defaultValues, superConstructorInvocation); | |
1010 } else { | |
1011 return new GenerativeConstantConstructor( | |
1012 type, defaultValues, fieldMap, superConstructorInvocation); | |
1013 } | |
1014 } | |
1015 } | |
1016 | |
1017 /// Interface for type inference results for kernel IR nodes. | 193 /// Interface for type inference results for kernel IR nodes. |
1018 abstract class KernelToTypeInferenceMap { | 194 abstract class KernelToTypeInferenceMap { |
1019 /// Returns the inferred return type of [function]. | 195 /// Returns the inferred return type of [function]. |
1020 TypeMask getReturnTypeOf(FunctionEntity function); | 196 TypeMask getReturnTypeOf(FunctionEntity function); |
1021 | 197 |
1022 /// Returns the inferred receiver type of the dynamic [invocation]. | 198 /// Returns the inferred receiver type of the dynamic [invocation]. |
1023 TypeMask typeOfInvocation( | 199 TypeMask typeOfInvocation( |
1024 ir.MethodInvocation invocation, ClosedWorld closedWorld); | 200 ir.MethodInvocation invocation, ClosedWorld closedWorld); |
1025 | 201 |
1026 /// Returns the inferred receiver type of the dynamic [read]. | 202 /// Returns the inferred receiver type of the dynamic [read]. |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1125 /// Returns the [LoopClosureScope] for the loop [node] in [closureClassMaps]. | 301 /// Returns the [LoopClosureScope] for the loop [node] in [closureClassMaps]. |
1126 LoopClosureScope getLoopClosureScope( | 302 LoopClosureScope getLoopClosureScope( |
1127 ClosureDataLookup closureLookup, ir.TreeNode node); | 303 ClosureDataLookup closureLookup, ir.TreeNode node); |
1128 } | 304 } |
1129 | 305 |
1130 /// Comparator for the canonical order or named arguments. | 306 /// Comparator for the canonical order or named arguments. |
1131 // TODO(johnniwinther): Remove this when named parameters are sorted in dill. | 307 // TODO(johnniwinther): Remove this when named parameters are sorted in dill. |
1132 int namedOrdering(ir.VariableDeclaration a, ir.VariableDeclaration b) { | 308 int namedOrdering(ir.VariableDeclaration a, ir.VariableDeclaration b) { |
1133 return a.name.compareTo(b.name); | 309 return a.name.compareTo(b.name); |
1134 } | 310 } |
OLD | NEW |