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

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

Issue 2115173002: fix #25220, infer generic type from constructor arguments (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: update tests to be AST summary friendly Created 4 years, 5 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
« no previous file with comments | « pkg/analyzer/lib/src/generated/resolver.dart ('k') | pkg/analyzer/lib/src/generated/type_system.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
}
/**
« no previous file with comments | « pkg/analyzer/lib/src/generated/resolver.dart ('k') | pkg/analyzer/lib/src/generated/type_system.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698