| Index: pkg/compiler/lib/src/kernel/element_map.dart
|
| diff --git a/pkg/compiler/lib/src/kernel/element_map.dart b/pkg/compiler/lib/src/kernel/element_map.dart
|
| index 6dcff310c781af918b18ba09432f2e945b255aaf..3b701de96d4bb9b9baa1efa0557106ec2b8627e1 100644
|
| --- a/pkg/compiler/lib/src/kernel/element_map.dart
|
| +++ b/pkg/compiler/lib/src/kernel/element_map.dart
|
| @@ -2,23 +2,17 @@
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| -import 'package:js_runtime/shared/embedded_names.dart';
|
| import 'package:kernel/ast.dart' as ir;
|
|
|
| import '../closure.dart';
|
| import '../common.dart';
|
| -import '../common/names.dart';
|
| -import '../constants/constructors.dart';
|
| -import '../constants/expressions.dart';
|
| import '../constants/values.dart';
|
| import '../common_elements.dart';
|
| import '../elements/entities.dart';
|
| import '../elements/jumps.dart';
|
| import '../elements/names.dart';
|
| -import '../elements/operators.dart';
|
| import '../elements/types.dart';
|
| import '../js/js.dart' as js;
|
| -import '../js_backend/backend.dart' show JavaScriptBackend;
|
| import '../js_backend/namer.dart';
|
| import '../js_emitter/code_emitter_task.dart';
|
| import '../native/native.dart' as native;
|
| @@ -26,7 +20,6 @@ import '../types/types.dart';
|
| import '../universe/call_structure.dart';
|
| import '../universe/selector.dart';
|
| import '../world.dart';
|
| -import 'kernel_debug.dart';
|
|
|
| /// Interface that translates between Kernel IR nodes and entities.
|
| abstract class KernelToElementMap {
|
| @@ -36,11 +29,20 @@ abstract class KernelToElementMap {
|
| /// Returns the [DartType] corresponding to [type].
|
| DartType getDartType(ir.DartType type);
|
|
|
| + /// Returns the [InterfaceType] corresponding to [type].
|
| + InterfaceType getInterfaceType(ir.InterfaceType type);
|
| +
|
| + /// Returns the [FunctionType] of the [node].
|
| + FunctionType getFunctionType(ir.FunctionNode node);
|
| +
|
| /// Return the [InterfaceType] corresponding to the [cls] with the given
|
| /// [typeArguments].
|
| InterfaceType createInterfaceType(
|
| ir.Class cls, List<ir.DartType> typeArguments);
|
|
|
| + /// Returns the [CallStructure] corresponding to the [arguments].
|
| + CallStructure getCallStructure(ir.Arguments arguments);
|
| +
|
| /// Returns the [Selector] corresponding to the invocation or getter/setter
|
| /// access of [node].
|
| Selector getSelector(ir.Expression node);
|
| @@ -58,6 +60,9 @@ abstract class KernelToElementMap {
|
| /// Returns the [FieldEntity] corresponding to the field [node].
|
| FieldEntity getField(ir.Field node);
|
|
|
| + /// Returns the [ClassEntity] corresponding to the class [node].
|
| + ClassEntity getClass(ir.Class node);
|
| +
|
| /// Returns the [Local] corresponding to the [node]. The node must be either
|
| /// a [ir.FunctionDeclaration] or [ir.FunctionExpression].
|
| Local getLocalFunction(ir.TreeNode node);
|
| @@ -103,9 +108,6 @@ abstract class KernelToElementMap {
|
| /// Interface that translates between Kernel IR nodes and entities used for
|
| /// computing the [WorldImpact] for members.
|
| abstract class KernelToElementMapForImpact extends KernelToElementMap {
|
| - /// Returns the [CallStructure] corresponding to the [arguments].
|
| - CallStructure getCallStructure(ir.Arguments arguments);
|
| -
|
| /// Returns the [ConstructorEntity] corresponding to a super initializer in
|
| /// [constructor].
|
| ///
|
| @@ -153,21 +155,12 @@ abstract class KernelToElementMapForBuilding implements KernelToElementMap {
|
| /// [ElementEnvironment] for library, class and member lookup.
|
| ElementEnvironment get elementEnvironment;
|
|
|
| - /// Returns the [FunctionType] of the [node].
|
| - FunctionType getFunctionType(ir.FunctionNode node);
|
| -
|
| /// Returns the list of [DartType]s corresponding to [types].
|
| List<DartType> getDartTypes(List<ir.DartType> types);
|
|
|
| - /// Returns the [InterfaceType] corresponding to [type].
|
| - InterfaceType getInterfaceType(ir.InterfaceType type);
|
| -
|
| /// Returns the kernel IR node that defines the [member].
|
| ir.Node getMemberNode(covariant MemberEntity member);
|
|
|
| - /// Returns the [ClassEntity] corresponding to the class [node].
|
| - ClassEntity getClass(ir.Class node);
|
| -
|
| /// Returns the [LibraryEntity] corresponding to the library [node].
|
| LibraryEntity getLibrary(ir.Library node);
|
|
|
| @@ -197,823 +190,6 @@ enum ForeignKind {
|
| NONE,
|
| }
|
|
|
| -abstract class KernelToElementMapMixin
|
| - implements KernelToElementMapForBuilding {
|
| - DiagnosticReporter get reporter;
|
| - native.BehaviorBuilder get nativeBehaviorBuilder;
|
| - ConstantValue computeConstantValue(ConstantExpression constant,
|
| - {bool requireConstant: true});
|
| -
|
| - @override
|
| - Name getName(ir.Name name) {
|
| - return new Name(
|
| - name.name, name.isPrivate ? getLibrary(name.library) : null);
|
| - }
|
| -
|
| - CallStructure getCallStructure(ir.Arguments arguments) {
|
| - int argumentCount = arguments.positional.length + arguments.named.length;
|
| - List<String> namedArguments = arguments.named.map((e) => e.name).toList();
|
| - return new CallStructure(argumentCount, namedArguments);
|
| - }
|
| -
|
| - @override
|
| - Selector getSelector(ir.Expression node) {
|
| - // TODO(efortuna): This is screaming for a common interface between
|
| - // PropertyGet and SuperPropertyGet (and same for *Get). Talk to kernel
|
| - // folks.
|
| - if (node is ir.PropertyGet) {
|
| - return getGetterSelector(node.name);
|
| - }
|
| - if (node is ir.SuperPropertyGet) {
|
| - return getGetterSelector(node.name);
|
| - }
|
| - if (node is ir.PropertySet) {
|
| - return getSetterSelector(node.name);
|
| - }
|
| - if (node is ir.SuperPropertySet) {
|
| - return getSetterSelector(node.name);
|
| - }
|
| - if (node is ir.InvocationExpression) {
|
| - return getInvocationSelector(node);
|
| - }
|
| - throw new SpannableAssertionFailure(
|
| - CURRENT_ELEMENT_SPANNABLE,
|
| - "Can only get the selector for a property get or an invocation: "
|
| - "${node}");
|
| - }
|
| -
|
| - Selector getInvocationSelector(ir.InvocationExpression invocation) {
|
| - Name name = getName(invocation.name);
|
| - SelectorKind kind;
|
| - if (Selector.isOperatorName(name.text)) {
|
| - if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) {
|
| - kind = SelectorKind.INDEX;
|
| - } else {
|
| - kind = SelectorKind.OPERATOR;
|
| - }
|
| - } else {
|
| - kind = SelectorKind.CALL;
|
| - }
|
| -
|
| - CallStructure callStructure = getCallStructure(invocation.arguments);
|
| - return new Selector(kind, name, callStructure);
|
| - }
|
| -
|
| - Selector getGetterSelector(ir.Name irName) {
|
| - Name name = new Name(
|
| - irName.name, irName.isPrivate ? getLibrary(irName.library) : null);
|
| - return new Selector.getter(name);
|
| - }
|
| -
|
| - Selector getSetterSelector(ir.Name irName) {
|
| - Name name = new Name(
|
| - irName.name, irName.isPrivate ? getLibrary(irName.library) : null);
|
| - return new Selector.setter(name);
|
| - }
|
| -
|
| - ConstantValue getConstantValue(ir.Expression node,
|
| - {bool requireConstant: true, bool implicitNull: false}) {
|
| - ConstantExpression constant;
|
| - if (node == null) {
|
| - if (!implicitNull) {
|
| - throw new SpannableAssertionFailure(
|
| - CURRENT_ELEMENT_SPANNABLE, 'No expression for constant.');
|
| - }
|
| - constant = new NullConstantExpression();
|
| - } else {
|
| - constant =
|
| - new Constantifier(this, requireConstant: requireConstant).visit(node);
|
| - }
|
| - if (constant == null) {
|
| - if (requireConstant) {
|
| - throw new UnsupportedError(
|
| - 'No constant for ${DebugPrinter.prettyPrint(node)}');
|
| - }
|
| - return null;
|
| - }
|
| - return computeConstantValue(constant, requireConstant: requireConstant);
|
| - }
|
| -
|
| - /// Converts [annotations] into a list of [ConstantValue]s.
|
| - List<ConstantValue> getMetadata(List<ir.Expression> annotations) {
|
| - if (annotations.isEmpty) return const <ConstantValue>[];
|
| - List<ConstantValue> metadata = <ConstantValue>[];
|
| - annotations.forEach((ir.Expression node) {
|
| - metadata.add(getConstantValue(node));
|
| - });
|
| - return metadata;
|
| - }
|
| -
|
| - /// Returns `true` is [node] has a `@Native(...)` annotation.
|
| - // TODO(johnniwinther): Cache this for later use.
|
| - bool isNativeClass(ir.Class node) {
|
| - for (ir.Expression annotation in node.annotations) {
|
| - if (annotation is ir.ConstructorInvocation) {
|
| - FunctionEntity target = getConstructor(annotation.target);
|
| - if (target.enclosingClass == commonElements.nativeAnnotationClass) {
|
| - return true;
|
| - }
|
| - }
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - /// Compute the kind of foreign helper function called by [node], if any.
|
| - ForeignKind getForeignKind(ir.StaticInvocation node) {
|
| - if (isForeignLibrary(node.target.enclosingLibrary)) {
|
| - switch (node.target.name.name) {
|
| - case JavaScriptBackend.JS:
|
| - return ForeignKind.JS;
|
| - case JavaScriptBackend.JS_BUILTIN:
|
| - return ForeignKind.JS_BUILTIN;
|
| - case JavaScriptBackend.JS_EMBEDDED_GLOBAL:
|
| - return ForeignKind.JS_EMBEDDED_GLOBAL;
|
| - case JavaScriptBackend.JS_INTERCEPTOR_CONSTANT:
|
| - return ForeignKind.JS_INTERCEPTOR_CONSTANT;
|
| - }
|
| - }
|
| - return ForeignKind.NONE;
|
| - }
|
| -
|
| - /// Return `true` if [node] is the `dart:_foreign_helper` library.
|
| - bool isForeignLibrary(ir.Library node) {
|
| - return node.importUri == Uris.dart__foreign_helper;
|
| - }
|
| -
|
| - /// Looks up [typeName] for use in the spec-string of a `JS` called.
|
| - // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling
|
| - // the `ForeignResolver`.
|
| - // TODO(johnniwinther): Cache the result to avoid redundant lookups?
|
| - native.TypeLookup typeLookup({bool resolveAsRaw: true}) {
|
| - DartType lookup(String typeName, {bool required}) {
|
| - DartType findIn(Uri uri) {
|
| - LibraryEntity library = elementEnvironment.lookupLibrary(uri);
|
| - if (library != null) {
|
| - ClassEntity cls = elementEnvironment.lookupClass(library, typeName);
|
| - if (cls != null) {
|
| - // TODO(johnniwinther): Align semantics.
|
| - return resolveAsRaw
|
| - ? elementEnvironment.getRawType(cls)
|
| - : elementEnvironment.getThisType(cls);
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - // TODO(johnniwinther): Narrow the set of lookups base on the depending
|
| - // library.
|
| - DartType type = findIn(Uris.dart_core);
|
| - type ??= findIn(Uris.dart__js_helper);
|
| - type ??= findIn(Uris.dart__interceptors);
|
| - type ??= findIn(Uris.dart__isolate_helper);
|
| - type ??= findIn(Uris.dart__native_typed_data);
|
| - type ??= findIn(Uris.dart_collection);
|
| - type ??= findIn(Uris.dart_math);
|
| - type ??= findIn(Uris.dart_html);
|
| - type ??= findIn(Uris.dart_html_common);
|
| - type ??= findIn(Uris.dart_svg);
|
| - type ??= findIn(Uris.dart_web_audio);
|
| - type ??= findIn(Uris.dart_web_gl);
|
| - type ??= findIn(Uris.dart_web_sql);
|
| - type ??= findIn(Uris.dart_indexed_db);
|
| - type ??= findIn(Uris.dart_typed_data);
|
| - if (type == null && required) {
|
| - reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE,
|
| - MessageKind.GENERIC, {'text': "Type '$typeName' not found."});
|
| - }
|
| - return type;
|
| - }
|
| -
|
| - return lookup;
|
| - }
|
| -
|
| - String _getStringArgument(ir.StaticInvocation node, int index) {
|
| - return node.arguments.positional[index].accept(new Stringifier());
|
| - }
|
| -
|
| - /// Computes the [native.NativeBehavior] for a call to the [JS] function.
|
| - // TODO(johnniwinther): Cache this for later use.
|
| - native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
|
| - if (node.arguments.positional.length < 2 ||
|
| - node.arguments.named.isNotEmpty) {
|
| - reporter.reportErrorMessage(
|
| - CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS);
|
| - return new native.NativeBehavior();
|
| - }
|
| - String specString = _getStringArgument(node, 0);
|
| - if (specString == null) {
|
| - reporter.reportErrorMessage(
|
| - CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
|
| - return new native.NativeBehavior();
|
| - }
|
| -
|
| - String codeString = _getStringArgument(node, 1);
|
| - if (codeString == null) {
|
| - reporter.reportErrorMessage(
|
| - CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
|
| - return new native.NativeBehavior();
|
| - }
|
| -
|
| - return native.NativeBehavior.ofJsCall(
|
| - specString,
|
| - codeString,
|
| - typeLookup(resolveAsRaw: true),
|
| - CURRENT_ELEMENT_SPANNABLE,
|
| - reporter,
|
| - commonElements);
|
| - }
|
| -
|
| - /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
|
| - /// function.
|
| - // TODO(johnniwinther): Cache this for later use.
|
| - native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
|
| - ir.StaticInvocation node) {
|
| - if (node.arguments.positional.length < 1) {
|
| - reporter.internalError(
|
| - CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type.");
|
| - return new native.NativeBehavior();
|
| - }
|
| - if (node.arguments.positional.length < 2) {
|
| - reporter.internalError(
|
| - CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name.");
|
| - return new native.NativeBehavior();
|
| - }
|
| - String specString = _getStringArgument(node, 0);
|
| - if (specString == null) {
|
| - reporter.internalError(
|
| - CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
|
| - return new native.NativeBehavior();
|
| - }
|
| - return native.NativeBehavior.ofJsBuiltinCall(
|
| - specString,
|
| - typeLookup(resolveAsRaw: true),
|
| - CURRENT_ELEMENT_SPANNABLE,
|
| - reporter,
|
| - commonElements);
|
| - }
|
| -
|
| - /// Computes the [native.NativeBehavior] for a call to the
|
| - /// [JS_EMBEDDED_GLOBAL] function.
|
| - // TODO(johnniwinther): Cache this for later use.
|
| - native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
|
| - ir.StaticInvocation node) {
|
| - if (node.arguments.positional.length < 1) {
|
| - reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
|
| - "JS embedded global expression has no type.");
|
| - return new native.NativeBehavior();
|
| - }
|
| - if (node.arguments.positional.length < 2) {
|
| - reporter.internalError(
|
| - CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name.");
|
| - return new native.NativeBehavior();
|
| - }
|
| - if (node.arguments.positional.length > 2 ||
|
| - node.arguments.named.isNotEmpty) {
|
| - reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
|
| - "JS embedded global has more than 2 arguments.");
|
| - return new native.NativeBehavior();
|
| - }
|
| - String specString = _getStringArgument(node, 0);
|
| - if (specString == null) {
|
| - reporter.internalError(
|
| - CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
|
| - return new native.NativeBehavior();
|
| - }
|
| - return native.NativeBehavior.ofJsEmbeddedGlobalCall(
|
| - specString,
|
| - typeLookup(resolveAsRaw: true),
|
| - CURRENT_ELEMENT_SPANNABLE,
|
| - reporter,
|
| - commonElements);
|
| - }
|
| -
|
| - /// Computes the [InterfaceType] referenced by a call to the
|
| - /// [JS_INTERCEPTOR_CONSTANT] function, if any.
|
| - InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node) {
|
| - if (node.arguments.positional.length != 1 ||
|
| - node.arguments.named.isNotEmpty) {
|
| - reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE,
|
| - MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
|
| - }
|
| - ir.Node argument = node.arguments.positional.first;
|
| - if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) {
|
| - return getInterfaceType(argument.type);
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /// Computes the native behavior for reading the native [field].
|
| - // TODO(johnniwinther): Cache this for later use.
|
| - native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field,
|
| - {bool isJsInterop}) {
|
| - DartType type = getDartType(field.type);
|
| - List<ConstantValue> metadata = getMetadata(field.annotations);
|
| - return nativeBehaviorBuilder.buildFieldLoadBehavior(
|
| - type, metadata, typeLookup(resolveAsRaw: false),
|
| - isJsInterop: isJsInterop);
|
| - }
|
| -
|
| - /// Computes the native behavior for writing to the native [field].
|
| - // TODO(johnniwinther): Cache this for later use.
|
| - native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
|
| - DartType type = getDartType(field.type);
|
| - return nativeBehaviorBuilder.buildFieldStoreBehavior(type);
|
| - }
|
| -
|
| - /// Computes the native behavior for calling [procedure].
|
| - // TODO(johnniwinther): Cache this for later use.
|
| - native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure,
|
| - {bool isJsInterop}) {
|
| - DartType type = getFunctionType(procedure.function);
|
| - List<ConstantValue> metadata = getMetadata(procedure.annotations);
|
| - return nativeBehaviorBuilder.buildMethodBehavior(
|
| - type, metadata, typeLookup(resolveAsRaw: false),
|
| - isJsInterop: isJsInterop);
|
| - }
|
| -
|
| - @override
|
| - FunctionEntity getSuperNoSuchMethod(ClassEntity cls) {
|
| - while (cls != null) {
|
| - cls = elementEnvironment.getSuperClass(cls);
|
| - MemberEntity member =
|
| - elementEnvironment.lookupClassMember(cls, Identifiers.noSuchMethod_);
|
| - if (member != null) {
|
| - if (member.isFunction) {
|
| - FunctionEntity function = member;
|
| - if (function.parameterStructure.positionalParameters >= 1) {
|
| - return function;
|
| - }
|
| - }
|
| - // If [member] is not a valid `noSuchMethod` the target is
|
| - // `Object.superNoSuchMethod`.
|
| - break;
|
| - }
|
| - }
|
| - FunctionEntity function = elementEnvironment.lookupClassMember(
|
| - commonElements.objectClass, Identifiers.noSuchMethod_);
|
| - assert(function != null,
|
| - failedAt(cls, "No super noSuchMethod found for class $cls."));
|
| - return function;
|
| - }
|
| -
|
| - js.Name getNameForJsGetName(ConstantValue constant, Namer namer) {
|
| - int index = _extractEnumIndexFromConstantValue(
|
| - constant, commonElements.jsGetNameEnum);
|
| - if (index == null) return null;
|
| - return namer.getNameForJsGetName(
|
| - CURRENT_ELEMENT_SPANNABLE, JsGetName.values[index]);
|
| - }
|
| -
|
| - js.Template getJsBuiltinTemplate(
|
| - ConstantValue constant, CodeEmitterTask emitter) {
|
| - int index = _extractEnumIndexFromConstantValue(
|
| - constant, commonElements.jsBuiltinEnum);
|
| - if (index == null) return null;
|
| - return emitter.builtinTemplateFor(JsBuiltin.values[index]);
|
| - }
|
| -
|
| - int _extractEnumIndexFromConstantValue(
|
| - ConstantValue constant, ClassEntity classElement) {
|
| - if (constant is ConstructedConstantValue) {
|
| - if (constant.type.element == classElement) {
|
| - assert(constant.fields.length == 1 || constant.fields.length == 2);
|
| - ConstantValue indexConstant = constant.fields.values.first;
|
| - if (indexConstant is IntConstantValue) {
|
| - return indexConstant.primitiveValue;
|
| - }
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -}
|
| -
|
| -/// Visitor that converts string literals and concatenations of string literals
|
| -/// into the string value.
|
| -class Stringifier extends ir.ExpressionVisitor<String> {
|
| - @override
|
| - String visitStringLiteral(ir.StringLiteral node) => node.value;
|
| -
|
| - @override
|
| - String visitStringConcatenation(ir.StringConcatenation node) {
|
| - StringBuffer sb = new StringBuffer();
|
| - for (ir.Expression expression in node.expressions) {
|
| - String value = expression.accept(this);
|
| - if (value == null) return null;
|
| - sb.write(value);
|
| - }
|
| - return sb.toString();
|
| - }
|
| -}
|
| -
|
| -/// Visitor that converts a kernel constant expression into a
|
| -/// [ConstantExpression].
|
| -class Constantifier extends ir.ExpressionVisitor<ConstantExpression> {
|
| - final bool requireConstant;
|
| - final KernelToElementMapMixin elementAdapter;
|
| -
|
| - Constantifier(this.elementAdapter, {this.requireConstant: true});
|
| -
|
| - CommonElements get _commonElements => elementAdapter.commonElements;
|
| -
|
| - ConstantExpression visit(ir.Expression node) {
|
| - ConstantExpression constant = node.accept(this);
|
| - if (constant == null && requireConstant) {
|
| - throw new UnsupportedError(
|
| - "No constant computed for $node (${node.runtimeType})");
|
| - }
|
| - return constant;
|
| - }
|
| -
|
| - ConstantExpression defaultExpression(ir.Expression node) {
|
| - if (requireConstant) {
|
| - throw new UnimplementedError(
|
| - 'Unimplemented constant expression $node (${node.runtimeType})');
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - List<ConstantExpression> _computeList(List<ir.Expression> expressions) {
|
| - List<ConstantExpression> list = <ConstantExpression>[];
|
| - for (ir.Expression expression in expressions) {
|
| - ConstantExpression constant = visit(expression);
|
| - if (constant == null) return null;
|
| - list.add(constant);
|
| - }
|
| - return list;
|
| - }
|
| -
|
| - List<ConstantExpression> _computeArguments(ir.Arguments node) {
|
| - List<ConstantExpression> arguments = <ConstantExpression>[];
|
| - for (ir.Expression argument in node.positional) {
|
| - ConstantExpression constant = visit(argument);
|
| - if (constant == null) return null;
|
| - arguments.add(constant);
|
| - }
|
| - for (ir.NamedExpression argument in node.named) {
|
| - ConstantExpression constant = visit(argument.value);
|
| - if (constant == null) return null;
|
| - arguments.add(constant);
|
| - }
|
| - return arguments;
|
| - }
|
| -
|
| - ConstructedConstantExpression _computeConstructorInvocation(
|
| - ir.Constructor target, ir.Arguments arguments) {
|
| - List<ConstantExpression> expressions = _computeArguments(arguments);
|
| - if (expressions == null) return null;
|
| - return new ConstructedConstantExpression(
|
| - elementAdapter.createInterfaceType(
|
| - target.enclosingClass, arguments.types),
|
| - elementAdapter.getConstructor(target),
|
| - elementAdapter.getCallStructure(arguments),
|
| - expressions);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitConstructorInvocation(ir.ConstructorInvocation node) {
|
| - return _computeConstructorInvocation(node.target, node.arguments);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitVariableGet(ir.VariableGet node) {
|
| - if (node.variable.parent is ir.FunctionNode) {
|
| - ir.FunctionNode function = node.variable.parent;
|
| - int index = function.positionalParameters.indexOf(node.variable);
|
| - if (index != -1) {
|
| - return new PositionalArgumentReference(index);
|
| - } else {
|
| - assert(function.namedParameters.contains(node.variable));
|
| - return new NamedArgumentReference(node.variable.name);
|
| - }
|
| - } else if (node.variable.isConst) {
|
| - return visit(node.variable.initializer);
|
| - }
|
| - return defaultExpression(node);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitStaticGet(ir.StaticGet node) {
|
| - ir.Member target = node.target;
|
| - if (target is ir.Field && target.isConst) {
|
| - return new FieldConstantExpression(elementAdapter.getField(node.target));
|
| - } else if (node.target is ir.Procedure) {
|
| - FunctionEntity function = elementAdapter.getMethod(node.target);
|
| - DartType type = elementAdapter.getFunctionType(node.target.function);
|
| - return new FunctionConstantExpression(function, type);
|
| - }
|
| - return defaultExpression(node);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitNullLiteral(ir.NullLiteral node) {
|
| - return new NullConstantExpression();
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitBoolLiteral(ir.BoolLiteral node) {
|
| - return new BoolConstantExpression(node.value);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitIntLiteral(ir.IntLiteral node) {
|
| - return new IntConstantExpression(node.value);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitDoubleLiteral(ir.DoubleLiteral node) {
|
| - return new DoubleConstantExpression(node.value);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitStringLiteral(ir.StringLiteral node) {
|
| - return new StringConstantExpression(node.value);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitSymbolLiteral(ir.SymbolLiteral node) {
|
| - return new SymbolConstantExpression(node.value);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitStringConcatenation(ir.StringConcatenation node) {
|
| - List<ConstantExpression> expressions = _computeList(node.expressions);
|
| - if (expressions == null) return null;
|
| - return new ConcatenateConstantExpression(expressions);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitMapLiteral(ir.MapLiteral node) {
|
| - if (!node.isConst) {
|
| - return defaultExpression(node);
|
| - }
|
| - DartType keyType = elementAdapter.getDartType(node.keyType);
|
| - DartType valueType = elementAdapter.getDartType(node.valueType);
|
| - List<ConstantExpression> keys = <ConstantExpression>[];
|
| - List<ConstantExpression> values = <ConstantExpression>[];
|
| - for (ir.MapEntry entry in node.entries) {
|
| - ConstantExpression key = visit(entry.key);
|
| - if (key == null) return null;
|
| - keys.add(key);
|
| - ConstantExpression value = visit(entry.value);
|
| - if (value == null) return null;
|
| - values.add(value);
|
| - }
|
| - return new MapConstantExpression(
|
| - _commonElements.mapType(keyType, valueType), keys, values);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitListLiteral(ir.ListLiteral node) {
|
| - if (!node.isConst) {
|
| - return defaultExpression(node);
|
| - }
|
| - DartType elementType = elementAdapter.getDartType(node.typeArgument);
|
| - List<ConstantExpression> values = <ConstantExpression>[];
|
| - for (ir.Expression expression in node.expressions) {
|
| - ConstantExpression value = visit(expression);
|
| - if (value == null) return null;
|
| - values.add(value);
|
| - }
|
| - return new ListConstantExpression(
|
| - _commonElements.listType(elementType), values);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitTypeLiteral(ir.TypeLiteral node) {
|
| - DartType type = elementAdapter.getDartType(node.type);
|
| - String name;
|
| - if (type.isDynamic) {
|
| - name = 'dynamic';
|
| - } else if (type is InterfaceType) {
|
| - name = type.element.name;
|
| - } else if (type.isFunctionType || type.isTypedef) {
|
| - // TODO(johnniwinther): Compute a name for the type literal? It is only
|
| - // used in error messages in the old SSA builder.
|
| - name = '?';
|
| - } else {
|
| - return defaultExpression(node);
|
| - }
|
| - return new TypeConstantExpression(type, name);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitNot(ir.Not node) {
|
| - ConstantExpression expression = visit(node.operand);
|
| - if (expression == null) return null;
|
| - return new UnaryConstantExpression(UnaryOperator.NOT, expression);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitConditionalExpression(ir.ConditionalExpression node) {
|
| - ConstantExpression condition = visit(node.condition);
|
| - if (condition == null) return null;
|
| - ConstantExpression trueExp = visit(node.then);
|
| - if (trueExp == null) return null;
|
| - ConstantExpression falseExp = visit(node.otherwise);
|
| - if (falseExp == null) return null;
|
| - return new ConditionalConstantExpression(condition, trueExp, falseExp);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitPropertyGet(ir.PropertyGet node) {
|
| - if (node.name.name != 'length') {
|
| - throw new UnimplementedError(
|
| - 'Unexpected constant expression $node (${node.runtimeType})');
|
| - }
|
| - ConstantExpression receiver = visit(node.receiver);
|
| - if (receiver == null) return null;
|
| - return new StringLengthConstantExpression(receiver);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitMethodInvocation(ir.MethodInvocation node) {
|
| - // Method invocations are generally not constant expressions but unary
|
| - // and binary expressions are encoded as method invocations in kernel.
|
| - if (node.arguments.named.isNotEmpty) {
|
| - return defaultExpression(node);
|
| - }
|
| - if (node.arguments.positional.length == 0) {
|
| - UnaryOperator operator;
|
| - if (node.name.name == UnaryOperator.NEGATE.selectorName) {
|
| - operator = UnaryOperator.NEGATE;
|
| - } else {
|
| - operator = UnaryOperator.parse(node.name.name);
|
| - }
|
| - if (operator != null) {
|
| - ConstantExpression expression = visit(node.receiver);
|
| - if (expression == null) return null;
|
| - return new UnaryConstantExpression(operator, expression);
|
| - }
|
| - }
|
| - if (node.arguments.positional.length == 1) {
|
| - BinaryOperator operator = BinaryOperator.parse(node.name.name);
|
| - if (operator != null) {
|
| - ConstantExpression left = visit(node.receiver);
|
| - if (left == null) return null;
|
| - ConstantExpression right = visit(node.arguments.positional.single);
|
| - if (right == null) return null;
|
| - return new BinaryConstantExpression(left, operator, right);
|
| - }
|
| - }
|
| - return defaultExpression(node);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitStaticInvocation(ir.StaticInvocation node) {
|
| - MemberEntity member = elementAdapter.getMember(node.target);
|
| - if (member == _commonElements.identicalFunction) {
|
| - if (node.arguments.positional.length == 2 &&
|
| - node.arguments.named.isEmpty) {
|
| - ConstantExpression left = visit(node.arguments.positional[0]);
|
| - if (left == null) return null;
|
| - ConstantExpression right = visit(node.arguments.positional[1]);
|
| - if (right == null) return null;
|
| - return new IdenticalConstantExpression(left, right);
|
| - }
|
| - } else if (member.name == 'fromEnvironment' &&
|
| - node.arguments.positional.length == 1) {
|
| - ConstantExpression name = visit(node.arguments.positional.single);
|
| - if (name == null) return null;
|
| - ConstantExpression defaultValue;
|
| - if (node.arguments.named.length == 1) {
|
| - if (node.arguments.named.single.name != 'defaultValue') {
|
| - return defaultExpression(node);
|
| - }
|
| - defaultValue = visit(node.arguments.named.single.value);
|
| - if (defaultValue == null) return null;
|
| - }
|
| - if (member.enclosingClass == _commonElements.boolClass) {
|
| - return new BoolFromEnvironmentConstantExpression(name, defaultValue);
|
| - } else if (member.enclosingClass == _commonElements.intClass) {
|
| - return new IntFromEnvironmentConstantExpression(name, defaultValue);
|
| - } else if (member.enclosingClass == _commonElements.stringClass) {
|
| - return new StringFromEnvironmentConstantExpression(name, defaultValue);
|
| - }
|
| - }
|
| - return defaultExpression(node);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitLogicalExpression(ir.LogicalExpression node) {
|
| - BinaryOperator operator = BinaryOperator.parse(node.operator);
|
| - if (operator != null) {
|
| - ConstantExpression left = visit(node.left);
|
| - if (left == null) return null;
|
| - ConstantExpression right = visit(node.right);
|
| - if (right == null) return null;
|
| - return new BinaryConstantExpression(left, operator, right);
|
| - }
|
| - return defaultExpression(node);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression visitLet(ir.Let node) {
|
| - ir.Expression body = node.body;
|
| - if (body is ir.ConditionalExpression) {
|
| - ir.Expression condition = body.condition;
|
| - if (condition is ir.MethodInvocation) {
|
| - ir.Expression receiver = condition.receiver;
|
| - ir.Expression otherwise = body.otherwise;
|
| - if (condition.name.name == BinaryOperator.EQ.name &&
|
| - receiver is ir.VariableGet &&
|
| - condition.arguments.positional.single is ir.NullLiteral &&
|
| - otherwise is ir.VariableGet) {
|
| - if (receiver.variable == node.variable &&
|
| - otherwise.variable == node.variable) {
|
| - // We have <left> ?? <right> encoded as:
|
| - // let #1 = <left> in #1 == null ? <right> : #1
|
| - ConstantExpression left = visit(node.variable.initializer);
|
| - if (left == null) return null;
|
| - ConstantExpression right = visit(body.then);
|
| - if (right == null) return null;
|
| - // TODO(johnniwinther): Remove [IF_NULL] binary constant expression
|
| - // when the resolver is removed; then we no longer need the
|
| - // expressions to be structurally equivalence for equivalence
|
| - // testing.
|
| - return new BinaryConstantExpression(
|
| - left, BinaryOperator.IF_NULL, right);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - return defaultExpression(node);
|
| - }
|
| -
|
| - /// Compute the [ConstantConstructor] corresponding to the const constructor
|
| - /// [node].
|
| - ConstantConstructor computeConstantConstructor(ir.Constructor node) {
|
| - assert(node.isConst);
|
| - ir.Class cls = node.enclosingClass;
|
| - InterfaceType type = elementAdapter.elementEnvironment
|
| - .getThisType(elementAdapter.getClass(cls));
|
| -
|
| - Map<dynamic, ConstantExpression> defaultValues =
|
| - <dynamic, ConstantExpression>{};
|
| - int parameterIndex = 0;
|
| - for (ir.VariableDeclaration parameter
|
| - in node.function.positionalParameters) {
|
| - if (parameterIndex >= node.function.requiredParameterCount) {
|
| - ConstantExpression defaultValue;
|
| - if (parameter.initializer != null) {
|
| - defaultValue = parameter.initializer.accept(this);
|
| - } else {
|
| - defaultValue = new NullConstantExpression();
|
| - }
|
| - if (defaultValue == null) return null;
|
| - defaultValues[parameterIndex] = defaultValue;
|
| - }
|
| - parameterIndex++;
|
| - }
|
| - for (ir.VariableDeclaration parameter in node.function.namedParameters) {
|
| - ConstantExpression defaultValue = parameter.initializer.accept(this);
|
| - if (defaultValue == null) return null;
|
| - defaultValues[parameter.name] = defaultValue;
|
| - }
|
| -
|
| - bool isRedirecting = node.initializers.length == 1 &&
|
| - node.initializers.single is ir.RedirectingInitializer;
|
| -
|
| - Map<FieldEntity, ConstantExpression> fieldMap =
|
| - <FieldEntity, ConstantExpression>{};
|
| -
|
| - void registerField(ir.Field field, ConstantExpression constant) {
|
| - fieldMap[elementAdapter.getField(field)] = constant;
|
| - }
|
| -
|
| - if (!isRedirecting) {
|
| - for (ir.Field field in cls.fields) {
|
| - if (field.isStatic) continue;
|
| - if (field.initializer != null) {
|
| - registerField(field, field.initializer.accept(this));
|
| - }
|
| - }
|
| - }
|
| -
|
| - ConstructedConstantExpression superConstructorInvocation;
|
| - for (ir.Initializer initializer in node.initializers) {
|
| - if (initializer is ir.FieldInitializer) {
|
| - registerField(initializer.field, initializer.value.accept(this));
|
| - } else if (initializer is ir.SuperInitializer) {
|
| - superConstructorInvocation = _computeConstructorInvocation(
|
| - initializer.target, initializer.arguments);
|
| - } else if (initializer is ir.RedirectingInitializer) {
|
| - superConstructorInvocation = _computeConstructorInvocation(
|
| - initializer.target, initializer.arguments);
|
| - } else {
|
| - throw new UnsupportedError(
|
| - 'Unexpected initializer $node (${node.runtimeType})');
|
| - }
|
| - }
|
| - if (isRedirecting) {
|
| - return new RedirectingGenerativeConstantConstructor(
|
| - defaultValues, superConstructorInvocation);
|
| - } else {
|
| - return new GenerativeConstantConstructor(
|
| - type, defaultValues, fieldMap, superConstructorInvocation);
|
| - }
|
| - }
|
| -}
|
| -
|
| /// Interface for type inference results for kernel IR nodes.
|
| abstract class KernelToTypeInferenceMap {
|
| /// Returns the inferred return type of [function].
|
|
|