@@ -12,6 +12,7 @@ import 'package:analyzer/dart/ast/visitor.dart';
12
12
import 'package:analyzer/dart/element/element.dart' ;
13
13
import 'package:analyzer/dart/element/type.dart' ;
14
14
import 'package:analyzer/src/dart/element/element.dart' ;
15
+ import 'package:analyzer/src/dart/element/member.dart' show ConstructorMember;
15
16
import 'package:analyzer/src/dart/element/type.dart' ;
16
17
import 'package:analyzer/src/generated/java_engine.dart' ;
17
18
import 'package:analyzer/src/generated/resolver.dart' ;
@@ -521,7 +522,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
521
522
@override
522
523
Object visitFunctionExpressionInvocation (FunctionExpressionInvocation node) {
523
524
if (_strongMode) {
524
- _inferGenericInvoke (node);
525
+ _inferGenericInvocationExpression (node);
525
526
}
526
527
DartType staticType = _computeInvokeReturnType (node.staticInvokeType);
527
528
_recordStaticType (node, staticType);
@@ -574,6 +575,10 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
574
575
*/
575
576
@override
576
577
Object visitInstanceCreationExpression (InstanceCreationExpression node) {
578
+ if (_strongMode) {
579
+ _inferInstanceCreationExpression (node);
580
+ }
581
+
577
582
_recordStaticType (node, node.constructorName.type.type);
578
583
ConstructorElement element = node.staticElement;
579
584
if (element != null && "Element" == element.enclosingElement.name) {
@@ -812,7 +817,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
812
817
SimpleIdentifier methodNameNode = node.methodName;
813
818
Element staticMethodElement = methodNameNode.staticElement;
814
819
if (_strongMode) {
815
- _inferGenericInvoke (node);
820
+ _inferGenericInvocationExpression (node);
816
821
}
817
822
// Record types of the variable invoked as a function.
818
823
if (staticMethodElement is VariableElement ) {
@@ -1605,6 +1610,33 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
1605
1610
return returnType.type;
1606
1611
}
1607
1612
1613
+ /**
1614
+ * Given a constructor for a generic type, returns the equivalent generic
1615
+ * function type that we could use to forward to the constructor, or for a
1616
+ * non-generic type simply returns the constructor type.
1617
+ *
1618
+ * For example given the type `class C<T> { C(T arg); }` , the generic function
1619
+ * type is `<T>(T) -> C<T>` .
1620
+ */
1621
+ FunctionType _constructorToGenericFunctionType (
1622
+ ConstructorElement constructor) {
1623
+ // TODO(jmesserly): it may be worth making this available from the
1624
+ // constructor. It's nice if our inference code can operate uniformly on
1625
+ // function types.
1626
+ ClassElement cls = constructor.enclosingElement;
1627
+ FunctionType type = constructor.type;
1628
+ if (cls.typeParameters.isEmpty) {
1629
+ return type;
1630
+ }
1631
+
1632
+ FunctionElementImpl function = new FunctionElementImpl ("" , - 1 );
1633
+ function.synthetic = true ;
1634
+ function.returnType = type.returnType;
1635
+ function.shareTypeParameters (cls.typeParameters);
1636
+ function.shareParameters (type.parameters);
1637
+ return function.type = new FunctionTypeImpl (function);
1638
+ }
1639
+
1608
1640
DartType _findIteratedType (DartType type, DartType targetType) {
1609
1641
// TODO(vsm): Use leafp's matchType here?
1610
1642
// Set by _find if match is found
@@ -1864,8 +1896,8 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
1864
1896
}
1865
1897
1866
1898
/**
1867
- * Given an uninstantiated generic type, try to infer the instantiated generic
1868
- * type from the surrounding context.
1899
+ * Given an uninstantiated generic function type, try to infer the
1900
+ * instantiated generic function type from the surrounding context.
1869
1901
*/
1870
1902
DartType _inferGenericInstantiationFromContext (
1871
1903
DartType context, DartType type) {
@@ -1878,14 +1910,40 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
1878
1910
return type;
1879
1911
}
1880
1912
1881
- bool _inferGenericInvoke (InvocationExpression node) {
1913
+ /**
1914
+ * Given a possibly generic invocation like `o.m(args)` or `(f)(args)` try to
1915
+ * infer the instantiated generic function type.
1916
+ *
1917
+ * This takes into account both the context type, as well as information from
1918
+ * the argument types.
1919
+ */
1920
+ void _inferGenericInvocationExpression (InvocationExpression node) {
1921
+ ArgumentList arguments = node.argumentList;
1922
+ FunctionType inferred = _inferGenericInvoke (
1923
+ node, node.function.staticType, node.typeArguments, arguments);
1924
+ if (inferred != null && inferred != node.staticInvokeType) {
1925
+ // Fix up the parameter elements based on inferred method.
1926
+ arguments.correspondingStaticParameters = ResolverVisitor
1927
+ .resolveArgumentsToParameters (arguments, inferred.parameters, null );
1928
+ node.staticInvokeType = inferred;
1929
+ }
1930
+ }
1931
+
1932
+ /**
1933
+ * Given a possibly generic invocation or instance creation, such as
1934
+ * `o.m(args)` or `(f)(args)` or `new T(args)` try to infer the instantiated
1935
+ * generic function type.
1936
+ *
1937
+ * This takes into account both the context type, as well as information from
1938
+ * the argument types.
1939
+ */
1940
+ FunctionType _inferGenericInvoke (Expression node, DartType fnType,
1941
+ TypeArgumentList typeArguments, ArgumentList argumentList) {
1882
1942
TypeSystem ts = _typeSystem;
1883
- DartType fnType = node.function.staticType;
1884
- if (node.typeArguments == null &&
1943
+ if (typeArguments == null &&
1885
1944
fnType is FunctionType &&
1886
1945
fnType.typeFormals.isNotEmpty &&
1887
1946
ts is StrongTypeSystemImpl ) {
1888
- ArgumentList argumentList = node.argumentList;
1889
1947
// Get the parameters that correspond to the uninstantiated generic.
1890
1948
List <ParameterElement > rawParameters = ResolverVisitor
1891
1949
.resolveArgumentsToParameters (argumentList, fnType.parameters, null );
@@ -1900,20 +1958,48 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
1900
1958
}
1901
1959
}
1902
1960
1903
- FunctionType inferred = ts.inferGenericFunctionCall (_typeProvider, fnType,
1904
- paramTypes, argTypes, InferenceContext .getType (node));
1961
+ return ts.inferGenericFunctionCall (_typeProvider, fnType, paramTypes,
1962
+ argTypes, InferenceContext .getType (node));
1963
+ }
1964
+ return null ;
1965
+ }
1905
1966
1906
- if (inferred != node.staticInvokeType) {
1907
- // Fix up the parameter elements based on inferred method.
1908
- List <ParameterElement > inferredParameters =
1909
- ResolverVisitor .resolveArgumentsToParameters (
1910
- argumentList, inferred.parameters, null );
1911
- argumentList.correspondingStaticParameters = inferredParameters;
1912
- node.staticInvokeType = inferred;
1913
- return true ;
1914
- }
1967
+ /**
1968
+ * Given an instance creation of a possibly generic type, infer the type
1969
+ * arguments using the current context type as well as the argument types.
1970
+ */
1971
+ void _inferInstanceCreationExpression (InstanceCreationExpression node) {
1972
+ ConstructorName constructor = node.constructorName;
1973
+ ConstructorElement originalElement = constructor.staticElement;
1974
+ // If the constructor is generic, we'll have a ConstructorMember that
1975
+ // substitutes in type arguments (possibly `dynamic`) from earlier in
1976
+ // resolution.
1977
+ //
1978
+ // Otherwise we'll have a ConstructorElement, and we can skip inference
1979
+ // because there's nothing to infer in a non-generic type.
1980
+ if (originalElement is ! ConstructorMember ) {
1981
+ return ;
1982
+ }
1983
+
1984
+ // Get back to the uninstantiated generic constructor.
1985
+ // TODO(jmesserly): should we store this earlier in resolution?
1986
+ // Or look it up, instead of jumping backwards through the Member?
1987
+ var rawElement = (originalElement as ConstructorMember ).baseElement;
1988
+
1989
+ FunctionType constructorType =
1990
+ _constructorToGenericFunctionType (rawElement);
1991
+
1992
+ ArgumentList arguments = node.argumentList;
1993
+ FunctionType inferred = _inferGenericInvoke (
1994
+ node, constructorType, constructor.type.typeArguments, arguments);
1995
+
1996
+ if (inferred != null && inferred != originalElement.type) {
1997
+ // Fix up the parameter elements based on inferred method.
1998
+ arguments.correspondingStaticParameters = ResolverVisitor
1999
+ .resolveArgumentsToParameters (arguments, inferred.parameters, null );
2000
+ inferConstructorName (constructor, inferred.returnType);
2001
+ // TODO(jmesserly): should we fix up the staticElement as well?
1915
2002
}
1916
- return false ;
1917
2003
}
1918
2004
1919
2005
/**
0 commit comments