Fix type inference for function expression parameters
This commit is contained in:
@@ -410,6 +410,14 @@ public class JetPsiUtil {
|
||||
return element instanceof JetSimpleNameExpression && isBackingFieldReference((JetSimpleNameExpression)element);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JetElement getExpressionOrLastStatementInBlock(@Nullable JetExpression expression) {
|
||||
if (expression instanceof JetBlockExpression) {
|
||||
return getLastStatementInABlock((JetBlockExpression) expression);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JetElement getLastStatementInABlock(@Nullable JetBlockExpression blockExpression) {
|
||||
if (blockExpression == null) return null;
|
||||
|
||||
+12
-10
@@ -136,7 +136,7 @@ public class ArgumentTypeResolver {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetFunctionLiteralExpression getFunctionLiteralArgument(
|
||||
public static JetFunction getFunctionLiteralArgument(
|
||||
@NotNull JetExpression expression, @NotNull ResolutionContext context
|
||||
) {
|
||||
assert isFunctionLiteralArgument(expression, context);
|
||||
@@ -145,12 +145,15 @@ public class ArgumentTypeResolver {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JetFunctionLiteralExpression getFunctionLiteralArgumentIfAny(
|
||||
private static JetFunction getFunctionLiteralArgumentIfAny(
|
||||
@NotNull JetExpression expression, @NotNull ResolutionContext context
|
||||
) {
|
||||
JetExpression deparenthesizedExpression = getLastElementDeparenthesized(expression, context);
|
||||
if (deparenthesizedExpression instanceof JetFunctionLiteralExpression) {
|
||||
return (JetFunctionLiteralExpression) deparenthesizedExpression;
|
||||
return ((JetFunctionLiteralExpression) deparenthesizedExpression).getFunctionLiteral();
|
||||
}
|
||||
if (deparenthesizedExpression instanceof JetFunction) {
|
||||
return (JetFunction) deparenthesizedExpression;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -199,12 +202,12 @@ public class ArgumentTypeResolver {
|
||||
@NotNull
|
||||
public JetTypeInfo getFunctionLiteralTypeInfo(
|
||||
@NotNull JetExpression expression,
|
||||
@NotNull JetFunctionLiteralExpression functionLiteralExpression,
|
||||
@NotNull JetFunction functionLiteral,
|
||||
@NotNull CallResolutionContext<?> context,
|
||||
@NotNull ResolveArgumentsMode resolveArgumentsMode
|
||||
) {
|
||||
if (resolveArgumentsMode == SHAPE_FUNCTION_ARGUMENTS) {
|
||||
JetType type = getShapeTypeOfFunctionLiteral(functionLiteralExpression, context.scope, context.trace, true);
|
||||
JetType type = getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, true);
|
||||
return JetTypeInfo.create(type, context.dataFlowInfo);
|
||||
}
|
||||
return expressionTypingServices.getTypeInfo(expression, context.replaceContextDependency(INDEPENDENT));
|
||||
@@ -212,28 +215,27 @@ public class ArgumentTypeResolver {
|
||||
|
||||
@Nullable
|
||||
public JetType getShapeTypeOfFunctionLiteral(
|
||||
@NotNull JetFunctionLiteralExpression expression,
|
||||
@NotNull JetFunction functionLiteral,
|
||||
@NotNull JetScope scope,
|
||||
@NotNull BindingTrace trace,
|
||||
boolean expectedTypeIsUnknown
|
||||
) {
|
||||
if (expression.getFunctionLiteral().getValueParameterList() == null) {
|
||||
if (functionLiteral.getValueParameterList() == null) {
|
||||
return expectedTypeIsUnknown ? PLACEHOLDER_FUNCTION_TYPE : builtIns.getFunctionType(
|
||||
Annotations.EMPTY, null, Collections.<JetType>emptyList(), DONT_CARE);
|
||||
}
|
||||
List<JetParameter> valueParameters = expression.getValueParameters();
|
||||
List<JetParameter> valueParameters = functionLiteral.getValueParameters();
|
||||
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
|
||||
trace, "trace to resolve function literal parameter types");
|
||||
List<JetType> parameterTypes = Lists.newArrayList();
|
||||
for (JetParameter parameter : valueParameters) {
|
||||
parameterTypes.add(resolveTypeRefWithDefault(parameter.getTypeReference(), scope, temporaryTrace, DONT_CARE));
|
||||
}
|
||||
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
||||
JetType returnType = resolveTypeRefWithDefault(functionLiteral.getTypeReference(), scope, temporaryTrace, DONT_CARE);
|
||||
assert returnType != null;
|
||||
JetType receiverType = resolveTypeRefWithDefault(functionLiteral.getReceiverTypeReference(), scope, temporaryTrace, null);
|
||||
return builtIns.getFunctionType(Annotations.EMPTY, receiverType, parameterTypes,
|
||||
returnType);
|
||||
returnType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -281,12 +281,12 @@ public class CandidateResolver {
|
||||
if (argumentExpression == null) return;
|
||||
if (!ArgumentTypeResolver.isFunctionLiteralArgument(argumentExpression, context)) return;
|
||||
|
||||
JetFunctionLiteralExpression functionLiteralExpression = ArgumentTypeResolver.getFunctionLiteralArgument(argumentExpression, context);
|
||||
JetFunction functionLiteral = ArgumentTypeResolver.getFunctionLiteralArgument(argumentExpression, context);
|
||||
|
||||
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
|
||||
JetType expectedType = constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT);
|
||||
if (expectedType == null || TypeUtils.isDontCarePlaceholder(expectedType)) {
|
||||
expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteralExpression, context.scope, context.trace, false);
|
||||
expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, false);
|
||||
}
|
||||
if (expectedType == null || !KotlinBuiltIns.isFunctionOrExtensionFunctionType(expectedType)
|
||||
|| CallResolverUtil.hasUnknownFunctionParameter(expectedType)) {
|
||||
@@ -301,7 +301,7 @@ public class CandidateResolver {
|
||||
TemporaryTraceAndCache temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create(
|
||||
context, "trace to resolve function literal with expected return type", argumentExpression);
|
||||
|
||||
JetElement statementExpression = JetPsiUtil.getLastStatementInABlock(functionLiteralExpression.getBodyExpression());
|
||||
JetElement statementExpression = JetPsiUtil.getExpressionOrLastStatementInBlock(functionLiteral.getBodyExpression());
|
||||
if (statementExpression == null) return;
|
||||
boolean[] mismatch = new boolean[1];
|
||||
ObservableBindingTrace errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
|
||||
@@ -311,7 +311,7 @@ public class CandidateResolver {
|
||||
.replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
|
||||
.replaceContextDependency(INDEPENDENT);
|
||||
JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(
|
||||
argumentExpression, functionLiteralExpression, newContext, RESOLVE_FUNCTION_ARGUMENTS).getType();
|
||||
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).getType();
|
||||
if (!mismatch[0]) {
|
||||
constraintSystem.addSubtypeConstraint(
|
||||
type, effectiveExpectedType, VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.getIndex()));
|
||||
@@ -323,7 +323,7 @@ public class CandidateResolver {
|
||||
CallCandidateResolutionContext<D> newContext = context
|
||||
.replaceExpectedType(expectedTypeWithoutReturnType).replaceDataFlowInfo(dataFlowInfoForArgument)
|
||||
.replaceContextDependency(INDEPENDENT);
|
||||
JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteralExpression, newContext,
|
||||
JetType type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext,
|
||||
RESOLVE_FUNCTION_ARGUMENTS).getType();
|
||||
constraintSystem.addSubtypeConstraint(
|
||||
type, effectiveExpectedType, VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.getIndex()));
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
|
||||
|
||||
fun <T> foo(f : (T) -> T) : T = throw Exception()
|
||||
|
||||
fun test() {
|
||||
val a : Int = foo(fun f(x) = x)
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
internal fun </*0*/ T> foo(/*0*/ f: (T) -> T): T
|
||||
internal fun test(): kotlin.Unit
|
||||
@@ -0,0 +1,18 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||
fun listOf<T>(): List<T> = null!!
|
||||
|
||||
fun test(a: (Int) -> Int) {
|
||||
test(fun (x) = 4)
|
||||
|
||||
test(fun (x) = x)
|
||||
|
||||
test(fun (x): Int { x: Int; return 4 })
|
||||
}
|
||||
|
||||
fun test2(a: () -> List<Int>) {
|
||||
test2(fun () = <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>listOf<!>())
|
||||
}
|
||||
|
||||
val a: (Int) -> Unit = fun(x) { x: Int }
|
||||
|
||||
val b: (Int) -> Unit = <!TYPE_MISMATCH!>fun(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) {}<!>
|
||||
@@ -0,0 +1,7 @@
|
||||
package
|
||||
|
||||
internal val a: (kotlin.Int) -> kotlin.Unit
|
||||
internal val b: (kotlin.Int) -> kotlin.Unit
|
||||
internal fun </*0*/ T> listOf(): kotlin.List<T>
|
||||
internal fun test(/*0*/ a: (kotlin.Int) -> kotlin.Int): kotlin.Unit
|
||||
internal fun test2(/*0*/ a: () -> kotlin.List<kotlin.Int>): kotlin.Unit
|
||||
@@ -13,13 +13,13 @@ val e: (Int, String) -> Int = <!TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_
|
||||
val f: (Int) -> Int = <!TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) = 3<!>
|
||||
|
||||
fun test1(a: (Int) -> Unit) {
|
||||
test1(fun (<!CANNOT_INFER_PARAMETER_TYPE!>x<!>) { <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>x<!> : Int})
|
||||
test1(fun (x) { x : Int})
|
||||
}
|
||||
|
||||
fun test2(a: (Int) -> Unit) {
|
||||
test2(<!TYPE_MISMATCH!>fun (x: String) {}<!>)
|
||||
test2(<!TYPE_MISMATCH!>fun (<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>) {}<!>)
|
||||
}
|
||||
|
||||
fun test3(a: (Int, String) -> Unit) {
|
||||
test3(<!TYPE_MISMATCH!>fun (x: String) {}<!>)
|
||||
test3(<!TYPE_MISMATCH!>fun <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>(<!EXPECTED_PARAMETER_TYPE_MISMATCH!>x: String<!>)<!> {}<!>)
|
||||
}
|
||||
@@ -4634,6 +4634,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("DifficultInferenceForParameter.kt")
|
||||
public void testDifficultInferenceForParameter() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionAsExpression/DifficultInferenceForParameter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ForbiddenNonLocalReturn.kt")
|
||||
public void testForbiddenNonLocalReturn() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionAsExpression/ForbiddenNonLocalReturn.kt");
|
||||
@@ -4646,6 +4652,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InferenceParametersTypes.kt")
|
||||
public void testInferenceParametersTypes() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionAsExpression/InferenceParametersTypes.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("MissingParameterTypes.kt")
|
||||
public void testMissingParameterTypes() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionAsExpression/MissingParameterTypes.kt");
|
||||
|
||||
Reference in New Issue
Block a user