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

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

Issue 2858223004: Rename KernelElementAdapter and element_adapter.dart to IrToElementMap and ir_map.dart (Closed)
Patch Set: Updated cf. comments. Created 3 years, 7 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.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'package:kernel/ast.dart' as ir;
6
7 import '../common.dart';
8 import '../common/names.dart';
9 import '../constants/constructors.dart';
10 import '../constants/expressions.dart';
11 import '../constants/values.dart';
12 import '../common_elements.dart';
13 import '../elements/elements.dart';
14 import '../elements/entities.dart';
15 import '../elements/operators.dart';
16 import '../elements/types.dart';
17 import '../js_backend/backend.dart' show JavaScriptBackend;
18 import '../native/native.dart' as native;
19 import '../universe/call_structure.dart';
20 import '../universe/selector.dart';
21 import 'kernel_debug.dart';
22
23 /// Interface that translates between Kernel IR nodes and entities.
24 abstract class KernelElementAdapter {
25 /// Access to the commonly used elements and types.
26 CommonElements get commonElements;
27
28 /// [ElementEnvironment] for library, class and member lookup.
29 ElementEnvironment get elementEnvironment;
30
31 /// Returns the [DartType] corresponding to [type].
32 DartType getDartType(ir.DartType type);
33
34 /// Returns the list of [DartType]s corresponding to [types].
35 List<DartType> getDartTypes(List<ir.DartType> types);
36
37 /// Returns the [InterfaceType] corresponding to [type].
38 InterfaceType getInterfaceType(ir.InterfaceType type);
39
40 /// Return the [InterfaceType] corresponding to the [cls] with the given
41 /// [typeArguments].
42 InterfaceType createInterfaceType(
43 ir.Class cls, List<ir.DartType> typeArguments);
44
45 /// Returns the [CallStructure] corresponding to the [arguments].
46 CallStructure getCallStructure(ir.Arguments arguments);
47
48 /// Returns the [Selector] corresponding to the invocation or getter/setter
49 /// access of [node].
50 Selector getSelector(ir.Expression node);
51
52 /// Returns the [ConstructorEntity] corresponding to the generative or factory
53 /// constructor [node].
54 ConstructorEntity getConstructor(ir.Member node);
55
56 /// Returns the [MemberEntity] corresponding to the member [node].
57 MemberEntity getMember(ir.Member node);
58
59 /// Returns the [FunctionEntity] corresponding to the procedure [node].
60 FunctionEntity getMethod(ir.Procedure node);
61
62 /// Returns the [FieldEntity] corresponding to the field [node].
63 FieldEntity getField(ir.Field node);
64
65 /// Returns the [ClassEntity] corresponding to the class [node].
66 ClassEntity getClass(ir.Class node);
67
68 /// Returns the [Local] corresponding to the [node]. The node must be either
69 /// a [ir.FunctionDeclaration] or [ir.FunctionExpression].
70 Local getLocalFunction(ir.TreeNode node);
71
72 /// Returns the [LibraryEntity] corresponding to the library [node].
73 LibraryEntity getLibrary(ir.Library node);
74
75 /// Returns the [Name] corresponding to [name].
76 Name getName(ir.Name name);
77
78 /// Returns `true` is [node] has a `@Native(...)` annotation.
79 bool isNativeClass(ir.Class node);
80
81 /// Return `true` if [node] is the `dart:_foreign_helper` library.
82 bool isForeignLibrary(ir.Library node);
83
84 /// Computes the native behavior for reading the native [field].
85 native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field);
86
87 /// Computes the native behavior for writing to the native [field].
88 native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field);
89
90 /// Computes the native behavior for calling [procedure].
91 native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure);
92
93 /// Computes the [native.NativeBehavior] for a call to the [JS] function.
94 native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node);
95
96 /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
97 /// function.
98 native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
99 ir.StaticInvocation node);
100
101 /// Computes the [native.NativeBehavior] for a call to the
102 /// [JS_EMBEDDED_GLOBAL] function.
103 native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
104 ir.StaticInvocation node);
105
106 /// Compute the kind of foreign helper function called by [node], if any.
107 ForeignKind getForeignKind(ir.StaticInvocation node);
108
109 /// Computes the [InterfaceType] referenced by a call to the
110 /// [JS_INTERCEPTOR_CONSTANT] function, if any.
111 InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node);
112
113 /// Computes the [ConstantValue] for the constant [expression].
114 ConstantValue getConstantValue(ir.Expression expression);
115 }
116
117 /// Kinds of foreign functions.
118 enum ForeignKind {
119 JS,
120 JS_BUILTIN,
121 JS_EMBEDDED_GLOBAL,
122 JS_INTERCEPTOR_CONSTANT,
123 NONE,
124 }
125
126 abstract class KernelElementAdapterMixin implements KernelElementAdapter {
127 DiagnosticReporter get reporter;
128 FunctionType getFunctionType(ir.FunctionNode node);
129 native.BehaviorBuilder get nativeBehaviorBuilder;
130 ConstantValue computeConstantValue(ConstantExpression constant);
131
132 @override
133 Name getName(ir.Name name) {
134 return new Name(
135 name.name, name.isPrivate ? getLibrary(name.library) : null);
136 }
137
138 @override
139 CallStructure getCallStructure(ir.Arguments arguments) {
140 int argumentCount = arguments.positional.length + arguments.named.length;
141 List<String> namedArguments = arguments.named.map((e) => e.name).toList();
142 return new CallStructure(argumentCount, namedArguments);
143 }
144
145 @override
146 Selector getSelector(ir.Expression node) {
147 // TODO(efortuna): This is screaming for a common interface between
148 // PropertyGet and SuperPropertyGet (and same for *Get). Talk to kernel
149 // folks.
150 if (node is ir.PropertyGet) {
151 return getGetterSelector(node.name);
152 }
153 if (node is ir.SuperPropertyGet) {
154 return getGetterSelector(node.name);
155 }
156 if (node is ir.PropertySet) {
157 return getSetterSelector(node.name);
158 }
159 if (node is ir.SuperPropertySet) {
160 return getSetterSelector(node.name);
161 }
162 if (node is ir.InvocationExpression) {
163 return getInvocationSelector(node);
164 }
165 throw new SpannableAssertionFailure(
166 CURRENT_ELEMENT_SPANNABLE,
167 "Can only get the selector for a property get or an invocation: "
168 "${node}");
169 }
170
171 Selector getInvocationSelector(ir.InvocationExpression invocation) {
172 Name name = getName(invocation.name);
173 SelectorKind kind;
174 if (Elements.isOperatorName(invocation.name.name)) {
175 if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) {
176 kind = SelectorKind.INDEX;
177 } else {
178 kind = SelectorKind.OPERATOR;
179 }
180 } else {
181 kind = SelectorKind.CALL;
182 }
183
184 CallStructure callStructure = getCallStructure(invocation.arguments);
185 return new Selector(kind, name, callStructure);
186 }
187
188 Selector getGetterSelector(ir.Name irName) {
189 Name name = new Name(
190 irName.name, irName.isPrivate ? getLibrary(irName.library) : null);
191 return new Selector.getter(name);
192 }
193
194 Selector getSetterSelector(ir.Name irName) {
195 Name name = new Name(
196 irName.name, irName.isPrivate ? getLibrary(irName.library) : null);
197 return new Selector.setter(name);
198 }
199
200 ConstantValue getConstantValue(ir.Expression node) {
201 ConstantExpression constant = new Constantifier(this).visit(node);
202 if (constant == null) {
203 throw new UnsupportedError(
204 'No constant for ${DebugPrinter.prettyPrint(node)}');
205 }
206 return computeConstantValue(constant);
207 }
208
209 /// Converts [annotations] into a list of [ConstantValue]s.
210 List<ConstantValue> getMetadata(List<ir.Expression> annotations) {
211 if (annotations.isEmpty) return const <ConstantValue>[];
212 List<ConstantValue> metadata = <ConstantValue>[];
213 annotations.forEach((ir.Expression node) {
214 metadata.add(getConstantValue(node));
215 });
216 return metadata;
217 }
218
219 /// Returns `true` is [node] has a `@Native(...)` annotation.
220 // TODO(johnniwinther): Cache this for later use.
221 bool isNativeClass(ir.Class node) {
222 for (ir.Expression annotation in node.annotations) {
223 if (annotation is ir.ConstructorInvocation) {
224 FunctionEntity target = getConstructor(annotation.target);
225 if (target.enclosingClass == commonElements.nativeAnnotationClass) {
226 return true;
227 }
228 }
229 }
230 return false;
231 }
232
233 /// Compute the kind of foreign helper function called by [node], if any.
234 ForeignKind getForeignKind(ir.StaticInvocation node) {
235 if (isForeignLibrary(node.target.enclosingLibrary)) {
236 switch (node.target.name.name) {
237 case JavaScriptBackend.JS:
238 return ForeignKind.JS;
239 case JavaScriptBackend.JS_BUILTIN:
240 return ForeignKind.JS_BUILTIN;
241 case JavaScriptBackend.JS_EMBEDDED_GLOBAL:
242 return ForeignKind.JS_EMBEDDED_GLOBAL;
243 case JavaScriptBackend.JS_INTERCEPTOR_CONSTANT:
244 return ForeignKind.JS_INTERCEPTOR_CONSTANT;
245 }
246 }
247 return ForeignKind.NONE;
248 }
249
250 /// Return `true` if [node] is the `dart:_foreign_helper` library.
251 bool isForeignLibrary(ir.Library node) {
252 return node.importUri == Uris.dart__foreign_helper;
253 }
254
255 /// Looks up [typeName] for use in the spec-string of a `JS` called.
256 // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling
257 // the `ForeignResolver`.
258 // TODO(johnniwinther): Cache the result to avoid redundant lookups?
259 native.TypeLookup typeLookup({bool resolveAsRaw: true}) {
260 DartType lookup(String typeName, {bool required}) {
261 DartType findIn(Uri uri) {
262 LibraryEntity library = elementEnvironment.lookupLibrary(uri);
263 if (library != null) {
264 ClassEntity cls = elementEnvironment.lookupClass(library, typeName);
265 if (cls != null) {
266 // TODO(johnniwinther): Align semantics.
267 return resolveAsRaw
268 ? elementEnvironment.getRawType(cls)
269 : elementEnvironment.getThisType(cls);
270 }
271 }
272 return null;
273 }
274
275 // TODO(johnniwinther): Narrow the set of lookups base on the depending
276 // library.
277 DartType type = findIn(Uris.dart_core);
278 type ??= findIn(Uris.dart__js_helper);
279 type ??= findIn(Uris.dart__interceptors);
280 type ??= findIn(Uris.dart__isolate_helper);
281 type ??= findIn(Uris.dart__native_typed_data);
282 type ??= findIn(Uris.dart_collection);
283 type ??= findIn(Uris.dart_math);
284 type ??= findIn(Uris.dart_html);
285 type ??= findIn(Uris.dart_html_common);
286 type ??= findIn(Uris.dart_svg);
287 type ??= findIn(Uris.dart_web_audio);
288 type ??= findIn(Uris.dart_web_gl);
289 type ??= findIn(Uris.dart_web_sql);
290 type ??= findIn(Uris.dart_indexed_db);
291 type ??= findIn(Uris.dart_typed_data);
292 if (type == null && required) {
293 reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE,
294 MessageKind.GENERIC, {'text': "Type '$typeName' not found."});
295 }
296 return type;
297 }
298
299 return lookup;
300 }
301
302 String _getStringArgument(ir.StaticInvocation node, int index) {
303 return node.arguments.positional[index].accept(new Stringifier());
304 }
305
306 /// Computes the [native.NativeBehavior] for a call to the [JS] function.
307 // TODO(johnniwinther): Cache this for later use.
308 native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
309 if (node.arguments.positional.length < 2 ||
310 node.arguments.named.isNotEmpty) {
311 reporter.reportErrorMessage(
312 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS);
313 return new native.NativeBehavior();
314 }
315 String specString = _getStringArgument(node, 0);
316 if (specString == null) {
317 reporter.reportErrorMessage(
318 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
319 return new native.NativeBehavior();
320 }
321
322 String codeString = _getStringArgument(node, 1);
323 if (codeString == null) {
324 reporter.reportErrorMessage(
325 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
326 return new native.NativeBehavior();
327 }
328
329 return native.NativeBehavior.ofJsCall(
330 specString,
331 codeString,
332 typeLookup(resolveAsRaw: true),
333 CURRENT_ELEMENT_SPANNABLE,
334 reporter,
335 commonElements);
336 }
337
338 /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
339 /// function.
340 // TODO(johnniwinther): Cache this for later use.
341 native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
342 ir.StaticInvocation node) {
343 if (node.arguments.positional.length < 1) {
344 reporter.internalError(
345 CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type.");
346 return new native.NativeBehavior();
347 }
348 if (node.arguments.positional.length < 2) {
349 reporter.internalError(
350 CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name.");
351 return new native.NativeBehavior();
352 }
353 String specString = _getStringArgument(node, 0);
354 if (specString == null) {
355 reporter.internalError(
356 CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
357 return new native.NativeBehavior();
358 }
359 return native.NativeBehavior.ofJsBuiltinCall(
360 specString,
361 typeLookup(resolveAsRaw: true),
362 CURRENT_ELEMENT_SPANNABLE,
363 reporter,
364 commonElements);
365 }
366
367 /// Computes the [native.NativeBehavior] for a call to the
368 /// [JS_EMBEDDED_GLOBAL] function.
369 // TODO(johnniwinther): Cache this for later use.
370 native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
371 ir.StaticInvocation node) {
372 if (node.arguments.positional.length < 1) {
373 reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
374 "JS embedded global expression has no type.");
375 return new native.NativeBehavior();
376 }
377 if (node.arguments.positional.length < 2) {
378 reporter.internalError(
379 CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name.");
380 return new native.NativeBehavior();
381 }
382 if (node.arguments.positional.length > 2 ||
383 node.arguments.named.isNotEmpty) {
384 reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
385 "JS embedded global has more than 2 arguments.");
386 return new native.NativeBehavior();
387 }
388 String specString = _getStringArgument(node, 0);
389 if (specString == null) {
390 reporter.internalError(
391 CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
392 return new native.NativeBehavior();
393 }
394 return native.NativeBehavior.ofJsEmbeddedGlobalCall(
395 specString,
396 typeLookup(resolveAsRaw: true),
397 CURRENT_ELEMENT_SPANNABLE,
398 reporter,
399 commonElements);
400 }
401
402 /// Computes the [InterfaceType] referenced by a call to the
403 /// [JS_INTERCEPTOR_CONSTANT] function, if any.
404 InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node) {
405 if (node.arguments.positional.length != 1 ||
406 node.arguments.named.isNotEmpty) {
407 reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE,
408 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
409 }
410 ir.Node argument = node.arguments.positional.first;
411 if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) {
412 return getInterfaceType(argument.type);
413 }
414 return null;
415 }
416
417 /// Computes the native behavior for reading the native [field].
418 // TODO(johnniwinther): Cache this for later use.
419 native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field) {
420 DartType type = getDartType(field.type);
421 List<ConstantValue> metadata = getMetadata(field.annotations);
422 // TODO(johnniwinther): Provide the correct value for [isJsInterop].
423 return nativeBehaviorBuilder.buildFieldLoadBehavior(
424 type, metadata, typeLookup(resolveAsRaw: false),
425 isJsInterop: false);
426 }
427
428 /// Computes the native behavior for writing to the native [field].
429 // TODO(johnniwinther): Cache this for later use.
430 native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
431 DartType type = getDartType(field.type);
432 return nativeBehaviorBuilder.buildFieldStoreBehavior(type);
433 }
434
435 /// Computes the native behavior for calling [procedure].
436 // TODO(johnniwinther): Cache this for later use.
437 native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure) {
438 DartType type = getFunctionType(procedure.function);
439 List<ConstantValue> metadata = getMetadata(procedure.annotations);
440 // TODO(johnniwinther): Provide the correct value for [isJsInterop].
441 return nativeBehaviorBuilder.buildMethodBehavior(
442 type, metadata, typeLookup(resolveAsRaw: false),
443 isJsInterop: false);
444 }
445 }
446
447 /// Visitor that converts string literals and concatenations of string literals
448 /// into the string value.
449 class Stringifier extends ir.ExpressionVisitor<String> {
450 @override
451 String visitStringLiteral(ir.StringLiteral node) => node.value;
452
453 @override
454 String visitStringConcatenation(ir.StringConcatenation node) {
455 StringBuffer sb = new StringBuffer();
456 for (ir.Expression expression in node.expressions) {
457 String value = expression.accept(this);
458 if (value == null) return null;
459 sb.write(value);
460 }
461 return sb.toString();
462 }
463 }
464
465 /// Visitor that converts a kernel constant expression into a
466 /// [ConstantExpression].
467 class Constantifier extends ir.ExpressionVisitor<ConstantExpression> {
468 final bool requireConstant;
469 final KernelElementAdapterMixin elementAdapter;
470
471 Constantifier(this.elementAdapter, {this.requireConstant: true});
472
473 CommonElements get _commonElements => elementAdapter.commonElements;
474
475 ConstantExpression visit(ir.Expression node) {
476 ConstantExpression constant = node.accept(this);
477 if (constant == null && requireConstant) {
478 throw new UnsupportedError(
479 "No constant computed for $node (${node.runtimeType})");
480 }
481 return constant;
482 }
483
484 ConstantExpression defaultExpression(ir.Expression node) {
485 throw new UnimplementedError(
486 'Unimplemented constant expression $node (${node.runtimeType})');
487 }
488
489 List<ConstantExpression> _computeList(List<ir.Expression> expressions) {
490 List<ConstantExpression> list = <ConstantExpression>[];
491 for (ir.Expression expression in expressions) {
492 ConstantExpression constant = visit(expression);
493 if (constant == null) return null;
494 list.add(constant);
495 }
496 return list;
497 }
498
499 List<ConstantExpression> _computeArguments(ir.Arguments node) {
500 List<ConstantExpression> arguments = <ConstantExpression>[];
501 for (ir.Expression argument in node.positional) {
502 ConstantExpression constant = visit(argument);
503 if (constant == null) return null;
504 arguments.add(constant);
505 }
506 for (ir.NamedExpression argument in node.named) {
507 ConstantExpression constant = visit(argument.value);
508 if (constant == null) return null;
509 arguments.add(constant);
510 }
511 return arguments;
512 }
513
514 ConstructedConstantExpression _computeConstructorInvocation(
515 ir.Constructor target, ir.Arguments arguments) {
516 return new ConstructedConstantExpression(
517 elementAdapter.createInterfaceType(
518 target.enclosingClass, arguments.types),
519 elementAdapter.getConstructor(target),
520 elementAdapter.getCallStructure(arguments),
521 _computeArguments(arguments));
522 }
523
524 @override
525 ConstantExpression visitConstructorInvocation(ir.ConstructorInvocation node) {
526 return _computeConstructorInvocation(node.target, node.arguments);
527 }
528
529 @override
530 ConstantExpression visitVariableGet(ir.VariableGet node) {
531 if (node.variable.parent is ir.FunctionNode) {
532 ir.FunctionNode function = node.variable.parent;
533 int index = function.positionalParameters.indexOf(node.variable);
534 if (index != -1) {
535 return new PositionalArgumentReference(index);
536 } else {
537 assert(function.namedParameters.contains(node.variable));
538 return new NamedArgumentReference(node.variable.name);
539 }
540 }
541 throw new UnimplementedError(
542 'Unimplemented constant expression $node (${node.runtimeType})');
543 }
544
545 @override
546 ConstantExpression visitStaticGet(ir.StaticGet node) {
547 if (node.target is ir.Field) {
548 return new FieldConstantExpression(elementAdapter.getField(node.target));
549 } else if (node.target is ir.Procedure) {
550 FunctionEntity function = elementAdapter.getMethod(node.target);
551 DartType type = elementAdapter.getFunctionType(node.target.function);
552 return new FunctionConstantExpression(function, type);
553 }
554 throw new UnimplementedError(
555 'Unexpected constant expression $node (${node.runtimeType})');
556 }
557
558 @override
559 ConstantExpression visitNullLiteral(ir.NullLiteral node) {
560 return new NullConstantExpression();
561 }
562
563 @override
564 ConstantExpression visitBoolLiteral(ir.BoolLiteral node) {
565 return new BoolConstantExpression(node.value);
566 }
567
568 @override
569 ConstantExpression visitIntLiteral(ir.IntLiteral node) {
570 return new IntConstantExpression(node.value);
571 }
572
573 @override
574 ConstantExpression visitDoubleLiteral(ir.DoubleLiteral node) {
575 return new DoubleConstantExpression(node.value);
576 }
577
578 @override
579 ConstantExpression visitStringLiteral(ir.StringLiteral node) {
580 return new StringConstantExpression(node.value);
581 }
582
583 @override
584 ConstantExpression visitSymbolLiteral(ir.SymbolLiteral node) {
585 return new SymbolConstantExpression(node.value);
586 }
587
588 @override
589 ConstantExpression visitStringConcatenation(ir.StringConcatenation node) {
590 return new ConcatenateConstantExpression(_computeList(node.expressions));
591 }
592
593 @override
594 ConstantExpression visitMapLiteral(ir.MapLiteral node) {
595 if (!node.isConst) {
596 throw new UnimplementedError(
597 'Unexpected constant expression $node (${node.runtimeType})');
598 }
599 DartType keyType = elementAdapter.getDartType(node.keyType);
600 DartType valueType = elementAdapter.getDartType(node.valueType);
601 List<ConstantExpression> keys = <ConstantExpression>[];
602 List<ConstantExpression> values = <ConstantExpression>[];
603 for (ir.MapEntry entry in node.entries) {
604 keys.add(visit(entry.key));
605 values.add(visit(entry.value));
606 }
607 return new MapConstantExpression(
608 _commonElements.mapType(keyType, valueType), keys, values);
609 }
610
611 @override
612 ConstantExpression visitListLiteral(ir.ListLiteral node) {
613 if (!node.isConst) {
614 throw new UnimplementedError(
615 'Unexpected constant expression $node (${node.runtimeType})');
616 }
617 DartType elementType = elementAdapter.getDartType(node.typeArgument);
618 List<ConstantExpression> values = <ConstantExpression>[];
619 for (ir.Expression value in node.expressions) {
620 values.add(visit(value));
621 }
622 return new ListConstantExpression(
623 _commonElements.listType(elementType), values);
624 }
625
626 @override
627 ConstantExpression visitConditionalExpression(ir.ConditionalExpression node) {
628 ConstantExpression condition = visit(node.condition);
629 ConstantExpression trueExp = visit(node.then);
630 ConstantExpression falseExp = visit(node.otherwise);
631 return new ConditionalConstantExpression(condition, trueExp, falseExp);
632 }
633
634 @override
635 ConstantExpression visitPropertyGet(ir.PropertyGet node) {
636 if (node.name.name != 'length') {
637 throw new UnimplementedError(
638 'Unexpected constant expression $node (${node.runtimeType})');
639 }
640 ConstantExpression receiver = visit(node.receiver);
641 return new StringLengthConstantExpression(receiver);
642 }
643
644 @override
645 ConstantExpression visitMethodInvocation(ir.MethodInvocation node) {
646 // Method invocations are generally not constant expressions but unary
647 // and binary expressions are encoded as method invocations in kernel.
648 if (node.arguments.named.isNotEmpty) {
649 throw new UnimplementedError(
650 'Unexpected constant expression $node (${node.runtimeType})');
651 }
652 if (node.arguments.positional.length == 0) {
653 UnaryOperator operator;
654 if (node.name.name == UnaryOperator.NEGATE.selectorName) {
655 operator = UnaryOperator.NEGATE;
656 } else {
657 operator = UnaryOperator.parse(node.name.name);
658 }
659 if (operator != null) {
660 ConstantExpression expression = visit(node.receiver);
661 return new UnaryConstantExpression(operator, expression);
662 }
663 }
664 if (node.arguments.positional.length == 1) {
665 BinaryOperator operator = BinaryOperator.parse(node.name.name);
666 if (operator != null) {
667 ConstantExpression left = visit(node.receiver);
668 ConstantExpression right = visit(node.arguments.positional.single);
669 return new BinaryConstantExpression(left, operator, right);
670 }
671 }
672 throw new UnimplementedError(
673 'Unexpected constant expression $node (${node.runtimeType})');
674 }
675
676 @override
677 ConstantExpression visitStaticInvocation(ir.StaticInvocation node) {
678 MemberEntity member = elementAdapter.getMember(node.target);
679 if (member == _commonElements.identicalFunction) {
680 if (node.arguments.positional.length == 2 &&
681 node.arguments.named.isEmpty) {
682 ConstantExpression left = visit(node.arguments.positional[0]);
683 ConstantExpression right = visit(node.arguments.positional[1]);
684 return new IdenticalConstantExpression(left, right);
685 }
686 } else if (member.name == 'fromEnvironment' &&
687 node.arguments.positional.length == 1) {
688 ConstantExpression name = visit(node.arguments.positional.single);
689 ConstantExpression defaultValue;
690 if (node.arguments.named.length == 1) {
691 if (node.arguments.named.single.name != 'defaultValue') {
692 throw new UnimplementedError(
693 'Unexpected constant expression $node (${node.runtimeType})');
694 }
695 defaultValue = visit(node.arguments.named.single.value);
696 }
697 if (member.enclosingClass == _commonElements.boolClass) {
698 return new BoolFromEnvironmentConstantExpression(name, defaultValue);
699 } else if (member.enclosingClass == _commonElements.intClass) {
700 return new IntFromEnvironmentConstantExpression(name, defaultValue);
701 } else if (member.enclosingClass == _commonElements.stringClass) {
702 return new StringFromEnvironmentConstantExpression(name, defaultValue);
703 }
704 }
705 throw new UnimplementedError(
706 'Unexpected constant expression $node (${node.runtimeType})');
707 }
708
709 @override
710 ConstantExpression visitLogicalExpression(ir.LogicalExpression node) {
711 BinaryOperator operator = BinaryOperator.parse(node.operator);
712 if (operator != null) {
713 ConstantExpression left = visit(node.left);
714 ConstantExpression right = visit(node.right);
715 return new BinaryConstantExpression(left, operator, right);
716 }
717 throw new UnimplementedError(
718 'Unexpected constant expression $node (${node.runtimeType})');
719 }
720
721 /// Compute the [ConstantConstructor] corresponding to the const constructor
722 /// [node].
723 ConstantConstructor computeConstantConstructor(ir.Constructor node) {
724 assert(node.isConst);
725 ir.Class cls = node.enclosingClass;
726 InterfaceType type = elementAdapter.elementEnvironment
727 .getThisType(elementAdapter.getClass(cls));
728
729 Map<dynamic, ConstantExpression> defaultValues =
730 <dynamic, ConstantExpression>{};
731 int parameterIndex = 0;
732 node.function.positionalParameters
733 .forEach((ir.VariableDeclaration parameter) {
734 if (parameterIndex >= node.function.requiredParameterCount) {
735 if (parameter.initializer != null) {
736 defaultValues[parameterIndex] = parameter.initializer.accept(this);
737 } else {
738 defaultValues[parameterIndex] = new NullConstantExpression();
739 }
740 }
741 parameterIndex++;
742 });
743 node.function.namedParameters.forEach((ir.VariableDeclaration parameter) {
744 defaultValues[parameter.name] = parameter.initializer.accept(this);
745 });
746
747 bool isRedirecting = node.initializers.length == 1 &&
748 node.initializers.single is ir.RedirectingInitializer;
749
750 Map<FieldEntity, ConstantExpression> fieldMap =
751 <FieldEntity, ConstantExpression>{};
752
753 void registerField(ir.Field field, ConstantExpression constant) {
754 fieldMap[elementAdapter.getField(field)] = constant;
755 }
756
757 if (!isRedirecting) {
758 for (ir.Field field in cls.fields) {
759 if (field.initializer != null) {
760 registerField(field, field.initializer.accept(this));
761 }
762 }
763 }
764
765 ConstructedConstantExpression superConstructorInvocation;
766 for (ir.Initializer initializer in node.initializers) {
767 if (initializer is ir.FieldInitializer) {
768 registerField(initializer.field, initializer.value.accept(this));
769 } else if (initializer is ir.SuperInitializer) {
770 superConstructorInvocation = _computeConstructorInvocation(
771 initializer.target, initializer.arguments);
772 } else if (initializer is ir.RedirectingInitializer) {
773 superConstructorInvocation = _computeConstructorInvocation(
774 initializer.target, initializer.arguments);
775 } else {
776 throw new UnsupportedError(
777 'Unexpected initializer $node (${node.runtimeType})');
778 }
779 }
780 if (isRedirecting) {
781 return new RedirectingGenerativeConstantConstructor(
782 defaultValues, superConstructorInvocation);
783 } else {
784 return new GenerativeConstantConstructor(
785 type, defaultValues, fieldMap, superConstructorInvocation);
786 }
787 }
788 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/kernel/element_map.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698