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

Unified Diff: pkg/analyzer/lib/src/generated/resolver.dart

Side-by-side diff isn't available for this file because of its large size.
Issue 561373002: Issue 19682. New analyzer snapshot that fixes an inline refactoring problem. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Changes for mock_sdk Created 6 years, 3 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:
Download patch
« no previous file with comments | « pkg/analyzer/lib/src/generated/parser.dart ('k') | pkg/analyzer/lib/src/generated/sdk.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/generated/resolver.dart
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 380a35d4a141288910059d09cb06dff5b4511bd6..f8ccff2fcd92337ab5de5f9e60ef266208275e65 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -4669,6 +4669,77 @@ class ElementResolver extends SimpleAstVisitor<Object> {
}
/**
+ * Return a method representing the merge of the given elements. The type of the merged element is
+ * the component-wise union of the types of the given elements. If not all input elements have the
+ * same shape then [null] is returned.
+ *
+ * @param elements the `ExecutableElement`s to merge
+ * @return an `ExecutableElement` representing the merge of `elements`
+ */
+ static ExecutableElement _computeMergedExecutableElement(Set<ExecutableElement> elements) {
+ List<ExecutableElement> elementArrayToMerge = new List.from(elements);
+ if (elementArrayToMerge.length == 0) {
+ return null;
+ } else {
+ // Flatten methods structurally. Based on
+ // [InheritanceManager.computeMergedExecutableElement] and
+ // [InheritanceManager.createSyntheticExecutableElement].
+ //
+ // However, the approach we take here is much simpler, but expected to work
+ // well in the common case. It degrades gracefully in the uncommon case,
+ // by computing the type [dynamic] for the method, preventing any
+ // hints from being generated (TODO: not done yet).
+ //
+ // The approach is: we require that each [ExecutableElement] has the
+ // same shape: the same number of required, optional positional, and optional named
+ // parameters, in the same positions, and with the named parameters in the
+ // same order. We compute a type by unioning pointwise.
+ ExecutableElement e_0 = elementArrayToMerge[0];
+ List<ParameterElement> ps_0 = e_0.parameters;
+ List<ParameterElementImpl> ps_out = new List<ParameterElementImpl>(ps_0.length);
+ for (int j = 0; j < ps_out.length; j++) {
+ ps_out[j] = new ParameterElementImpl(ps_0[j].name, 0);
+ ps_out[j].synthetic = true;
+ ps_out[j].type = ps_0[j].type;
+ ps_out[j].parameterKind = ps_0[j].parameterKind;
+ }
+ DartType r_out = e_0.returnType;
+ for (int i = 1; i < elementArrayToMerge.length; i++) {
+ ExecutableElement e_i = elementArrayToMerge[i];
+ r_out = UnionTypeImpl.union([r_out, e_i.returnType]);
+ List<ParameterElement> ps_i = e_i.parameters;
+ // Each function must have the same number of params.
+ if (ps_0.length != ps_i.length) {
+ return null;
+ } else {
+ // Each function must have the same kind of params, with the same names,
+ // in the same order.
+ for (int j = 0; j < ps_i.length; j++) {
+ if (ps_0[j].parameterKind != ps_i[j].parameterKind || !identical(ps_0[j].name, ps_i[j].name)) {
+ return null;
+ } else {
+ // The output parameter type is the union of the input parameter types.
+ ps_out[j].type = UnionTypeImpl.union([ps_out[j].type, ps_i[j].type]);
+ }
+ }
+ }
+ }
+ // TODO (collinsn): this code should work for functions and methods,
+ // so we may want [FunctionElementImpl]
+ // instead here in some cases? And then there are constructors and property accessors.
+ // Maybe the answer is to create a new subclass of [ExecutableElementImpl] which
+ // is used for merged executable elements, in analogy with [MultiplyInheritedMethodElementImpl]
+ // and [MultiplyInheritedPropertyAcessorElementImpl].
+ ExecutableElementImpl e_out = new MethodElementImpl(e_0.name, 0);
+ e_out.synthetic = true;
+ e_out.returnType = r_out;
+ e_out.parameters = ps_out;
+ e_out.type = new FunctionTypeImpl.con1(e_out);
+ return e_out;
+ }
+ }
+
+ /**
* Return `true` if the given identifier is the return type of a constructor declaration.
*
* @return `true` if the given identifier is the return type of a constructor declaration.
@@ -6237,6 +6308,19 @@ class ElementResolver extends SimpleAstVisitor<Object> {
}
return _lookUpMethodInInterfaces(interfaceType, false, methodName, new HashSet<ClassElement>());
}
+ if (type is UnionType) {
+ Set<ExecutableElement> methods = new HashSet<ExecutableElement>();
+ for (DartType t in type.elements) {
+ MethodElement m = _lookUpMethod(target, t, methodName);
+ if (m != null) {
+ methods.add(m);
+ }
+ }
+ // TODO (collinsn): I want [computeMergedExecutableElement] to be general
+ // and work with functions, methods, constructors, and property accessors. However,
+ // I won't be able to assume it returns [MethodElement] here then.
+ return _computeMergedExecutableElement(methods) as MethodElement;
+ }
return null;
}
@@ -6609,6 +6693,7 @@ class ElementResolver extends SimpleAstVisitor<Object> {
List<ParameterElement> resolvedParameters = new List<ParameterElement>(argumentCount);
int positionalArgumentCount = 0;
HashSet<String> usedNames = new HashSet<String>();
+ bool noBlankArguments = true;
for (int i = 0; i < argumentCount; i++) {
Expression argument = arguments[i];
if (argument is NamedExpression) {
@@ -6626,16 +6711,19 @@ class ElementResolver extends SimpleAstVisitor<Object> {
_resolver.reportErrorForNode(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name]);
}
} else {
+ if (argument is SimpleIdentifier && argument.name.isEmpty) {
+ noBlankArguments = false;
+ }
positionalArgumentCount++;
if (unnamedIndex < unnamedParameterCount) {
resolvedParameters[i] = unnamedParameters[unnamedIndex++];
}
}
}
- if (positionalArgumentCount < requiredParameters.length) {
+ if (positionalArgumentCount < requiredParameters.length && noBlankArguments) {
ErrorCode errorCode = (reportError ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
_resolver.reportErrorForNode(errorCode, argumentList, [requiredParameters.length, positionalArgumentCount]);
- } else if (positionalArgumentCount > unnamedParameterCount) {
+ } else if (positionalArgumentCount > unnamedParameterCount && noBlankArguments) {
ErrorCode errorCode = (reportError ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS);
_resolver.reportErrorForNode(errorCode, argumentList, [unnamedParameterCount, positionalArgumentCount]);
}
@@ -6751,14 +6839,14 @@ class ElementResolver extends SimpleAstVisitor<Object> {
* @return the element being invoked
*/
Element _resolveInvokedElementWithTarget(Expression target, DartType targetType, SimpleIdentifier methodName) {
- if (targetType is InterfaceType) {
- InterfaceType classType = targetType;
- Element element = _lookUpMethod(target, classType, methodName.name);
+ if (targetType is InterfaceType || targetType is UnionType) {
+ Element element = _lookUpMethod(target, targetType, methodName.name);
if (element == null) {
//
// If there's no method, then it's possible that 'm' is a getter that returns a function.
//
- element = _lookUpGetter(target, classType, methodName.name);
+ // TODO (collinsn): need to add union type support here too, in the style of [lookUpMethod].
+ element = _lookUpGetter(target, targetType, methodName.name);
}
return element;
} else if (target is SimpleIdentifier) {
@@ -14028,8 +14116,6 @@ class InheritanceManager {
* <b>dynamic</b>, <i>h</i> positional parameters of type <b>dynamic</b>, named parameters
* <i>s</i> of type <b>dynamic</b> and return type <b>dynamic</b>.
*
- * TODO (jwren) Associate a propagated type to the synthetic method element using least upper
- * bounds instead of dynamic
*/
static ExecutableElement _computeMergedExecutableElement(List<ExecutableElement> elementArrayToMerge) {
int h = _getNumOfPositionalParameters(elementArrayToMerge[0]);
@@ -15412,7 +15498,7 @@ class LibraryElementBuilder {
//
// Create and populate the library element.
//
- LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(_analysisContext, libraryNameNode);
+ LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(_analysisContext.getContextFor(librarySource), libraryNameNode);
libraryElement.definingCompilationUnit = definingCompilationUnitElement;
if (entryPoint != null) {
libraryElement.entryPoint = entryPoint;
@@ -15496,7 +15582,7 @@ class LibraryElementBuilder {
//
// Create and populate the library element.
//
- LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(_analysisContext, libraryNameNode);
+ LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(_analysisContext.getContextFor(librarySource), libraryNameNode);
libraryElement.definingCompilationUnit = definingCompilationUnitElement;
if (entryPoint != null) {
libraryElement.entryPoint = entryPoint;
@@ -18820,7 +18906,7 @@ class ResolverVisitor extends ScopedVisitor {
try {
super.visitFieldDeclaration(node);
} finally {
- HashMap<Element, DartType> overrides = _overrideManager.captureOverrides(node.fields);
+ Map<Element, DartType> overrides = _overrideManager.captureOverrides(node.fields);
_overrideManager.exitScope();
_overrideManager.applyOverrides(overrides);
}
@@ -18912,7 +18998,7 @@ class ResolverVisitor extends ScopedVisitor {
Object visitIfStatement(IfStatement node) {
Expression condition = node.condition;
safelyVisit(condition);
- HashMap<Element, DartType> thenOverrides = null;
+ Map<Element, DartType> thenOverrides = null;
Statement thenStatement = node.thenStatement;
if (thenStatement != null) {
_overrideManager.enterScope();
@@ -18934,7 +19020,7 @@ class ResolverVisitor extends ScopedVisitor {
_overrideManager.exitScope();
}
}
- HashMap<Element, DartType> elseOverrides = null;
+ Map<Element, DartType> elseOverrides = null;
Statement elseStatement = node.elseStatement;
if (elseStatement != null) {
_overrideManager.enterScope();
@@ -18960,10 +19046,16 @@ class ResolverVisitor extends ScopedVisitor {
if (elseOverrides != null) {
_overrideManager.applyOverrides(elseOverrides);
}
+ } else if (!thenIsAbrupt && !elseIsAbrupt) {
+ // It would be more precise to ignore the existing override for any variable that
+ // is overridden in both branches.
+ if (thenOverrides != null) {
+ _overrideManager.mergeOverrides(thenOverrides);
+ }
+ if (elseOverrides != null) {
+ _overrideManager.mergeOverrides(elseOverrides);
+ }
}
- // TODO(collinsn): union the [thenOverrides] and [elseOverrides] if both branches
- // are not abrupt. If both branches are abrupt, then we can mark the
- // remaining code as dead.
return null;
}
@@ -19086,7 +19178,7 @@ class ResolverVisitor extends ScopedVisitor {
try {
super.visitTopLevelVariableDeclaration(node);
} finally {
- HashMap<Element, DartType> overrides = _overrideManager.captureOverrides(node.variables);
+ Map<Element, DartType> overrides = _overrideManager.captureOverrides(node.variables);
_overrideManager.exitScope();
_overrideManager.applyOverrides(overrides);
}
@@ -19475,7 +19567,7 @@ class ResolverVisitor extends ScopedVisitor {
//
// In the presence of exceptions things become much more complicated, but while
// we only use this to propagate at [if]-statement join points, checking for [return]
- // is probably sound.
+ // may work well enough in the common case.
if (statement is ReturnStatement) {
return true;
} else if (statement is ExpressionStatement) {
@@ -19486,6 +19578,21 @@ class ResolverVisitor extends ScopedVisitor {
if (size == 0) {
return false;
}
+ // This last-statement-is-return heuristic is unsound for adversarial code,
+ // but probably works well in the common case:
+ //
+ // var x = 123;
+ // var c = true;
+ // L: if (c) {
+ // x = "hello";
+ // c = false;
+ // break L;
+ // return;
+ // }
+ // print(x);
+ //
+ // Unsound to assume that [x = "hello";] never executed after the if-statement.
+ // Of course, a dead-code analysis could point out that [return] here is dead.
return _isAbruptTerminationStatement(statements[size - 1]);
}
return false;
@@ -22516,7 +22623,7 @@ class TypeOverrideManager {
*
* @param overrides the overrides to be applied
*/
- void applyOverrides(HashMap<Element, DartType> overrides) {
+ void applyOverrides(Map<Element, DartType> overrides) {
if (_currentScope == null) {
throw new IllegalStateException("Cannot apply overrides without a scope");
}
@@ -22529,7 +22636,7 @@ class TypeOverrideManager {
*
* @return the overrides in the current scope
*/
- HashMap<Element, DartType> captureLocalOverrides() {
+ Map<Element, DartType> captureLocalOverrides() {
if (_currentScope == null) {
throw new IllegalStateException("Cannot capture local overrides without a scope");
}
@@ -22543,7 +22650,7 @@ class TypeOverrideManager {
* @param variableList the list of variables whose overriding types are to be captured
* @return a table mapping elements to their overriding types
*/
- HashMap<Element, DartType> captureOverrides(VariableDeclarationList variableList) {
+ Map<Element, DartType> captureOverrides(VariableDeclarationList variableList) {
if (_currentScope == null) {
throw new IllegalStateException("Cannot capture overrides without a scope");
}
@@ -22582,6 +22689,15 @@ class TypeOverrideManager {
}
/**
+ * Merge new overrides with existing overrides using union types.
+ *
+ * @param overrides the new overrides to merge in.
+ */
+ void mergeOverrides(Map<Element, DartType> overrides) {
+ _currentScope.mergeOverrides(overrides);
+ }
+
+ /**
* Set the overridden type of the given element to the given type
*
* @param element the element whose type might have been overridden
@@ -22608,7 +22724,7 @@ class TypeOverrideManager_TypeOverrideScope {
/**
* A table mapping elements to the overridden type of that element.
*/
- HashMap<Element, DartType> _overridenTypes = new HashMap<Element, DartType>();
+ Map<Element, DartType> _overridenTypes = new HashMap<Element, DartType>();
/**
* Initialize a newly created scope to be an empty child of the given scope.
@@ -22622,7 +22738,7 @@ class TypeOverrideManager_TypeOverrideScope {
*
* @param overrides the overrides to be applied
*/
- void applyOverrides(HashMap<Element, DartType> overrides) {
+ void applyOverrides(Map<Element, DartType> overrides) {
for (MapEntry<Element, DartType> entry in getMapEntrySet(overrides)) {
_overridenTypes[entry.getKey()] = entry.getValue();
}
@@ -22634,7 +22750,7 @@ class TypeOverrideManager_TypeOverrideScope {
*
* @return the overrides in the current scope
*/
- HashMap<Element, DartType> captureLocalOverrides() => _overridenTypes;
+ Map<Element, DartType> captureLocalOverrides() => _overridenTypes;
/**
* Return a map from the elements for the variables in the given list that have their types
@@ -22643,8 +22759,8 @@ class TypeOverrideManager_TypeOverrideScope {
* @param variableList the list of variables whose overriding types are to be captured
* @return a table mapping elements to their overriding types
*/
- HashMap<Element, DartType> captureOverrides(VariableDeclarationList variableList) {
- HashMap<Element, DartType> overrides = new HashMap<Element, DartType>();
+ Map<Element, DartType> captureOverrides(VariableDeclarationList variableList) {
+ Map<Element, DartType> overrides = new HashMap<Element, DartType>();
if (variableList.isConst || variableList.isFinal) {
for (VariableDeclaration variable in variableList.variables) {
Element element = variable.element;
@@ -22680,6 +22796,18 @@ class TypeOverrideManager_TypeOverrideScope {
}
/**
+ * Merge new overrides with existing overrides using union types.
+ *
+ * @param overrides the new overrides to merge in.
+ */
+ void mergeOverrides(Map<Element, DartType> overrides) {
+ for (MapEntry<Element, DartType> entry in getMapEntrySet(overrides)) {
+ Element key = entry.getKey();
+ _overridenTypes[key] = UnionTypeImpl.union([_overridenTypes[key], entry.getValue()]);
+ }
+ }
+
+ /**
* Set the overridden type of the given element to the given type
*
* @param element the element whose type might have been overridden
« no previous file with comments | « pkg/analyzer/lib/src/generated/parser.dart ('k') | pkg/analyzer/lib/src/generated/sdk.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698