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

Unified Diff: editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/resolver/ResolverVisitor.java

Issue 34523011: Issue 13807. Support for type promotion rules. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updates after review comments 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: editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/resolver/ResolverVisitor.java
diff --git a/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/resolver/ResolverVisitor.java b/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/resolver/ResolverVisitor.java
index 0e42f1d2217fc847be827062aa97af0f665fa742..7af9af2859090802cfa7abc112fb9e2027f904fb 100644
--- a/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/resolver/ResolverVisitor.java
+++ b/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/resolver/ResolverVisitor.java
@@ -68,8 +68,10 @@ import com.google.dart.engine.ast.ThrowExpression;
import com.google.dart.engine.ast.TopLevelVariableDeclaration;
import com.google.dart.engine.ast.TypeName;
import com.google.dart.engine.ast.WhileStatement;
+import com.google.dart.engine.ast.visitor.RecursiveASTVisitor;
import com.google.dart.engine.element.ClassElement;
import com.google.dart.engine.element.Element;
+import com.google.dart.engine.element.ElementKind;
import com.google.dart.engine.element.ExecutableElement;
import com.google.dart.engine.element.LibraryElement;
import com.google.dart.engine.element.LocalVariableElement;
@@ -79,6 +81,7 @@ import com.google.dart.engine.element.VariableElement;
import com.google.dart.engine.error.AnalysisError;
import com.google.dart.engine.error.AnalysisErrorListener;
import com.google.dart.engine.error.ErrorCode;
+import com.google.dart.engine.internal.element.VariableElementImpl;
import com.google.dart.engine.scanner.Token;
import com.google.dart.engine.scanner.TokenType;
import com.google.dart.engine.source.Source;
@@ -129,6 +132,11 @@ public class ResolverVisitor extends ScopedVisitor {
private TypeOverrideManager overrideManager = new TypeOverrideManager();
/**
+ * The object keeping track of which elements have had their types promoted.
+ */
+ private TypePromotionManager promoteManager = new TypePromotionManager();
+
+ /**
* Proxy conditional error codes.
*/
private ArrayList<ProxyConditionalAnalysisError> proxyConditionalAnalysisErrors = new ArrayList<ProxyConditionalAnalysisError>();
@@ -174,6 +182,15 @@ public class ResolverVisitor extends ScopedVisitor {
return overrideManager;
}
+ /**
+ * Return the object keeping track of which elements have had their types promoted.
+ *
+ * @return the object keeping track of which elements have had their types promoted
+ */
+ public TypePromotionManager getPromoteManager() {
+ return promoteManager;
+ }
+
public ArrayList<ProxyConditionalAnalysisError> getProxyConditionalAnalysisErrors() {
return proxyConditionalAnalysisErrors;
}
@@ -202,10 +219,18 @@ public class ResolverVisitor extends ScopedVisitor {
if (rightOperand != null) {
try {
overrideManager.enterScope();
+ promoteManager.enterScope();
propagateTrueState(leftOperand);
+ // Type promotion.
+ promoteTypes(leftOperand);
+ clearTypePromotionsIfPotentiallyMutatedIn(leftOperand);
+ clearTypePromotionsIfPotentiallyMutatedIn(rightOperand);
+ clearTypePromotionsIfAccessedInScopeAndProtentiallyMutated(rightOperand);
+ // Visit right operand.
rightOperand.accept(this);
} finally {
overrideManager.exitScope();
+ promoteManager.exitScope();
}
}
} else if (operatorType == TokenType.BAR_BAR) {
@@ -516,11 +541,18 @@ public class ResolverVisitor extends ScopedVisitor {
if (thenStatement != null) {
try {
overrideManager.enterScope();
+ promoteManager.enterScope();
propagateTrueState(condition);
+ // Type promotion.
+ promoteTypes(condition);
+ clearTypePromotionsIfPotentiallyMutatedIn(thenStatement);
+ clearTypePromotionsIfAccessedInScopeAndProtentiallyMutated(thenStatement);
+ // Visit "then".
visitStatementInScope(thenStatement);
} finally {
thenOverrides = overrideManager.captureLocalOverrides();
overrideManager.exitScope();
+ promoteManager.exitScope();
}
}
HashMap<Element, Type> elseOverrides = null;
@@ -792,6 +824,32 @@ public class ResolverVisitor extends ScopedVisitor {
}
/**
+ * Return the static element associated with the given expression whose type can be promoted, or
+ * {@code null} if there is no element whose type can be promoted.
+ *
+ * @param expression the expression with which the element is associated
+ * @return the element associated with the given expression
+ */
+ protected VariableElement getPromotionStaticElement(Expression expression) {
+ if (!(expression instanceof SimpleIdentifier)) {
+ return null;
+ }
+ SimpleIdentifier identifier = (SimpleIdentifier) expression;
+ Element element = identifier.getStaticElement();
+ if (!(element instanceof VariableElement)) {
+ return null;
+ }
+ ElementKind kind = element.getKind();
+ if (kind == ElementKind.LOCAL_VARIABLE) {
+ return (VariableElement) element;
+ }
+ if (kind == ElementKind.PARAMETER) {
+ return (VariableElement) element;
+ }
+ return null;
+ }
+
+ /**
* If it is appropriate to do so, override the current type of the static and propagated elements
* associated with the given expression with the given type. Generally speaking, it is appropriate
* if the given type is more specific than the current type.
@@ -836,6 +894,48 @@ public class ResolverVisitor extends ScopedVisitor {
}
/**
+ * If it is appropriate to do so, promotes the current type of the static element associated with
+ * the given expression with the given type. Generally speaking, it is appropriate if the given
+ * type is more specific than the current type.
+ *
+ * @param expression the expression used to access the static element whose types might be
+ * promoted
+ * @param potentialType the potential type of the elements
+ */
+ protected void promote(Expression expression, Type potentialType) {
+ VariableElement element = getPromotionStaticElement(expression);
+ if (element != null) {
+ promote(element, potentialType);
+ }
+ }
+
+ /**
+ * If it is appropriate to do so, promotes the current type of the given element with the given
+ * type. Generally speaking, it is appropriate if the given type is more specific than the current
+ * type.
+ *
+ * @param element the element whose type might be promoted
+ * @param potentialType the potential type of the element
+ */
+ protected void promote(VariableElement element, Type potentialType) {
+ // Declared type should not be "dynamic".
+ Type type = element.getType();
+ if (type == null || type.isDynamic()) {
+ return;
+ }
+ // Promoted type should not be "dynamic".
+ if (potentialType == null || potentialType.isDynamic()) {
+ return;
+ }
+ // Promoted type should be more specific than declared.
+ if (!potentialType.isMoreSpecificThan(type)) {
+ return;
+ }
+ // Do promote type of variable.
+ promoteManager.setType(element, potentialType);
+ }
+
+ /**
* Report a conditional analysis error with the given error code and arguments.
*
* @param enclosingElement the enclosing element
@@ -939,6 +1039,37 @@ public class ResolverVisitor extends ScopedVisitor {
}
/**
+ * Checks each promoted variable in the current scope for compliance with the following
+ * specification statement:
+ * <p>
+ * If the variable <i>v</i> is accessed by a closure in <i>s<sub>1</sub></i> then the variable
+ * <i>v</i> is not potentially mutated anywhere in the scope of <i>v</i>.
+ */
+ private void clearTypePromotionsIfAccessedInScopeAndProtentiallyMutated(ASTNode target) {
+ for (Element element : promoteManager.getPromotedElements()) {
+ if (((VariableElementImpl) element).isPotentiallyMutated()) {
+ if (isVariableAccessedInClosure(element, target)) {
+ promoteManager.setType(element, null);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks each promoted variable in the current scope for compliance with the following
+ * specification statement:
+ * <p>
+ * <i>v</i> is not potentially mutated in <i>s<sub>1</sub></i> or within a closure.
+ */
+ private void clearTypePromotionsIfPotentiallyMutatedIn(ASTNode target) {
+ for (Element element : promoteManager.getPromotedElements()) {
+ if (isVariablePotentiallyMutatedIn(element, target)) {
+ promoteManager.setType(element, null);
+ }
+ }
+ }
+
+ /**
* Return the best type information available for the given element. If the type of the element
* has been overridden, then return the overriding type. Otherwise, return the static type.
*
@@ -1083,6 +1214,95 @@ public class ResolverVisitor extends ScopedVisitor {
}
/**
+ * Return {@code true} if the given variable is accessed within a closure in the given
+ * {@link ASTNode} and also mutated somewhere in variable scope. This information is only
+ * available for local variables (including parameters).
+ *
+ * @param variable the variable to check
+ * @param target the {@link ASTNode} to check within
+ * @return {@code true} if this variable is potentially mutated somewhere in the given ASTNode
+ */
+ private boolean isVariableAccessedInClosure(final Element variable, ASTNode target) {
+ final boolean[] result = {false};
+ target.accept(new RecursiveASTVisitor<Void>() {
+ private boolean inClosure = false;
+
+ @Override
+ public Void visitFunctionExpression(FunctionExpression node) {
+ boolean inClosure = this.inClosure;
+ try {
+ this.inClosure = true;
+ return super.visitFunctionExpression(node);
+ } finally {
+ this.inClosure = inClosure;
+ }
+ }
+
+ @Override
+ public Void visitSimpleIdentifier(SimpleIdentifier node) {
+ if (result[0]) {
+ return null;
+ }
+ if (inClosure && node.getStaticElement() == variable) {
+ result[0] |= true;
+ }
+ return null;
+ }
+ });
+ return result[0];
+ }
+
+ /**
+ * Return {@code true} if the given variable is potentially mutated somewhere in the given
+ * {@link ASTNode}. This information is only available for local variables (including parameters).
+ *
+ * @param variable the variable to check
+ * @param target the {@link ASTNode} to check within
+ * @return {@code true} if this variable is potentially mutated somewhere in the given ASTNode
+ */
+ private boolean isVariablePotentiallyMutatedIn(final Element variable, ASTNode target) {
+ final boolean[] result = {false};
+ target.accept(new RecursiveASTVisitor<Void>() {
+ @Override
+ public Void visitSimpleIdentifier(SimpleIdentifier node) {
+ if (result[0]) {
+ return null;
+ }
+ if (node.getStaticElement() == variable) {
+ if (node.inSetterContext()) {
+ result[0] |= true;
+ }
+ }
+ return null;
+ }
+ });
+ return result[0];
+ }
+
+ /**
+ * Promotes type information using given condition.
+ */
+ private void promoteTypes(Expression condition) {
+ if (condition instanceof BinaryExpression) {
+ BinaryExpression binary = (BinaryExpression) condition;
+ if (binary.getOperator().getType() == TokenType.AMPERSAND_AMPERSAND) {
+ Expression left = binary.getLeftOperand();
+ Expression right = binary.getRightOperand();
+ promoteTypes(left);
+ promoteTypes(right);
+ clearTypePromotionsIfPotentiallyMutatedIn(right);
+ }
+ } else if (condition instanceof IsExpression) {
+ IsExpression is = (IsExpression) condition;
+ if (is.getNotOperator() == null) {
+ promote(is.getExpression(), is.getType().getType());
+ }
+ } else if (condition instanceof ParenthesizedExpression) {
+ promoteTypes(((ParenthesizedExpression) condition).getExpression());
+ }
+ }
+
+ /**
* Propagate any type information that results from knowing that the given condition will have
* been evaluated to 'false'.
*

Powered by Google App Engine
This is Rietveld 408576698