From 25e08663cef1f2a7b755c37e642b2e141c93e5bb Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Mon, 3 Aug 2020 14:12:51 +0000 Subject: [PATCH] [cfe] Pass return type as part of callee type for invocation inference Change-Id: I3b2f54fe73cc7f7c427e51e20cb60b25fc45f6bc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/156885 Reviewed-by: Dmitry Stefantsov Commit-Queue: Johnni Winther --- .../src/fasta/kernel/inference_visitor.dart | 57 +++++++-------- .../fasta/type_inference/type_inferrer.dart | 70 +++++++------------ 2 files changed, 51 insertions(+), 76 deletions(-) diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart index 610dae3d901..bf4ca5ef329 100644 --- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart +++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart @@ -433,14 +433,12 @@ class InferenceVisitor inferrer.inferConstructorParameterTypes(node.target); bool hasExplicitTypeArguments = getExplicitTypeArguments(node.arguments) != null; - InvocationInferenceResult result = inferrer.inferInvocation( - typeContext, - node.fileOffset, + FunctionType functionType = replaceReturnType( node.target.function .computeThisFunctionType(inferrer.library.nonNullable), - node.arguments, - returnType: - computeConstructorReturnType(node.target, inferrer.coreTypes), + computeConstructorReturnType(node.target, inferrer.coreTypes)); + InvocationInferenceResult result = inferrer.inferInvocation( + typeContext, node.fileOffset, functionType, node.arguments, isConst: node.isConst); if (!inferrer.isTopLevel) { SourceLibraryBuilder library = inferrer.library; @@ -721,14 +719,14 @@ class InferenceVisitor FactoryConstructorInvocationJudgment node, DartType typeContext) { bool hadExplicitTypeArguments = getExplicitTypeArguments(node.arguments) != null; - InvocationInferenceResult result = inferrer.inferInvocation( - typeContext, - node.fileOffset, + + FunctionType functionType = replaceReturnType( node.target.function .computeThisFunctionType(inferrer.library.nonNullable), - node.arguments, - returnType: - computeConstructorReturnType(node.target, inferrer.coreTypes), + computeConstructorReturnType(node.target, inferrer.coreTypes)); + + InvocationInferenceResult result = inferrer.inferInvocation( + typeContext, node.fileOffset, functionType, node.arguments, isConst: node.isConst); node.hasBeenInferred = true; Expression resultNode = node; @@ -757,9 +755,10 @@ class InferenceVisitor FunctionType calleeType = node.target.function .computeAliasedConstructorFunctionType( typedef, inferrer.library.library); + calleeType = replaceReturnType(calleeType, calleeType.returnType.unalias); InvocationInferenceResult result = inferrer.inferInvocation( typeContext, node.fileOffset, calleeType, node.arguments, - returnType: calleeType.returnType.unalias, isConst: node.isConst); + isConst: node.isConst); node.hasBeenInferred = true; Expression resultNode = node; if (!inferrer.isTopLevel) { @@ -784,9 +783,10 @@ class InferenceVisitor Typedef typedef = node.typeAliasBuilder.typedef; FunctionType calleeType = node.target.function .computeAliasedFactoryFunctionType(typedef, inferrer.library.library); + calleeType = replaceReturnType(calleeType, calleeType.returnType.unalias); InvocationInferenceResult result = inferrer.inferInvocation( typeContext, node.fileOffset, calleeType, node.arguments, - returnType: calleeType.returnType.unalias, isConst: node.isConst); + isConst: node.isConst); node.hasBeenInferred = true; Expression resultNode = node; if (!inferrer.isTopLevel) { @@ -1133,14 +1133,13 @@ class InferenceVisitor Substitution substitution = Substitution.fromSupertype( inferrer.classHierarchy.getClassAsInstanceOf( inferrer.thisType.classNode, node.target.enclosingClass)); - inferrer.inferInvocation( - null, - node.fileOffset, + FunctionType functionType = replaceReturnType( substitution.substituteType(node.target.function .computeThisFunctionType(inferrer.library.nonNullable) .withoutTypeParameters), - node.argumentsJudgment, - returnType: inferrer.thisType, + inferrer.thisType); + inferrer.inferInvocation( + null, node.fileOffset, functionType, node.argumentsJudgment, skipTypeArgumentInference: true); } @@ -5013,14 +5012,13 @@ class InferenceVisitor classTypeParameters[i], inferrer.library.library); } ArgumentsImpl.setNonInferrableArgumentTypes(node.arguments, typeArguments); - inferrer.inferInvocation( - null, - node.fileOffset, + FunctionType functionType = replaceReturnType( node.target.function .computeThisFunctionType(inferrer.library.nonNullable), - node.arguments, - returnType: inferrer.coreTypes.thisInterfaceType( - node.target.enclosingClass, inferrer.library.nonNullable), + inferrer.coreTypes.thisInterfaceType( + node.target.enclosingClass, inferrer.library.nonNullable)); + inferrer.inferInvocation( + null, node.fileOffset, functionType, node.arguments, skipTypeArgumentInference: true); ArgumentsImpl.removeNonInferrableArgumentTypes(node.arguments); } @@ -5225,14 +5223,13 @@ class InferenceVisitor Substitution substitution = Substitution.fromSupertype( inferrer.classHierarchy.getClassAsInstanceOf( inferrer.thisType.classNode, node.target.enclosingClass)); - inferrer.inferInvocation( - null, - node.fileOffset, + FunctionType functionType = replaceReturnType( substitution.substituteType(node.target.function .computeThisFunctionType(inferrer.library.nonNullable) .withoutTypeParameters), - node.arguments, - returnType: inferrer.thisType, + inferrer.thisType); + inferrer.inferInvocation( + null, node.fileOffset, functionType, node.arguments, skipTypeArgumentInference: true); } diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart index 33686f2100f..0603833310b 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart @@ -218,14 +218,6 @@ class TypeInferrerImpl implements TypeInferrer { /// inside a closure. ClosureContext closureContext; - /// The [Substitution] inferred by the last [inferInvocation], or `null` if - /// the last invocation didn't require any inference. - Substitution lastInferredSubstitution; - - /// The [FunctionType] of the callee in the last [inferInvocation], or `null` - /// if the last invocation didn't require any inference. - FunctionType lastCalleeType; - TypeInferrerImpl(this.engine, this.uriForInstrumentation, bool topLevel, this.thisType, this.library, this.assignedVariables, this.dataForTesting) : assert(library != null), @@ -1653,20 +1645,13 @@ class TypeInferrerImpl implements TypeInferrer { {List hoistedExpressions, bool isSpecialCasedBinaryOperator: false, bool isSpecialCasedTernaryOperator: false, - DartType returnType, DartType receiverType, bool skipTypeArgumentInference: false, bool isConst: false, bool isImplicitExtensionMember: false, bool isImplicitCall: false}) { - assert( - returnType == null || !containsFreeFunctionTypeVariables(returnType), - "Return type $returnType contains free variables." - "Provided function type: $calleeType."); int extensionTypeParameterCount = getExtensionTypeParameterCount(arguments); if (extensionTypeParameterCount != 0) { - assert(returnType == null, - "Unexpected explicit return type for extension method invocation."); return _inferGenericExtensionMethodInvocation(extensionTypeParameterCount, typeContext, offset, calleeType, arguments, hoistedExpressions, isSpecialCasedBinaryOperator: isSpecialCasedBinaryOperator, @@ -1681,7 +1666,6 @@ class TypeInferrerImpl implements TypeInferrer { isSpecialCasedBinaryOperator: isSpecialCasedBinaryOperator, isSpecialCasedTernaryOperator: isSpecialCasedTernaryOperator, receiverType: receiverType, - returnType: returnType, skipTypeArgumentInference: skipTypeArgumentInference, isConst: isConst, isImplicitExtensionMember: isImplicitExtensionMember, @@ -1770,17 +1754,10 @@ class TypeInferrerImpl implements TypeInferrer { {bool isSpecialCasedBinaryOperator: false, bool isSpecialCasedTernaryOperator: false, DartType receiverType, - DartType returnType, bool skipTypeArgumentInference: false, bool isConst: false, bool isImplicitExtensionMember: false, bool isImplicitCall}) { - assert( - returnType == null || !containsFreeFunctionTypeVariables(returnType), - "Return type $returnType contains free variables." - "Provided function type: $calleeType."); - lastInferredSubstitution = null; - lastCalleeType = null; List calleeTypeParameters = calleeType.typeParameters; if (calleeTypeParameters.isNotEmpty) { // It's possible that one of the callee type parameters might match a type @@ -1794,9 +1771,6 @@ class TypeInferrerImpl implements TypeInferrer { // in which me must do this, to avoid a performance regression? FreshTypeParameters fresh = getFreshTypeParameters(calleeTypeParameters); calleeType = fresh.applyToFunctionType(calleeType); - if (returnType != null) { - returnType = fresh.substitute(returnType); - } calleeTypeParameters = fresh.freshTypeParameters; } List explicitTypeArguments = getExplicitTypeArguments(arguments); @@ -1825,8 +1799,8 @@ class TypeInferrerImpl implements TypeInferrer { calleeTypeParameters.length, const UnknownType()); typeSchemaEnvironment.inferGenericFunctionOrType( isNonNullableByDefault - ? returnType ?? calleeType.returnType - : legacyErasure(coreTypes, returnType ?? calleeType.returnType), + ? calleeType.returnType + : legacyErasure(coreTypes, calleeType.returnType), calleeTypeParameters, null, null, @@ -1893,12 +1867,16 @@ class TypeInferrerImpl implements TypeInferrer { } } if (isSpecialCasedBinaryOperator) { - returnType = typeSchemaEnvironment.getTypeOfSpecialCasedBinaryOperator( - receiverType, actualTypes[0], - isNonNullableByDefault: isNonNullableByDefault); + calleeType = replaceReturnType( + calleeType, + typeSchemaEnvironment.getTypeOfSpecialCasedBinaryOperator( + receiverType, actualTypes[0], + isNonNullableByDefault: isNonNullableByDefault)); } else if (isSpecialCasedTernaryOperator) { - returnType = typeSchemaEnvironment.getTypeOfSpecialCasedTernaryOperator( - receiverType, actualTypes[0], actualTypes[1], library.library); + calleeType = replaceReturnType( + calleeType, + typeSchemaEnvironment.getTypeOfSpecialCasedTernaryOperator( + receiverType, actualTypes[0], actualTypes[1], library.library)); } for (NamedExpression namedArgument in arguments.named) { DartType formalType = @@ -1968,7 +1946,7 @@ class TypeInferrerImpl implements TypeInferrer { if (inferenceNeeded) { typeSchemaEnvironment.inferGenericFunctionOrType( - returnType ?? calleeType.returnType, + calleeType.returnType, calleeTypeParameters, formalTypes, actualTypes, @@ -2034,19 +2012,11 @@ class TypeInferrerImpl implements TypeInferrer { } } DartType inferredType; - lastInferredSubstitution = substitution; - lastCalleeType = calleeType; - if (returnType != null) { - inferredType = substitution == null - ? returnType - : substitution.substituteType(returnType); - } else { - if (substitution != null) { - calleeType = - substitution.substituteType(calleeType.withoutTypeParameters); - } - inferredType = calleeType.returnType; + if (substitution != null) { + calleeType = + substitution.substituteType(calleeType.withoutTypeParameters); } + inferredType = calleeType.returnType; assert( !containsFreeFunctionTypeVariables(inferredType), "Inferred return type $inferredType contains free variables." @@ -4227,3 +4197,11 @@ class TypedTearoff { TypedTearoff(this.tearoffType, this.tearoff); } + +FunctionType replaceReturnType(FunctionType functionType, DartType returnType) { + return new FunctionType(functionType.positionalParameters, returnType, + functionType.declaredNullability, + requiredParameterCount: functionType.requiredParameterCount, + namedParameters: functionType.namedParameters, + typeParameters: functionType.typeParameters); +}