mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 15:01:30 +00:00
fixes #25477, downward inference of generic methods
* we now push the context return type down when inferring * we also take this into account in our initial downards inference for arguments * adds a common AST interface for FunctionExpressionInvocation and MethodInvocation, so we can handle these more uniformly R=brianwilkerson@google.com, leafp@google.com Review URL: https://codereview.chromium.org/1720433002 .
This commit is contained in:
parent
9001fa7d06
commit
0c4e64c8ef
8 changed files with 255 additions and 210 deletions
|
@ -536,7 +536,7 @@ abstract class AstNode {
|
|||
* (either AST nodes or tokens) that make up the contents of this node,
|
||||
* including doc comments but excluding other comments.
|
||||
*/
|
||||
Iterable /*<AstNode | Token>*/ get childEntities;
|
||||
Iterable/*<AstNode | Token>*/ get childEntities;
|
||||
|
||||
/**
|
||||
* Return the offset of the character immediately following the last character
|
||||
|
@ -591,7 +591,7 @@ abstract class AstNode {
|
|||
* Use the given [visitor] to visit this node. Return the value returned by
|
||||
* the visitor as a result of visiting this node.
|
||||
*/
|
||||
dynamic /* =E */ accept /*<E>*/ (AstVisitor /*<E>*/ visitor);
|
||||
dynamic /* =E */ accept/*<E>*/(AstVisitor/*<E>*/ visitor);
|
||||
|
||||
/**
|
||||
* Return the most immediate ancestor of this node for which the [predicate]
|
||||
|
@ -3994,7 +3994,7 @@ abstract class FunctionExpression extends Expression {
|
|||
*
|
||||
* Clients may not extend, implement or mix-in this class.
|
||||
*/
|
||||
abstract class FunctionExpressionInvocation extends Expression {
|
||||
abstract class FunctionExpressionInvocation extends InvocationExpression {
|
||||
/**
|
||||
* Initialize a newly created function expression invocation.
|
||||
*/
|
||||
|
@ -4003,11 +4003,6 @@ abstract class FunctionExpressionInvocation extends Expression {
|
|||
TypeArgumentList typeArguments,
|
||||
ArgumentList argumentList) = FunctionExpressionInvocationImpl;
|
||||
|
||||
/**
|
||||
* Return the list of arguments to the method.
|
||||
*/
|
||||
ArgumentList get argumentList;
|
||||
|
||||
/**
|
||||
* Set the list of arguments to the method to the given [argumentList].
|
||||
*/
|
||||
|
@ -4093,12 +4088,6 @@ abstract class FunctionExpressionInvocation extends Expression {
|
|||
*/
|
||||
void set staticInvokeType(DartType type);
|
||||
|
||||
/**
|
||||
* Return the type arguments to be applied to the method being invoked, or
|
||||
* `null` if no type arguments were provided.
|
||||
*/
|
||||
TypeArgumentList get typeArguments;
|
||||
|
||||
/**
|
||||
* Set the type arguments to be applied to the method being invoked to the
|
||||
* given [typeArguments].
|
||||
|
@ -4977,6 +4966,61 @@ abstract class InterpolationString extends InterpolationElement {
|
|||
void set value(String value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The invocation of a function or method; either a
|
||||
* [FunctionExpressionInvocation] or a [MethodInvocation].
|
||||
*
|
||||
* Clients may not extend, implement or mix-in this class.
|
||||
*/
|
||||
abstract class InvocationExpression extends Expression {
|
||||
/**
|
||||
* Return the function type of the invocation based on the propagated type
|
||||
* information, or `null` if the AST structure has not been resolved, or if
|
||||
* the invoke could not be resolved.
|
||||
*
|
||||
* This will usually be a [FunctionType], but it can also be an
|
||||
* [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
|
||||
* interface type that implements `Function`.
|
||||
*/
|
||||
DartType propagatedInvokeType;
|
||||
|
||||
/**
|
||||
* Return the function type of the invocation based on the static type
|
||||
* information, or `null` if the AST structure has not been resolved, or if
|
||||
* the invoke could not be resolved.
|
||||
*
|
||||
* This will usually be a [FunctionType], but it can also be an
|
||||
* [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
|
||||
* interface type that implements `Function`.
|
||||
*/
|
||||
DartType staticInvokeType;
|
||||
|
||||
/**
|
||||
* Return the list of arguments to the method.
|
||||
*/
|
||||
ArgumentList get argumentList;
|
||||
|
||||
/**
|
||||
* The expression that identifies the function or method being invoked.
|
||||
* For example:
|
||||
*
|
||||
* (o.m)<TArgs>(args); // target will be `o.m`
|
||||
* o.m<TArgs>(args); // target will be `m`
|
||||
*
|
||||
* In either case, the [function.staticType] will be the
|
||||
* [staticInvokeType] before applying type arguments `TArgs`. Similarly,
|
||||
* [function.propagatedType] will be the [propagatedInvokeType]
|
||||
* before applying type arguments `TArgs`.
|
||||
*/
|
||||
Expression get function;
|
||||
|
||||
/**
|
||||
* Return the type arguments to be applied to the method being invoked, or
|
||||
* `null` if no type arguments were provided.
|
||||
*/
|
||||
TypeArgumentList get typeArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* An is expression.
|
||||
*
|
||||
|
@ -5519,7 +5563,7 @@ abstract class MethodDeclaration extends ClassMember {
|
|||
*
|
||||
* Clients may not extend, implement or mix-in this class.
|
||||
*/
|
||||
abstract class MethodInvocation extends Expression {
|
||||
abstract class MethodInvocation extends InvocationExpression {
|
||||
/**
|
||||
* Initialize a newly created method invocation. The [target] and [operator]
|
||||
* can be `null` if there is no target.
|
||||
|
@ -5531,11 +5575,6 @@ abstract class MethodInvocation extends Expression {
|
|||
TypeArgumentList typeArguments,
|
||||
ArgumentList argumentList) = MethodInvocationImpl;
|
||||
|
||||
/**
|
||||
* Return the list of arguments to the method.
|
||||
*/
|
||||
ArgumentList get argumentList;
|
||||
|
||||
/**
|
||||
* Set the list of arguments to the method to the given [argumentList].
|
||||
*/
|
||||
|
@ -5630,12 +5669,6 @@ abstract class MethodInvocation extends Expression {
|
|||
*/
|
||||
void set target(Expression expression);
|
||||
|
||||
/**
|
||||
* Return the type arguments to be applied to the method being invoked, or
|
||||
* `null` if no type arguments were provided.
|
||||
*/
|
||||
TypeArgumentList get typeArguments;
|
||||
|
||||
/**
|
||||
* Set the type arguments to be applied to the method being invoked to the
|
||||
* given [typeArguments].
|
||||
|
|
|
@ -5054,24 +5054,13 @@ class FunctionExpressionImpl extends ExpressionImpl
|
|||
* > functionExpressionInvocation ::=
|
||||
* > [Expression] [TypeArgumentList]? [ArgumentList]
|
||||
*/
|
||||
class FunctionExpressionInvocationImpl extends ExpressionImpl
|
||||
class FunctionExpressionInvocationImpl extends InvocationExpressionImpl
|
||||
implements FunctionExpressionInvocation {
|
||||
/**
|
||||
* The expression producing the function being invoked.
|
||||
*/
|
||||
Expression _function;
|
||||
|
||||
/**
|
||||
* The type arguments to be applied to the method being invoked, or `null` if
|
||||
* no type arguments were provided.
|
||||
*/
|
||||
TypeArgumentList _typeArguments;
|
||||
|
||||
/**
|
||||
* The list of arguments to the function.
|
||||
*/
|
||||
ArgumentList _argumentList;
|
||||
|
||||
/**
|
||||
* The element associated with the function being invoked based on static type
|
||||
* information, or `null` if the AST structure has not been resolved or the
|
||||
|
@ -5079,16 +5068,6 @@ class FunctionExpressionInvocationImpl extends ExpressionImpl
|
|||
*/
|
||||
ExecutableElement staticElement;
|
||||
|
||||
/**
|
||||
* The function type of the method invocation, or `null` if the AST
|
||||
* structure has not been resolved, or if the invoke could not be resolved.
|
||||
*
|
||||
* This will usually be a [FunctionType], but it can also be an
|
||||
* [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
|
||||
* interface type that implements `Function`.
|
||||
*/
|
||||
DartType staticInvokeType;
|
||||
|
||||
/**
|
||||
* The element associated with the function being invoked based on propagated
|
||||
* type information, or `null` if the AST structure has not been resolved or
|
||||
|
@ -5096,27 +5075,13 @@ class FunctionExpressionInvocationImpl extends ExpressionImpl
|
|||
*/
|
||||
ExecutableElement propagatedElement;
|
||||
|
||||
/**
|
||||
* Like [staticInvokeType], but reflects propagated type information.
|
||||
*/
|
||||
DartType propagatedInvokeType;
|
||||
|
||||
/**
|
||||
* Initialize a newly created function expression invocation.
|
||||
*/
|
||||
FunctionExpressionInvocationImpl(Expression function,
|
||||
TypeArgumentList typeArguments, ArgumentList argumentList) {
|
||||
TypeArgumentList typeArguments, ArgumentList argumentList)
|
||||
: super(typeArguments, argumentList) {
|
||||
_function = _becomeParentOf(function);
|
||||
_typeArguments = _becomeParentOf(typeArguments);
|
||||
_argumentList = _becomeParentOf(argumentList);
|
||||
}
|
||||
|
||||
@override
|
||||
ArgumentList get argumentList => _argumentList;
|
||||
|
||||
@override
|
||||
void set argumentList(ArgumentList argumentList) {
|
||||
_argumentList = _becomeParentOf(argumentList);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -5149,14 +5114,6 @@ class FunctionExpressionInvocationImpl extends ExpressionImpl
|
|||
@override
|
||||
int get precedence => 15;
|
||||
|
||||
@override
|
||||
TypeArgumentList get typeArguments => _typeArguments;
|
||||
|
||||
@override
|
||||
void set typeArguments(TypeArgumentList typeArguments) {
|
||||
_typeArguments = _becomeParentOf(typeArguments);
|
||||
}
|
||||
|
||||
@override
|
||||
accept(AstVisitor visitor) => visitor.visitFunctionExpressionInvocation(this);
|
||||
|
||||
|
@ -6166,6 +6123,55 @@ class InterpolationStringImpl extends InterpolationElementImpl
|
|||
void visitChildren(AstVisitor visitor) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Common base class for [FunctionExpressionInvocationImpl] and
|
||||
* [MethodInvocationImpl].
|
||||
*/
|
||||
abstract class InvocationExpressionImpl extends ExpressionImpl
|
||||
implements InvocationExpression {
|
||||
/**
|
||||
* The type arguments to be applied to the method being invoked, or `null` if
|
||||
* no type arguments were provided.
|
||||
*/
|
||||
TypeArgumentList _typeArguments;
|
||||
|
||||
/**
|
||||
* The list of arguments to the function.
|
||||
*/
|
||||
ArgumentList _argumentList;
|
||||
|
||||
@override
|
||||
DartType propagatedInvokeType;
|
||||
|
||||
@override
|
||||
DartType staticInvokeType;
|
||||
|
||||
/**
|
||||
* Initialize a newly created invocation.
|
||||
*/
|
||||
InvocationExpressionImpl(
|
||||
TypeArgumentList typeArguments, ArgumentList argumentList) {
|
||||
_typeArguments = _becomeParentOf(typeArguments);
|
||||
_argumentList = _becomeParentOf(argumentList);
|
||||
}
|
||||
|
||||
@override
|
||||
ArgumentList get argumentList => _argumentList;
|
||||
|
||||
@override
|
||||
void set argumentList(ArgumentList argumentList) {
|
||||
_argumentList = _becomeParentOf(argumentList);
|
||||
}
|
||||
|
||||
@override
|
||||
TypeArgumentList get typeArguments => _typeArguments;
|
||||
|
||||
@override
|
||||
void set typeArguments(TypeArgumentList typeArguments) {
|
||||
_typeArguments = _becomeParentOf(typeArguments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An is expression.
|
||||
*
|
||||
|
@ -6959,7 +6965,8 @@ class MethodDeclarationImpl extends ClassMemberImpl
|
|||
* > methodInvocation ::=
|
||||
* > ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
|
||||
*/
|
||||
class MethodInvocationImpl extends ExpressionImpl implements MethodInvocation {
|
||||
class MethodInvocationImpl extends InvocationExpressionImpl
|
||||
implements MethodInvocation {
|
||||
/**
|
||||
* The expression producing the object on which the method is defined, or
|
||||
* `null` if there is no target (that is, the target is implicitly `this`).
|
||||
|
@ -6979,32 +6986,6 @@ class MethodInvocationImpl extends ExpressionImpl implements MethodInvocation {
|
|||
*/
|
||||
SimpleIdentifier _methodName;
|
||||
|
||||
/**
|
||||
* The type arguments to be applied to the method being invoked, or `null` if
|
||||
* no type arguments were provided.
|
||||
*/
|
||||
TypeArgumentList _typeArguments;
|
||||
|
||||
/**
|
||||
* The list of arguments to the method.
|
||||
*/
|
||||
ArgumentList _argumentList;
|
||||
|
||||
/**
|
||||
* The function type of the method invocation, or `null` if the AST
|
||||
* structure has not been resolved, or if the invoke could not be resolved.
|
||||
*
|
||||
* This will usually be a [FunctionType], but it can also be an
|
||||
* [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
|
||||
* interface type that implements `Function`.
|
||||
*/
|
||||
DartType staticInvokeType;
|
||||
|
||||
/**
|
||||
* Like [staticInvokeType], but reflects propagated type information.
|
||||
*/
|
||||
DartType propagatedInvokeType;
|
||||
|
||||
/**
|
||||
* Initialize a newly created method invocation. The [target] and [operator]
|
||||
* can be `null` if there is no target.
|
||||
|
@ -7014,19 +6995,10 @@ class MethodInvocationImpl extends ExpressionImpl implements MethodInvocation {
|
|||
this.operator,
|
||||
SimpleIdentifier methodName,
|
||||
TypeArgumentList typeArguments,
|
||||
ArgumentList argumentList) {
|
||||
ArgumentList argumentList)
|
||||
: super(typeArguments, argumentList) {
|
||||
_target = _becomeParentOf(target);
|
||||
_methodName = _becomeParentOf(methodName);
|
||||
_typeArguments = _becomeParentOf(typeArguments);
|
||||
_argumentList = _becomeParentOf(argumentList);
|
||||
}
|
||||
|
||||
@override
|
||||
ArgumentList get argumentList => _argumentList;
|
||||
|
||||
@override
|
||||
void set argumentList(ArgumentList argumentList) {
|
||||
_argumentList = _becomeParentOf(argumentList);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -7049,6 +7021,9 @@ class MethodInvocationImpl extends ExpressionImpl implements MethodInvocation {
|
|||
@override
|
||||
Token get endToken => _argumentList.endToken;
|
||||
|
||||
@override
|
||||
Expression get function => methodName;
|
||||
|
||||
@override
|
||||
bool get isCascaded =>
|
||||
operator != null && operator.type == TokenType.PERIOD_PERIOD;
|
||||
|
@ -7087,14 +7062,6 @@ class MethodInvocationImpl extends ExpressionImpl implements MethodInvocation {
|
|||
_target = _becomeParentOf(expression);
|
||||
}
|
||||
|
||||
@override
|
||||
TypeArgumentList get typeArguments => _typeArguments;
|
||||
|
||||
@override
|
||||
void set typeArguments(TypeArgumentList typeArguments) {
|
||||
_typeArguments = _becomeParentOf(typeArguments);
|
||||
}
|
||||
|
||||
@override
|
||||
accept(AstVisitor visitor) => visitor.visitMethodInvocation(this);
|
||||
|
||||
|
|
|
@ -8162,7 +8162,7 @@ class ResolverVisitor extends ScopedVisitor {
|
|||
safelyVisit(node.function);
|
||||
node.accept(elementResolver);
|
||||
_inferFunctionExpressionsParametersTypes(node.argumentList);
|
||||
InferenceContext.setType(node.argumentList, node.function.staticType);
|
||||
_inferArgumentTypesFromContext(node);
|
||||
safelyVisit(node.argumentList);
|
||||
node.accept(typeAnalyzer);
|
||||
return null;
|
||||
|
@ -8381,15 +8381,32 @@ class ResolverVisitor extends ScopedVisitor {
|
|||
safelyVisit(node.typeArguments);
|
||||
node.accept(elementResolver);
|
||||
_inferFunctionExpressionsParametersTypes(node.argumentList);
|
||||
DartType contextType = node.staticInvokeType;
|
||||
if (contextType is FunctionType) {
|
||||
InferenceContext.setType(node.argumentList, contextType);
|
||||
}
|
||||
_inferArgumentTypesFromContext(node);
|
||||
safelyVisit(node.argumentList);
|
||||
node.accept(typeAnalyzer);
|
||||
return null;
|
||||
}
|
||||
|
||||
void _inferArgumentTypesFromContext(InvocationExpression node) {
|
||||
DartType contextType = node.staticInvokeType;
|
||||
if (contextType is FunctionType) {
|
||||
DartType originalType = node.function.staticType;
|
||||
DartType returnContextType = InferenceContext.getType(node);
|
||||
TypeSystem ts = typeSystem;
|
||||
if (returnContextType != null &&
|
||||
node.typeArguments == null &&
|
||||
originalType is FunctionType &&
|
||||
originalType.typeFormals.isNotEmpty &&
|
||||
ts is StrongTypeSystemImpl) {
|
||||
|
||||
contextType = ts.inferGenericFunctionCall(typeProvider, originalType,
|
||||
DartType.EMPTY_LIST, DartType.EMPTY_LIST, returnContextType);
|
||||
}
|
||||
|
||||
InferenceContext.setType(node.argumentList, contextType);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitNamedExpression(NamedExpression node) {
|
||||
InferenceContext.setType(node.expression, InferenceContext.getType(node));
|
||||
|
|
|
@ -510,7 +510,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
|||
@override
|
||||
Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
|
||||
if (_strongMode) {
|
||||
_inferFunctionInvocationGeneric(node);
|
||||
_inferGenericInvoke(node);
|
||||
}
|
||||
DartType staticType = _computeInvokeReturnType(node.staticInvokeType);
|
||||
_recordStaticType(node, staticType);
|
||||
|
@ -742,7 +742,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
|||
SimpleIdentifier methodNameNode = node.methodName;
|
||||
Element staticMethodElement = methodNameNode.staticElement;
|
||||
if (_strongMode) {
|
||||
_inferMethodInvocationGeneric(node);
|
||||
_inferGenericInvoke(node);
|
||||
}
|
||||
// Record types of the variable invoked as a function.
|
||||
if (staticMethodElement is VariableElement) {
|
||||
|
@ -1814,26 +1814,6 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to [_inferMethodInvocationGeneric] but for function expression
|
||||
* invocations.
|
||||
*/
|
||||
// TODO(jmesserly): if we had a common AST interface between these two nodes,
|
||||
// we could remove this duplicated code.
|
||||
bool _inferFunctionInvocationGeneric(FunctionExpressionInvocation node) {
|
||||
DartType instantiatedType = node.staticInvokeType;
|
||||
DartType originalType = node.function.staticType;
|
||||
if (instantiatedType is FunctionType && originalType is FunctionType) {
|
||||
FunctionType inferred = _inferGenericInvoke(instantiatedType,
|
||||
originalType, node.typeArguments, node.argumentList);
|
||||
if (inferred != null) {
|
||||
node.staticInvokeType = inferred;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an uninstantiated generic type, try to infer the instantiated generic
|
||||
* type from the surrounding context.
|
||||
|
@ -1849,41 +1829,42 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
|||
return type;
|
||||
}
|
||||
|
||||
FunctionType _inferGenericInvoke(FunctionType invokeType, FunctionType fnType,
|
||||
TypeArgumentList typeArguments, ArgumentList argumentList) {
|
||||
bool _inferGenericInvoke(InvocationExpression node) {
|
||||
TypeSystem ts = _typeSystem;
|
||||
if (typeArguments == null && ts is StrongTypeSystemImpl) {
|
||||
if (fnType.typeFormals.isNotEmpty &&
|
||||
ts.instantiateToBounds(fnType) == invokeType) {
|
||||
// Get the parameters that correspond to the uninstantiated generic.
|
||||
List<ParameterElement> rawParameters =
|
||||
ResolverVisitor.resolveArgumentsToParameters(
|
||||
argumentList, fnType.parameters, null);
|
||||
DartType fnType = node.function.staticType;
|
||||
if (node.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);
|
||||
|
||||
List<DartType> paramTypes = <DartType>[];
|
||||
List<DartType> argTypes = <DartType>[];
|
||||
for (int i = 0, length = rawParameters.length; i < length; i++) {
|
||||
ParameterElement parameter = rawParameters[i];
|
||||
if (parameter != null) {
|
||||
paramTypes.add(parameter.type);
|
||||
argTypes.add(argumentList.arguments[i].staticType);
|
||||
}
|
||||
}
|
||||
|
||||
FunctionType inferred = ts.inferCallFromArguments(
|
||||
_typeProvider, fnType, paramTypes, argTypes);
|
||||
|
||||
if (inferred != fnType) {
|
||||
// Fix up the parameter elements based on inferred method.
|
||||
List<ParameterElement> inferredParameters =
|
||||
ResolverVisitor.resolveArgumentsToParameters(
|
||||
argumentList, inferred.parameters, null);
|
||||
argumentList.correspondingStaticParameters = inferredParameters;
|
||||
return inferred;
|
||||
List<DartType> paramTypes = <DartType>[];
|
||||
List<DartType> argTypes = <DartType>[];
|
||||
for (int i = 0, length = rawParameters.length; i < length; i++) {
|
||||
ParameterElement parameter = rawParameters[i];
|
||||
if (parameter != null) {
|
||||
paramTypes.add(parameter.type);
|
||||
argTypes.add(argumentList.arguments[i].staticType);
|
||||
}
|
||||
}
|
||||
|
||||
FunctionType inferred = ts.inferGenericFunctionCall(_typeProvider, fnType,
|
||||
paramTypes, argTypes, InferenceContext.getType(node));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1905,27 +1886,6 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a generic method invocation [node], attempt to infer the method's
|
||||
* type variables, using the actual types of the arguments.
|
||||
*/
|
||||
bool _inferMethodInvocationGeneric(MethodInvocation node) {
|
||||
DartType instantiatedType = node.staticInvokeType;
|
||||
DartType originalType = node.methodName.staticType;
|
||||
// TODO(jmesserly): support generic `call` methods.
|
||||
// Perhaps we should always record a FunctionType in staticInvokeType
|
||||
// and the methodName's staticType.
|
||||
if (instantiatedType is FunctionType && originalType is FunctionType) {
|
||||
FunctionType inferred = _inferGenericInvoke(instantiatedType,
|
||||
originalType, node.typeArguments, node.argumentList);
|
||||
if (inferred != null) {
|
||||
node.staticInvokeType = inferred;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a method invocation [node], attempt to infer a better
|
||||
* type for the result if it is an inline JS invocation
|
||||
|
|
|
@ -68,11 +68,12 @@ class StrongTypeSystemImpl implements TypeSystem {
|
|||
/// As a simplification, we do not actually store all constraints on each type
|
||||
/// parameter Tj. Instead we track Uj and Lj where U is the upper bound and
|
||||
/// L is the lower bound of that type parameter.
|
||||
FunctionType inferCallFromArguments(
|
||||
FunctionType inferGenericFunctionCall(
|
||||
TypeProvider typeProvider,
|
||||
FunctionType fnType,
|
||||
List<DartType> correspondingParameterTypes,
|
||||
List<DartType> argumentTypes) {
|
||||
List<DartType> argumentTypes,
|
||||
DartType returnContextType) {
|
||||
if (fnType.typeFormals.isEmpty) {
|
||||
return fnType;
|
||||
}
|
||||
|
@ -84,6 +85,10 @@ class StrongTypeSystemImpl implements TypeSystem {
|
|||
var inferringTypeSystem =
|
||||
new _StrongInferenceTypeSystem(typeProvider, fnType.typeFormals);
|
||||
|
||||
if (returnContextType != null) {
|
||||
inferringTypeSystem.isSubtypeOf(fnType.returnType, returnContextType);
|
||||
}
|
||||
|
||||
for (int i = 0; i < argumentTypes.length; i++) {
|
||||
// Try to pass each argument to each parameter, recording any type
|
||||
// parameter bounds that were implied by this assignment.
|
||||
|
@ -105,7 +110,7 @@ class StrongTypeSystemImpl implements TypeSystem {
|
|||
* Given a generic function type `F<T0, T1, ... Tn>` and a context type C,
|
||||
* infer an instantiation of F, such that `F<S0, S1, ..., Sn>` <: C.
|
||||
*
|
||||
* This is similar to [inferCallFromArguments], but the return type is also
|
||||
* This is similar to [inferGenericFunctionCall], but the return type is also
|
||||
* considered as part of the solution.
|
||||
*
|
||||
* If this function is called with a [contextType] that is also
|
||||
|
|
|
@ -467,6 +467,27 @@ class StrongGenericFunctionInferenceTest {
|
|||
[intType]);
|
||||
}
|
||||
|
||||
void test_returnTypeFromContext() {
|
||||
// <T>() -> T
|
||||
var t = TypeBuilder.variable('T');
|
||||
var f = TypeBuilder.function(types: [t], required: [], result: t);
|
||||
expect(_inferCall(f, [], stringType), [stringType]);
|
||||
}
|
||||
|
||||
void test_returnTypeWithBoundFromContext() {
|
||||
// <T extends num>() -> T
|
||||
var t = TypeBuilder.variable('T', bound: numType);
|
||||
var f = TypeBuilder.function(types: [t], required: [], result: t);
|
||||
expect(_inferCall(f, [], doubleType), [doubleType]);
|
||||
}
|
||||
|
||||
void test_returnTypeWithBoundFromInvalidContext() {
|
||||
// <T extends num>() -> T
|
||||
var t = TypeBuilder.variable('T', bound: numType);
|
||||
var f = TypeBuilder.function(types: [t], required: [], result: t);
|
||||
expect(_inferCall(f, [], stringType), [numType]);
|
||||
}
|
||||
|
||||
void test_unifyParametersToFunctionParam() {
|
||||
// <T>(f(T t), g(T t)) -> T
|
||||
var t = TypeBuilder.variable('T');
|
||||
|
@ -498,9 +519,10 @@ class StrongGenericFunctionInferenceTest {
|
|||
expect(_inferCall(f, []), [numType]);
|
||||
}
|
||||
|
||||
List<DartType> _inferCall(FunctionTypeImpl ft, List<DartType> arguments) {
|
||||
FunctionType inferred = typeSystem.inferCallFromArguments(
|
||||
typeProvider, ft, ft.parameters.map((p) => p.type).toList(), arguments);
|
||||
List<DartType> _inferCall(FunctionTypeImpl ft, List<DartType> arguments,
|
||||
[DartType returnType]) {
|
||||
FunctionType inferred = typeSystem.inferGenericFunctionCall(typeProvider,
|
||||
ft, ft.parameters.map((p) => p.type).toList(), arguments, returnType);
|
||||
return inferred.typeArguments;
|
||||
}
|
||||
}
|
||||
|
@ -1314,7 +1336,7 @@ class LeastUpperBoundTest {
|
|||
if (returns == null) {
|
||||
returns = voidType;
|
||||
}
|
||||
|
||||
|
||||
return ElementFactory
|
||||
.functionElement8(required, returns, optional: optional, named: named)
|
||||
.type;
|
||||
|
|
|
@ -1738,16 +1738,16 @@ void main() {
|
|||
x = foo/*warning:EXTRA_POSITIONAL_ARGUMENTS*/('1', '2', '3');
|
||||
foo/*warning:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(1);
|
||||
x = foo/*warning:NOT_ENOUGH_REQUIRED_ARGUMENTS*/('1');
|
||||
x = /*severe:STATIC_TYPE_ERROR*/foo/*warning:EXTRA_POSITIONAL_ARGUMENTS*/(1, 2, 3);
|
||||
x = /*severe:STATIC_TYPE_ERROR*/foo/*warning:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(1);
|
||||
x = /*info:DYNAMIC_CAST*/foo/*warning:EXTRA_POSITIONAL_ARGUMENTS*/(1, 2, 3);
|
||||
x = /*info:DYNAMIC_CAST*/foo/*warning:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(1);
|
||||
|
||||
// named arguments
|
||||
bar(y: 1, x: 2, /*warning:UNDEFINED_NAMED_PARAMETER*/z: 3);
|
||||
x = bar(/*warning:UNDEFINED_NAMED_PARAMETER*/z: '1', x: '2', y: '3');
|
||||
bar(y: 1);
|
||||
x = bar(x: '1', /*warning:UNDEFINED_NAMED_PARAMETER*/z: 42);
|
||||
x = /*severe:STATIC_TYPE_ERROR*/bar(y: 1, x: 2, /*warning:UNDEFINED_NAMED_PARAMETER*/z: 3);
|
||||
x = /*severe:STATIC_TYPE_ERROR*/bar(x: 1);
|
||||
x = /*info:DYNAMIC_CAST*/bar(y: 1, x: 2, /*warning:UNDEFINED_NAMED_PARAMETER*/z: 3);
|
||||
x = /*info:DYNAMIC_CAST*/bar(x: 1);
|
||||
}
|
||||
''');
|
||||
});
|
||||
|
|
|
@ -1695,7 +1695,7 @@ main() {
|
|||
Iterable<Future<int>> list = <int>[1, 2, 3].map(make);
|
||||
Future<List<int>> results = Future.wait(list);
|
||||
Future<String> results2 = results.then((List<int> list)
|
||||
=> list.fold('', (String x, int y) => x + y.toString()));
|
||||
=> list.fold('', /*info:INFERRED_TYPE_CLOSURE*/(x, y) => x + y.toString()));
|
||||
}
|
||||
''');
|
||||
});
|
||||
|
@ -1838,7 +1838,7 @@ main() {
|
|||
|
||||
test('correctly recognize generic upper bound', () {
|
||||
// Regression test for https://github.com/dart-lang/sdk/issues/25740.
|
||||
checkFile('''
|
||||
checkFile(r'''
|
||||
class Foo<T extends Pattern> {
|
||||
void method/*<U extends T>*/(dynamic/*=U*/ u) {}
|
||||
}
|
||||
|
@ -1853,11 +1853,52 @@ main() {
|
|||
}
|
||||
''');
|
||||
});
|
||||
|
||||
test('basic downwards inference', () {
|
||||
checkFile(r'''
|
||||
/*=T*/ f/*<S, T>*/(/*=S*/ s) => null;
|
||||
main() {
|
||||
String x = f(42);
|
||||
String y = (f)(42);
|
||||
}
|
||||
''');
|
||||
});
|
||||
|
||||
test('downwards inference affects arguments', () {
|
||||
checkFile(r'''
|
||||
/*=T*/ f/*<T>*/(List/*<T>*/ s) => null;
|
||||
main() {
|
||||
String x = f(/*info:INFERRED_TYPE_LITERAL*/['hi']);
|
||||
String y = f(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/42]);
|
||||
}
|
||||
''');
|
||||
});
|
||||
|
||||
test('downwards inference fold', () {
|
||||
// Regression from https://github.com/dart-lang/sdk/issues/25491
|
||||
// The first example works now, but the latter requires a full solution to
|
||||
// https://github.com/dart-lang/sdk/issues/25490
|
||||
checkFile(r'''
|
||||
void main() {
|
||||
List<int> o;
|
||||
int y = o.fold(0, /*info:INFERRED_TYPE_CLOSURE*/(x, y) => x + y);
|
||||
var z = o.fold(0, /*info:INFERRED_TYPE_CLOSURE*/(x, y) => /*info:DYNAMIC_INVOKE*/x + y);
|
||||
y = /*info:DYNAMIC_CAST*/z;
|
||||
}
|
||||
void functionExpressionInvocation() {
|
||||
List<int> o;
|
||||
int y = (o.fold)(0, /*info:INFERRED_TYPE_CLOSURE*/(x, y) => x + y);
|
||||
var z = (o.fold)(0, /*info:INFERRED_TYPE_CLOSURE*/(x, y) => /*info:DYNAMIC_INVOKE*/x + y);
|
||||
y = /*info:DYNAMIC_CAST*/z;
|
||||
}
|
||||
''');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/dart-lang/dev_compiler/issues/47
|
||||
test('null literal should not infer as bottom', () {
|
||||
checkFile('''
|
||||
checkFile(r'''
|
||||
var h = null;
|
||||
void foo(int f(Object _)) {}
|
||||
|
||||
|
|
Loading…
Reference in a new issue