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

Unified Diff: sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart

Issue 19784005: Cleanup in the type inferrer. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 5 months 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/types/inferrer_visitor.dart
===================================================================
--- sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart (revision 25331)
+++ sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart (working copy)
@@ -48,11 +48,6 @@
* [secondType].
*/
T computeLUB(T firstType, T secondType);
-
- /**
- * Returns the type inferred by the inferrer for [element].
- */
- T getTypeOfCapturedAndBoxedVariable(Element element);
}
/**
@@ -121,10 +116,6 @@
TypeMask nonNullExact(DartType type) => new TypeMask.nonNullExact(type);
TypeMask nonNullEmpty() => new TypeMask.nonNullEmpty();
- TypeMask getTypeOfCapturedAndBoxedVariable(Element element) {
- return compiler.typesTask.typesInferrer.getTypeOfElement(element);
- }
-
TypeMask nullable(TypeMask type) {
return type.nullable();
}
@@ -205,17 +196,61 @@
}
}
+class FieldInitializationScope<T> {
+ final TypeSystem<T> types;
+ final Map<Element, T> fields;
+ bool isThisExposed;
+
+ FieldInitializationScope(this.types)
+ : fields = new Map<Element, T>(),
+ isThisExposed = false;
+
+ FieldInitializationScope.internalFrom(FieldInitializationScope<T> other)
+ : fields = new Map<Element, T>.from(other.fields),
+ types = other.types,
+ isThisExposed = other.isThisExposed;
+
+ factory FieldInitializationScope.from(FieldInitializationScope other) {
+ if (other == null) return null;
+ return new FieldInitializationScope<T>.internalFrom(other);
+ }
+
+ void updateField(Element field, T type) {
+ if (isThisExposed) return;
+ fields[field] = type;
+ }
+
+ void merge(FieldInitializationScope other) {
+ isThisExposed = isThisExposed || other.isThisExposed;
+ List<Element> toRemove = <Element>[];
+ // Iterate over the map in [:this:]. The map in [other] may
+ // contain different fields, but if this map does not contain it,
+ // then we know the field can be null and we don't need to track
+ // it.
+ fields.forEach((Element field, T type) {
+ T otherType = other.fields[field];
+ if (otherType == null) {
+ toRemove.add(field);
+ } else {
+ fields[field] = types.computeLUB(type, otherType);
+ }
+ });
+ // Remove fields that were not initialized in [other].
+ toRemove.forEach((Element element) { fields.remove(element); });
+ }
+}
+
/**
* Placeholder for inferred types of local variables.
*/
class LocalsHandler<T> {
final Compiler compiler;
final TypeSystem<T> types;
+ final InferrerEngine<T> inferrer;
final VariableScope<T> locals;
final Map<Element, Element> capturedAndBoxed;
- final Map<Element, T> fieldsInitializedInConstructor;
+ final FieldInitializationScope<T> fieldScope;
final bool inTryBlock;
- bool isThisExposed;
bool seenReturnOrThrow = false;
bool seenBreakOrContinue = false;
@@ -223,57 +258,51 @@
return seenReturnOrThrow || seenBreakOrContinue;
}
- LocalsHandler(this.types, this.compiler)
+ LocalsHandler(this.inferrer, this.types, this.compiler, [this.fieldScope])
: locals = new VariableScope<T>(),
capturedAndBoxed = new Map<Element, Element>(),
- fieldsInitializedInConstructor = new Map<Element, T>(),
- inTryBlock = false,
- isThisExposed = true;
+ inTryBlock = false;
- LocalsHandler.from(LocalsHandler<T> other, {bool inTryBlock: false})
+ LocalsHandler.from(LocalsHandler<T> other, {bool inTryBlock})
: locals = new VariableScope<T>(other.locals),
- capturedAndBoxed = new Map<Element, Element>.from(
- other.capturedAndBoxed),
- fieldsInitializedInConstructor = new Map<Element, T>.from(
- other.fieldsInitializedInConstructor),
- inTryBlock = other.inTryBlock || inTryBlock,
+ fieldScope = new FieldInitializationScope<T>.from(other.fieldScope),
+ capturedAndBoxed = other.capturedAndBoxed,
+ inTryBlock = inTryBlock == null ? other.inTryBlock : inTryBlock,
types = other.types,
- compiler = other.compiler,
- isThisExposed = other.isThisExposed;
+ inferrer = other.inferrer,
+ compiler = other.compiler;
LocalsHandler.deepCopyOf(LocalsHandler<T> other)
: locals = new VariableScope<T>.deepCopyOf(other.locals),
- capturedAndBoxed = new Map<Element, Element>.from(
- other.capturedAndBoxed),
- fieldsInitializedInConstructor = new Map<Element, T>.from(
- other.fieldsInitializedInConstructor),
+ fieldScope = new FieldInitializationScope<T>.from(other.fieldScope),
+ capturedAndBoxed = other.capturedAndBoxed,
inTryBlock = other.inTryBlock,
types = other.types,
- compiler = other.compiler,
- isThisExposed = other.isThisExposed;
+ inferrer = other.inferrer,
+ compiler = other.compiler;
T use(Element local) {
- if (capturedAndBoxed.containsKey(local)) {
- return types.getTypeOfCapturedAndBoxedVariable(capturedAndBoxed[local]);
- }
- return locals[local];
+ return capturedAndBoxed.containsKey(local)
+ ? inferrer.typeOfElement(capturedAndBoxed[local])
+ : locals[local];
}
- void update(Element local, T type) {
+ void update(Element local, T type, Node node) {
assert(type != null);
if (compiler.trustTypeAnnotations || compiler.enableTypeAssertions) {
type = types.narrowType(type, local.computeType(compiler));
}
- if (capturedAndBoxed.containsKey(local) || inTryBlock) {
- // If a local is captured and boxed, or is set in a try block,
- // we compute the LUB of its assignments.
- //
+ if (capturedAndBoxed.containsKey(local)) {
+ inferrer.recordTypeOfNonFinalField(
+ node, capturedAndBoxed[local], type, null);
+ } else if (inTryBlock) {
// We don't know if an assignment in a try block
// will be executed, so all assigments in that block are
// potential types after we have left it.
- type = types.computeLUB(locals[local], type);
+ locals[local] = types.computeLUB(locals[local], type);
+ } else {
+ locals[local] = type;
}
- locals[local] = type;
}
void setCapturedAndBoxed(Element local, Element field) {
@@ -295,10 +324,10 @@
currentOther.forEachOwnLocal((Element local, T otherType) {
T myType = locals[local];
if (myType == null) return;
- bool isCaptured = capturedAndBoxed.containsKey(local);
- if (!isCaptured && aborts && discardIfAborts) {
+ if (capturedAndBoxed.containsKey(local)) return;
+ if (aborts && discardIfAborts) {
locals[local] = otherType;
- } else if (!isCaptured && other.aborts && discardIfAborts) {
+ } else if (other.aborts && discardIfAborts) {
// Don't do anything.
} else {
T type = types.computeLUB(myType, otherType);
@@ -314,10 +343,8 @@
List<Element> toRemove = <Element>[];
locals.forEachOwnLocal((Element local, _) {
- bool isCaptured = capturedAndBoxed.containsKey(local);
- if (other.locals[local] == null && !isCaptured) {
- // If [local] is not in the other map and is not captured
- // and boxed, we know it is not a
+ if (other.locals[local] == null) {
+ // If [local] is not in the other map we know it is not a
// local we want to keep. For example, in an if/else, we don't
// want to keep variables declared in the if or in the else
// branch at the merge point.
@@ -330,39 +357,10 @@
locals.remove(element);
});
- // Update the locals that are captured and boxed. We
- // unconditionally add them to [this] because we register the type
- // of boxed variables after analyzing all closures.
- other.capturedAndBoxed.forEach((Element local, Element field) {
- capturedAndBoxed[local] = field;
- // If [element] is not in our [locals], we need to update it.
- // Otherwise, we have already computed the LUB of it.
- if (locals[local] == null && other.locals[local] != null) {
- locals[local] = other.locals[local];
- }
- });
+ if (fieldScope != null) {
+ fieldScope.merge(other.fieldScope);
+ }
- // Merge instance fields initialized in both handlers. This is
- // only relevant for generative constructors.
- toRemove = <Element>[];
- // Iterate over the map in [:this:]. The map in [other] may
- // contain different fields, but if this map does not contain it,
- // then we know the field can be null and we don't need to track
- // it.
- fieldsInitializedInConstructor.forEach((Element element, T type) {
- T otherType = other.fieldsInitializedInConstructor[element];
- if (otherType == null) {
- toRemove.add(element);
- } else {
- fieldsInitializedInConstructor[element] =
- types.computeLUB(type, otherType);
- }
- });
- // Remove fields that were not initialized in [other].
- toRemove.forEach((Element element) {
- fieldsInitializedInConstructor.remove(element);
- });
- isThisExposed = isThisExposed || other.isThisExposed;
seenReturnOrThrow = seenReturnOrThrow && other.seenReturnOrThrow;
seenBreakOrContinue = seenBreakOrContinue && other.seenBreakOrContinue;
@@ -370,16 +368,14 @@
}
void updateField(Element element, T type) {
- if (isThisExposed) return;
- fieldsInitializedInConstructor[element] = type;
+ fieldScope.updateField(element, type);
}
}
abstract class InferrerVisitor<T> extends ResolvedVisitor<T> {
final Element analyzedElement;
- // Subclasses know more about this field. Typing it dynamic to avoid
- // warnings.
final TypeSystem<T> types;
+ final InferrerEngine<T> inferrer;
final Compiler compiler;
final Map<TargetElement, List<LocalsHandler<T>>> breaksFor =
new Map<TargetElement, List<LocalsHandler<T>>>();
@@ -393,19 +389,32 @@
int loopLevel = 0;
bool get inLoop => loopLevel > 0;
- bool get isThisExposed => locals.isThisExposed;
- void set isThisExposed(value) { locals.isThisExposed = value; }
+ bool get isThisExposed {
+ return analyzedElement.isGenerativeConstructor()
+ ? locals.fieldScope.isThisExposed
+ : true;
+ }
+ void set isThisExposed(value) {
+ if (analyzedElement.isGenerativeConstructor()) {
+ locals.fieldScope.isThisExposed = value;
+ }
+ }
InferrerVisitor(Element analyzedElement,
+ this.inferrer,
this.types,
Compiler compiler,
[LocalsHandler<T> handler])
: this.compiler = compiler,
this.analyzedElement = analyzedElement,
+ this.locals = handler,
super(compiler.enqueuer.resolution.getCachedElements(analyzedElement)) {
- locals = (handler == null)
- ? new LocalsHandler<T>(types, compiler)
- : handler;
+ if (handler != null) return;
+ FieldInitializationScope<T> fieldScope =
+ analyzedElement.isGenerativeConstructor()
+ ? new FieldInitializationScope<T>(types)
+ : null;
+ locals = new LocalsHandler<T>(inferrer, types, compiler, fieldScope);
}
T visitSendSet(SendSet node);
@@ -424,6 +433,8 @@
T visitReturn(Return node);
+ T visitFunctionExpression(FunctionExpression node);
+
T visitNode(Node node) {
node.visitChildren(this);
}
@@ -436,13 +447,8 @@
return node == null ? null : node.accept(this);
}
- T visitFunctionExpression(FunctionExpression node) {
- node.visitChildren(this);
- return types.functionType;
- }
-
T visitFunctionDeclaration(FunctionDeclaration node) {
- locals.update(elements[node], types.functionType);
+ locals.update(elements[node], types.functionType, node);
return visit(node.function);
}
@@ -549,7 +555,7 @@
Element element = elements[node.receiver];
T existing = locals.use(element);
T newType = types.narrowType(existing, type, isNullable: false);
- locals.update(element, newType);
+ locals.update(element, newType, node);
}
}
@@ -640,7 +646,7 @@
link = link.tail) {
Node definition = link.head;
if (definition is Identifier) {
- locals.update(elements[definition], types.nullType);
+ locals.update(elements[definition], types.nullType, node);
} else {
assert(definition.asSendSet() != null);
visit(definition);
@@ -782,11 +788,11 @@
T mask = type == null
? types.dynamicType
: types.nonNullSubtype(type.asRaw());
- locals.update(elements[exception], mask);
+ locals.update(elements[exception], mask, node);
}
Node trace = node.trace;
if (trace != null) {
- locals.update(elements[trace], types.dynamicType);
+ locals.update(elements[trace], types.dynamicType, node);
}
visit(node.block);
}

Powered by Google App Engine
This is Rietveld 408576698