[NI] Make behaviour of anonymous functions consistent with lambdas
Fix completion of anonymous functions with expression body without expected type. Premature completion led to losing type info from outer calls. Also report type mismatches on empty lambda expressions. KT-34729 In progress
This commit is contained in:
Generated
+10
@@ -8469,6 +8469,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
|
||||
runTest("compiler/testData/diagnostics/tests/generics/kt30590.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt34729.kt")
|
||||
public void testKt34729() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/generics/kt34729.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt5508.kt")
|
||||
public void testKt5508() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/generics/kt5508.kt");
|
||||
@@ -10537,6 +10542,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/completion"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousFunction.kt")
|
||||
public void testAnonymousFunction() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("basic.kt")
|
||||
public void testBasic() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/basic.kt");
|
||||
|
||||
+1
@@ -273,6 +273,7 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
is ArgumentConstraintPosition -> position.argument
|
||||
is ReceiverConstraintPosition -> position.argument
|
||||
is LHSArgumentConstraintPosition -> position.argument
|
||||
is LambdaArgumentConstraintPosition -> position.lambda.atom
|
||||
else -> null
|
||||
}
|
||||
argument?.let {
|
||||
|
||||
+1
-11
@@ -56,6 +56,7 @@ import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||
import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
|
||||
import static org.jetbrains.kotlin.types.TypeUtils.*;
|
||||
import static org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.*;
|
||||
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingServices.getNewInferenceLambdaInfo;
|
||||
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*;
|
||||
|
||||
public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
@@ -945,17 +946,6 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
replaceJumpOutPossible(true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static KotlinResolutionCallbacksImpl.LambdaInfo getNewInferenceLambdaInfo(
|
||||
@NotNull ExpressionTypingContext context,
|
||||
@NotNull KtElement function
|
||||
) {
|
||||
if (function instanceof KtFunction) {
|
||||
return context.trace.get(BindingContext.NEW_INFERENCE_LAMBDA_INFO, (KtFunction) function);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static KotlinType getFunctionExpectedReturnType(
|
||||
@NotNull FunctionDescriptor descriptor,
|
||||
|
||||
+42
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionCallbacksImpl;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.LambdaContextInfo;
|
||||
import org.jetbrains.kotlin.resolve.scopes.*;
|
||||
import org.jetbrains.kotlin.types.ErrorUtils;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
@@ -224,7 +225,11 @@ public class ExpressionTypingServices {
|
||||
trace, functionInnerScope, dataFlowInfo, NO_EXPECTED_TYPE, getLanguageVersionSettings(),
|
||||
expressionTypingComponents.dataFlowValueFactory
|
||||
);
|
||||
|
||||
KotlinResolutionCallbacksImpl.LambdaInfo lambdaInfo = getNewInferenceLambdaInfo(context, function);
|
||||
context = updateContextFromNILambdaInfo(lambdaInfo, context);
|
||||
KotlinTypeInfo typeInfo = expressionTypingFacade.getTypeInfo(bodyExpression, context, function.hasBlockBody());
|
||||
updateLambdaContextInfoForAnonymousFunction(lambdaInfo, typeInfo, context);
|
||||
|
||||
KotlinType type = typeInfo.getType();
|
||||
if (type != null) {
|
||||
@@ -235,6 +240,43 @@ public class ExpressionTypingServices {
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateLambdaContextInfoForAnonymousFunction(
|
||||
@Nullable KotlinResolutionCallbacksImpl.LambdaInfo lambdaInfo,
|
||||
@NotNull KotlinTypeInfo bodyExpressionTypeInfo,
|
||||
@NotNull ExpressionTypingContext context
|
||||
) {
|
||||
if (lambdaInfo == null) return;
|
||||
|
||||
LambdaContextInfo contextInfo = lambdaInfo.getLastExpressionInfo();
|
||||
contextInfo.setTypeInfo(bodyExpressionTypeInfo);
|
||||
contextInfo.setDataFlowInfoAfter(null);
|
||||
contextInfo.setLexicalScope(context.scope);
|
||||
contextInfo.setTrace(context.trace);
|
||||
}
|
||||
|
||||
private static ExpressionTypingContext updateContextFromNILambdaInfo(
|
||||
@Nullable KotlinResolutionCallbacksImpl.LambdaInfo lambdaInfo,
|
||||
@NotNull ExpressionTypingContext context
|
||||
) {
|
||||
if (lambdaInfo != null) {
|
||||
context = context
|
||||
.replaceContextDependency(lambdaInfo.getContextDependency())
|
||||
.replaceExpectedType(lambdaInfo.getExpectedType());
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static KotlinResolutionCallbacksImpl.LambdaInfo getNewInferenceLambdaInfo(
|
||||
@NotNull ExpressionTypingContext context,
|
||||
@NotNull KtElement function
|
||||
) {
|
||||
if (function instanceof KtFunction) {
|
||||
return context.trace.get(BindingContext.NEW_INFERENCE_LAMBDA_INFO, (KtFunction) function);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits block statements propagating data flow information from the first to the last.
|
||||
* Determines block returned type and data flow information at the end of the block AND
|
||||
|
||||
-1
@@ -139,7 +139,6 @@ class PostponedArgumentsAnalyzer(
|
||||
if (returnArguments.isEmpty()) {
|
||||
val unitType = lambda.returnType.builtIns.unitType
|
||||
val lambdaReturnType = lambda.returnType.let(::substitute)
|
||||
c.getBuilder().addSubtypeConstraint(lambdaReturnType, unitType, LambdaArgumentConstraintPosition(lambda))
|
||||
c.getBuilder().addSubtypeConstraint(unitType, lambdaReturnType, LambdaArgumentConstraintPosition(lambda))
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ fun test(a: (Int) -> Int) {
|
||||
}
|
||||
|
||||
fun test2(a: () -> List<Int>) {
|
||||
test2(fun () = <!NI;NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, OI;TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>listOf<!>())
|
||||
test2(fun () = <!OI;TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>listOf<!>())
|
||||
}
|
||||
|
||||
val a: (Int) -> Unit = fun(x) { checkSubtype<Int>(x) }
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// !LANGUAGE: +NewInference
|
||||
|
||||
interface ILength {
|
||||
val length: Int
|
||||
}
|
||||
|
||||
class Impl(override val length: Int) : ILength
|
||||
|
||||
fun <T> foo(a: (Int) -> T) = 0
|
||||
fun <T : ILength> bar(a: (Int) -> T) {
|
||||
a(42).length
|
||||
}
|
||||
|
||||
fun test() {
|
||||
foo<String> { }
|
||||
bar<Impl> { }
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// !LANGUAGE: +NewInference
|
||||
|
||||
interface ILength {
|
||||
val length: Int
|
||||
}
|
||||
|
||||
class Impl(override val length: Int) : ILength
|
||||
|
||||
fun <T> foo(a: (Int) -> T) = 0
|
||||
fun <T : ILength> bar(a: (Int) -> T) {
|
||||
a(42).length
|
||||
}
|
||||
|
||||
fun test() {
|
||||
foo<String> <!NI;TYPE_MISMATCH!>{ <!OI;TYPE_MISMATCH!><!>}<!>
|
||||
bar<Impl> <!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH!>{ <!OI;TYPE_MISMATCH!><!>}<!>
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ T : ILength> bar(/*0*/ a: (kotlin.Int) -> T): kotlin.Unit
|
||||
public fun </*0*/ T> foo(/*0*/ a: (kotlin.Int) -> T): kotlin.Int
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public interface ILength {
|
||||
public abstract val length: kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Impl : ILength {
|
||||
public constructor Impl(/*0*/ length: kotlin.Int)
|
||||
public open override /*1*/ val length: kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
fun take(fn: () -> List<String>) {}
|
||||
fun <L> inferFromLambda(fn: () -> L): L = TODO()
|
||||
|
||||
fun <T> materialize(): T = TODO()
|
||||
fun <I> id(arg: I) = arg
|
||||
|
||||
fun testFunctions() {
|
||||
take { materialize() }
|
||||
take(fun() = materialize())
|
||||
take(fun(): List<String> = materialize())
|
||||
take(fun(): List<String> {
|
||||
return materialize()
|
||||
})
|
||||
}
|
||||
|
||||
fun testNestedCalls() {
|
||||
id<String>(inferFromLambda { materialize() })
|
||||
id<String>(inferFromLambda(fun() = materialize()))
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
fun take(fn: () -> List<String>) {}
|
||||
fun <L> inferFromLambda(fn: () -> L): L = TODO()
|
||||
|
||||
fun <T> materialize(): T = TODO()
|
||||
fun <I> id(arg: I) = arg
|
||||
|
||||
fun testFunctions() {
|
||||
take { materialize() }
|
||||
take(fun() = materialize())
|
||||
take(fun(): List<String> = materialize())
|
||||
take(fun(): List<String> {
|
||||
return materialize()
|
||||
})
|
||||
}
|
||||
|
||||
fun testNestedCalls() {
|
||||
id<String>(inferFromLambda { materialize() })
|
||||
id<String>(inferFromLambda(fun() = materialize()))
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ I> id(/*0*/ arg: I): I
|
||||
public fun </*0*/ L> inferFromLambda(/*0*/ fn: () -> L): L
|
||||
public fun </*0*/ T> materialize(): T
|
||||
public fun take(/*0*/ fn: () -> kotlin.collections.List<kotlin.String>): kotlin.Unit
|
||||
public fun testFunctions(): kotlin.Unit
|
||||
public fun testNestedCalls(): kotlin.Unit
|
||||
@@ -8476,6 +8476,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
runTest("compiler/testData/diagnostics/tests/generics/kt30590.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt34729.kt")
|
||||
public void testKt34729() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/generics/kt34729.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt5508.kt")
|
||||
public void testKt5508() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/generics/kt5508.kt");
|
||||
@@ -10544,6 +10549,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/completion"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousFunction.kt")
|
||||
public void testAnonymousFunction() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("basic.kt")
|
||||
public void testBasic() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/basic.kt");
|
||||
|
||||
Generated
+10
@@ -8471,6 +8471,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
runTest("compiler/testData/diagnostics/tests/generics/kt30590.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt34729.kt")
|
||||
public void testKt34729() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/generics/kt34729.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt5508.kt")
|
||||
public void testKt5508() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/generics/kt5508.kt");
|
||||
@@ -10539,6 +10544,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/completion"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousFunction.kt")
|
||||
public void testAnonymousFunction() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/anonymousFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("basic.kt")
|
||||
public void testBasic() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/basic.kt");
|
||||
|
||||
Reference in New Issue
Block a user