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

Unified Diff: packages/analyzer/lib/src/generated/static_type_analyzer.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 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: packages/analyzer/lib/src/generated/static_type_analyzer.dart
diff --git a/analyzer/lib/src/generated/static_type_analyzer.dart b/packages/analyzer/lib/src/generated/static_type_analyzer.dart
similarity index 86%
rename from analyzer/lib/src/generated/static_type_analyzer.dart
rename to packages/analyzer/lib/src/generated/static_type_analyzer.dart
index 096c14b0abb4c95b4f5ca10dea94c34e46698db6..7362c4de016b5baacdaf6d352a1cd2f69afa72a6 100644
--- a/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/packages/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -58,6 +58,11 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
InterfaceType thisType;
/**
+ * Are we running in strong mode or not.
+ */
+ bool _strongMode;
+
+ /**
* The object keeping track of which elements have had their types overridden.
*/
TypeOverrideManager _overrideManager;
@@ -80,10 +85,11 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
*/
StaticTypeAnalyzer(this._resolver) {
_typeProvider = _resolver.typeProvider;
+ _typeSystem = _resolver.typeSystem;
_dynamicType = _typeProvider.dynamicType;
_overrideManager = _resolver.overrideManager;
_promoteManager = _resolver.promoteManager;
- _typeSystem = new TypeSystemImpl(_typeProvider);
+ _strongMode = _resolver.definingLibrary.context.analysisOptions.strongMode;
}
/**
@@ -303,6 +309,15 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
return null;
}
+ @override
+ Object visitDeclaredIdentifier(DeclaredIdentifier node) {
+ super.visitDeclaredIdentifier(node);
+ if (_strongMode) {
+ _inferForEachLoopVariableType(node);
+ }
+ return null;
+ }
+
/**
* The Dart Language Specification, 12.3: <blockquote>The static type of a literal double is
* double.</blockquote>
@@ -320,7 +335,9 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
node.element as ExecutableElementImpl;
functionElement.returnType =
_computeStaticReturnTypeOfFunctionDeclaration(node);
- _recordPropagatedTypeOfFunction(functionElement, function.body);
+ if (node.parent is FunctionDeclarationStatement) {
+ _recordPropagatedTypeOfFunction(functionElement, function.body);
+ }
_recordStaticType(function, functionElement.type);
return null;
}
@@ -543,8 +560,10 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
}
}
}
- _recordStaticType(node, _typeProvider.mapType
- .substitute4(<DartType>[staticKeyType, staticValueType]));
+ _recordStaticType(
+ node,
+ _typeProvider.mapType
+ .substitute4(<DartType>[staticKeyType, staticValueType]));
return null;
}
@@ -606,6 +625,15 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
// Check for special cases.
bool needPropagatedType = true;
String methodName = methodNameNode.name;
+ if (_strongMode) {
+ // TODO(leafp): Revisit this. It's here to associate a type with the
+ // method name, which is important to the DDC backend (but apparently
+ // no-one else). Not sure that there's a problem having this here, but
+ // it's a little ad hoc.
+ visitSimpleIdentifier(methodNameNode);
+
+ _inferMethodInvocation(node);
+ }
if (methodName == "then") {
Expression target = node.realTarget;
if (target != null) {
@@ -870,8 +898,11 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
} else if (staticElement is VariableElement) {
staticType = staticElement.type;
}
- _recordStaticType(prefixedIdentifier, staticType);
- _recordStaticType(node, staticType);
+ if (!(_strongMode &&
+ _inferObjectAccess(node, staticType, prefixedIdentifier))) {
+ _recordStaticType(prefixedIdentifier, staticType);
+ _recordStaticType(node, staticType);
+ }
Element propagatedElement = prefixedIdentifier.propagatedElement;
// HACK: special case for object getters ([hashCode] and [runtimeType]) on
// dynamic expressions. More special cases in [visitMethodInvocation].
@@ -999,8 +1030,10 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
} else {
// TODO(brianwilkerson) Report this internal error.
}
- _recordStaticType(propertyName, staticType);
- _recordStaticType(node, staticType);
+ if (!(_strongMode && _inferObjectAccess(node, staticType, propertyName))) {
+ _recordStaticType(propertyName, staticType);
+ _recordStaticType(node, staticType);
+ }
Element propagatedElement = propertyName.propagatedElement;
DartType propagatedType = _overrideManager.getType(propagatedElement);
if (propagatedElement is MethodElement) {
@@ -1182,6 +1215,9 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
@override
Object visitVariableDeclaration(VariableDeclaration node) {
Expression initializer = node.initializer;
+ if (_strongMode) {
+ _inferLocalVariableType(node, initializer);
+ }
if (initializer != null) {
DartType rightType = initializer.bestType;
SimpleIdentifier name = node.name;
@@ -1211,7 +1247,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
staticType2 = _dynamicType;
}
DartType staticType =
- _typeSystem.getLeastUpperBound(staticType1, staticType2);
+ _typeSystem.getLeastUpperBound(_typeProvider, staticType1, staticType2);
if (staticType == null) {
staticType = _dynamicType;
}
@@ -1225,8 +1261,8 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
if (propagatedType2 == null) {
propagatedType2 = staticType2;
}
- DartType propagatedType =
- _typeSystem.getLeastUpperBound(propagatedType1, propagatedType2);
+ DartType propagatedType = _typeSystem.getLeastUpperBound(
+ _typeProvider, propagatedType1, propagatedType2);
_resolver.recordPropagatedTypeIfBetter(node, propagatedType);
}
}
@@ -1276,7 +1312,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
if (body is BlockFunctionBody) {
_StaticTypeAnalyzer_computePropagatedReturnTypeOfFunction visitor =
new _StaticTypeAnalyzer_computePropagatedReturnTypeOfFunction(
- _typeSystem);
+ _typeProvider, _typeSystem);
body.accept(visitor);
return visitor.result;
}
@@ -1382,6 +1418,43 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
}
}
+ // TODO(vsm): Use leafp's matchType here?
+ DartType _findIteratedType(InterfaceType type, DartType targetType) {
+ // Set by _find if match is found
+ DartType result = null;
+ // Elements we've already visited on a given inheritance path.
+ HashSet<ClassElement> visitedClasses = null;
+
+ bool _find(InterfaceType type) {
+ ClassElement element = type.element;
+ if (type == _typeProvider.objectType || element == null) {
+ return false;
+ }
+ if (element == targetType.element) {
+ List<DartType> typeArguments = type.typeArguments;
+ assert(typeArguments.length == 1);
+ result = typeArguments[0];
+ return true;
+ }
+ if (visitedClasses == null) {
+ visitedClasses = new HashSet<ClassElement>();
+ }
+ // Already visited this class along this path
+ if (!visitedClasses.add(element)) {
+ return false;
+ }
+ try {
+ return _find(type.superclass) ||
+ type.interfaces.any(_find) ||
+ type.mixins.any(_find);
+ } finally {
+ visitedClasses.remove(element);
+ }
+ }
+ _find(type);
+ return result;
+ }
+
/**
* Return the best type of the given [expression].
*/
@@ -1604,6 +1677,174 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
}
/**
+ * Given a declared identifier from a foreach loop, attempt to infer
+ * a type for it if one is not already present. Inference is based
+ * on the type of the iterator or stream over which the foreach loop
+ * is defined.
+ */
+ void _inferForEachLoopVariableType(DeclaredIdentifier loopVariable) {
+ if (loopVariable != null &&
+ loopVariable.type == null &&
+ loopVariable.parent is ForEachStatement) {
+ ForEachStatement loop = loopVariable.parent;
+ if (loop.iterable != null) {
+ Expression expr = loop.iterable;
+ LocalVariableElementImpl element = loopVariable.element;
+ DartType exprType = expr.staticType;
+ if (exprType is InterfaceType) {
+ DartType targetType = (loop.awaitKeyword == null)
+ ? _typeProvider.iterableType
+ : _typeProvider.streamType;
+ DartType iteratedType = _findIteratedType(exprType, targetType);
+ if (element != null && iteratedType != null) {
+ element.type = iteratedType;
+ loopVariable.identifier.staticType = iteratedType;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Given a method invocation [node], attempt to infer a better
+ * type for the result.
+ */
+ bool _inferMethodInvocation(MethodInvocation node) {
+ return _inferMethodInvocationObject(node) ||
+ _inferMethodInvocationGeneric(node) ||
+ _inferMethodInvocationInlineJS(node);
+ }
+
+ /**
+ * Given a method invocation [node], attempt to infer a better
+ * type for the result using an ad-hoc list of psuedo-generic methods.
+ */
+ bool _inferMethodInvocationGeneric(MethodInvocation node) {
+ DartType inferredType = _matchGeneric(node);
+ // TODO(vsm): If the inferred type is not a subtype,
+ // should we use a GLB instead?
+ if (inferredType != null &&
+ _typeSystem.isSubtypeOf(inferredType, node.staticType)) {
+ _recordStaticType(node, inferredType);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Given a method invocation [node], attempt to infer a better
+ * type for the result if it is an inline JS invocation
+ */
+ bool _inferMethodInvocationInlineJS(MethodInvocation node) {
+ Element e = node.methodName.staticElement;
+ if (e is FunctionElement &&
+ e.library.source.uri.toString() == 'dart:_foreign_helper' &&
+ e.name == 'JS') {
+ String typeStr = _getFirstArgumentAsString(node.argumentList);
+ DartType returnType = null;
+ if (typeStr == '-dynamic') {
+ returnType = _typeProvider.bottomType;
+ } else {
+ returnType = _getElementNameAsType(
+ _typeProvider.objectType.element.library, typeStr, null);
+ }
+ if (returnType != null) {
+ _recordStaticType(node, returnType);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Given a method invocation [node], attempt to infer a better
+ * type for the result if the target is dynamic and the method
+ * being called is one of the object methods.
+ */
+ bool _inferMethodInvocationObject(MethodInvocation node) {
+ // If we have a call like `toString()` or `libraryPrefix.toString()` don't
+ // infer it.
+ Expression target = node.realTarget;
+ if (target == null ||
+ target is SimpleIdentifier && target.staticElement is PrefixElement) {
+ return false;
+ }
+
+ // Object methods called on dynamic targets can have their types improved.
+ String name = node.methodName.name;
+ MethodElement inferredElement =
+ _typeProvider.objectType.element.getMethod(name);
+ if (inferredElement == null || inferredElement.isStatic) {
+ return false;
+ }
+ DartType inferredType = inferredElement.type;
+ DartType nodeType = node.staticType;
+ if (nodeType != null &&
+ nodeType.isDynamic &&
+ inferredType is FunctionType &&
+ inferredType.parameters.isEmpty &&
+ node.argumentList.arguments.isEmpty &&
+ _typeProvider.nonSubtypableTypes.contains(inferredType.returnType)) {
+ _recordStaticType(node.methodName, inferredType);
+ _recordStaticType(node, inferredType.returnType);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Given a local variable declaration and its initializer, attempt to infer
+ * a type for the local variable declaration based on the initializer.
+ * Inference is only done if an explicit type is not present, and if
+ * inferring a type improves the type.
+ */
+ void _inferLocalVariableType(
+ VariableDeclaration node, Expression initializer) {
+ if (initializer != null &&
+ (node.parent as VariableDeclarationList).type == null &&
+ (node.element is LocalVariableElementImpl) &&
+ (initializer.staticType != null) &&
+ (!initializer.staticType.isBottom)) {
+ LocalVariableElementImpl element = node.element;
+ element.type = initializer.staticType;
+ node.name.staticType = initializer.staticType;
+ }
+ }
+
+ /**
+ * Given a property access [node] with static type [nodeType],
+ * and [id] is the property name being accessed, infer a type for the
+ * access itself and its constituent components if the access is to one of the
+ * methods or getters of the built in 'Object' type, and if the result type is
+ * a sealed type. Returns true if inference succeeded.
+ */
+ bool _inferObjectAccess(
+ Expression node, DartType nodeType, SimpleIdentifier id) {
+ // If we have an access like `libraryPrefix.hashCode` don't infer it.
+ if (node is PrefixedIdentifier &&
+ node.prefix.staticElement is PrefixElement) {
+ return false;
+ }
+ // Search for Object accesses.
+ String name = id.name;
+ PropertyAccessorElement inferredElement =
+ _typeProvider.objectType.element.getGetter(name);
+ if (inferredElement == null || inferredElement.isStatic) {
+ return false;
+ }
+ DartType inferredType = inferredElement.type.returnType;
+ if (nodeType != null &&
+ nodeType.isDynamic &&
+ inferredType != null &&
+ _typeProvider.nonSubtypableTypes.contains(inferredType)) {
+ _recordStaticType(id, inferredType);
+ _recordStaticType(node, inferredType);
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Return `true` if the given [Type] is the `Future` form the 'dart:async'
* library.
*/
@@ -1648,6 +1889,91 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
}
/**
+ * Return a more specialized type for a method invocation based on
+ * an ad-hoc list of pseudo-generic methods.
+ */
+ DartType _matchGeneric(MethodInvocation node) {
+ Element e = node.methodName.staticElement;
+
+ if (e == null || e.name == null) {
+ return null;
+ }
+
+ List<DartType> arguments =
+ node.argumentList.arguments.map((arg) => arg.staticType).toList();
+
+ bool matchInvocation(DartType t, int c) {
+ return (node.realTarget != null) &&
+ node.realTarget.staticType.isSubtypeOf(t) &&
+ arguments.length == c;
+ }
+
+ switch (e.name) {
+ case 'max':
+ case 'min':
+ if (e.library.source.uri.toString() == 'dart:math' &&
+ arguments.length == 2) {
+ DartType tx = arguments[0];
+ DartType ty = arguments[1];
+ if (tx == ty &&
+ (tx == _typeProvider.intType || tx == _typeProvider.doubleType)) {
+ return tx;
+ }
+ }
+ return null;
+ case 'wait':
+ if (matchInvocation(_typeProvider.futureType, 1)) {
+ DartType tx = arguments[0];
+ // Iterable<Future<T>> -> Future<List<T>>
+ DartType futureType =
+ _findIteratedType(tx, _typeProvider.iterableType);
+ if (futureType.element != _typeProvider.futureType.element) {
+ return null;
+ }
+ List<DartType> typeArguments =
+ (futureType as InterfaceType).typeArguments;
+ if (typeArguments.length != 1) {
+ return null;
+ }
+ DartType baseType = typeArguments[0];
+ if (baseType.isDynamic) {
+ return null;
+ }
+ return _typeProvider.futureType.substitute4([
+ _typeProvider.listType.substitute4([baseType])
+ ]);
+ }
+ return null;
+ case 'map':
+ if (matchInvocation(_typeProvider.iterableDynamicType, 1)) {
+ DartType tx = arguments[0];
+ return (tx is FunctionType)
+ ? _typeProvider.iterableType.substitute4([tx.returnType])
+ : null;
+ }
+ return null;
+ case 'fold':
+ if (matchInvocation(_typeProvider.iterableDynamicType, 2)) {
+ DartType tx = arguments[0];
+ DartType ty = arguments[1];
+ // TODO(vsm): LUB?
+ return (ty is FunctionType && tx == ty.returnType) ? tx : null;
+ }
+ return null;
+ case 'then':
+ if (matchInvocation(_typeProvider.futureDynamicType, 1)) {
+ DartType tx = arguments[0];
+ return (tx is FunctionType)
+ ? _typeProvider.futureType.substitute4([tx.returnType])
+ : null;
+ }
+ return null;
+ default:
+ return null;
+ }
+ }
+
+ /**
* Record that the propagated type of the given node is the given type.
*
* @param expression the node whose type is to be recorded
@@ -1941,10 +2267,12 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
class _StaticTypeAnalyzer_computePropagatedReturnTypeOfFunction
extends GeneralizingAstVisitor<Object> {
- final TypeSystem typeSystem;
+ final TypeSystem _typeSystem;
+ final TypeProvider _typeProvider;
DartType result = null;
- _StaticTypeAnalyzer_computePropagatedReturnTypeOfFunction(this.typeSystem);
+ _StaticTypeAnalyzer_computePropagatedReturnTypeOfFunction(
+ this._typeProvider, this._typeSystem);
@override
Object visitExpression(Expression node) => null;
@@ -1963,7 +2291,7 @@ class _StaticTypeAnalyzer_computePropagatedReturnTypeOfFunction
if (result == null) {
result = type;
} else {
- result = typeSystem.getLeastUpperBound(result, type);
+ result = _typeSystem.getLeastUpperBound(_typeProvider, result, type);
}
return null;
}
« no previous file with comments | « packages/analyzer/lib/src/generated/source_io.dart ('k') | packages/analyzer/lib/src/generated/testing/ast_factory.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698