Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: pkg/compiler/lib/src/kernel/element_map.dart

Issue 2955093002: Split KernelToElementMap mixins to match interfaces (Closed)
Patch Set: Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/kernel/element_map_impl.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/kernel/element_map_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698