Index: pkg/analyzer/lib/src/generated/static_type_analyzer.dart |
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart |
index 434354903790154e98f2afdf7f0300d598a8b176..75dccdf42fdee60426c9d44eaa98cc0961a66b6b 100644 |
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart |
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart |
@@ -13,6 +13,7 @@ import 'element.dart'; |
import 'java_engine.dart'; |
import 'resolver.dart'; |
import 'scanner.dart' as sc; |
+import 'utilities_dart.dart'; |
/** |
* Instances of the class `StaticTypeAnalyzer` perform two type-related tasks. First, they |
@@ -92,6 +93,78 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
_strongMode = _resolver.definingLibrary.context.analysisOptions.strongMode; |
} |
+ /** Given a constructor name [node] and a type [type], record an inferred type |
+ * for the constructor if in strong mode. This is used to fill in any |
+ * inferred type parameters found by the resolver. |
+ */ |
+ Object inferConstructorName(ConstructorName node, InterfaceType type) { |
Jennifer Messerly
2015/11/23 22:11:58
oh funny, I read this the first time as "infer con
|
+ if (_strongMode) { |
+ node.type.type = type; |
+ _resolver.inferenceContext.recordInference(node.parent, type); |
+ } |
+ } |
+ |
+ /** Given a formal parameter list and a function type use the function type |
+ * to infer types for any of the parameters which have implicit (missing) |
+ * types. Only infers types in strong mode. Returns true if inference |
+ * has occurred. |
+ */ |
+ bool inferFormalParameterList( |
+ FormalParameterList node, DartType functionType) { |
+ bool inferred = false; |
+ if (_strongMode && node != null && functionType is FunctionType) { |
+ DartType inferType(ParameterElementImpl p, DartType inferredType) { |
+ if (p.hasImplicitType && |
+ (p.type == null || p.type.isDynamic) && |
Jennifer Messerly
2015/11/23 22:11:58
aside: this might be worth a TODO. Ideally we can
Leaf
2015/11/24 19:32:12
Not sure what the TODO would be to do? The extra
Jennifer Messerly
2015/11/24 20:10:58
Ah, makes sense. Maybe worth a comment. I was conf
Leaf
2015/12/01 21:49:11
Done.
|
+ !inferredType.isDynamic) { |
+ p.type = inferredType; |
+ inferred = true; |
+ } |
+ } |
+ |
+ List<ParameterElement> parameters = node.parameterElements; |
+ |
+ { |
+ List<DartType> normalParameterTypes = functionType.normalParameterTypes; |
+ int normalCount = normalParameterTypes.length; |
+ Iterable<ParameterElement> required = parameters |
+ .where((p) => p.parameterKind == ParameterKind.REQUIRED) |
+ .take(normalCount); |
+ int index = 0; |
+ for (ParameterElementImpl p in required) { |
+ inferType(p, normalParameterTypes[index++]); |
+ } |
+ } |
+ |
+ { |
+ List<DartType> optionalParameterTypes = |
+ functionType.optionalParameterTypes; |
+ int optionalCount = optionalParameterTypes.length; |
+ Iterable<ParameterElement> optional = parameters |
+ .where((p) => p.parameterKind == ParameterKind.POSITIONAL) |
+ .take(optionalCount); |
+ int index = 0; |
+ for (ParameterElementImpl p in optional) { |
+ inferType(p, optionalParameterTypes[index++]); |
+ } |
+ } |
+ |
+ { |
+ Map<String, DartType> namedParameterTypes = |
+ functionType.namedParameterTypes; |
+ Iterable<ParameterElement> named = |
+ parameters.where((p) => p.parameterKind == ParameterKind.NAMED); |
+ for (ParameterElementImpl p in named) { |
+ if (!namedParameterTypes.containsKey(p.name)) { |
+ continue; |
+ } |
+ inferType(p, namedParameterTypes[p.name]); |
+ } |
+ } |
+ } |
+ return inferred; |
+ } |
+ |
/** |
* The Dart Language Specification, 12.5: <blockquote>The static type of a string literal is |
* `String`.</blockquote> |
@@ -381,8 +454,20 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
} |
ExecutableElementImpl functionElement = |
node.element as ExecutableElementImpl; |
- functionElement.returnType = |
- _computeStaticReturnTypeOfFunctionExpression(node); |
+ DartType computedType = _computeStaticReturnTypeOfFunctionExpression(node); |
+ if (_strongMode) { |
+ DartType functionType = InferenceContext.get(node); |
+ // TODO(leafp) handle async et al |
Jennifer Messerly
2015/11/23 22:11:58
for now should we skip if isGenerator or isAsync?
Leaf
2015/12/01 21:49:11
Actually, nothing to do here for those cases, remo
|
+ if (functionType is FunctionType) { |
+ DartType returnType = functionType.returnType; |
+ if ((computedType.isDynamic || computedType.isBottom) && |
+ !(returnType.isDynamic || returnType.isBottom)) { |
+ computedType = functionType.returnType; |
+ _resolver.inferenceContext.recordInference(node, functionType); |
+ } |
+ } |
+ } |
+ functionElement.returnType = computedType; |
_recordPropagatedTypeOfFunction(functionElement, node.body); |
_recordStaticType(node, node.element.type); |
return null; |
@@ -522,6 +607,15 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
staticType = argumentType; |
} |
} |
+ } else { |
+ DartType contextType = InferenceContext.get(node); |
+ if (_strongMode && |
+ contextType is InterfaceType && |
+ contextType.typeArguments.length == 1 && |
+ contextType.element == _typeProvider.listType.element) { |
+ staticType = contextType.typeArguments[0]; |
+ _resolver.inferenceContext.recordInference(node, contextType); |
+ } |
} |
_recordStaticType( |
node, _typeProvider.listType.substitute4(<DartType>[staticType])); |
@@ -559,6 +653,16 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
staticValueType = entryValueType; |
} |
} |
+ } else { |
+ DartType contextType = InferenceContext.get(node); |
+ if (_strongMode && |
+ contextType is InterfaceType && |
+ contextType.typeArguments.length == 2 && |
+ contextType.element == _typeProvider.mapType.element) { |
+ staticKeyType = contextType.typeArguments[0] ?? staticKeyType; |
+ staticValueType = contextType.typeArguments[1] ?? staticValueType; |
+ _resolver.inferenceContext.recordInference(node, contextType); |
+ } |
} |
_recordStaticType( |
node, |
@@ -1679,6 +1783,25 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
} |
/** |
+ * 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 method invocation [node], attempt to infer a better |
* type for the result. |
*/ |
@@ -1766,25 +1889,6 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
} |
/** |
- * 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 |