Chromium Code Reviews| 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 8ec48e4f3d1bfb60555c3bf2e8a0e5b2fc55f0db..cc639459e38759e4916e2740d243b98e3022ebc9 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 |
| @@ -93,6 +94,83 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
| } |
| /** |
| + * 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. |
| + */ |
| + void inferConstructorName(ConstructorName node, InterfaceType type) { |
| + if (_strongMode) { |
| + node.type.type = type; |
| + _resolver.inferenceContext.recordInference(node.parent, type); |
| + } |
| + return; |
| + } |
| + |
| + /** |
| + * 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) { |
| + void inferType(ParameterElementImpl p, DartType inferredType) { |
| + // Check that there is no declared type, and that we have not already |
| + // inferred a type in some fashion. |
| + if (p.hasImplicitType && |
| + (p.type == null || p.type.isDynamic) && |
| + !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 +459,19 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
| } |
| ExecutableElementImpl functionElement = |
| node.element as ExecutableElementImpl; |
| - functionElement.returnType = |
| - _computeStaticReturnTypeOfFunctionExpression(node); |
| + DartType computedType = _computeStaticReturnTypeOfFunctionExpression(node); |
| + if (_strongMode) { |
| + DartType functionType = InferenceContext.getType(node); |
| + if (functionType is FunctionType) { |
| + DartType returnType = functionType.returnType; |
| + if ((computedType.isDynamic || computedType.isBottom) && |
| + !(returnType.isDynamic || returnType.isBottom)) { |
| + computedType = functionType.returnType; |
|
Brian Wilkerson
2015/12/01 22:31:09
"functionType.returnType" --> "returnType"?
Leaf
2015/12/01 23:39:24
Done.
|
| + _resolver.inferenceContext.recordInference(node, functionType); |
| + } |
| + } |
| + } |
| + functionElement.returnType = computedType; |
| _recordPropagatedTypeOfFunction(functionElement, node.body); |
| _recordStaticType(node, node.element.type); |
| return null; |
| @@ -522,6 +611,15 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
| staticType = argumentType; |
| } |
| } |
| + } else { |
| + DartType contextType = InferenceContext.getType(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 +657,16 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
| staticValueType = entryValueType; |
| } |
| } |
| + } else { |
| + DartType contextType = InferenceContext.getType(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 +1787,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. |
| */ |
| @@ -1791,25 +1918,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 |