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 5c57bb8f945f9fc4f3e3a3387fd54c159f8f7baa..1d36a3667896952a9971d29e414fe5c673a5dbf0 100644 |
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart |
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart |
@@ -12,6 +12,7 @@ import 'package:analyzer/dart/ast/visitor.dart'; |
import 'package:analyzer/dart/element/element.dart'; |
import 'package:analyzer/dart/element/type.dart'; |
import 'package:analyzer/src/dart/element/element.dart'; |
+import 'package:analyzer/src/dart/element/member.dart' show ConstructorMember; |
import 'package:analyzer/src/dart/element/type.dart'; |
import 'package:analyzer/src/generated/java_engine.dart'; |
import 'package:analyzer/src/generated/resolver.dart'; |
@@ -521,7 +522,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
@override |
Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |
if (_strongMode) { |
- _inferGenericInvoke(node); |
+ _inferGenericInvocationExpression(node); |
} |
DartType staticType = _computeInvokeReturnType(node.staticInvokeType); |
_recordStaticType(node, staticType); |
@@ -574,6 +575,10 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
*/ |
@override |
Object visitInstanceCreationExpression(InstanceCreationExpression node) { |
+ if (_strongMode) { |
+ _inferInstanceCreationExpression(node); |
+ } |
+ |
_recordStaticType(node, node.constructorName.type.type); |
ConstructorElement element = node.staticElement; |
if (element != null && "Element" == element.enclosingElement.name) { |
@@ -812,7 +817,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
SimpleIdentifier methodNameNode = node.methodName; |
Element staticMethodElement = methodNameNode.staticElement; |
if (_strongMode) { |
- _inferGenericInvoke(node); |
+ _inferGenericInvocationExpression(node); |
} |
// Record types of the variable invoked as a function. |
if (staticMethodElement is VariableElement) { |
@@ -1605,6 +1610,33 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
return returnType.type; |
} |
+ /** |
+ * Given a constructor for a generic type, returns the equivalent generic |
+ * function type that we could use to forward to the constructor, or for a |
+ * non-generic type simply returns the constructor type. |
+ * |
+ * For example given the type `class C<T> { C(T arg); }`, the generic function |
+ * type is `<T>(T) -> C<T>`. |
+ */ |
+ FunctionType _constructorToGenericFunctionType( |
+ ConstructorElement constructor) { |
+ // TODO(jmesserly): it may be worth making this available from the |
+ // constructor. It's nice if our inference code can operate uniformly on |
+ // function types. |
+ ClassElement cls = constructor.enclosingElement; |
+ FunctionType type = constructor.type; |
+ if (cls.typeParameters.isEmpty) { |
+ return type; |
+ } |
+ |
+ FunctionElementImpl function = new FunctionElementImpl("", -1); |
+ function.synthetic = true; |
+ function.returnType = type.returnType; |
+ function.shareTypeParameters(cls.typeParameters); |
+ function.shareParameters(type.parameters); |
+ return function.type = new FunctionTypeImpl(function); |
+ } |
+ |
DartType _findIteratedType(DartType type, DartType targetType) { |
// TODO(vsm): Use leafp's matchType here? |
// Set by _find if match is found |
@@ -1864,8 +1896,8 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
} |
/** |
- * Given an uninstantiated generic type, try to infer the instantiated generic |
- * type from the surrounding context. |
+ * Given an uninstantiated generic function type, try to infer the |
+ * instantiated generic function type from the surrounding context. |
*/ |
DartType _inferGenericInstantiationFromContext( |
DartType context, DartType type) { |
@@ -1878,14 +1910,40 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
return type; |
} |
- bool _inferGenericInvoke(InvocationExpression node) { |
+ /** |
+ * Given a possibly generic invocation like `o.m(args)` or `(f)(args)` try to |
+ * infer the instantiated generic function type. |
+ * |
+ * This takes into account both the context type, as well as information from |
+ * the argument types. |
+ */ |
+ void _inferGenericInvocationExpression(InvocationExpression node) { |
+ ArgumentList arguments = node.argumentList; |
+ FunctionType inferred = _inferGenericInvoke( |
+ node, node.function.staticType, node.typeArguments, arguments); |
+ if (inferred != null && inferred != node.staticInvokeType) { |
+ // Fix up the parameter elements based on inferred method. |
+ arguments.correspondingStaticParameters = ResolverVisitor |
+ .resolveArgumentsToParameters(arguments, inferred.parameters, null); |
+ node.staticInvokeType = inferred; |
+ } |
+ } |
+ |
+ /** |
+ * Given a possibly generic invocation or instance creation, such as |
+ * `o.m(args)` or `(f)(args)` or `new T(args)` try to infer the instantiated |
+ * generic function type. |
+ * |
+ * This takes into account both the context type, as well as information from |
+ * the argument types. |
+ */ |
+ FunctionType _inferGenericInvoke(Expression node, DartType fnType, |
+ TypeArgumentList typeArguments, ArgumentList argumentList) { |
TypeSystem ts = _typeSystem; |
- DartType fnType = node.function.staticType; |
- if (node.typeArguments == null && |
+ if (typeArguments == null && |
fnType is FunctionType && |
fnType.typeFormals.isNotEmpty && |
ts is StrongTypeSystemImpl) { |
- ArgumentList argumentList = node.argumentList; |
// Get the parameters that correspond to the uninstantiated generic. |
List<ParameterElement> rawParameters = ResolverVisitor |
.resolveArgumentsToParameters(argumentList, fnType.parameters, null); |
@@ -1900,20 +1958,48 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
} |
} |
- FunctionType inferred = ts.inferGenericFunctionCall(_typeProvider, fnType, |
- paramTypes, argTypes, InferenceContext.getType(node)); |
+ return ts.inferGenericFunctionCall(_typeProvider, fnType, paramTypes, |
+ argTypes, InferenceContext.getType(node)); |
+ } |
+ return null; |
+ } |
- if (inferred != node.staticInvokeType) { |
- // Fix up the parameter elements based on inferred method. |
- List<ParameterElement> inferredParameters = |
- ResolverVisitor.resolveArgumentsToParameters( |
- argumentList, inferred.parameters, null); |
- argumentList.correspondingStaticParameters = inferredParameters; |
- node.staticInvokeType = inferred; |
- return true; |
- } |
+ /** |
+ * Given an instance creation of a possibly generic type, infer the type |
+ * arguments using the current context type as well as the argument types. |
+ */ |
+ void _inferInstanceCreationExpression(InstanceCreationExpression node) { |
+ ConstructorName constructor = node.constructorName; |
+ ConstructorElement originalElement = constructor.staticElement; |
+ // If the constructor is generic, we'll have a ConstructorMember that |
+ // substitutes in type arguments (possibly `dynamic`) from earlier in |
+ // resolution. |
+ // |
+ // Otherwise we'll have a ConstructorElement, and we can skip inference |
+ // because there's nothing to infer in a non-generic type. |
+ if (originalElement is! ConstructorMember) { |
+ return; |
+ } |
+ |
+ // Get back to the uninstantiated generic constructor. |
+ // TODO(jmesserly): should we store this earlier in resolution? |
+ // Or look it up, instead of jumping backwards through the Member? |
+ var rawElement = (originalElement as ConstructorMember).baseElement; |
+ |
+ FunctionType constructorType = |
+ _constructorToGenericFunctionType(rawElement); |
+ |
+ ArgumentList arguments = node.argumentList; |
+ FunctionType inferred = _inferGenericInvoke( |
+ node, constructorType, constructor.type.typeArguments, arguments); |
+ |
+ if (inferred != null && inferred != originalElement.type) { |
+ // Fix up the parameter elements based on inferred method. |
+ arguments.correspondingStaticParameters = ResolverVisitor |
+ .resolveArgumentsToParameters(arguments, inferred.parameters, null); |
+ inferConstructorName(constructor, inferred.returnType); |
+ // TODO(jmesserly): should we fix up the staticElement as well? |
} |
- return false; |
} |
/** |