| Index: pkg/compiler/lib/src/cps_ir/type_mask_system.dart
|
| diff --git a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
|
| deleted file mode 100644
|
| index 773b96f5c75e4fb3f5ef10e1456501f0a5ffc962..0000000000000000000000000000000000000000
|
| --- a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
|
| +++ /dev/null
|
| @@ -1,616 +0,0 @@
|
| -// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
| -// 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.
|
| -
|
| -library dart2js.type_mask_system;
|
| -
|
| -import '../closure.dart' show ClosureFieldElement, BoxLocal, TypeVariableLocal;
|
| -import '../common/names.dart' show Identifiers;
|
| -import '../compiler.dart' as dart2js show Compiler;
|
| -import '../constants/values.dart';
|
| -import '../dart_types.dart' as types;
|
| -import '../elements/elements.dart';
|
| -import '../js_backend/backend_helpers.dart' show BackendHelpers;
|
| -import '../js_backend/js_backend.dart' show JavaScriptBackend;
|
| -import '../types/abstract_value_domain.dart';
|
| -import '../types/constants.dart' show computeTypeMask;
|
| -import '../types/types.dart';
|
| -import '../universe/selector.dart' show Selector;
|
| -import '../world.dart' show World;
|
| -
|
| -class TypeMaskSystem implements AbstractValueDomain {
|
| - final TypesTask inferrer;
|
| - final World classWorld;
|
| - final JavaScriptBackend backend;
|
| -
|
| - TypeMask _numStringBoolType;
|
| - TypeMask _fixedLengthType;
|
| - TypeMask _interceptorType;
|
| - TypeMask _interceptedTypes; // Does not include null.
|
| -
|
| - TypeMask __indexableTypeTest;
|
| -
|
| - // The full type of a constant (e.g. a ContainerTypeMask) is not available on
|
| - // the constant. Type inference flows the type to some place where it is used,
|
| - // e.g. a parameter. For constant values that are the value of static const
|
| - // fields we need to remember the association.
|
| - final Map<ConstantValue, TypeMask> _constantMasks =
|
| - <ConstantValue, TypeMask>{};
|
| -
|
| - @override
|
| - TypeMask get dynamicType => inferrer.dynamicType;
|
| -
|
| - @override
|
| - TypeMask get typeType => inferrer.typeType;
|
| -
|
| - @override
|
| - TypeMask get functionType => inferrer.functionType;
|
| -
|
| - @override
|
| - TypeMask get boolType => inferrer.boolType;
|
| -
|
| - @override
|
| - TypeMask get intType => inferrer.intType;
|
| -
|
| - @override
|
| - TypeMask get doubleType => inferrer.doubleType;
|
| -
|
| - @override
|
| - TypeMask get numType => inferrer.numType;
|
| -
|
| - @override
|
| - TypeMask get stringType => inferrer.stringType;
|
| -
|
| - @override
|
| - TypeMask get listType => inferrer.listType;
|
| -
|
| - @override
|
| - TypeMask get mapType => inferrer.mapType;
|
| -
|
| - @override
|
| - TypeMask get nonNullType => inferrer.nonNullType;
|
| -
|
| - @override
|
| - TypeMask get nullType => inferrer.nullType;
|
| -
|
| - @override
|
| - TypeMask get extendableArrayType => backend.extendableArrayType;
|
| -
|
| - @override
|
| - TypeMask get fixedArrayType => backend.fixedArrayType;
|
| -
|
| - @override
|
| - TypeMask get arrayType =>
|
| - new TypeMask.nonNullSubclass(helpers.jsArrayClass, classWorld);
|
| -
|
| - @override
|
| - TypeMask get uint31Type => inferrer.uint31Type;
|
| -
|
| - @override
|
| - TypeMask get uint32Type => inferrer.uint32Type;
|
| -
|
| - @override
|
| - TypeMask get uintType => inferrer.positiveIntType;
|
| -
|
| - @override
|
| - TypeMask get numStringBoolType {
|
| - if (_numStringBoolType == null) {
|
| - // Build the number+string+bool type. To make containment tests more
|
| - // inclusive, we use the num, String, bool types for this, not
|
| - // the JSNumber, JSString, JSBool subclasses.
|
| - TypeMask anyNum =
|
| - new TypeMask.nonNullSubtype(classWorld.numClass, classWorld);
|
| - TypeMask anyString =
|
| - new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld);
|
| - TypeMask anyBool =
|
| - new TypeMask.nonNullSubtype(classWorld.boolClass, classWorld);
|
| - _numStringBoolType = new TypeMask.unionOf(
|
| - <TypeMask>[anyNum, anyString, anyBool], classWorld);
|
| - }
|
| - return _numStringBoolType;
|
| - }
|
| -
|
| - @override
|
| - TypeMask get fixedLengthType {
|
| - if (_fixedLengthType == null) {
|
| - List<TypeMask> fixedLengthTypes = <TypeMask>[
|
| - stringType,
|
| - backend.fixedArrayType
|
| - ];
|
| - if (classWorld.isInstantiated(helpers.typedArrayClass)) {
|
| - fixedLengthTypes.add(nonNullSubclass(helpers.typedArrayClass));
|
| - }
|
| - _fixedLengthType = new TypeMask.unionOf(fixedLengthTypes, classWorld);
|
| - }
|
| - return _fixedLengthType;
|
| - }
|
| -
|
| - @override
|
| - TypeMask get interceptorType {
|
| - if (_interceptorType == null) {
|
| - _interceptorType =
|
| - new TypeMask.nonNullSubtype(helpers.jsInterceptorClass, classWorld);
|
| - }
|
| - return _interceptorType;
|
| - }
|
| -
|
| - @override
|
| - TypeMask get interceptedTypes {
|
| - // Does not include null.
|
| - if (_interceptedTypes == null) {
|
| - // We redundantly include subtypes of num/string/bool as intercepted
|
| - // types, because the type system does not infer that their
|
| - // implementations are all subclasses of Interceptor.
|
| - _interceptedTypes = new TypeMask.unionOf(
|
| - <TypeMask>[interceptorType, numStringBoolType], classWorld);
|
| - }
|
| - return _interceptedTypes;
|
| - }
|
| -
|
| - TypeMask get _indexableTypeTest {
|
| - if (__indexableTypeTest == null) {
|
| - // Make a TypeMask containing Indexable and (redundantly) subtypes of
|
| - // string because the type inference does not infer that all strings are
|
| - // indexables.
|
| - TypeMask indexable =
|
| - new TypeMask.nonNullSubtype(helpers.jsIndexableClass, classWorld);
|
| - TypeMask anyString =
|
| - new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld);
|
| - __indexableTypeTest =
|
| - new TypeMask.unionOf(<TypeMask>[indexable, anyString], classWorld);
|
| - }
|
| - return __indexableTypeTest;
|
| - }
|
| -
|
| - ClassElement get jsNullClass => helpers.jsNullClass;
|
| -
|
| - BackendHelpers get helpers => backend.helpers;
|
| -
|
| - // TODO(karlklose): remove compiler here.
|
| - TypeMaskSystem(dart2js.Compiler compiler)
|
| - : inferrer = compiler.typesTask,
|
| - classWorld = compiler.world,
|
| - backend = compiler.backend {}
|
| -
|
| - @override
|
| - bool methodIgnoresReceiverArgument(FunctionElement function) {
|
| - assert(backend.isInterceptedMethod(function));
|
| - ClassElement clazz = function.enclosingClass.declaration;
|
| - return !clazz.isSubclassOf(helpers.jsInterceptorClass) &&
|
| - !classWorld.isUsedAsMixin(clazz);
|
| - }
|
| -
|
| - @override
|
| - bool targetIgnoresReceiverArgument(TypeMask type, Selector selector) {
|
| - // Check if any of the possible targets depend on the extra receiver
|
| - // argument. Mixins do this, and tear-offs always needs the extra receiver
|
| - // argument because BoundClosure uses it for equality and hash code.
|
| - // TODO(15933): Make automatically generated property extraction
|
| - // closures work with the dummy receiver optimization.
|
| - bool needsReceiver(Element target) {
|
| - if (target is! FunctionElement) return false;
|
| - FunctionElement function = target;
|
| - return selector.isGetter && !function.isGetter ||
|
| - !methodIgnoresReceiverArgument(function);
|
| - }
|
| -
|
| - return !classWorld.allFunctions.filter(selector, type).any(needsReceiver);
|
| - }
|
| -
|
| - @override
|
| - Element locateSingleElement(TypeMask mask, Selector selector) {
|
| - return mask.locateSingleElement(selector, mask, classWorld.compiler);
|
| - }
|
| -
|
| - @override
|
| - ClassElement singleClass(TypeMask mask) {
|
| - return mask.singleClass(classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool needsNoSuchMethodHandling(TypeMask mask, Selector selector) {
|
| - return mask.needsNoSuchMethodHandling(selector, classWorld);
|
| - }
|
| -
|
| - @override
|
| - TypeMask getReceiverType(MethodElement method) {
|
| - assert(method.isInstanceMember);
|
| - if (classWorld.isUsedAsMixin(method.enclosingClass.declaration)) {
|
| - // If used as a mixin, the receiver could be any of the classes that mix
|
| - // in the class, and these are not considered subclasses.
|
| - // TODO(asgerf): Exclude the subtypes that only `implement` the class.
|
| - return nonNullSubtype(method.enclosingClass);
|
| - } else {
|
| - return nonNullSubclass(method.enclosingClass);
|
| - }
|
| - }
|
| -
|
| - @override
|
| - TypeMask getParameterType(ParameterElement parameter) {
|
| - return inferrer.getGuaranteedTypeOfElement(parameter);
|
| - }
|
| -
|
| - @override
|
| - TypeMask getReturnType(FunctionElement function) {
|
| - return inferrer.getGuaranteedReturnTypeOfElement(function);
|
| - }
|
| -
|
| - @override
|
| - TypeMask getInvokeReturnType(Selector selector, TypeMask mask) {
|
| - TypeMask result = inferrer.getGuaranteedTypeOfSelector(selector, mask);
|
| - // Tearing off .call from a function returns the function itself.
|
| - if (selector.isGetter &&
|
| - selector.name == Identifiers.call &&
|
| - !areDisjoint(functionType, mask)) {
|
| - result = join(result, functionType);
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - @override
|
| - TypeMask getFieldType(FieldElement field) {
|
| - if (field is ClosureFieldElement) {
|
| - // The type inference does not report types for all closure fields.
|
| - // Box fields are never null.
|
| - if (field.local is BoxLocal) return nonNullType;
|
| - // Closure fields for type variables contain the internal representation
|
| - // of the type (which can be null), not the Type object.
|
| - if (field.local is TypeVariableLocal) return dynamicType;
|
| - }
|
| - return inferrer.getGuaranteedTypeOfElement(field);
|
| - }
|
| -
|
| - @override
|
| - TypeMask join(TypeMask a, TypeMask b) {
|
| - return a.union(b, classWorld);
|
| - }
|
| -
|
| - @override
|
| - TypeMask intersection(TypeMask a, TypeMask b) {
|
| - if (a == null) return b;
|
| - if (b == null) return a;
|
| - return a.intersection(b, classWorld);
|
| - }
|
| -
|
| - void associateConstantValueWithElement(
|
| - ConstantValue constant, Element element) {
|
| - // TODO(25093): Replace this code with an approach that works for anonymous
|
| - // constants and non-constant literals.
|
| - if (constant is ListConstantValue || constant is MapConstantValue) {
|
| - // Inferred type is usually better (e.g. a ContainerTypeMask) but is
|
| - // occasionally less general.
|
| - TypeMask computed = computeTypeMask(inferrer.compiler, constant);
|
| - TypeMask inferred = inferrer.getGuaranteedTypeOfElement(element);
|
| - TypeMask best = intersection(inferred, computed);
|
| - assert(!best.isEmptyOrNull);
|
| - _constantMasks[constant] = best;
|
| - }
|
| - }
|
| -
|
| - @override
|
| - TypeMask getTypeOf(ConstantValue constant) {
|
| - return _constantMasks[constant] ??
|
| - computeTypeMask(inferrer.compiler, constant);
|
| - }
|
| -
|
| - @override
|
| - ConstantValue getConstantOf(TypeMask mask) {
|
| - if (!mask.isValue) return null;
|
| - if (mask.isNullable) return null; // e.g. 'true or null'.
|
| - ValueTypeMask valueMask = mask;
|
| - if (valueMask.value.isBool) return valueMask.value;
|
| - // TODO(sra): Consider other values. Be careful with large strings.
|
| - return null;
|
| - }
|
| -
|
| - @override
|
| - TypeMask nonNullExact(ClassElement element) {
|
| - // TODO(johnniwinther): I don't think the follow is valid anymore.
|
| - // The class world does not know about classes created by
|
| - // closure conversion, so just treat those as a subtypes of Function.
|
| - // TODO(asgerf): Maybe closure conversion should create a new ClassWorld?
|
| - if (element.isClosure) return functionType;
|
| - return new TypeMask.nonNullExact(element.declaration, classWorld);
|
| - }
|
| -
|
| - @override
|
| - TypeMask nonNullSubclass(ClassElement element) {
|
| - if (element.isClosure) return functionType;
|
| - return new TypeMask.nonNullSubclass(element.declaration, classWorld);
|
| - }
|
| -
|
| - @override
|
| - TypeMask nonNullSubtype(ClassElement element) {
|
| - if (element.isClosure) return functionType;
|
| - return new TypeMask.nonNullSubtype(element.declaration, classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyBool(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return t.nonNullable().containsOnlyBool(classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyNum(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return t.nonNullable().containsOnlyNum(classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyString(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return t.nonNullable().containsOnlyString(classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyNumStringBool(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return numStringBoolType.containsMask(t.nonNullable(), classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyNotNumStringBool(TypeMask t) {
|
| - return areDisjoint(t, numStringBoolType);
|
| - }
|
| -
|
| - /// True if all values of [t] are either integers or not numbers at all.
|
| - ///
|
| - /// This does not imply that the value is an integer, since most other values
|
| - /// such as null are also not a non-integer double.
|
| - @override
|
| - bool isDefinitelyNotNonIntegerDouble(TypeMask t) {
|
| - // Even though int is a subclass of double in the JS type system, we can
|
| - // still check this with disjointness, because [doubleType] is the *exact*
|
| - // double class, so this excludes things that are known to be instances of a
|
| - // more specific class.
|
| - // We currently exploit that there are no subclasses of double that are
|
| - // not integers (e.g. there is no UnsignedDouble class or whatever).
|
| - return areDisjoint(t, doubleType);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyNonNegativeInt(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - // The JSPositiveInt class includes zero, despite the name.
|
| - return t.satisfies(helpers.jsPositiveIntClass, classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyInt(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return t.nonNullable().containsOnlyInt(classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyUint31(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return t.satisfies(helpers.jsUInt31Class, classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyUint32(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return t.satisfies(helpers.jsUInt32Class, classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyUint(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return t.satisfies(helpers.jsPositiveIntClass, classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyArray(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return t.nonNullable().satisfies(helpers.jsArrayClass, classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyMutableArray(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return t.nonNullable().satisfies(helpers.jsMutableArrayClass, classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyFixedArray(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return t.nonNullable().satisfies(helpers.jsFixedArrayClass, classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyExtendableArray(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return t
|
| - .nonNullable()
|
| - .satisfies(helpers.jsExtendableArrayClass, classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyIndexable(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return _indexableTypeTest.containsMask(t.nonNullable(), classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyMutableIndexable(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return t
|
| - .nonNullable()
|
| - .satisfies(helpers.jsMutableIndexableClass, classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyFixedLengthIndexable(TypeMask t, {bool allowNull: false}) {
|
| - if (!allowNull && t.isNullable) return false;
|
| - return fixedLengthType.containsMask(t.nonNullable(), classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelyIntercepted(TypeMask t, {bool allowNull}) {
|
| - assert(allowNull != null);
|
| - if (!allowNull && t.isNullable) return false;
|
| - return interceptedTypes.containsMask(t.nonNullable(), classWorld);
|
| - }
|
| -
|
| - @override
|
| - bool isDefinitelySelfInterceptor(TypeMask t, {bool allowNull: false}) {
|
| - assert(allowNull != null);
|
| - if (!allowNull && t.isNullable) return false;
|
| - return areDisjoint(t, interceptorType);
|
| - }
|
| -
|
| - /// Given a class from the interceptor hierarchy, returns a [TypeMask]
|
| - /// matching all values with that interceptor (or a subtype thereof).
|
| - @override
|
| - TypeMask getInterceptorSubtypes(ClassElement class_) {
|
| - if (class_ == helpers.jsInterceptorClass) {
|
| - return interceptorType.nullable();
|
| - } else if (class_ == helpers.jsNullClass) {
|
| - return nullType;
|
| - } else {
|
| - return nonNullSubclass(class_);
|
| - }
|
| - }
|
| -
|
| - @override
|
| - bool areDisjoint(TypeMask leftType, TypeMask rightType) =>
|
| - leftType.isDisjoint(rightType, classWorld);
|
| -
|
| - @override
|
| - bool isMorePreciseOrEqual(TypeMask t1, TypeMask t2) {
|
| - return t2.containsMask(t1, classWorld);
|
| - }
|
| -
|
| - @override
|
| - AbstractBool isSubtypeOf(TypeMask value, types.DartType type,
|
| - {bool allowNull}) {
|
| - assert(allowNull != null);
|
| - if (type is types.DynamicType) {
|
| - return AbstractBool.True;
|
| - }
|
| - if (type is types.InterfaceType) {
|
| - TypeMask typeAsMask = allowNull
|
| - ? new TypeMask.subtype(type.element, classWorld)
|
| - : new TypeMask.nonNullSubtype(type.element, classWorld);
|
| - if (areDisjoint(value, typeAsMask)) {
|
| - // Disprove the subtype relation based on the class alone.
|
| - return AbstractBool.False;
|
| - }
|
| - if (!type.treatAsRaw) {
|
| - // If there are type arguments, we cannot prove the subtype relation,
|
| - // because the type arguments are unknown on both the value and type.
|
| - return AbstractBool.Maybe;
|
| - }
|
| - if (typeAsMask.containsMask(value, classWorld)) {
|
| - // All possible values are contained in the set of allowed values.
|
| - // Note that we exploit the fact that [typeAsMask] is an exact
|
| - // representation of [type], not an approximation.
|
| - return AbstractBool.True;
|
| - }
|
| - // The value is neither contained in the type, nor disjoint from the type.
|
| - return AbstractBool.Maybe;
|
| - }
|
| - // TODO(asgerf): Support function types, and what else might be missing.
|
| - return AbstractBool.Maybe;
|
| - }
|
| -
|
| - /// Returns whether [type] is one of the falsy values: false, 0, -0, NaN,
|
| - /// the empty string, or null.
|
| - @override
|
| - AbstractBool boolify(TypeMask type) {
|
| - if (isDefinitelyNotNumStringBool(type) && !type.isNullable) {
|
| - return AbstractBool.True;
|
| - }
|
| - return AbstractBool.Maybe;
|
| - }
|
| -
|
| - @override
|
| - AbstractBool strictBoolify(TypeMask type) {
|
| - if (areDisjoint(type, boolType)) return AbstractBool.False;
|
| - return AbstractBool.Maybe;
|
| - }
|
| -
|
| - /// Create a type mask containing at least all subtypes of [type].
|
| - @override
|
| - TypeMask subtypesOf(types.DartType type) {
|
| - if (type is types.InterfaceType) {
|
| - ClassElement element = type.element;
|
| - if (element.isObject) {
|
| - return dynamicType;
|
| - }
|
| - if (element == classWorld.nullClass) {
|
| - return nullType;
|
| - }
|
| - if (element == classWorld.stringClass) {
|
| - return stringType;
|
| - }
|
| - if (element == classWorld.numClass || element == classWorld.doubleClass) {
|
| - return numType;
|
| - }
|
| - if (element == classWorld.intClass) {
|
| - return intType;
|
| - }
|
| - if (element == classWorld.boolClass) {
|
| - return boolType;
|
| - }
|
| - return new TypeMask.nonNullSubtype(element, classWorld);
|
| - }
|
| - if (type is types.FunctionType) {
|
| - return functionType;
|
| - }
|
| - return dynamicType;
|
| - }
|
| -
|
| - /// Returns a subset of [mask] containing at least the types
|
| - /// that can respond to [selector] without throwing.
|
| - @override
|
| - TypeMask receiverTypeFor(Selector selector, TypeMask mask) {
|
| - return classWorld.allFunctions.receiverType(selector, mask);
|
| - }
|
| -
|
| - /// The result of an index operation on something of [type], or the dynamic
|
| - /// type if unknown.
|
| - @override
|
| - TypeMask elementTypeOfIndexable(TypeMask type) {
|
| - if (type is UnionTypeMask) {
|
| - return new TypeMask.unionOf(
|
| - type.disjointMasks.map(elementTypeOfIndexable), classWorld);
|
| - }
|
| - if (type is ContainerTypeMask) {
|
| - return type.elementType;
|
| - }
|
| - if (isDefinitelyString(type)) {
|
| - return stringType;
|
| - }
|
| - if (type.satisfies(helpers.jsIndexingBehaviorInterface, classWorld)) {
|
| - return getInvokeReturnType(new Selector.index(), type);
|
| - }
|
| - return dynamicType;
|
| - }
|
| -
|
| - /// The length of something of [type], or `null` if unknown.
|
| - @override
|
| - int getContainerLength(TypeMask type) {
|
| - if (type is ContainerTypeMask) {
|
| - return type.length;
|
| - } else {
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - /// Returns the type of the entry at a given index, `null` if unknown.
|
| - TypeMask indexWithConstant(TypeMask container, ConstantValue indexValue) {
|
| - if (container is DictionaryTypeMask) {
|
| - if (indexValue is StringConstantValue) {
|
| - String key = indexValue.primitiveValue.slowToString();
|
| - TypeMask result = container.typeMap[key];
|
| - if (result != null) return result;
|
| - }
|
| - }
|
| - if (container is ContainerTypeMask) {
|
| - return container.elementType;
|
| - }
|
| - return null;
|
| - }
|
| -}
|
|
|