FE: Preserve context parameter names for anonymous functions
Otherwise, UNRESOLVED_REFERENCE is reported on `a` usages.
Without this change, the test was red even in the original state
because we start resolving `val f = context(a: String) fun () = a`
as it belongs to the call.
diff --git a/compiler/fir/analysis-tests/testData/resolve/contextParameters/declarationAndUsages/contextualAnonymousFunction.fir.txt b/compiler/fir/analysis-tests/testData/resolve/contextParameters/declarationAndUsages/contextualAnonymousFunction.fir.txt
index 3f7a531..85b0845 100644
--- a/compiler/fir/analysis-tests/testData/resolve/contextParameters/declarationAndUsages/contextualAnonymousFunction.fir.txt
+++ b/compiler/fir/analysis-tests/testData/resolve/contextParameters/declarationAndUsages/contextualAnonymousFunction.fir.txt
@@ -11,19 +11,19 @@
}
}
- public final val t: R|@ContextFunctionTypeParams (A) -> kotlin/Unit| = context(<unused var>: R|A|) fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
+ public final val t: R|@ContextFunctionTypeParams (A) -> kotlin/Unit| = context(a: R|A|) fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
}
public get(): R|@ContextFunctionTypeParams (A) -> kotlin/Unit|
- public final val t2: R|@ContextFunctionTypeParams (A) -> kotlin/Unit| = context(<unused var>: R|A|) @R|Ann|() fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
+ public final val t2: R|@ContextFunctionTypeParams (A) -> kotlin/Unit| = context(a: R|A|) @R|Ann|() fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
}
public get(): R|@ContextFunctionTypeParams (A) -> kotlin/Unit|
public final fun foo(): R|kotlin/Unit| {
- lval t: R|@ContextFunctionTypeParams (A) -> kotlin/Unit| = context(<unused var>: R|A|) fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
+ lval t: R|@ContextFunctionTypeParams (A) -> kotlin/Unit| = context(a: R|A|) fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
}
- lval t2: R|@ContextFunctionTypeParams (A) -> kotlin/Unit| = context(<unused var>: R|A|) @R|Ann|() fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
+ lval t2: R|@ContextFunctionTypeParams (A) -> kotlin/Unit| = context(a: R|A|) @R|Ann|() fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
}
}
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt
index 9ae00db..e8d01d7 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt
@@ -407,27 +407,42 @@
}
if (contextParameters.isNotEmpty()) {
- lambda.replaceContextParameters(
- contextParameters.map { contextParameterType ->
- buildValueParameter {
- resolvePhase = FirResolvePhase.BODY_RESOLVE
- source = lambdaAtom.anonymousFunction.source?.fakeElement(KtFakeSourceElementKind.LambdaContextParameter)
- containingDeclarationSymbol = lambda.symbol
- moduleData = session.moduleData
- origin = FirDeclarationOrigin.Source
- name = SpecialNames.UNDERSCORE_FOR_UNUSED_VAR
- symbol = FirValueParameterSymbol(name)
- returnTypeRef = contextParameterType
- .approximateLambdaInputType(symbol, withPCLASession, candidate)
- .toFirResolvedTypeRef(lambdaAtom.anonymousFunction.source?.fakeElement(KtFakeSourceElementKind.LambdaContextParameter))
- valueParameterKind = if (session.languageVersionSettings.supportsFeature(LanguageFeature.ContextParameters)) {
- FirValueParameterKind.ContextParameter
- } else {
- FirValueParameterKind.LegacyContextReceiver
+ if (lambda.isLambda) {
+ lambda.replaceContextParameters(
+ contextParameters.map { contextParameterType ->
+ buildValueParameter {
+ resolvePhase = FirResolvePhase.BODY_RESOLVE
+ source = lambdaAtom.anonymousFunction.source?.fakeElement(KtFakeSourceElementKind.LambdaContextParameter)
+ containingDeclarationSymbol = lambda.symbol
+ moduleData = session.moduleData
+ origin = FirDeclarationOrigin.Source
+ name = SpecialNames.UNDERSCORE_FOR_UNUSED_VAR
+ symbol = FirValueParameterSymbol(name)
+ returnTypeRef = contextParameterType
+ .approximateLambdaInputType(symbol, withPCLASession, candidate)
+ .toFirResolvedTypeRef(lambdaAtom.anonymousFunction.source?.fakeElement(KtFakeSourceElementKind.LambdaContextParameter))
+ valueParameterKind =
+ if (session.languageVersionSettings.supportsFeature(LanguageFeature.ContextParameters)) {
+ FirValueParameterKind.ContextParameter
+ } else {
+ FirValueParameterKind.LegacyContextReceiver
+ }
}
}
+ )
+ } else {
+ check(lambda.contextParameters.size == contextParameters.size)
+ lambda.contextParameters.forEachIndexed { index, parameter ->
+ val contextParameterType = contextParameters[index]
+ parameter.replaceReturnTypeRef(
+ contextParameterType
+ .approximateLambdaInputType(parameter.symbol, withPCLASession, candidate)
+ .toFirResolvedTypeRef(
+ lambdaAtom.anonymousFunction.source?.fakeElement(KtFakeSourceElementKind.LambdaContextParameter)
+ )
+ )
}
- )
+ }
}
val lookupTracker = session.lookupTracker
diff --git a/compiler/testData/codegen/box/contextParameters/contextualAnonymousFunction.kt b/compiler/testData/codegen/box/contextParameters/contextualAnonymousFunction.kt
index 8bc9e98..5bd633d 100644
--- a/compiler/testData/codegen/box/contextParameters/contextualAnonymousFunction.kt
+++ b/compiler/testData/codegen/box/contextParameters/contextualAnonymousFunction.kt
@@ -1,10 +1,15 @@
// IGNORE_BACKEND_K1: ANY
// LANGUAGE: +ContextParameters
+fun foo(f: Any): String = (f as Function1<String, String>).invoke("OK")
+
fun box(): String {
+ val x = foo(context(a: String) fun () = a)
+ if (x != "OK") return "fail"
+
val f = context(a: String) fun () = a
return with("OK") {
f()
}
-}
\ No newline at end of file
+}