| Index: pkg/compiler/lib/src/inferrer/locals_handler.dart
|
| diff --git a/pkg/compiler/lib/src/inferrer/locals_handler.dart b/pkg/compiler/lib/src/inferrer/locals_handler.dart
|
| index b5935f2e446658c6ef620bb6a7e842a020d3a53d..3e71335cc70e443cc02ffcab34addd1fd1d1d967 100644
|
| --- a/pkg/compiler/lib/src/inferrer/locals_handler.dart
|
| +++ b/pkg/compiler/lib/src/inferrer/locals_handler.dart
|
| @@ -9,6 +9,7 @@ import 'dart:collection' show IterableMixin;
|
| import '../options.dart' show CompilerOptions;
|
| import '../elements/elements.dart';
|
| import '../elements/entities.dart';
|
| +import '../elements/types.dart';
|
| import '../tree/tree.dart';
|
| import '../util/util.dart';
|
| import 'inferrer_engine.dart';
|
| @@ -22,20 +23,20 @@ import 'type_system.dart';
|
| * The inferrer makes sure updates get merged into the parent scope,
|
| * once the control flow block has been visited.
|
| */
|
| -class VariableScope {
|
| +class VariableScope<T> {
|
| Map<Local, TypeInformation> variables;
|
|
|
| /// The parent of this scope. Null for the root scope.
|
| final VariableScope parent;
|
|
|
| /// The [Node] that created this scope.
|
| - final Node block;
|
| + final T block;
|
|
|
| VariableScope(this.block, [parent])
|
| : this.variables = null,
|
| this.parent = parent;
|
|
|
| - VariableScope.deepCopyOf(VariableScope other)
|
| + VariableScope.deepCopyOf(VariableScope<T> other)
|
| : variables = other.variables == null
|
| ? null
|
| : new Map<Local, TypeInformation>.from(other.variables),
|
| @@ -44,7 +45,7 @@ class VariableScope {
|
| ? null
|
| : new VariableScope.deepCopyOf(other.parent);
|
|
|
| - VariableScope.topLevelCopyOf(VariableScope other)
|
| + VariableScope.topLevelCopyOf(VariableScope<T> other)
|
| : variables = other.variables == null
|
| ? null
|
| : new Map<Local, TypeInformation>.from(other.variables),
|
| @@ -73,7 +74,7 @@ class VariableScope {
|
| }
|
|
|
| void forEachLocalUntilNode(
|
| - Node node, void f(Local variable, TypeInformation type),
|
| + T node, void f(Local variable, TypeInformation type),
|
| [Setlet<Local> seenLocals]) {
|
| if (seenLocals == null) seenLocals = new Setlet<Local>();
|
| if (variables != null) {
|
| @@ -103,9 +104,9 @@ class VariableScope {
|
| }
|
|
|
| /// Tracks initializers via initializations and assignments.
|
| -class FieldInitializationScope {
|
| - final TypeSystem<Node> types;
|
| - Map<Element, TypeInformation> fields;
|
| +class FieldInitializationScope<T> {
|
| + final TypeSystem<T> types;
|
| + Map<FieldEntity, TypeInformation> fields;
|
| bool isThisExposed;
|
|
|
| /// `true` when control flow prevents accumulating definite assignments,
|
| @@ -116,42 +117,42 @@ class FieldInitializationScope {
|
| : isThisExposed = false,
|
| isIndefinite = false;
|
|
|
| - FieldInitializationScope.internalFrom(FieldInitializationScope other)
|
| + FieldInitializationScope.internalFrom(FieldInitializationScope<T> other)
|
| : types = other.types,
|
| isThisExposed = other.isThisExposed,
|
| isIndefinite = other.isIndefinite;
|
|
|
| - factory FieldInitializationScope.from(FieldInitializationScope other) {
|
| + factory FieldInitializationScope.from(FieldInitializationScope<T> other) {
|
| if (other == null) return null;
|
| - return new FieldInitializationScope.internalFrom(other);
|
| + return new FieldInitializationScope<T>.internalFrom(other);
|
| }
|
|
|
| - void updateField(Element field, TypeInformation type) {
|
| + void updateField(FieldEntity field, TypeInformation type) {
|
| if (isThisExposed) return;
|
| if (isIndefinite) return;
|
| - fields ??= new Map<Element, TypeInformation>();
|
| + fields ??= new Map<FieldEntity, TypeInformation>();
|
| fields[field] = type;
|
| }
|
|
|
| - TypeInformation readField(Element field) {
|
| + TypeInformation readField(FieldEntity field) {
|
| return fields == null ? null : fields[field];
|
| }
|
|
|
| - void forEach(void f(Element element, TypeInformation type)) {
|
| + void forEach(void f(FieldEntity element, TypeInformation type)) {
|
| fields?.forEach(f);
|
| }
|
|
|
| - void mergeDiamondFlow(
|
| - FieldInitializationScope thenScope, FieldInitializationScope elseScope) {
|
| + void mergeDiamondFlow(FieldInitializationScope<T> thenScope,
|
| + FieldInitializationScope<T> elseScope) {
|
| // Quick bailout check. If [isThisExposed] or [isIndefinite] is true, we
|
| // know the code following won'TypeInformation do anything.
|
| if (isThisExposed) return;
|
| if (isIndefinite) return;
|
|
|
| - FieldInitializationScope otherScope =
|
| + FieldInitializationScope<T> otherScope =
|
| (elseScope == null || elseScope.fields == null) ? this : elseScope;
|
|
|
| - thenScope.forEach((Element field, TypeInformation type) {
|
| + thenScope.forEach((FieldEntity field, TypeInformation type) {
|
| TypeInformation otherType = otherScope.readField(field);
|
| if (otherType == null) return;
|
| updateField(field, types.allocateDiamondPhi(type, otherType));
|
| @@ -241,15 +242,15 @@ class ArgumentsTypesIterator implements Iterator<TypeInformation> {
|
| /**
|
| * Placeholder for inferred types of local variables.
|
| */
|
| -class LocalsHandler {
|
| +class LocalsHandler<T> {
|
| final CompilerOptions options;
|
| - final TypeSystem<Node> types;
|
| - final InferrerEngine inferrer;
|
| - final VariableScope locals;
|
| + final TypeSystem<T> types;
|
| + final InferrerEngine<T> inferrer;
|
| + final VariableScope<T> locals;
|
| final Map<Local, FieldEntity> captured;
|
| final Map<Local, FieldEntity> capturedAndBoxed;
|
| - final FieldInitializationScope fieldScope;
|
| - LocalsHandler tryBlock;
|
| + final FieldInitializationScope<T> fieldScope;
|
| + LocalsHandler<T> tryBlock;
|
| bool seenReturnOrThrow = false;
|
| bool seenBreakOrContinue = false;
|
|
|
| @@ -259,17 +260,17 @@ class LocalsHandler {
|
|
|
| bool get inTryBlock => tryBlock != null;
|
|
|
| - LocalsHandler(this.inferrer, this.types, this.options, Node block,
|
| + LocalsHandler(this.inferrer, this.types, this.options, T block,
|
| [this.fieldScope])
|
| - : locals = new VariableScope(block),
|
| + : locals = new VariableScope<T>(block),
|
| captured = new Map<Local, FieldEntity>(),
|
| capturedAndBoxed = new Map<Local, FieldEntity>(),
|
| tryBlock = null;
|
|
|
| - LocalsHandler.from(LocalsHandler other, Node block,
|
| + LocalsHandler.from(LocalsHandler<T> other, T block,
|
| {bool useOtherTryBlock: true})
|
| - : locals = new VariableScope(block, other.locals),
|
| - fieldScope = new FieldInitializationScope.from(other.fieldScope),
|
| + : locals = new VariableScope<T>(block, other.locals),
|
| + fieldScope = new FieldInitializationScope<T>.from(other.fieldScope),
|
| captured = other.captured,
|
| capturedAndBoxed = other.capturedAndBoxed,
|
| types = other.types,
|
| @@ -278,9 +279,9 @@ class LocalsHandler {
|
| tryBlock = useOtherTryBlock ? other.tryBlock : this;
|
| }
|
|
|
| - LocalsHandler.deepCopyOf(LocalsHandler other)
|
| - : locals = new VariableScope.deepCopyOf(other.locals),
|
| - fieldScope = new FieldInitializationScope.from(other.fieldScope),
|
| + LocalsHandler.deepCopyOf(LocalsHandler<T> other)
|
| + : locals = new VariableScope<T>.deepCopyOf(other.locals),
|
| + fieldScope = new FieldInitializationScope<T>.from(other.fieldScope),
|
| captured = other.captured,
|
| capturedAndBoxed = other.capturedAndBoxed,
|
| tryBlock = other.tryBlock,
|
| @@ -288,9 +289,9 @@ class LocalsHandler {
|
| inferrer = other.inferrer,
|
| options = other.options;
|
|
|
| - LocalsHandler.topLevelCopyOf(LocalsHandler other)
|
| - : locals = new VariableScope.topLevelCopyOf(other.locals),
|
| - fieldScope = new FieldInitializationScope.from(other.fieldScope),
|
| + LocalsHandler.topLevelCopyOf(LocalsHandler<T> other)
|
| + : locals = new VariableScope<T>.topLevelCopyOf(other.locals),
|
| + fieldScope = new FieldInitializationScope<T>.from(other.fieldScope),
|
| captured = other.captured,
|
| capturedAndBoxed = other.capturedAndBoxed,
|
| tryBlock = other.tryBlock,
|
| @@ -308,16 +309,16 @@ class LocalsHandler {
|
| }
|
| }
|
|
|
| - void update(LocalElement local, TypeInformation type, Node node) {
|
| + void update(Local local, TypeInformation type, T node, DartType staticType,
|
| + {bool isSetIfNull: false}) {
|
| assert(type != null);
|
| if (options.trustTypeAnnotations || options.enableTypeAssertions) {
|
| - type = types.narrowType(type, local.type);
|
| + type = types.narrowType(type, staticType);
|
| }
|
| updateLocal() {
|
| TypeInformation currentType = locals[local];
|
|
|
| - SendSet send = node != null ? node.asSendSet() : null;
|
| - if (send != null && send.isIfNullAssignment && currentType != null) {
|
| + if (isSetIfNull && currentType != null) {
|
| // If-null assignments may return either the new or the original value
|
| // narrowed to non-null.
|
| type = types.addPhiInput(
|
| @@ -354,6 +355,13 @@ class LocalsHandler {
|
| }
|
| }
|
|
|
| + void narrow(Local local, DartType type, T node, {bool isSetIfNull: false}) {
|
| + TypeInformation existing = use(local);
|
| + TypeInformation newType =
|
| + types.narrowType(existing, type, isNullable: false);
|
| + update(local, newType, node, type, isSetIfNull: isSetIfNull);
|
| + }
|
| +
|
| void setCaptured(Local local, FieldEntity field) {
|
| captured[local] = field;
|
| }
|
| @@ -362,7 +370,8 @@ class LocalsHandler {
|
| capturedAndBoxed[local] = field;
|
| }
|
|
|
| - void mergeDiamondFlow(LocalsHandler thenBranch, LocalsHandler elseBranch) {
|
| + void mergeDiamondFlow(
|
| + LocalsHandler<T> thenBranch, LocalsHandler<T> elseBranch) {
|
| if (fieldScope != null && elseBranch != null) {
|
| fieldScope.mergeDiamondFlow(thenBranch.fieldScope, elseBranch.fieldScope);
|
| }
|
| @@ -374,7 +383,7 @@ class LocalsHandler {
|
| elseBranch.seenBreakOrContinue;
|
| if (aborts) return;
|
|
|
| - void mergeOneBranch(LocalsHandler other) {
|
| + void mergeOneBranch(LocalsHandler<T> other) {
|
| other.locals.forEachOwnLocal((Local local, TypeInformation type) {
|
| TypeInformation myType = locals[local];
|
| if (myType == null) return; // Variable is only defined in [other].
|
| @@ -383,7 +392,7 @@ class LocalsHandler {
|
| });
|
| }
|
|
|
| - void inPlaceUpdateOneBranch(LocalsHandler other) {
|
| + void inPlaceUpdateOneBranch(LocalsHandler<T> other) {
|
| other.locals.forEachOwnLocal((Local local, TypeInformation type) {
|
| TypeInformation myType = locals[local];
|
| if (myType == null) return; // Variable is only defined in [other].
|
| @@ -453,17 +462,17 @@ class LocalsHandler {
|
| * where [:this:] is the [LocalsHandler] for the paths through the
|
| * labeled statement that do not break out.
|
| */
|
| - void mergeAfterBreaks(List<LocalsHandler> handlers,
|
| + void mergeAfterBreaks(List<LocalsHandler<T>> handlers,
|
| {bool keepOwnLocals: true}) {
|
| - Node level = locals.block;
|
| + T level = locals.block;
|
| // Use a separate locals handler to perform the merge in, so that Phi
|
| // creation does not invalidate previous type knowledge while we might
|
| // still look it up.
|
| - LocalsHandler merged = new LocalsHandler.from(this, level);
|
| + LocalsHandler<T> merged = new LocalsHandler<T>.from(this, level);
|
| Set<Local> seenLocals = new Setlet<Local>();
|
| bool allBranchesAbort = true;
|
| // Merge all other handlers.
|
| - for (LocalsHandler handler in handlers) {
|
| + for (LocalsHandler<T> handler in handlers) {
|
| allBranchesAbort = allBranchesAbort && handler.seenReturnOrThrow;
|
| merged.mergeHandler(handler, seenLocals);
|
| }
|
| @@ -493,7 +502,7 @@ class LocalsHandler {
|
| * unless the local is already present in the set [seen]. This effectively
|
| * overwrites the current type knowledge in this handler.
|
| */
|
| - bool mergeHandler(LocalsHandler other, [Set<Local> seen]) {
|
| + bool mergeHandler(LocalsHandler<T> other, [Set<Local> seen]) {
|
| if (other.seenReturnOrThrow) return false;
|
| bool changed = false;
|
| other.locals.forEachLocalUntilNode(locals.block, (local, otherType) {
|
| @@ -528,7 +537,7 @@ class LocalsHandler {
|
| return changed;
|
| }
|
|
|
| - void startLoop(Node loop) {
|
| + void startLoop(T loop) {
|
| locals.forEachLocal((Local variable, TypeInformation type) {
|
| TypeInformation newType = types.allocateLoopPhi(loop, variable, type,
|
| isTry: loop is TryStatement);
|
| @@ -538,7 +547,7 @@ class LocalsHandler {
|
| });
|
| }
|
|
|
| - void endLoop(Node loop) {
|
| + void endLoop(T loop) {
|
| locals.forEachLocal((Local variable, TypeInformation type) {
|
| TypeInformation newType = types.simplifyPhi(loop, variable, type);
|
| if (newType != type) {
|
| @@ -547,7 +556,7 @@ class LocalsHandler {
|
| });
|
| }
|
|
|
| - void updateField(Element element, TypeInformation type) {
|
| + void updateField(FieldEntity element, TypeInformation type) {
|
| fieldScope.updateField(element, type);
|
| }
|
| }
|
|
|