| Index: sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
|
| index 86602247a6ca606ebf50b26d8233b2e5673a9cba..00c9295b7b2e5edca100e04e89480302a43f79fc 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
|
| @@ -2,7 +2,14 @@
|
| // 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.
|
|
|
| -part of simple_types_inferrer;
|
| +library inferrer_visitor;
|
| +
|
| +import '../dart2jslib.dart' hide Selector, TypedSelector;
|
| +import '../dart_types.dart';
|
| +import '../elements/elements.dart';
|
| +import '../tree/tree.dart';
|
| +import '../universe/universe.dart';
|
| +import '../util/util.dart';
|
|
|
| /**
|
| * The interface [InferrerVisitor] will use when working on types.
|
| @@ -75,106 +82,6 @@ abstract class TypeSystem<T> {
|
| }
|
|
|
| /**
|
| - * An implementation of [TypeSystem] for [TypeMask].
|
| - */
|
| -class TypeMaskSystem implements TypeSystem<TypeMask> {
|
| - final Compiler compiler;
|
| - TypeMaskSystem(this.compiler);
|
| -
|
| - TypeMask narrowType(TypeMask type,
|
| - DartType annotation,
|
| - {bool isNullable: true}) {
|
| - if (annotation.treatAsDynamic) return type;
|
| - if (annotation.isVoid) return nullType;
|
| - if (annotation.element == compiler.objectClass) return type;
|
| - TypeMask otherType;
|
| - if (annotation.kind == TypeKind.TYPEDEF
|
| - || annotation.kind == TypeKind.FUNCTION) {
|
| - otherType = functionType;
|
| - } else if (annotation.kind == TypeKind.TYPE_VARIABLE) {
|
| - // TODO(ngeoffray): Narrow to bound.
|
| - return type;
|
| - } else {
|
| - assert(annotation.kind == TypeKind.INTERFACE);
|
| - otherType = new TypeMask.nonNullSubtype(annotation);
|
| - }
|
| - if (isNullable) otherType = otherType.nullable();
|
| - if (type == null) return otherType;
|
| - return type.intersection(otherType, compiler);
|
| - }
|
| -
|
| - TypeMask computeLUB(TypeMask firstType, TypeMask secondType) {
|
| - if (firstType == null) {
|
| - return secondType;
|
| - } else if (secondType == dynamicType || firstType == dynamicType) {
|
| - return dynamicType;
|
| - } else if (firstType == secondType) {
|
| - return firstType;
|
| - } else {
|
| - TypeMask union = firstType.union(secondType, compiler);
|
| - // TODO(kasperl): If the union isn't nullable it seems wasteful
|
| - // to use dynamic. Fix that.
|
| - return union.containsAll(compiler) ? dynamicType : union;
|
| - }
|
| - }
|
| -
|
| - TypeMask allocateDiamondPhi(TypeMask firstType, TypeMask secondType) {
|
| - return computeLUB(firstType, secondType);
|
| - }
|
| -
|
| - TypeMask get dynamicType => compiler.typesTask.dynamicType;
|
| - TypeMask get nullType => compiler.typesTask.nullType;
|
| - TypeMask get intType => compiler.typesTask.intType;
|
| - TypeMask get doubleType => compiler.typesTask.doubleType;
|
| - TypeMask get numType => compiler.typesTask.numType;
|
| - TypeMask get boolType => compiler.typesTask.boolType;
|
| - TypeMask get functionType => compiler.typesTask.functionType;
|
| - TypeMask get listType => compiler.typesTask.listType;
|
| - TypeMask get constListType => compiler.typesTask.constListType;
|
| - TypeMask get fixedListType => compiler.typesTask.fixedListType;
|
| - TypeMask get growableListType => compiler.typesTask.growableListType;
|
| - TypeMask get mapType => compiler.typesTask.mapType;
|
| - TypeMask get constMapType => compiler.typesTask.constMapType;
|
| - TypeMask get stringType => compiler.typesTask.stringType;
|
| - TypeMask get typeType => compiler.typesTask.typeType;
|
| -
|
| - TypeMask nonNullSubtype(DartType type) => new TypeMask.nonNullSubtype(type);
|
| - TypeMask nonNullSubclass(DartType type) => new TypeMask.nonNullSubclass(type);
|
| - TypeMask nonNullExact(DartType type) => new TypeMask.nonNullExact(type);
|
| - TypeMask nonNullEmpty() => new TypeMask.nonNullEmpty();
|
| -
|
| - TypeMask nullable(TypeMask type) {
|
| - return type.nullable();
|
| - }
|
| -
|
| - TypeMask allocateContainer(TypeMask type,
|
| - Node node,
|
| - Element enclosing,
|
| - [TypeMask elementType, int length]) {
|
| - ContainerTypeMask mask = new ContainerTypeMask(type, node, enclosing);
|
| - mask.elementType = elementType;
|
| - mask.length = length;
|
| - return mask;
|
| - }
|
| -
|
| - Selector newTypedSelector(TypeMask receiver, Selector selector) {
|
| - return new TypedSelector(receiver, selector);
|
| - }
|
| -
|
| - TypeMask addPhiInput(Element element, TypeMask phiType, TypeMask newType) {
|
| - return computeLUB(phiType, newType);
|
| - }
|
| -
|
| - TypeMask allocatePhi(Node node, Element element, TypeMask inputType) {
|
| - return inputType;
|
| - }
|
| -
|
| - TypeMask simplifyPhi(Node node, Element element, TypeMask phiType) {
|
| - return phiType;
|
| - }
|
| -}
|
| -
|
| -/**
|
| * A variable scope holds types for variables. It has a link to a
|
| * parent scope, but never changes the types in that parent. Instead,
|
| * updates to locals of a parent scope are put in the current scope.
|
| @@ -304,12 +211,73 @@ class FieldInitializationScope<T> {
|
| }
|
|
|
| /**
|
| + * Placeholder for inferred arguments types on sends.
|
| + */
|
| +class ArgumentsTypes<T> {
|
| + final List<T> positional;
|
| + final Map<SourceString, T> named;
|
| + ArgumentsTypes(this.positional, named)
|
| + : this.named = (named == null) ? new Map<SourceString, T>() : named;
|
| +
|
| + int get length => positional.length + named.length;
|
| +
|
| + String toString() => "{ positional = $positional, named = $named }";
|
| +
|
| + bool operator==(other) {
|
| + if (positional.length != other.positional.length) return false;
|
| + if (named.length != other.named.length) return false;
|
| + for (int i = 0; i < positional.length; i++) {
|
| + if (positional[i] != other.positional[i]) return false;
|
| + }
|
| + named.forEach((name, type) {
|
| + if (other.named[name] != type) return false;
|
| + });
|
| + return true;
|
| + }
|
| +
|
| + int get hashCode => throw new UnsupportedError('ArgumentsTypes.hashCode');
|
| +
|
| + bool hasNoArguments() => positional.isEmpty && named.isEmpty;
|
| +
|
| + bool hasOnePositionalArgumentWithType(T type) {
|
| + return named.isEmpty && positional.length == 1 && positional[0] == type;
|
| + }
|
| +}
|
| +
|
| +class CallSite {
|
| + final Selector selector;
|
| + final ArgumentsTypes arguments;
|
| + CallSite(this.selector, this.arguments) {
|
| + assert(selector != null);
|
| + }
|
| +}
|
| +
|
| +abstract class MinimalInferrerEngine<T> {
|
| + /**
|
| + * Returns the type of [element].
|
| + */
|
| + T typeOfElement(Element element);
|
| +
|
| + /**
|
| + * Records that [node] sets non-final field [element] to be of type
|
| + * [type].
|
| + *
|
| + * [constraint] is a field assignment constraint, as described in
|
| + * [InternalSimpleTypesInferrer].
|
| + */
|
| + void recordTypeOfNonFinalField(Node node,
|
| + Element field,
|
| + T type,
|
| + CallSite constraint);
|
| +}
|
| +
|
| +/**
|
| * Placeholder for inferred types of local variables.
|
| */
|
| class LocalsHandler<T> {
|
| final Compiler compiler;
|
| final TypeSystem<T> types;
|
| - final InferrerEngine<T> inferrer;
|
| + final MinimalInferrerEngine<T> inferrer;
|
| final VariableScope<T> locals;
|
| final Map<Element, Element> capturedAndBoxed;
|
| final FieldInitializationScope<T> fieldScope;
|
| @@ -535,10 +503,11 @@ class LocalsHandler<T> {
|
| }
|
| }
|
|
|
| -abstract class InferrerVisitor<T> extends ResolvedVisitor<T> {
|
| +abstract class InferrerVisitor
|
| + <T, E extends MinimalInferrerEngine<T>> extends ResolvedVisitor<T> {
|
| final Element analyzedElement;
|
| final TypeSystem<T> types;
|
| - final InferrerEngine<T> inferrer;
|
| + final E inferrer;
|
| final Compiler compiler;
|
| final Map<TargetElement, List<LocalsHandler<T>>> breaksFor =
|
| new Map<TargetElement, List<LocalsHandler<T>>>();
|
|
|