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

Unified Diff: sdk/lib/_internal/compiler/implementation/typechecker.dart

Issue 26232003: Support type promotion in dart2js. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updated to latest spec change Created 7 years, 2 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/typechecker.dart
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index aa24ea04a001e93e7c04b384164110ba082d59e6..8545eaadd48657314f7c3b8f58c3a8d318889b2f 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -113,6 +113,21 @@ class ResolvedAccess extends ElementAccess {
String toString() => 'ResolvedAccess($element)';
}
+/// An access to a promoted variable.
+class PromotedAccess extends ElementAccess {
+ final VariableElement element;
+ final DartType type;
+
+ PromotedAccess(VariableElement this.element, DartType this.type) {
+ assert(element != null);
+ assert(type != null);
+ }
+
+ DartType computeType(Compiler compiler) => type;
+
+ String toString() => 'PromotedAccess($element,$type)';
+}
+
/**
* An access of a resolved top-level or static property or function, or an
* access of a resolved element through [:this:].
@@ -167,6 +182,46 @@ class TypeCheckerVisitor extends Visitor<DartType> {
DartType objectType;
DartType listType;
+ Map<Node, Map<VariableElement, DartType>> shownTypesMap =
+ new Map<Node, Map<VariableElement, DartType>>();
+
+ Map<VariableElement, Link<DartType>> knownTypesMap =
+ new Map<VariableElement, Link<DartType>>();
+
+ void showType(Node node, VariableElement element, DartType type) {
+ Map<VariableElement, DartType> shownTypes = shownTypesMap.putIfAbsent(node,
+ () => new Map<VariableElement, DartType>());
+ shownTypes[element] = type;
+ }
+
+ void registerKnownType(VariableElement element, DartType type) {
+ Link<DartType> knownTypes =
+ knownTypesMap.putIfAbsent(element, () => const Link<DartType>());
+ knownTypesMap[element] = knownTypes.prepend(type);
+ }
+
+ void unregisterKnownType(VariableElement element) {
+ Link<DartType> knownTypes = knownTypesMap[element].tail;
+ if (knownTypes.isEmpty) {
+ knownTypesMap.remove(element);
+ } else {
+ knownTypesMap[element] = knownTypes;
+ }
+ }
+
+ Map<VariableElement, DartType> getShownTypesFor(Node node) {
+ Map<VariableElement, DartType> shownTypes = shownTypesMap[node];
+ return shownTypes != null ? shownTypes : const {};
+ }
+
+ DartType getKnownType(VariableElement element) {
+ Link<DartType> promotions = knownTypesMap[element];
+ if (promotions != null) {
+ return promotions.head;
+ }
+ return element.computeType(compiler);
+ }
+
TypeCheckerVisitor(this.compiler, TreeElements elements, this.types)
: this.elements = elements,
currentClass = elements.currentElement != null
@@ -230,6 +285,32 @@ class TypeCheckerVisitor extends Visitor<DartType> {
return result;
}
+ /// Analyze [node] in the context of the known types shown in [context].
+ DartType analyzeInPromotedContext(Node context, Node node) {
+ Link<VariableElement> knownForArgument = const Link<VariableElement>();
+ Map<VariableElement, DartType> shownForReceiver =
+ getShownTypesFor(context);
+ shownForReceiver.forEach((VariableElement variable, DartType type) {
+ if (elements.isPotentiallyMutatedIn(node, variable)) return;
+ if (elements.isPotentiallyMutatedInClosure(variable)) return;
+ if (elements.isAccessedByClosureIn(node, variable) &&
+ elements.isPotentiallyMutated(variable)) {
+ return;
+ }
+ knownForArgument = knownForArgument.prepend(variable);
+ registerKnownType(variable, type);
+ });
+
+ final DartType type = analyze(node);
+
+ while (!knownForArgument.isEmpty) {
+ unregisterKnownType(knownForArgument.head);
+ knownForArgument = knownForArgument.tail;
+ }
+
+ return type;
+ }
+
/**
* Check if a value of type t can be assigned to a variable,
* parameter or return value of type s.
@@ -371,8 +452,13 @@ class TypeCheckerVisitor extends Visitor<DartType> {
}
DartType visitIf(If node) {
+ Expression condition = node.condition.expression;
+ Statement thenPart = node.thenPart;
+
checkCondition(node.condition);
- StatementType thenType = analyze(node.thenPart);
+
+ StatementType thenType = analyzeInPromotedContext(condition, thenPart);
+
StatementType elseType = node.hasElsePart ? analyze(node.elsePart)
: StatementType.NOT_RETURNING;
return thenType.join(elseType);
@@ -538,6 +624,7 @@ class TypeCheckerVisitor extends Visitor<DartType> {
analyzeArguments(node, elementAccess.element, types.dynamicType,
argumentTypes);
}
+ type = type.unalias(compiler);
if (identical(type.kind, TypeKind.FUNCTION)) {
FunctionType funType = type;
return funType.returnType;
@@ -621,6 +708,16 @@ class TypeCheckerVisitor extends Visitor<DartType> {
ElementAccess createResolvedAccess(Send node, SourceString name,
Element element) {
checkPrivateAccess(node, element, name);
+ return createPromotedAccess(element);
+ }
+
+ ElementAccess createPromotedAccess(Element element) {
+ if (element.isVariable() || element.isParameter()) {
+ Link<DartType> knownTypes = knownTypesMap[element];
+ if (knownTypes != null) {
+ return new PromotedAccess(element, knownTypes.head);
+ }
+ }
return new ResolvedAccess(element);
}
@@ -660,7 +757,7 @@ class TypeCheckerVisitor extends Visitor<DartType> {
if (Elements.isClosureSend(node, element)) {
if (element != null) {
// foo() where foo is a local or a parameter.
- return analyzeInvocation(node, new ResolvedAccess(element));
+ return analyzeInvocation(node, createPromotedAccess(element));
} else {
// exp() where exp is some complex expression like (o) or foo().
DartType type = analyze(node.selector);
@@ -673,6 +770,19 @@ class TypeCheckerVisitor extends Visitor<DartType> {
if (node.isOperator && identical(name, 'is')) {
analyze(node.receiver);
+ if (!node.isIsNotCheck) {
+ Element variable = elements[node.receiver];
+ if (variable != null &&
+ (variable.isVariable() || variable.isParameter())) {
+ DartType knownType = getKnownType(variable);
+ if (!knownType.isDynamic) {
+ DartType isType = elements.getType(node.arguments.head);
+ if (types.isMoreSpecific(isType, knownType)) {
+ showType(node, variable, isType);
+ }
+ }
+ }
+ }
return boolType;
} if (node.isOperator && identical(name, 'as')) {
analyze(node.receiver);
@@ -686,13 +796,30 @@ class TypeCheckerVisitor extends Visitor<DartType> {
// Analyze argument.
analyze(node.arguments.head);
return boolType;
- } else if (identical(name, '||') ||
- identical(name, '&&')) {
+ } else if (identical(name, '||')) {
checkAssignable(receiver, receiverType, boolType);
final Node argument = node.arguments.head;
final DartType argumentType = analyze(argument);
checkAssignable(argument, argumentType, boolType);
return boolType;
+ } else if (identical(name, '&&')) {
+ checkAssignable(receiver, receiverType, boolType);
+ final Node argument = node.arguments.head;
+
+ final DartType argumentType =
+ analyzeInPromotedContext(receiver, argument);
+
+ void reshowTypes(VariableElement variable, DartType type) {
+ if (elements.isPotentiallyMutatedIn(argument, variable)) return;
+ if (elements.isPotentiallyMutatedInClosure(variable)) return;
+ showType(node, variable, type);
+ }
+
+ getShownTypesFor(receiver).forEach(reshowTypes);
+ getShownTypesFor(argument).forEach(reshowTypes);
+
+ checkAssignable(argument, argumentType, boolType);
+ return boolType;
} else if (identical(name, '!')) {
checkAssignable(receiver, receiverType, boolType);
return boolType;
@@ -1124,8 +1251,13 @@ class TypeCheckerVisitor extends Visitor<DartType> {
}
DartType visitConditional(Conditional node) {
- checkCondition(node.condition);
- DartType thenType = analyzeNonVoid(node.thenExpression);
+ Expression condition = node.condition;
+ Expression thenExpression = node.thenExpression;
+
+ checkCondition(condition);
+
+ DartType thenType = analyzeInPromotedContext(condition, thenExpression);
+
DartType elseType = analyzeNonVoid(node.elseExpression);
if (types.isSubtype(thenType, elseType)) {
return thenType;
« no previous file with comments | « sdk/lib/_internal/compiler/implementation/resolution/members.dart ('k') | tests/compiler/dart2js/type_promotion_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698