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

Unified Diff: sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart
deleted file mode 100644
index 129f49c1bfc0cdd84542d05fa2f39677b810b73f..0000000000000000000000000000000000000000
--- a/sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart
+++ /dev/null
@@ -1,2381 +0,0 @@
-// Copyright (c) 2012, 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 concrete_types_inferrer;
-
-import 'dart:collection' show Queue, IterableBase;
-import '../native/native.dart' as native;
-import '../dart2jslib.dart' hide Selector, TypedSelector;
-import '../dart_types.dart' show DartType, TypeKind;
-import '../elements/elements.dart';
-import '../tree/tree.dart';
-import '../universe/universe.dart';
-import '../util/util.dart';
-
-import 'inferrer_visitor.dart';
-import '../types/types.dart' show TypeMask, FlatTypeMask, UnionTypeMask,
- TypesInferrer;
-import 'simple_types_inferrer.dart';
-
-/**
- * A singleton concrete type. More precisely, a [BaseType] is one of the
- * following:
- *
- * - a non-asbtract class like [:int:] or [:Uri:] (but not [:List:])
- * - the null base type
- * - the unknown base type
- */
-abstract class BaseType {
- bool isClass();
- bool isUnknown();
- bool isNull();
-}
-
-/**
- * A non-asbtract class like [:int:] or [:Uri:] (but not [:List:]).
- */
-class ClassBaseType implements BaseType {
- final ClassElement element;
-
- ClassBaseType(this.element);
-
- bool operator ==(var other) {
- if (identical(this, other)) return true;
- if (other is! ClassBaseType) return false;
- return element == other.element;
- }
- int get hashCode => element.hashCode;
- String toString() {
- return element == null ? 'toplevel' : element.name;
- }
- bool isClass() => true;
- bool isUnknown() => false;
- bool isNull() => false;
-}
-
-/**
- * The unknown base type.
- */
-class UnknownBaseType implements BaseType {
- const UnknownBaseType();
- bool operator ==(BaseType other) => other is UnknownBaseType;
- int get hashCode => 0;
- bool isClass() => false;
- bool isUnknown() => true;
- bool isNull() => false;
- toString() => "unknown";
-}
-
-/**
- * The null base type.
- */
-class NullBaseType implements BaseType {
- const NullBaseType();
- bool operator ==(BaseType other) => identical(other, this);
- int get hashCode => 1;
- bool isClass() => false;
- bool isUnknown() => false;
- bool isNull() => true;
- toString() => "null";
-}
-
-/**
- * An immutable set of base types like [:{int, bool}:], or the unknown concrete
- * type.
- */
-abstract class ConcreteType {
- ConcreteType();
-
- factory ConcreteType.empty(int maxConcreteTypeSize,
- BaseTypes classBaseTypes) {
- return new UnionType(maxConcreteTypeSize, classBaseTypes,
- new Set<BaseType>());
- }
-
- /**
- * The singleton constituted of the unknown base type is the unknown concrete
- * type.
- */
- factory ConcreteType.singleton(int maxConcreteTypeSize,
- BaseTypes classBaseTypes,
- BaseType baseType) {
- if (baseType.isUnknown() || maxConcreteTypeSize < 1) {
- return const UnknownConcreteType();
- }
- Set<BaseType> singletonSet = new Set<BaseType>();
- singletonSet.add(baseType);
- return new UnionType(maxConcreteTypeSize, classBaseTypes, singletonSet);
- }
-
- factory ConcreteType.unknown() {
- return const UnknownConcreteType();
- }
-
- ConcreteType union(ConcreteType other);
- ConcreteType intersection(ConcreteType other);
- ConcreteType refine(Selector selector, Compiler compiler);
- bool isUnknown();
- bool isEmpty();
- Set<BaseType> get baseTypes;
-
- /**
- * Returns the unique element of [:this:] if [:this:] is a singleton, null
- * otherwise.
- */
- ClassElement getUniqueType();
-}
-
-/**
- * The unkown concrete type: it is absorbing for the union.
- */
-class UnknownConcreteType implements ConcreteType {
- const UnknownConcreteType();
- bool isUnknown() => true;
- bool isEmpty() => false;
- bool operator ==(ConcreteType other) => identical(this, other);
- Set<BaseType> get baseTypes =>
- new Set<BaseType>.from([const UnknownBaseType()]);
- int get hashCode => 0;
- ConcreteType union(ConcreteType other) => this;
- ConcreteType intersection(ConcreteType other) => other;
- ConcreteType refine(Selector selector, Compiler compiler) => this;
- ClassElement getUniqueType() => null;
- toString() => "unknown";
-}
-
-/**
- * An immutable set of base types, like [: {int, bool} :].
- */
-class UnionType implements ConcreteType {
- final int maxConcreteTypeSize;
- final BaseTypes classBaseTypes;
-
- final Set<BaseType> baseTypes;
-
- /**
- * The argument should NOT be mutated later. Do not call directly, use
- * ConcreteType.singleton instead.
- */
- UnionType(this.maxConcreteTypeSize, this.classBaseTypes, this.baseTypes);
-
- bool isUnknown() => false;
- bool isEmpty() => baseTypes.isEmpty;
-
- bool operator ==(ConcreteType other) {
- if (other is! UnionType) return false;
- if (baseTypes.length != other.baseTypes.length) return false;
- return baseTypes.containsAll(other.baseTypes);
- }
-
- int get hashCode {
- int result = 1;
- for (final baseType in baseTypes) {
- result = 31 * result + baseType.hashCode;
- }
- return result;
- }
-
- ConcreteType _simplify(Set<BaseType> baseTypes) {
- // normalize all flavors of ints to int
- // TODO(polux): handle different ints better
- if (baseTypes.contains(classBaseTypes.uint31Type)) {
- baseTypes.remove(classBaseTypes.uint31Type);
- baseTypes.add(classBaseTypes.intBaseType);
- }
- if (baseTypes.contains(classBaseTypes.uint32Type)) {
- baseTypes.remove(classBaseTypes.uint32Type);
- baseTypes.add(classBaseTypes.intBaseType);
- }
- if (baseTypes.contains(classBaseTypes.positiveIntType)) {
- baseTypes.remove(classBaseTypes.positiveIntType);
- baseTypes.add(classBaseTypes.intBaseType);
- }
- // normalize {int, float}, {int, num} or {float, num} into num
- // TODO(polux): generalize this to all types when we extend the concept of
- // "concrete type" to other abstract classes than num
- if (baseTypes.contains(classBaseTypes.numBaseType) ||
- (baseTypes.contains(classBaseTypes.intBaseType)
- && baseTypes.contains(classBaseTypes.doubleBaseType))) {
- baseTypes.remove(classBaseTypes.intBaseType);
- baseTypes.remove(classBaseTypes.doubleBaseType);
- baseTypes.add(classBaseTypes.numBaseType);
- }
-
- // widen big types to dynamic
- return baseTypes.length > maxConcreteTypeSize
- ? const UnknownConcreteType()
- : new UnionType(maxConcreteTypeSize, classBaseTypes, baseTypes);
- }
-
- ConcreteType union(ConcreteType other) {
- if (other.isUnknown()) {
- return const UnknownConcreteType();
- }
- UnionType otherUnion = other; // cast
- Set<BaseType> newBaseTypes = new Set<BaseType>.from(baseTypes);
- newBaseTypes.addAll(otherUnion.baseTypes);
- return _simplify(newBaseTypes);
- }
-
- ConcreteType intersection(ConcreteType other) {
- if (other.isUnknown()) {
- return this;
- }
- Set<BaseType> thisBaseTypes = new Set<BaseType>.from(baseTypes);
- Set<BaseType> otherBaseTypes = new Set<BaseType>.from(other.baseTypes);
- return _simplify(thisBaseTypes.intersection(otherBaseTypes));
- }
-
- ConcreteType refine(Selector selector, Compiler compiler) {
- Set<BaseType> newBaseTypes = new Set<BaseType>();
- for (BaseType baseType in baseTypes) {
- if (baseType.isClass()) {
- ClassBaseType classBaseType = baseType;
- if (classBaseType.element.lookupSelector(selector) != null) {
- newBaseTypes.add(baseType);
- }
- } else {
- newBaseTypes.add(baseType);
- }
- }
- return _simplify(newBaseTypes);
- }
-
- ClassElement getUniqueType() {
- if (baseTypes.length == 1) {
- var iterator = baseTypes.iterator;
- iterator.moveNext();
- BaseType uniqueBaseType = iterator.current;
- if (uniqueBaseType.isClass()) {
- ClassBaseType uniqueClassType = uniqueBaseType;
- return uniqueClassType.element;
- }
- }
- return null;
- }
-
- String toString() => baseTypes.toString();
-}
-
-class ConcreteTypeSystem extends TypeSystem<ConcreteType> {
- final Compiler compiler;
- final ConcreteTypesInferrer inferrer;
- final BaseTypes baseTypes;
-
- final ConcreteType nullType;
- final ConcreteType _intType;
- final ConcreteType _uint31Type;
- final ConcreteType _uint32Type;
- final ConcreteType _positiveIntType;
- final ConcreteType _doubleType;
- final ConcreteType _numType;
- final ConcreteType _boolType;
- final ConcreteType _functionType;
- final ConcreteType _listType;
- final ConcreteType _constListType;
- final ConcreteType _fixedListType;
- final ConcreteType _growableListType;
- final ConcreteType _mapType;
- final ConcreteType _constMapType;
- final ConcreteType _stringType;
-
- final ConcreteType dynamicType;
- final ConcreteType typeType;
- final ConcreteType nonNullEmptyType;
-
- ConcreteTypeSystem.internal(ConcreteTypesInferrer inferrer,
- BaseTypes baseTypes,
- ConcreteType singleton(BaseType baseType))
- : this.compiler = inferrer.compiler
- , this.inferrer = inferrer
- , this.baseTypes = baseTypes
- , this._constListType = singleton(baseTypes.constMapBaseType)
- , this._constMapType = singleton(baseTypes.constMapBaseType)
- , this._doubleType = singleton(baseTypes.doubleBaseType)
- , this._fixedListType = singleton(baseTypes.fixedListBaseType)
- , this._functionType = singleton(baseTypes.functionBaseType)
- , this._growableListType = singleton(baseTypes.growableListBaseType)
- , this._intType = singleton(baseTypes.intBaseType)
- , this._listType = singleton(baseTypes.listBaseType)
- , this._mapType = singleton(baseTypes.mapBaseType)
- , this._numType = singleton(baseTypes.numBaseType)
- , this._boolType = singleton(baseTypes.boolBaseType)
- , this._stringType = singleton(baseTypes.stringBaseType)
- , this.typeType = singleton(baseTypes.typeBaseType)
- , this.dynamicType = const UnknownConcreteType()
- , this.nullType = singleton(const NullBaseType())
- , this.nonNullEmptyType = new ConcreteType.empty(
- inferrer.compiler.maxConcreteTypeSize, baseTypes)
- // TODO(polux): have better types here
- , this._uint31Type = singleton(baseTypes.intBaseType)
- , this._uint32Type = singleton(baseTypes.intBaseType)
- , this._positiveIntType = singleton(baseTypes.intBaseType);
-
- factory ConcreteTypeSystem(ConcreteTypesInferrer inferrer) {
- Compiler compiler = inferrer.compiler;
- BaseTypes baseTypes = new BaseTypes(compiler);
- return new ConcreteTypeSystem.internal(
- inferrer,
- baseTypes,
- (BaseType baseType) => new ConcreteType.singleton(
- compiler.maxConcreteTypeSize, baseTypes, baseType));
- }
-
- @override
- ConcreteType get intType {
- inferrer.augmentSeenClasses(compiler.backend.intImplementation);
- return _intType;
- }
-
- @override
- ConcreteType get uint31Type {
- inferrer.augmentSeenClasses(compiler.backend.uint31Implementation);
- return _uint31Type;
- }
-
- @override
- ConcreteType get uint32Type {
- inferrer.augmentSeenClasses(compiler.backend.uint32Implementation);
- return _uint32Type;
- }
-
- @override
- ConcreteType get positiveIntType {
- inferrer.augmentSeenClasses(compiler.backend.positiveIntImplementation);
- return _positiveIntType;
- }
-
- @override
- ConcreteType get doubleType {
- inferrer.augmentSeenClasses(compiler.backend.doubleImplementation);
- return _doubleType;
- }
-
- @override
- ConcreteType get numType {
- inferrer.augmentSeenClasses(compiler.backend.numImplementation);
- return _numType;
- }
-
- @override
- ConcreteType get boolType {
- inferrer.augmentSeenClasses(compiler.backend.boolImplementation);
- return _boolType;
- }
-
- @override
- ConcreteType get functionType {
- inferrer.augmentSeenClasses(compiler.backend.functionImplementation);
- return _functionType;
- }
-
- @override
- ConcreteType get listType {
- inferrer.augmentSeenClasses(compiler.backend.listImplementation);
- return _listType;
- }
-
- @override
- ConcreteType get constListType {
- inferrer.augmentSeenClasses(compiler.backend.constListImplementation);
- return _constListType;
- }
-
- @override
- ConcreteType get fixedListType {
- inferrer.augmentSeenClasses(compiler.backend.fixedListImplementation);
- return _fixedListType;
- }
-
- @override
- ConcreteType get growableListType {
- inferrer.augmentSeenClasses(compiler.backend.growableListImplementation);
- return _growableListType;
- }
-
- @override
- ConcreteType get mapType {
- inferrer.augmentSeenClasses(compiler.backend.mapImplementation);
- return _mapType;
- }
-
- @override
- ConcreteType get constMapType {
- inferrer.augmentSeenClasses(compiler.backend.constMapImplementation);
- return _constMapType;
- }
-
- @override
- ConcreteType get stringType {
- inferrer.augmentSeenClasses(compiler.backend.stringImplementation);
- return _stringType;
- }
-
- @override
- ConcreteType stringLiteralType(_) {
- inferrer.augmentSeenClasses(compiler.backend.stringImplementation);
- return _stringType;
- }
-
- /**
- * Returns the [TypeMask] representation of [baseType].
- */
- TypeMask baseTypeToTypeMask(BaseType baseType) {
- if (baseType.isUnknown()) {
- return const DynamicTypeMask();
- } else if (baseType.isNull()) {
- return new TypeMask.empty();
- } else {
- ClassBaseType classBaseType = baseType;
- final element = classBaseType.element;
- assert(element != null);
- if (element == compiler.backend.numImplementation) {
- return new TypeMask.nonNullSubclass(compiler.backend.numImplementation,
- compiler.world);
- } else if (element == compiler.backend.intImplementation) {
- return new TypeMask.nonNullSubclass(compiler.backend.intImplementation,
- compiler.world);
- } else {
- return new TypeMask.nonNullExact(element.declaration, compiler.world);
- }
- }
- }
-
- /**
- * Returns the [TypeMask] representation of [concreteType].
- */
- TypeMask concreteTypeToTypeMask(ConcreteType concreteType) {
- if (concreteType == null) return null;
- TypeMask typeMask = new TypeMask.nonNullEmpty();
- for (BaseType baseType in concreteType.baseTypes) {
- TypeMask baseMask = baseTypeToTypeMask(baseType);
- if (baseMask == const DynamicTypeMask()) return baseMask;
- typeMask = typeMask.union(baseMask, compiler.world);
- }
- return typeMask;
- }
-
- @override
- ConcreteType addPhiInput(Local variable,
- ConcreteType phiType,
- ConcreteType newType) {
- return computeLUB(phiType, newType);
- }
-
- @override
- ConcreteType allocateDiamondPhi(ConcreteType firstInput,
- ConcreteType secondInput) {
- return computeLUB(firstInput, secondInput);
- }
-
- @override
- ConcreteType allocatePhi(Node node, Local variable, ConcreteType inputType) {
- return inputType;
- }
-
- @override
- ConcreteType allocateLoopPhi(Node node, Local variable,
- ConcreteType inputType) {
- return inputType;
- }
-
- @override
- ConcreteType computeLUB(ConcreteType firstType, ConcreteType secondType) {
- if (firstType == null) {
- return secondType;
- } else if (secondType == null) {
- return firstType;
- } else {
- return firstType.union(secondType);
- }
- }
-
- // Implementation Inspired by
- // type_graph_inferrer.TypeInformationSystem.narrowType
- @override
- ConcreteType narrowType(ConcreteType type,
- DartType annotation,
- {bool isNullable: true}) {
- if (annotation.treatAsDynamic) return type;
- if (annotation.isVoid) return nullType;
- if (annotation.element == compiler.objectClass) return type;
- ConcreteType otherType;
- if (annotation.isTypedef || annotation.isFunctionType) {
- otherType = functionType;
- } else if (annotation.isTypeVariable) {
- // TODO(polux): Narrow to bound.
- return type;
- } else {
- assert(annotation.isInterfaceType);
- otherType = nonNullSubtype(annotation.element);
- }
- if (isNullable) otherType = otherType.union(nullType);
- if (type == null) return otherType;
- return type.intersection(otherType);
- }
-
- @override
- Selector newTypedSelector(ConcreteType receiver, Selector selector) {
- return new TypedSelector(concreteTypeToTypeMask(receiver), selector,
- compiler.world);
- }
-
- @override
- ConcreteType nonNullEmpty() {
- return nonNullEmptyType;
- }
-
- @override
- ConcreteType nonNullExact(ClassElement cls) {
- return nonNullSubtype(cls);
- }
-
- /**
- * Helper method for [nonNullSubtype] and [nonNullSubclass].
- */
- ConcreteType nonNullSubX(ClassElement cls,
- Iterable<ClassElement> extractor(ClassElement cls)) {
- if (cls == compiler.objectClass) {
- return dynamicType;
- }
- ConcreteType result = nonNullEmptyType;
- void registerClass(ClassElement element) {
- if (!element.isAbstract) {
- result = result.union(
- new ConcreteType.singleton(compiler.maxConcreteTypeSize,
- baseTypes,
- new ClassBaseType(element)));
- inferrer.augmentSeenClasses(element);
- }
- }
- registerClass(cls);
- Iterable<ClassElement> subtypes = extractor(cls);
- subtypes.forEach(registerClass);
- return result;
- }
-
- @override
- ConcreteType nonNullSubclass(ClassElement cls) {
- return nonNullSubX(cls, compiler.world.subclassesOf);
- }
-
- @override
- ConcreteType nonNullSubtype(ClassElement cls) {
- return nonNullSubX(cls, compiler.world.subtypesOf);
- }
-
- @override
- ConcreteType simplifyPhi(Node node,
- Local variable,
- ConcreteType phiType) {
- return phiType;
- }
-
- @override
- bool selectorNeedsUpdate(ConcreteType type, Selector selector) {
- return concreteTypeToTypeMask(type) != selector.mask;
- }
-
- @override
- ConcreteType refineReceiver(Selector selector, ConcreteType receiverType) {
- return receiverType.refine(selector, compiler);
- }
-
- @override
- bool isNull(ConcreteType type) {
- return (type.baseTypes.length == 1) && (type.baseTypes.first.isNull());
- }
-
- @override
- ConcreteType allocateClosure(Node node, Element element) {
- // TODO(polux): register closure here instead of in visitor?
- return functionType;
- }
-
- @override
- ConcreteType allocateList(ConcreteType type,
- Node node,
- Element enclosing,
- [ConcreteType elementType, int length]) {
- if (elementType != null) {
- inferrer.augmentListElementType(elementType);
- }
- return type;
- }
-
- @override
- ConcreteType allocateMap(ConcreteType type,
- Node node,
- Element element,
- [List<ConcreteType> keyTypes,
- List<ConcreteType> valueTypes]) {
- // TODO(polux): treat maps the same way we treat lists
- return type;
- }
-
- @override
- ConcreteType getConcreteTypeFor(TypeMask mask) {
- if (mask.isUnion) {
- UnionTypeMask union = mask;
- return union.disjointMasks.fold(
- nonNullEmptyType,
- (type1, type2) => type1.union(getConcreteTypeFor(type2)));
- } else {
- FlatTypeMask flat = mask;
- ConcreteType result;
- if (flat.isEmpty) {
- result = nonNullEmptyType;
- } else if (flat.isExact) {
- result = nonNullExact(flat.base);
- } else if (flat.isSubclass) {
- result = nonNullSubclass(flat.base);
- } else if (flat.isSubtype) {
- result = nonNullSubtype(flat.base);
- } else {
- throw new ArgumentError("unexpected mask");
- }
- return flat.isNullable ? result.union(nullType) : result;
- }
- }
-}
-
-/**
- * The cartesian product of concrete types: an iterable of
- * [ConcreteTypesEnvironment]s.
- */
-class ConcreteTypeCartesianProduct
- extends IterableBase<ConcreteTypesEnvironment> {
- final ConcreteTypesInferrer inferrer;
- final ClassElement typeOfThis;
- final Map<Element, ConcreteType> concreteTypes;
- ConcreteTypeCartesianProduct(this.inferrer, this.typeOfThis,
- this.concreteTypes);
- Iterator get iterator => concreteTypes.isEmpty
- ? [new ConcreteTypesEnvironment(typeOfThis)].iterator
- : new ConcreteTypeCartesianProductIterator(inferrer, typeOfThis,
- concreteTypes);
- String toString() => this.toList().toString();
-}
-
-/**
- * An helper class for [ConcreteTypeCartesianProduct].
- */
-class ConcreteTypeCartesianProductIterator
- implements Iterator<ConcreteTypesEnvironment> {
- final ConcreteTypesInferrer inferrer;
- final ClassElement classOfThis;
- final Map<Element, ConcreteType> concreteTypes;
- final Map<Element, BaseType> nextValues;
- final Map<Element, Iterator> state;
- int size = 1;
- int counter = 0;
- ConcreteTypesEnvironment _current;
-
- ConcreteTypeCartesianProductIterator(this.inferrer, this.classOfThis,
- Map<Element, ConcreteType> concreteTypes)
- : this.concreteTypes = concreteTypes,
- nextValues = new Map<Element, BaseType>(),
- state = new Map<Element, Iterator>() {
- if (concreteTypes.isEmpty) {
- size = 0;
- return;
- }
- for (final e in concreteTypes.keys) {
- final baseTypes = concreteTypes[e].baseTypes;
- size *= baseTypes.length;
- }
- }
-
- ConcreteTypesEnvironment get current => _current;
-
- ConcreteTypesEnvironment takeSnapshot() {
- Map<Element, ConcreteType> result = new Map<Element, ConcreteType>();
- nextValues.forEach((k, v) {
- result[k] = inferrer.singletonConcreteType(v);
- });
- return new ConcreteTypesEnvironment.of(result, classOfThis);
- }
-
- bool moveNext() {
- if (counter >= size) {
- _current = null;
- return false;
- }
- Element keyToIncrement = null;
- for (final key in concreteTypes.keys) {
- final iterator = state[key];
- if (iterator != null && iterator.moveNext()) {
- nextValues[key] = state[key].current;
- break;
- }
- Iterator newIterator = concreteTypes[key].baseTypes.iterator;
- state[key] = newIterator;
- newIterator.moveNext();
- nextValues[key] = newIterator.current;
- }
- counter++;
- _current = takeSnapshot();
- return true;
- }
-}
-
-/**
- * [BaseType] Constants.
- */
-class BaseTypes {
- final ClassBaseType intBaseType;
- final ClassBaseType doubleBaseType;
- final ClassBaseType numBaseType;
- final ClassBaseType boolBaseType;
- final ClassBaseType stringBaseType;
- final ClassBaseType listBaseType;
- final ClassBaseType growableListBaseType;
- final ClassBaseType fixedListBaseType;
- final ClassBaseType constListBaseType;
- final ClassBaseType mapBaseType;
- final ClassBaseType constMapBaseType;
- final ClassBaseType objectBaseType;
- final ClassBaseType typeBaseType;
- final ClassBaseType functionBaseType;
- final ClassBaseType uint31Type;
- final ClassBaseType uint32Type;
- final ClassBaseType positiveIntType;
-
- BaseTypes(Compiler compiler) :
- intBaseType = new ClassBaseType(compiler.backend.intImplementation),
- doubleBaseType = new ClassBaseType(compiler.backend.doubleImplementation),
- numBaseType = new ClassBaseType(compiler.backend.numImplementation),
- boolBaseType = new ClassBaseType(compiler.backend.boolImplementation),
- stringBaseType = new ClassBaseType(compiler.backend.stringImplementation),
- listBaseType = new ClassBaseType(compiler.backend.listImplementation),
- growableListBaseType =
- new ClassBaseType(compiler.backend.growableListImplementation),
- fixedListBaseType =
- new ClassBaseType(compiler.backend.fixedListImplementation),
- constListBaseType =
- new ClassBaseType(compiler.backend.constListImplementation),
- mapBaseType = new ClassBaseType(compiler.backend.mapImplementation),
- constMapBaseType =
- new ClassBaseType(compiler.backend.constMapImplementation),
- objectBaseType = new ClassBaseType(compiler.objectClass),
- typeBaseType = new ClassBaseType(compiler.backend.typeImplementation),
- functionBaseType =
- new ClassBaseType(compiler.backend.functionImplementation),
- uint31Type = new ClassBaseType(compiler.backend.uint31Implementation),
- uint32Type = new ClassBaseType(compiler.backend.uint32Implementation),
- positiveIntType =
- new ClassBaseType(compiler.backend.positiveIntImplementation);
-}
-
-/**
- * An immutable mapping from method arguments to [ConcreteTypes].
- */
-class ConcreteTypesEnvironment {
- final Map<Element, ConcreteType> environment;
- final ClassElement classOfThis;
-
- ConcreteTypesEnvironment([this.classOfThis]) :
- environment = new Map<Element, ConcreteType>();
- ConcreteTypesEnvironment.of(this.environment, this.classOfThis);
-
- ConcreteType lookupType(Element element) => environment[element];
-
- bool operator ==(ConcreteTypesEnvironment other) {
- if (other is! ConcreteTypesEnvironment) return false;
- if (classOfThis != other.classOfThis) return false;
- if (environment.length != other.environment.length) return false;
- for (Element key in environment.keys) {
- if (!other.environment.containsKey(key)
- || (environment[key] != other.environment[key])) {
- return false;
- }
- }
- return true;
- }
-
- int get hashCode {
- int result = (classOfThis != null) ? classOfThis.hashCode : 1;
- environment.forEach((element, concreteType) {
- result = 31 * (31 * result + element.hashCode) + concreteType.hashCode;
- });
- return result;
- }
-
- String toString() => "{ this: $classOfThis, env: $environment }";
-}
-
-class ClosureEnvironment {
- ConcreteType thisType;
- final LocalsHandler locals;
-
- ClosureEnvironment(this.thisType, this.locals);
-
- bool mergeLocals(LocalsHandler newLocals) {
- assert((locals == null) == (newLocals == null));
- return (locals != null) ? locals.mergeAll([newLocals]) : false;
- }
-
- /// Returns true if changed.
- bool merge(ConcreteType thisType, LocalsHandler locals) {
- ConcreteType oldThisType = this.thisType;
- if (this.thisType == null) {
- this.thisType = thisType;
- } else if (thisType != null) {
- this.thisType = this.thisType.union(thisType);
- }
- return mergeLocals(locals) || (this.thisType != oldThisType);
- }
-
- toString() => "ClosureEnvironment { thisType = $thisType, locals = ... }";
-}
-
-/**
- * A set of encoutered closures.
- */
-class Closures {
- final Compiler compiler;
- final Map<FunctionElement, ClosureEnvironment> closures =
- new Map<FunctionElement, ClosureEnvironment>();
-
- Closures(this.compiler);
-
- /// Returns true if the environment of the closure has changed.
- bool put(FunctionElement closure,
- ConcreteType typeOfThis,
- LocalsHandler locals) {
- ClosureEnvironment oldEnvironent = closures[closure];
- if (oldEnvironent == null) {
- closures[closure] = new ClosureEnvironment(typeOfThis, locals);
- return true;
- } else {
- return oldEnvironent.merge(typeOfThis, locals);
- }
- }
-
- ClosureEnvironment getEnvironmentOrNull(FunctionElement function) {
- return closures[function];
- }
-
- Iterable<FunctionElement> get functionElements => closures.keys;
-
- bool contains(FunctionElement function) => closures.containsKey(function);
-
- String toString() => closures.toString();
-}
-
-/**
- * A work item for the type inference queue.
- */
-class InferenceWorkItem {
- Element method;
- ConcreteTypesEnvironment environment;
- InferenceWorkItem(this.method, this.environment);
-
- toString() => "{ method = $method, environment = $environment }";
-
- bool operator ==(other) {
- return (other is InferenceWorkItem)
- && method == other.method
- && environment == other.environment;
- }
-
- int get hashCode => 31 * method.hashCode + environment.hashCode;
-}
-
-/**
- * A sentinel type mask class representing the dynamicType. It is absorbing
- * for [:ConcreteTypesEnvironment.typeMaskUnion:].
- */
-class DynamicTypeMask implements TypeMask {
- const DynamicTypeMask();
-
- String toString() => 'sentinel type mask';
-
- TypeMask nullable() {
- throw new UnsupportedError("");
- }
-
- TypeMask nonNullable() {
- throw new UnsupportedError("");
- }
-
- bool get isEmpty {
- throw new UnsupportedError("");
- }
-
- bool get isNullable {
- throw new UnsupportedError("");
- }
-
- bool get isExact {
- throw new UnsupportedError("");
- }
-
- bool get isUnion {
- throw new UnsupportedError("");
- }
-
- bool get isContainer {
- throw new UnsupportedError("");
- }
-
- bool get isMap {
- throw new UnsupportedError("");
- }
-
- bool get isDictionary {
- throw new UnsupportedError("");
- }
-
- bool get isForwarding {
- throw new UnsupportedError("");
- }
-
- bool get isValue {
- throw new UnsupportedError("");
- }
-
- bool containsOnlyInt(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsOnlyDouble(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsOnlyNum(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsOnlyBool(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsOnlyString(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsOnly(ClassElement element) {
- throw new UnsupportedError("");
- }
-
- bool satisfies(ClassElement cls, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool contains(ClassElement type, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsAll(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- ClassElement singleClass(ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- TypeMask union(TypeMask other, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- TypeMask intersection(TypeMask other, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool canHit(Element element, Selector selector, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- Element locateSingleElement(Selector selector, Compiler compiler) {
- throw new UnsupportedError("");
- }
-
- bool needsNoSuchMethodHandling(Selector selector, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool isInMask(TypeMask other, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-
- bool containsMask(TypeMask other, ClassWorld classWorld) {
- throw new UnsupportedError("");
- }
-}
-
-class WorkQueue {
- final Queue<InferenceWorkItem> queue = new Queue<InferenceWorkItem>();
-
- void add(InferenceWorkItem workItem) {
- if (!queue.contains(workItem)) {
- queue.addLast(workItem);
- }
- }
-
- InferenceWorkItem remove() {
- return queue.removeFirst();
- }
-
- bool get isEmpty => queue.isEmpty;
-}
-
-/**
- * A task which conservatively infers a [ConcreteType] for each sub expression
- * of the program. The entry point is [analyzeMain].
- */
-class ConcreteTypesInferrer
- extends InferrerEngine<ConcreteType, ConcreteTypeSystem>
- implements TypesInferrer {
-
- final String name = "Type inferrer";
-
- /**
- * When true, the string literal [:"__dynamic_for_test":] is inferred to
- * have the unknown type.
- */
- // TODO(polux): get rid of this hack once we have a natural way of inferring
- // the unknown type.
- bool testMode = false;
-
- // --- constants ---
-
- /**
- * Constants representing builtin base types. Initialized by [initialize]
- * and not by the constructor because the compiler elements are not yet
- * populated.
- */
- BaseTypes baseTypes;
-
- /** The associated type system */
- ConcreteTypeSystem types;
-
- /**
- * Constant representing [:ConcreteList#[]:] where [:ConcreteList:] is the
- * concrete implementation of lists for the selected backend.
- */
- FunctionElement listIndex;
-
- /**
- * Constant representing [:ConcreteList#[]=:] where [:ConcreteList:] is the
- * concrete implementation of lists for the selected backend.
- */
- FunctionElement listIndexSet;
-
- /**
- * Constant representing [:ConcreteList#add:] where [:ConcreteList:] is the
- * concrete implementation of lists for the selected backend.
- */
- FunctionElement listAdd;
-
- /**
- * Constant representing [:ConcreteList#removeAt:] where [:ConcreteList:] is
- * the concrete implementation of lists for the selected backend.
- */
- FunctionElement listRemoveAt;
-
- /**
- * Constant representing [:ConcreteList#insert:] where [:ConcreteList:] is
- * the concrete implementation of lists for the selected backend.
- */
- FunctionElement listInsert;
-
- /**
- * Constant representing [:ConcreteList#removeLast:] where [:ConcreteList:] is
- * the concrete implementation of lists for the selected backend.
- */
- FunctionElement listRemoveLast;
-
- /** Constant representing [:List():]. */
- FunctionElement listConstructor;
-
- /** The unknown concrete type */
- final ConcreteType unknownConcreteType;
-
- /** The empty concrete type */
- ConcreteType emptyConcreteType;
-
- /** The null concrete type */
- ConcreteType nullConcreteType;
-
- // --- state updated by the inference ---
-
- /**
- * A map from (function x argument base types) to their inferred concrete
- * type. Another way of seeing [methodToTemplates] is as a map from
- * [FunctionElement]s to "templates" in the sense of "The Cartesian Product
- * Algorithm - Simple and Precise Type Inference of Parametric Polymorphism"
- * by Ole Agesen.
- */
- // TODO(polux): build a better abstraction, like Closures
- final Map<FunctionElement, Map<ConcreteTypesEnvironment, ConcreteType>>
- methodToTemplates;
-
- /** The set of encountered closures. */
- final Closures closures;
-
- /** A map from expressions to their inferred concrete types. */
- final Map<Node, ConcreteType> inferredTypes;
-
- /** A map from fields to their inferred concrete types. */
- final Map<Element, ConcreteType> inferredFieldTypes;
-
- /**
- * [:callers[f]:] is the list of [:f:]'s possible callers or fields
- * whose initialization is a call to [:f:].
- */
- final Map<FunctionElement, Set<Element>> callers;
-
- /**
- * [:readers[field]:] is the list of [:field:]'s possible readers or fields
- * whose initialization is a read of [:field:].
- */
- final Map<Element, Set<Element>> fieldReaders;
-
- /**
- * [:readers[local]:] is the list of [:local:]'s possible readers.
- */
- final Map<Local, Set<FunctionElement>> capturedLocalsReaders;
-
- /// The set of classes encountered so far.
- final Set<ClassElement> seenClasses;
-
- /**
- * A map from selector names to callers of methods with this name on objects
- * of unknown inferred type.
- */
- final Map<String, Set<FunctionElement>> dynamicCallers;
-
- /** The inferred type of elements stored in Lists. */
- ConcreteType listElementType;
-
- /**
- * A map from parameters to their inferred concrete types. It plays no role
- * in the analysis, it is write only.
- */
- final Map<VariableElement, ConcreteType> inferredParameterTypes;
-
- /**
- * A map from selectors to their inferred type masks, indexed by the mask
- * of the receiver. It plays no role in the analysis, it is write only.
- */
- final Map<Selector, Map<TypeMask, TypeMask>> inferredSelectorTypes;
-
- /** The work queue consumed by [analyzeMain]. */
- final WorkQueue workQueue;
-
- /** The item being worked on. */
- InferenceWorkItem currentWorkItem;
-
- ConcreteTypesInferrer(Compiler compiler)
- : methodToTemplates = new Map<FunctionElement,
- Map<ConcreteTypesEnvironment, ConcreteType>>(),
- closures = new Closures(compiler),
- inferredTypes = new Map<Node, ConcreteType>(),
- inferredFieldTypes = new Map<Element, ConcreteType>(),
- inferredParameterTypes = new Map<VariableElement, ConcreteType>(),
- workQueue = new WorkQueue(),
- callers = new Map<FunctionElement, Set<Element>>(),
- fieldReaders = new Map<Element, Set<Element>>(),
- capturedLocalsReaders = new Map<Local, Set<FunctionElement>>(),
- seenClasses = new Set<ClassElement>(),
- dynamicCallers = new Map<String, Set<FunctionElement>>(),
- inferredSelectorTypes = new Map<Selector, Map<TypeMask, TypeMask>>(),
- unknownConcreteType = new ConcreteType.unknown(),
- super(compiler, null);
-
- /* Initialization code that cannot be run in the constructor because it
- * requires the compiler's elements to be populated.
- */
- void initialize() {
- baseTypes = new BaseTypes(compiler);
- types = new ConcreteTypeSystem(this);
- ClassElement jsArrayClass = baseTypes.listBaseType.element;
- listIndex = jsArrayClass.lookupMember('[]');
- listIndexSet = jsArrayClass.lookupMember('[]=');
- listAdd = jsArrayClass.lookupMember('add');
- listRemoveAt = jsArrayClass.lookupMember('removeAt');
- listInsert = jsArrayClass.lookupMember('insert');
- listRemoveLast =
- jsArrayClass.lookupMember('removeLast');
- List<String> typePreservingOps = const ['+', '-', '*'];
- listConstructor =
- compiler.listClass.lookupConstructor(
- new Selector.callConstructor(
- '',
- compiler.listClass.library)).implementation;
- emptyConcreteType = new ConcreteType.empty(compiler.maxConcreteTypeSize,
- baseTypes);
- nullConcreteType = singletonConcreteType(const NullBaseType());
- listElementType = emptyConcreteType;
- }
-
- // --- utility methods ---
-
- /** Creates a singleton concrete type containing [baseType]. */
- ConcreteType singletonConcreteType(BaseType baseType) {
- return new ConcreteType.singleton(compiler.maxConcreteTypeSize, baseTypes,
- baseType);
- }
-
- /**
- * Computes the union of [mask1] and [mask2] where [mask1] and [mask2] are
- * possibly equal to [: DynamicTypeMask.instance :].
- */
- TypeMask typeMaskUnion(TypeMask mask1, TypeMask mask2) {
- if (mask1 == const DynamicTypeMask() || mask2 == const DynamicTypeMask()) {
- return const DynamicTypeMask();
- }
- return mask1.union(mask2, compiler.world);
- }
-
- /**
- * Returns all the members matching [selector].
- */
- Set<Element> getMembersBySelector(Selector selector) {
- // TODO(polux): memoize?
- Set<Element> result = new Set<Element>();
- for (ClassElement cls in seenClasses) {
- Element elem = cls.lookupSelector(selector);
- if (elem != null) {
- result.add(elem.implementation);
- }
- }
- return result;
- }
-
- /**
- * Returns all the subtypes of [cls], [cls] included.
- */
- Set<ClassElement> getReflexiveSubtypesOf(ClassElement cls) {
- // TODO(polux): memoize?
- Set<ClassElement> result = new Set<ClassElement>()..add(cls);
- for (ClassElement candidate in seenClasses) {
- if (compiler.world.isSubtypeOf(candidate, cls)) {
- result.add(candidate);
- }
- }
- return result;
- }
-
- /**
- * Sets the concrete type associated to [node] to the union of the inferred
- * concrete type so far and of [type].
- */
- void augmentInferredType(Node node, ConcreteType type) {
- ConcreteType currentType = inferredTypes[node];
- inferredTypes[node] =
- (currentType == null) ? type : currentType.union(type);
- }
-
- /**
- * Sets the concrete type associated to [selector] to the union of the
- * inferred concrete type so far and of [returnType].
- *
- * Precondition: [:(typeOfThis != null) && (returnType != null):]
- */
- void augmentInferredSelectorType(Selector selector, TypeMask typeOfThis,
- TypeMask returnType) {
- assert(returnType != null);
- assert(typeOfThis != null);
-
- selector = selector.asUntyped;
- Map<TypeMask, TypeMask> currentMap = inferredSelectorTypes.putIfAbsent(
- selector, () => new Map<TypeMask, TypeMask>());
- TypeMask currentReturnType = currentMap[typeOfThis];
- currentMap[typeOfThis] = (currentReturnType == null)
- ? returnType
- : typeMaskUnion(currentReturnType, returnType);
- }
-
- /**
- * Returns the current inferred concrete type of [field].
- */
- ConcreteType getFieldType(Selector selector, Element field) {
- ensureFieldInitialized(field);
- ConcreteType result = inferredFieldTypes[field];
- result = (result == null) ? emptyConcreteType : result;
- if (selector != null) {
- Element enclosing = field.enclosingElement;
- if (enclosing.isClass) {
- ClassElement cls = enclosing;
- TypeMask receiverMask = new TypeMask.exact(cls.declaration, classWorld);
- TypeMask resultMask = types.concreteTypeToTypeMask(result);
- augmentInferredSelectorType(selector, receiverMask, resultMask);
- }
- }
- return result;
- }
-
- /**
- * Sets the concrete type associated to [field] to the union of the inferred
- * concrete type so far and of [type].
- */
- void augmentFieldType(Element field, ConcreteType type) {
- ensureFieldInitialized(field);
- ConcreteType oldType = inferredFieldTypes[field];
- ConcreteType newType = (oldType != null) ? oldType.union(type) : type;
- if (oldType != newType) {
- inferredFieldTypes[field] = newType;
- invalidateReaders(field);
- }
- }
-
- /** Augment the inferred type of elements stored in Lists. */
- void augmentListElementType(ConcreteType type) {
- ConcreteType newType = listElementType.union(type);
- if (newType != listElementType) {
- invalidateCallers(listIndex);
- listElementType = newType;
- }
- }
-
- /**
- * Sets the concrete type associated to [parameter] to the union of the
- * inferred concrete type so far and of [type].
- */
- void augmentParameterType(VariableElement parameter, ConcreteType type) {
- ConcreteType oldType = inferredParameterTypes[parameter];
- inferredParameterTypes[parameter] =
- (oldType == null) ? type : oldType.union(type);
- }
-
- /** Augments the set of classes encountered so far. */
- void augmentSeenClasses(ClassElement cls) {
- if (!seenClasses.contains(cls)) {
- seenClasses.add(cls);
- cls.forEachMember((_, Element member) {
- Set<FunctionElement> functions = dynamicCallers[member.name];
- if (functions != null) {
- functions.forEach(invalidate);
- }
- }, includeSuperAndInjectedMembers: true);
- }
- }
-
- /**
- * Add [caller] to the set of [callee]'s callers.
- */
- void addCaller(FunctionElement callee, Element caller) {
- callers.putIfAbsent(callee, () => new Set<Element>())
- .add(caller);
- }
-
- /**
- * Add [caller] to the set of [callee]'s dynamic callers.
- */
- void addDynamicCaller(Selector callee, FunctionElement caller) {
- dynamicCallers
- .putIfAbsent(callee.name, () => new Set<FunctionElement>())
- .add(caller);
- }
-
- /**
- * Add [reader] to the set of [field]'s readers.
- */
- void addFieldReader(Element field, Element reader) {
- fieldReaders.putIfAbsent(field, () => new Set<Element>())
- .add(reader);
- }
-
- /**
- * Add [reader] to the set of [local]'s readers.
- */
- void addCapturedLocalReader(Local local, FunctionElement reader) {
- capturedLocalsReaders.putIfAbsent(local, () => new Set<FunctionElement>())
- .add(reader);
- }
-
- /**
- * Add a closure to the set of seen closures. Invalidate callers if
- * the set of locals has changed.
- */
- void addClosure(FunctionElement closure,
- ConcreteType typeOfThis,
- LocalsHandler locals) {
- if (closures.put(closure, typeOfThis, locals)) {
- invalidateCallers(closure);
- }
- }
-
- /**
- * Invalidate all callers of [function].
- */
- void invalidateCallers(FunctionElement function) {
- Set<Element> methodCallers = callers[function];
- if (methodCallers != null) {
- methodCallers.forEach(invalidate);
- }
- }
-
- /**
- * Invalidate all reader of [field].
- */
- void invalidateReaders(Element field) {
- Set<Element> readers = fieldReaders[field];
- if (readers != null) {
- readers.forEach(invalidate);
- }
- }
-
- /**
- * Add all templates of [methodOrField] to the workqueue.
- */
- void invalidate(Element methodOrField) {
- if (methodOrField.isField) {
- workQueue.add(new InferenceWorkItem(
- methodOrField, new ConcreteTypesEnvironment()));
- } else {
- Map<ConcreteTypesEnvironment, ConcreteType> templates =
- methodToTemplates[methodOrField];
- if (templates != null) {
- templates.forEach((environment, _) {
- workQueue.add(
- new InferenceWorkItem(methodOrField, environment));
- });
- }
- }
- }
-
- /**
- * Returns the template associated to [function] or create an empty template
- * for [function] return it.
- */
- // TODO(polux): encapsulate this in an abstraction for templates
- Map<ConcreteTypesEnvironment, ConcreteType>
- getTemplatesOrEmpty(FunctionElement function) {
- return methodToTemplates.putIfAbsent(
- function,
- () => new Map<ConcreteTypesEnvironment, ConcreteType>());
- }
-
- // -- methods of types.TypesInferrer (interface with the backend) --
-
- /** Get the inferred concrete type of [node]. */
- @override
- TypeMask getTypeOfNode(Element owner, Node node) {
- TypeMask result = types.concreteTypeToTypeMask(inferredTypes[node]);
- return (result == const DynamicTypeMask()) ? null : result;
- }
-
- /** Get the inferred concrete type of [element]. */
- @override
- TypeMask getTypeOfElement(Element element) {
- final result = types.concreteTypeToTypeMask(typeOfElement(element));
- return (result == const DynamicTypeMask()) ? null : result;
- }
-
- /**
- * Get the inferred concrete return type of [element]. A null return value
- * means "I don't know".
- */
- @override
- TypeMask getReturnTypeOfElement(Element element) {
- assert(element is FunctionElement);
- Map<ConcreteTypesEnvironment, ConcreteType> templates =
- methodToTemplates[element];
- if (templates == null) return null;
- ConcreteType returnType = emptyConcreteType;
- templates.forEach((_, concreteType) {
- returnType = returnType.union(concreteType);
- });
- TypeMask result = types.concreteTypeToTypeMask(returnType);
- return (result == const DynamicTypeMask()) ? null : result;
- }
-
- /**
- * Get the inferred concrete type of [selector]. A null return value means
- * "I don't know".
- */
- @override
- TypeMask getTypeOfSelector(Selector selector) {
- Map<TypeMask, TypeMask> candidates =
- inferredSelectorTypes[selector.asUntyped];
- if (candidates == null) {
- return null;
- }
- TypeMask result = new TypeMask.nonNullEmpty();
- if (selector.mask == null) {
- candidates.forEach((TypeMask receiverType, TypeMask returnType) {
- result = typeMaskUnion(result, returnType);
- });
- } else {
- candidates.forEach((TypeMask receiverType, TypeMask returnType) {
- TypeMask intersection =
- receiverType.intersection(selector.mask, compiler.world);
- if (!intersection.isEmpty || intersection.isNullable) {
- result = typeMaskUnion(result, returnType);
- }
- });
- }
- return result == const DynamicTypeMask() ? null : result;
- }
-
- @override
- void clear() {
- throw new UnsupportedError("clearing is not yet implemented");
- }
-
- @override
- bool isCalledOnce(Element element) {
- // Never called by SimpleTypeInferrer.
- throw new UnsupportedError("");
- }
-
- @override
- bool isFixedArrayCheckedForGrowable(Node node) {
- // Never called by SimpleTypeInferrer.
- throw new UnsupportedError("");
- }
-
- // --- analysis ---
-
- /**
- * Returns the concrete type returned by [function] given arguments of
- * concrete types [argumentsTypes]. If [function] is static then
- * [receiverType] must be null, else [function] must be a member of
- * [receiverType].
- */
- ConcreteType getSendReturnType(Selector selector,
- FunctionElement function,
- ClassElement receiverType,
- ArgumentsTypes<ConcreteType> argumentsTypes) {
- assert(function != null);
-
- ConcreteType result = emptyConcreteType;
- Map<Element, ConcreteType> argumentMap =
- associateArguments(function, argumentsTypes);
- // if the association failed, this send will never occur or will fail
- if (argumentMap == null) {
- return emptyConcreteType;
- }
-
- argumentMap.forEach(augmentParameterType);
- ConcreteTypeCartesianProduct product =
- new ConcreteTypeCartesianProduct(this, receiverType, argumentMap);
- for (ConcreteTypesEnvironment environment in product) {
- result = result.union(
- getMonomorphicSendReturnType(function, environment));
- }
-
- if (selector != null && receiverType != null) {
- // TODO(polux): generalize to any abstract class if we ever handle other
- // abstract classes than num.
- TypeMask receiverMask =
- (receiverType == compiler.backend.numImplementation
- || receiverType == compiler.backend.intImplementation)
- ? new TypeMask.nonNullSubclass(receiverType.declaration,
- compiler.world)
- : new TypeMask.nonNullExact(receiverType.declaration,
- compiler.world);
- TypeMask resultMask = types.concreteTypeToTypeMask(result);
- augmentInferredSelectorType(selector, receiverMask, resultMask);
- }
-
- return result;
- }
-
- /**
- * Given a method signature and a list of concrete types, builds a map from
- * formals to their corresponding concrete types. Returns null if the
- * association is impossible (for instance: too many arguments).
- */
- Map<Element, ConcreteType> associateArguments(
- FunctionElement function,
- ArgumentsTypes<ConcreteType> argumentsTypes) {
- final Map<Element, ConcreteType> result = new Map<Element, ConcreteType>();
- final FunctionSignature signature = function.functionSignature;
-
- // guard 1: too many arguments
- if (argumentsTypes.length > signature.parameterCount) {
- return null;
- }
- // guard 2: not enough arguments
- if (argumentsTypes.positional.length < signature.requiredParameterCount) {
- return null;
- }
- // guard 3: too many positional arguments
- if (signature.optionalParametersAreNamed &&
- argumentsTypes.positional.length > signature.requiredParameterCount) {
- return null;
- }
-
- handleLeftoverOptionalParameter(ParameterElement parameter) {
- Expression initializer = parameter.initializer;
- result[parameter] = (initializer == null)
- ? nullConcreteType
- : analyzeDefaultValue(function, initializer);
- }
-
- final Iterator<ConcreteType> remainingPositionalArguments =
- argumentsTypes.positional.iterator;
- // we attach each positional parameter to its corresponding positional
- // argument
- for (Link<Element> requiredParameters = signature.requiredParameters;
- !requiredParameters.isEmpty;
- requiredParameters = requiredParameters.tail) {
- final Element requiredParameter = requiredParameters.head;
- // we know moveNext() succeeds because of guard 2
- remainingPositionalArguments.moveNext();
- result[requiredParameter] = remainingPositionalArguments.current;
- }
- if (signature.optionalParametersAreNamed) {
- // we build a map out of the remaining named parameters
- Link<Element> remainingOptionalParameters = signature.optionalParameters;
- final Map<String, Element> leftOverNamedParameters =
- new Map<String, Element>();
- for (;
- !remainingOptionalParameters.isEmpty;
- remainingOptionalParameters = remainingOptionalParameters.tail) {
- final Element namedParameter = remainingOptionalParameters.head;
- leftOverNamedParameters[namedParameter.name] = namedParameter;
- }
- // we attach the named arguments to their corresponding optional
- // parameters
- for (String source in argumentsTypes.named.keys) {
- final ConcreteType concreteType = argumentsTypes.named[source];
- final Element namedParameter = leftOverNamedParameters[source];
- // unexisting or already used named parameter
- if (namedParameter == null) return null;
- result[namedParameter] = concreteType;
- leftOverNamedParameters.remove(source);
- }
- leftOverNamedParameters.forEach((_, Element parameter) {
- handleLeftoverOptionalParameter(parameter);
- });
- } else { // optional parameters are positional
- // we attach the remaining positional arguments to their corresponding
- // optional parameters
- Link<Element> remainingOptionalParameters = signature.optionalParameters;
- while (remainingPositionalArguments.moveNext()) {
- final Element optionalParameter = remainingOptionalParameters.head;
- result[optionalParameter] = remainingPositionalArguments.current;
- // we know tail is defined because of guard 1
- remainingOptionalParameters = remainingOptionalParameters.tail;
- }
- for (;
- !remainingOptionalParameters.isEmpty;
- remainingOptionalParameters = remainingOptionalParameters.tail) {
- handleLeftoverOptionalParameter(remainingOptionalParameters.head);
- }
- }
- return result;
- }
-
- ConcreteType getMonomorphicSendReturnType(
- FunctionElement function,
- ConcreteTypesEnvironment environment) {
- Map<ConcreteTypesEnvironment, ConcreteType> template =
- getTemplatesOrEmpty(function);
- ConcreteType type = template[environment];
- ConcreteType specialType = getSpecialCaseReturnType(function, environment);
- if (type != null) {
- return specialType != null ? specialType : type;
- } else {
- workQueue.add(new InferenceWorkItem(function, environment));
- return specialType != null ? specialType : emptyConcreteType;
- }
- }
-
- /**
- * Handles external methods that cannot be cached because they depend on some
- * other state of [ConcreteTypesInferrer] like [:List#[]:] and
- * [:List#[]=:]. Returns null if [function] and [environment] don't form a
- * special case
- */
- ConcreteType getSpecialCaseReturnType(FunctionElement function,
- ConcreteTypesEnvironment environment) {
- // Handles int + int, double + double, int - int, ...
- // We cannot compare function to int#+, int#-, etc. because int and double
- // don't override these methods. So for 1+2, getSpecialCaseReturnType will
- // be invoked with function = num#+. We use environment.typeOfThis instead.
- ClassElement cls = environment.classOfThis;
- if (cls != null) {
- String name = function.name;
- if ((cls == baseTypes.intBaseType.element
- || cls == baseTypes.doubleBaseType.element)
- && (name == '+' || name == '-' || name == '*')) {
- Link<Element> parameters =
- function.functionSignature.requiredParameters;
- ConcreteType argumentType = environment.lookupType(parameters.head);
- if (argumentType.getUniqueType() == cls) {
- return singletonConcreteType(new ClassBaseType(cls));
- }
- }
- }
-
- if (function == listIndex || function == listRemoveAt) {
- Link<Element> parameters = function.functionSignature.requiredParameters;
- ConcreteType indexType = environment.lookupType(parameters.head);
- if (!indexType.baseTypes.contains(baseTypes.intBaseType)) {
- return emptyConcreteType;
- }
- return listElementType;
- } else if (function == listIndexSet || function == listInsert) {
- Link<Element> parameters = function.functionSignature.requiredParameters;
- ConcreteType indexType = environment.lookupType(parameters.head);
- if (!indexType.baseTypes.contains(baseTypes.intBaseType)) {
- return emptyConcreteType;
- }
- ConcreteType elementType = environment.lookupType(parameters.tail.head);
- augmentListElementType(elementType);
- return emptyConcreteType;
- } else if (function == listAdd) {
- Link<Element> parameters = function.functionSignature.requiredParameters;
- ConcreteType elementType = environment.lookupType(parameters.head);
- augmentListElementType(elementType);
- return emptyConcreteType;
- } else if (function == listRemoveLast) {
- return listElementType;
- }
- return null;
- }
-
- ConcreteType analyzeMethodOrClosure(Element element,
- ConcreteTypesEnvironment environment) {
- ConcreteType specialResult = handleSpecialMethod(element, environment);
- if (specialResult != null) return specialResult;
- ClosureEnvironment closureEnv = closures.getEnvironmentOrNull(element);
- return (closureEnv == null)
- ? analyzeMethod(element, environment)
- : analyzeClosure(element, closureEnv, environment);
- }
-
- ConcreteType analyzeMethod(Element element,
- ConcreteTypesEnvironment environment) {
- TypeInferrerVisitor visitor = new TypeInferrerVisitor(
- element,
- this,
- singletonConcreteType(new ClassBaseType(environment.classOfThis)),
- environment.environment);
- visitor.run();
- return visitor.returnType;
- }
-
- ConcreteType analyzeClosure(Element element,
- ClosureEnvironment closureEnv,
- ConcreteTypesEnvironment environment) {
- assert(environment.classOfThis == null);
- LocalsHandler locals = (closureEnv.locals != null)
- ? new LocalsHandler.deepCopyOf(closureEnv.locals)
- : null;
- TypeInferrerVisitor visitor = new TypeInferrerVisitor(element, this,
- closureEnv.thisType, environment.environment, locals);
- visitor.run();
- return visitor.returnType;
- }
-
- /**
- * Analyze the initializer of a field if it has not yet been done and update
- * [inferredFieldTypes] accordingly. Invalidate the readers of the field if
- * needed.
- */
- void ensureFieldInitialized(Element field) {
- // This is test is needed for fitering out BoxFieldElements.
- if (field is FieldElement && inferredFieldTypes[field] == null) {
- analyzeFieldInitialization(field);
- }
- }
-
- /**
- * Analyze the initializer of a field and update [inferredFieldTypes]
- * accordingly. Invalidate the readers of the field if needed.
- */
- ConcreteType analyzeFieldInitialization(VariableElement field) {
- Visitor visitor = new TypeInferrerVisitor(field, this, null, new Map());
- ConcreteType type;
- if (field.initializer != null) {
- type = field.initializer.accept(visitor);
- inferredFieldTypes[field] = type;
- invalidateReaders(field);
- }
- return type;
- }
-
- /**
- * Analyze a default value.
- */
- ConcreteType analyzeDefaultValue(Element function, Node expression) {
- assert((function != null) && (expression != null));
- Visitor visitor = new TypeInferrerVisitor(function, this, null, {});
- return expression.accept(visitor);
- }
-
- /**
- * Hook that performs side effects on some special method calls (like
- * [:List(length):]) and possibly returns a concrete type.
- */
- ConcreteType handleSpecialMethod(FunctionElement element,
- ConcreteTypesEnvironment environment) {
- // We trust the return type of native elements
- if (isNativeElement(element)) {
- var elementType = element.type;
- assert(elementType.isFunctionType);
- return typeOfNativeBehavior(
- native.NativeBehavior.ofMethod(element, compiler));
- }
- // When List([length]) is called with some length, we must augment
- // listElementType with {null}.
- if (element == listConstructor) {
- Link<Element> parameters =
- listConstructor.functionSignature.optionalParameters;
- ConcreteType lengthType = environment.lookupType(parameters.head);
- if (lengthType.baseTypes.contains(baseTypes.intBaseType)) {
- augmentListElementType(nullConcreteType);
- }
- }
- return null;
- }
-
- /**
- * Performs concrete type inference of the code reachable from [element].
- */
- @override
- bool analyzeMain(Element element) {
- initialize();
- workQueue.add(
- new InferenceWorkItem(element, new ConcreteTypesEnvironment()));
- while (!workQueue.isEmpty) {
- currentWorkItem = workQueue.remove();
- if (currentWorkItem.method.isField) {
- analyzeFieldInitialization(currentWorkItem.method);
- } else {
- Map<ConcreteTypesEnvironment, ConcreteType> template =
- getTemplatesOrEmpty(currentWorkItem.method);
- template.putIfAbsent(
- currentWorkItem.environment, () => emptyConcreteType);
- recordReturnType(
- currentWorkItem.method,
- analyzeMethodOrClosure(currentWorkItem.method,
- currentWorkItem.environment));
- }
- }
- return true;
- }
-
- /**
- * Dumps debugging information on the standard output.
- */
- void debug() {
- print("queue:");
- for (InferenceWorkItem workItem in workQueue.queue) {
- print(" $workItem");
- }
- print("seen classes:");
- for (ClassElement cls in seenClasses) {
- print(" ${cls.name}");
- }
- print("callers:");
- callers.forEach((k,v) {
- print(" $k: $v");
- });
- print("dynamic callers:");
- dynamicCallers.forEach((k,v) {
- print(" $k: $v");
- });
- print("readers:");
- fieldReaders.forEach((k,v) {
- print(" $k: $v");
- });
- print("readers of captured locals:");
- capturedLocalsReaders.forEach((k,v) {
- print(" $k: $v");
- });
- print("inferredFieldTypes:");
- inferredFieldTypes.forEach((k,v) {
- print(" $k: $v");
- });
- print("listElementType:");
- print(" $listElementType");
- print("inferredParameterTypes:");
- inferredParameterTypes.forEach((k,v) {
- print(" $k: $v");
- });
- print("inferred selector types:");
- inferredSelectorTypes.forEach((selector, map) {
- print(" $selector:");
- map.forEach((k, v) {
- print(" $k: $v");
- });
- });
- print("cache:");
- methodToTemplates.forEach((k,v) {
- print(" $k: $v");
- });
- print("closures:");
- closures.closures.forEach((k, ClosureEnvironment v) {
- print(" $k");
- print(" this: ${v.thisType}");
- if (v.locals != null) {
- v.locals.locals.forEachLocal((local, type) {
- print(" $local: $type");
- });
- }
- });
- print("inferred expression types:");
- inferredTypes.forEach((k,v) {
- print(" $k: $v");
- });
- }
-
- @override
- ConcreteType addReturnTypeFor(Element analyzedElement,
- ConcreteType currentType,
- ConcreteType newType) {
- return (currentType == null) ? newType : currentType.union(newType);
- }
-
- @override
- void forEachElementMatching(Selector selector, bool f(Element element)) {
- getMembersBySelector(selector).forEach(f);
- }
-
- @override
- void recordReturnType(Element element, ConcreteType type) {
- assert((type != null) && (element == currentWorkItem.method));
- Map<ConcreteTypesEnvironment, ConcreteType> template =
- getTemplatesOrEmpty(element);
- if (template[currentWorkItem.environment] != type) {
- template[currentWorkItem.environment] = type;
- invalidateCallers(element);
- }
- }
-
- @override
- void recordType(Element element, ConcreteType type) {
- assert(element is FieldElement);
- augmentFieldType(element, type);
- }
-
- @override
- void recordTypeOfFinalField(Node node,
- Element nodeHolder,
- Element field,
- ConcreteType type) {
- augmentFieldType(field, type);
- }
-
- @override
- void recordTypeOfNonFinalField(Spannable node, Element field,
- ConcreteType type) {
- augmentFieldType(field, type);
- }
-
- @override
- void recordCapturedLocalRead(Local local) {
- addCapturedLocalReader(local, currentWorkItem.method);
- }
-
- @override
- void recordLocalUpdate(Local local, ConcreteType type) {
- Set<FunctionElement> localReaders = capturedLocalsReaders[local];
- if (localReaders != null) {
- localReaders.forEach(invalidate);
- }
- }
-
- /**
- * Returns the caller of the current analyzed element, given the alleged
- * caller provided by SimpleTypeInferrer.
- *
- * SimpleTypeInferrer lies about the caller when it's a closure.
- * Unfortunately we cannot always trust currentWorkItem.method either because
- * it is wrong for fields initializers.
- */
- Element getRealCaller(Element allegedCaller) {
- Element currentMethod = currentWorkItem.method;
- if ((currentMethod != allegedCaller)
- && currentMethod.isFunction
- && closures.contains(currentMethod)) {
- return currentMethod;
- } else {
- return allegedCaller;
- }
- }
-
- @override
- ConcreteType registerCalledElement(Spannable node,
- Selector selector,
- Element caller,
- Element callee,
- ArgumentsTypes<ConcreteType> arguments,
- SideEffects sideEffects,
- bool inLoop) {
- caller = getRealCaller(caller);
- if ((selector == null) || (selector.kind == SelectorKind.CALL)) {
- callee = callee.implementation;
- if (selector != null && selector.name == 'JS') {
- return null;
- }
- if (callee.isField) { // toplevel closure call
- getFieldType(selector, callee); // trigger toplevel field analysis
- addFieldReader(callee, caller);
- ConcreteType result = emptyConcreteType;
- for (FunctionElement function in closures.functionElements) {
- addCaller(function, caller);
- result = result.union(
- getSendReturnType(selector, function, null, arguments));
- }
- return result;
- } else { // method or constructor call
- addCaller(callee, caller);
- ClassElement receiverClass = null;
- if (callee.isGenerativeConstructor) {
- receiverClass = callee.enclosingClass;
- } else if (node is Send) {
- Send send = node;
- if (send.receiver != null) {
- if (send.receiver.isSuper()) {
- receiverClass =
- currentWorkItem.environment.classOfThis.superclass;
- } else {
- receiverClass = currentWorkItem.environment.classOfThis;
- }
- }
- }
- return getSendReturnType(selector, callee, receiverClass, arguments);
- }
- } else if (selector.kind == SelectorKind.GETTER) {
- if (callee.isField) {
- addFieldReader(callee, caller);
- return getFieldType(selector, callee);
- } else if (callee.isGetter) {
- Element enclosing = callee.enclosingElement.isCompilationUnit
- ? null : callee.enclosingElement;
- addCaller(callee, caller);
- ArgumentsTypes noArguments = new ArgumentsTypes([], new Map());
- return getSendReturnType(selector, callee, enclosing, noArguments);
- } else if (callee.isFunction) {
- addClosure(callee, null, null);
- return singletonConcreteType(baseTypes.functionBaseType);
- }
- } else if (selector.kind == SelectorKind.SETTER) {
- ConcreteType argumentType = arguments.positional.first;
- if (callee.isField) {
- augmentFieldType(callee, argumentType);
- } else if (callee.isSetter) {
- FunctionElement setter = callee;
- // TODO(polux): A setter always returns void so there's no need to
- // invalidate its callers even if it is called with new arguments.
- // However, if we start to record more than returned types, like
- // exceptions for instance, we need to do it by uncommenting the
- // following line.
- // inferrer.addCaller(setter, currentMethod);
- Element enclosing = callee.enclosingElement.isCompilationUnit
- ? null : callee.enclosingElement;
- return getSendReturnType(selector, setter, enclosing,
- new ArgumentsTypes([argumentType], new Map()));
- }
- } else {
- throw new ArgumentError("unexpected selector kind");
- }
- return null;
- }
-
- @override
- ConcreteType registerCalledSelector(Node node,
- Selector selector,
- ConcreteType receiverType,
- Element caller,
- ArgumentsTypes<ConcreteType> arguments,
- SideEffects sideEffects,
- bool inLoop) {
- caller = getRealCaller(caller);
- switch (selector.kind) {
- case SelectorKind.GETTER:
- return registerDynamicGetterSend(selector, receiverType, caller);
- case SelectorKind.SETTER:
- return registerDynamicSetterSend(
- selector, receiverType, caller, arguments);
- default:
- return registerDynamicSend(selector, receiverType, caller, arguments);
- }
- }
-
- ConcreteType registerDynamicGetterSend(Selector selector,
- ConcreteType receiverType,
- Element caller) {
- caller = getRealCaller(caller);
- ConcreteType result = emptyConcreteType;
-
- void augmentResult(ClassElement baseReceiverType, Element member) {
- if (member.isField) {
- addFieldReader(member, caller);
- result = result.union(getFieldType(selector, member));
- } else if (member.isGetter) {
- addCaller(member, caller);
- ArgumentsTypes noArguments = new ArgumentsTypes([], new Map());
- result = result.union(
- getSendReturnType(selector, member, baseReceiverType, noArguments));
- } else if (member.isFunction) {
- addClosure(member, receiverType, null);
- result = result.union(
- singletonConcreteType(baseTypes.functionBaseType));
- } else {
- throw new ArgumentError("unexpected element type");
- }
- }
-
- if (receiverType.isUnknown()) {
- addDynamicCaller(selector, caller);
- Set<Element> members = getMembersBySelector(selector);
- for (Element member in members) {
- if (!(member.isField || member.isGetter)) continue;
- for (ClassElement cls in
- getReflexiveSubtypesOf(member.enclosingElement)) {
- augmentResult(cls, member);
- }
- }
- } else {
- for (BaseType baseReceiverType in receiverType.baseTypes) {
- if (!baseReceiverType.isNull()) {
- ClassBaseType classBaseType = baseReceiverType;
- ClassElement cls = classBaseType.element;
- Element getterOrField = cls.lookupSelector(selector);
- if (getterOrField != null) {
- augmentResult(cls, getterOrField.implementation);
- }
- }
- }
- }
- return result;
- }
-
- ConcreteType registerDynamicSetterSend(
- Selector selector,
- ConcreteType receiverType,
- Element caller,
- ArgumentsTypes<ConcreteType> arguments) {
- caller = getRealCaller(caller);
- ConcreteType argumentType = arguments.positional.first;
-
- void augmentField(ClassElement receiverType, Element setterOrField) {
- if (setterOrField.isField) {
- augmentFieldType(setterOrField, argumentType);
- } else if (setterOrField.isSetter) {
- // A setter always returns void so there's no need to invalidate its
- // callers even if it is called with new arguments. However, if we
- // start to record more than returned types, like exceptions for
- // instance, we need to do it by uncommenting the following line.
- // inferrer.addCaller(setter, currentMethod);
- getSendReturnType(selector, setterOrField, receiverType,
- new ArgumentsTypes([argumentType], new Map()));
- } else {
- throw new ArgumentError("unexpected element type");
- }
- }
-
- if (receiverType.isUnknown()) {
- // Same remark as above
- // addDynamicCaller(selector, caller);
- for (Element member in getMembersBySelector(selector)) {
- if (!(member.isField || member.isSetter)) continue;
- Element cls = member.enclosingClass;
- augmentField(cls, member);
- }
- } else {
- for (BaseType baseReceiverType in receiverType.baseTypes) {
- if (!baseReceiverType.isNull()) {
- ClassBaseType classBaseType = baseReceiverType;
- ClassElement cls = classBaseType.element;
- Element setterOrField = cls.lookupSelector(selector);
- if (setterOrField != null) {
- augmentField(cls, setterOrField.implementation);
- }
- }
- }
- }
- return argumentType;
- }
-
- ConcreteType registerDynamicSend(Selector selector,
- ConcreteType receiverType,
- Element caller,
- ArgumentsTypes<ConcreteType> arguments) {
- caller = getRealCaller(caller);
- ConcreteType result = emptyConcreteType;
- if (receiverType.isUnknown()) {
- addDynamicCaller(selector, caller);
- Set<Element> elements = getMembersBySelector(selector);
- for (Element element in elements) {
- if (element.isFunction) {
- FunctionElement method = element;
- addCaller(method, caller);
- for (ClassElement cls in
- getReflexiveSubtypesOf(method.enclosingElement)) {
- result = result.union(
- getSendReturnType(selector, method, cls, arguments));
- }
- } else { // closure call
- assert(element.isField);
- for (FunctionElement function in closures.functionElements) {
- addCaller(function, caller);
- result = result.union(
- getSendReturnType(selector, function, null, arguments));
- }
- }
- }
- } else {
- for (BaseType baseReceiverType in receiverType.baseTypes) {
- if (!baseReceiverType.isNull()) {
- ClassBaseType classBaseReceiverType = baseReceiverType;
- ClassElement cls = classBaseReceiverType.element;
- Element method = cls.lookupSelector(selector);
- if (method != null) {
- if (method.isFunction) {
- assert(method is FunctionElement);
- method = method.implementation;
- addCaller(method, caller);
- result = result.union(
- getSendReturnType(selector, method, cls, arguments));
- } else { // closure call
- for (FunctionElement function in closures.functionElements) {
- addCaller(function, caller);
- result = result.union(
- getSendReturnType(selector, function, null, arguments));
- }
- }
- }
- }
- }
- }
- return result;
- }
-
- @override
- void setDefaultTypeOfParameter(ParameterElement parameter,
- ConcreteType type) {
- // We handle default parameters our own way in associateArguments
- }
-
- /**
- * TODO(johnniwinther): Remove once synthetic parameters get their own default
- * values.
- */
- bool hasAlreadyComputedTypeOfParameterDefault(Element parameter) => false;
-
- @override
- ConcreteType registerCalledClosure(Node node,
- Selector selector,
- ConcreteType closure,
- Element caller,
- ArgumentsTypes<ConcreteType> arguments,
- SideEffects sideEffects,
- bool inLoop) {
- caller = getRealCaller(caller);
- ConcreteType result = emptyConcreteType;
- for (FunctionElement function in closures.functionElements) {
- addCaller(function, caller);
- result = result.union(
- getSendReturnType(selector, function, null, arguments));
- }
- return result;
- }
-
- @override
- ConcreteType returnTypeOfElement(Element element) {
- // Never called by SimpleTypeInferrer.
- throw new UnsupportedError("");
- }
-
- @override
- ConcreteType typeOfElement(Element element) {
- if (currentWorkItem != null) {
- final result = currentWorkItem.environment.lookupType(element);
- if (result != null) return result;
- }
- if (element.isParameter || element.isInitializingFormal) {
- return inferredParameterTypes[element];
- } else if (element.isField) {
- return inferredFieldTypes[element];
- }
- throw new ArgumentError("unexpected element type");
- }
-
- @override
- void analyze(Element element, ArgumentsTypes arguments) {
- FunctionElement function = element;
- getSendReturnType(
- null, function, currentWorkItem.environment.classOfThis, arguments);
- }
-}
-
-class TypeInferrerVisitor extends SimpleTypeInferrerVisitor<ConcreteType> {
- final ConcreteType thisType;
- ConcreteTypesInferrer get inferrer => super.inferrer;
-
- TypeInferrerVisitor(Element element,
- ConcreteTypesInferrer inferrer,
- this.thisType,
- Map<Element, ConcreteType> environment,
- [LocalsHandler<ConcreteType> handler])
- : super(element, inferrer.compiler, inferrer, handler);
-
- @override
- ConcreteType visitFunctionExpression(FunctionExpression node) {
- Element element = elements[node];
- // visitFunctionExpression should be only called for closures
- assert(element != analyzedElement);
- inferrer.addClosure(
- element, thisType, new LocalsHandler.deepCopyOf(locals));
- return types.functionType;
- }
-
- @override
- ConcreteType visitLiteralString(LiteralString node) {
- // TODO(polux): get rid of this hack once we have a natural way of inferring
- // the unknown type.
- if (inferrer.testMode
- && (node.dartString.slowToString() == "__dynamic_for_test")) {
- return inferrer.unknownConcreteType;
- }
- return super.visitLiteralString(node);
- }
-
- /**
- * Same as super.visitLiteralList except it doesn't cache anything.
- */
- @override
- ConcreteType visitLiteralList(LiteralList node) {
- ConcreteType elementType;
- int length = 0;
- for (Node element in node.elements.nodes) {
- ConcreteType type = visit(element);
- elementType = elementType == null
- ? types.allocatePhi(null, null, type)
- : types.addPhiInput(null, elementType, type);
- length++;
- }
- elementType = elementType == null
- ? types.nonNullEmpty()
- : types.simplifyPhi(null, null, elementType);
- ConcreteType containerType = node.isConst
- ? types.constListType
- : types.growableListType;
- return types.allocateList(
- containerType,
- node,
- outermostElement,
- elementType,
- length);
- }
-
- /**
- * Same as super.visitGetterSend except it records the type of nodes in test
- * mode.
- */
- @override
- ConcreteType visitGetterSend(Send node) {
- if (inferrer.testMode) {
- var element = elements[node];
- if (element is Local) {
- ConcreteType type = locals.use(element);
- if (type != null) {
- inferrer.augmentInferredType(node, type);
- }
- }
- }
- return super.visitGetterSend(node);
- }
-}

Powered by Google App Engine
This is Rietveld 408576698