diff --git a/compiler/fir/analysis-tests/testData/resolve/labelAndReceiverForInfix.kt b/compiler/fir/analysis-tests/testData/resolve/labelAndReceiverForInfix.kt new file mode 100644 index 00000000000..95e4ecd030f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/labelAndReceiverForInfix.kt @@ -0,0 +1,14 @@ +class A { + fun bar() {} +} + +infix fun (() -> Unit).foo(x: A.() -> Unit) {} + +fun main() { + { + return@foo + } foo { + bar() + return@foo + } +} diff --git a/compiler/fir/analysis-tests/testData/resolve/labelAndReceiverForInfix.txt b/compiler/fir/analysis-tests/testData/resolve/labelAndReceiverForInfix.txt new file mode 100644 index 00000000000..24a275d7817 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/labelAndReceiverForInfix.txt @@ -0,0 +1,22 @@ +FILE: labelAndReceiverForInfix.kt + public final class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + public final fun bar(): R|kotlin/Unit| { + } + + } + public final infix fun R|() -> kotlin/Unit|.foo(x: R|A.() -> kotlin/Unit|): R|kotlin/Unit| { + } + public final fun main(): R|kotlin/Unit| { + foo@fun (): R|kotlin/Unit| { + ^@foo Unit + } + .R|/foo|(foo@fun R|A|.(): R|kotlin/Unit| { + this@R|special/anonymous|.R|/A.bar|() + ^@foo Unit + } + ) + } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index 4a8b9fa6145..e486b0fae4b 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -228,6 +228,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/analysis-tests/testData/resolve/javaStaticScopeInheritance.kt"); } + @TestMetadata("labelAndReceiverForInfix.kt") + public void testLabelAndReceiverForInfix() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/labelAndReceiverForInfix.kt"); + } + @TestMetadata("lambdaArgInScopeFunction.kt") public void testLambdaArgInScopeFunction() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/lambdaArgInScopeFunction.kt"); diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index f7c43f130d4..d1a1cd55012 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -228,6 +228,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/javaStaticScopeInheritance.kt"); } + @TestMetadata("labelAndReceiverForInfix.kt") + public void testLabelAndReceiverForInfix() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/labelAndReceiverForInfix.kt"); + } + @TestMetadata("lambdaArgInScopeFunction.kt") public void testLambdaArgInScopeFunction() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/lambdaArgInScopeFunction.kt"); diff --git a/compiler/fir/raw-fir/fir-common/src/org/jetbrains/kotlin/fir/builder/Context.kt b/compiler/fir/raw-fir/fir-common/src/org/jetbrains/kotlin/fir/builder/Context.kt index d027de24f94..7168cd48318 100644 --- a/compiler/fir/raw-fir/fir-common/src/org/jetbrains/kotlin/fir/builder/Context.kt +++ b/compiler/fir/raw-fir/fir-common/src/org/jetbrains/kotlin/fir/builder/Context.kt @@ -10,10 +10,10 @@ import org.jetbrains.kotlin.fir.FirFunctionTarget import org.jetbrains.kotlin.fir.FirLabel import org.jetbrains.kotlin.fir.FirLoopTarget import org.jetbrains.kotlin.fir.expressions.FirExpression -import org.jetbrains.kotlin.fir.expressions.builder.FirFunctionCallBuilder import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name class Context { lateinit var packageFqName: FqName @@ -21,9 +21,9 @@ class Context { val currentClassId get() = ClassId(packageFqName, className, firFunctionTargets.isNotEmpty()) val firFunctionTargets = mutableListOf() - val firFunctionCalls = mutableListOf() + val calleeNamesForLambda = mutableListOf() val firLabels = mutableListOf() val firLoopTargets = mutableListOf() var capturedTypeParameters = persistentListOf() val arraySetArgument = mutableMapOf() -} \ No newline at end of file +} diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt index b35ad65c88f..226a9ea94fd 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt @@ -137,7 +137,7 @@ class ExpressionsConverter( receiverTypeRef = implicitType symbol = FirAnonymousFunctionSymbol() isLambda = true - label = context.firLabels.pop() ?: context.firFunctionCalls.lastOrNull()?.calleeReference?.name?.let { + label = context.firLabels.pop() ?: context.calleeNamesForLambda.lastOrNull()?.let { buildLabel { name = it.asString() } } target = FirFunctionTarget(labelName = label?.name, isLambda = true) @@ -203,7 +203,6 @@ class ExpressionsConverter( var isLeftArgument = true lateinit var operationTokenName: String var leftArgNode: LighterASTNode? = null - var rightArgAsFir: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("No right operand", DiagnosticKind.Syntax)) var rightArg: LighterASTNode? = null var operationReferenceSource: FirLightSourceElement? = null binaryExpression.forEachChildren { @@ -217,7 +216,6 @@ class ExpressionsConverter( if (isLeftArgument) { leftArgNode = it } else { - rightArgAsFir = getAsFirExpression(it, "No right operand") rightArg = it } } @@ -226,7 +224,23 @@ class ExpressionsConverter( val baseSource = binaryExpression.toFirSourceElement() val operationToken = operationTokenName.getOperationSymbol() + if (operationToken == IDENTIFIER) { + context.calleeNamesForLambda += operationTokenName.nameAsSafeName() + } + + val rightArgAsFir = + if (rightArg != null) + getAsFirExpression(rightArg, "No right operand") + else + buildErrorExpression(null, ConeSimpleDiagnostic("No right operand", DiagnosticKind.Syntax)) + val leftArgAsFir = getAsFirExpression(leftArgNode, "No left operand") + + if (operationToken == IDENTIFIER) { + // No need for the callee name since arguments are already generated + context.calleeNamesForLambda.removeLast() + } + when (operationToken) { ELVIS -> return leftArgAsFir.generateNotNullOrOther(baseSession, rightArgAsFir, "elvis", baseSource) @@ -544,9 +558,9 @@ class ExpressionsConverter( this.source = source this.calleeReference = calleeReference - context.firFunctionCalls += this + context.calleeNamesForLambda += calleeReference.name this.extractArgumentsFrom(valueArguments.flatMap { convertValueArguments(it) }, stubMode) - context.firFunctionCalls.removeLast() + context.calleeNamesForLambda.removeLast() } } else { FirQualifiedAccessExpressionBuilder().apply { diff --git a/compiler/fir/raw-fir/light-tree2fir/tests/org/jetbrains/kotlin/fir/lightTree/LightTree2FirConverterTestCaseGenerated.java b/compiler/fir/raw-fir/light-tree2fir/tests/org/jetbrains/kotlin/fir/lightTree/LightTree2FirConverterTestCaseGenerated.java index 4afd936ab50..31de7b9493f 100644 --- a/compiler/fir/raw-fir/light-tree2fir/tests/org/jetbrains/kotlin/fir/lightTree/LightTree2FirConverterTestCaseGenerated.java +++ b/compiler/fir/raw-fir/light-tree2fir/tests/org/jetbrains/kotlin/fir/lightTree/LightTree2FirConverterTestCaseGenerated.java @@ -248,6 +248,11 @@ public class LightTree2FirConverterTestCaseGenerated extends AbstractLightTree2F runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/init.kt"); } + @TestMetadata("labelForInfix.kt") + public void testLabelForInfix() throws Exception { + runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/labelForInfix.kt"); + } + @TestMetadata("lambda.kt") public void testLambda() throws Exception { runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.kt"); diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index 1255c5e1380..a6a2e1209a5 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -911,7 +911,7 @@ class RawFirBuilder( } } val expressionSource = expression.toFirSourceElement() - label = context.firLabels.pop() ?: context.firFunctionCalls.lastOrNull()?.calleeReference?.name?.let { + label = context.firLabels.pop() ?: context.calleeNamesForLambda.lastOrNull()?.let { buildLabel { source = expressionSource name = it.asString() @@ -1472,9 +1472,21 @@ class RawFirBuilder( override fun visitBinaryExpression(expression: KtBinaryExpression, data: Unit): FirElement { val operationToken = expression.operationToken + + if (operationToken == IDENTIFIER) { + context.calleeNamesForLambda += expression.operationReference.getReferencedNameAsName() + } + val leftArgument = expression.left.toFirExpression("No left operand") val rightArgument = expression.right.toFirExpression("No right operand") + + if (operationToken == IDENTIFIER) { + // No need for the callee name since arguments are already generated + context.calleeNamesForLambda.removeLast() + } + val source = expression.toFirSourceElement() + when (operationToken) { ELVIS -> return leftArgument.generateNotNullOrOther(baseSession, rightArgument, "elvis", source) @@ -1617,9 +1629,9 @@ class RawFirBuilder( FirFunctionCallBuilder().apply { this.source = source this.calleeReference = calleeReference - context.firFunctionCalls += this + context.calleeNamesForLambda += calleeReference.name expression.extractArgumentsTo(this) - context.firFunctionCalls.removeLast() + context.calleeNamesForLambda.removeLast() } } diff --git a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/labelForInfix.kt b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/labelForInfix.kt new file mode 100644 index 00000000000..a265b97dc2b --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/labelForInfix.kt @@ -0,0 +1,3 @@ +fun main() { + { length } foo { bar() } +} diff --git a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/labelForInfix.txt b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/labelForInfix.txt new file mode 100644 index 00000000000..e4054a47a02 --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/labelForInfix.txt @@ -0,0 +1,10 @@ +FILE: labelForInfix.kt + public? final? fun main(): R|kotlin/Unit| { + foo@fun .(): { + length# + } + .foo#(foo@fun .(): { + bar#() + } + ) + } diff --git a/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/RawFirBuilderTestCaseGenerated.java b/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/RawFirBuilderTestCaseGenerated.java index 8a7238052ac..0e9231187de 100644 --- a/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/RawFirBuilderTestCaseGenerated.java +++ b/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/RawFirBuilderTestCaseGenerated.java @@ -248,6 +248,11 @@ public class RawFirBuilderTestCaseGenerated extends AbstractRawFirBuilderTestCas runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/init.kt"); } + @TestMetadata("labelForInfix.kt") + public void testLabelForInfix() throws Exception { + runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/labelForInfix.kt"); + } + @TestMetadata("lambda.kt") public void testLambda() throws Exception { runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.kt"); diff --git a/compiler/testData/codegen/box/labels/infixCallLabelling.kt b/compiler/testData/codegen/box/labels/infixCallLabelling.kt index e471dad7174..8b8fa9fc7f3 100644 --- a/compiler/testData/codegen/box/labels/infixCallLabelling.kt +++ b/compiler/testData/codegen/box/labels/infixCallLabelling.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR fun test(x: Int): Int { x myMap { return@myMap @@ -22,4 +21,4 @@ fun box(): String { myMap(0) return "OK" -} \ No newline at end of file +} diff --git a/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/fir/FirVisualizerForRawFirDataGenerated.java b/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/fir/FirVisualizerForRawFirDataGenerated.java index a992fdce975..b032e340c60 100644 --- a/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/fir/FirVisualizerForRawFirDataGenerated.java +++ b/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/fir/FirVisualizerForRawFirDataGenerated.java @@ -248,6 +248,11 @@ public class FirVisualizerForRawFirDataGenerated extends AbstractFirVisualizer { runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/init.kt"); } + @TestMetadata("labelForInfix.kt") + public void testLabelForInfix() throws Exception { + runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/labelForInfix.kt"); + } + @TestMetadata("lambda.kt") public void testLambda() throws Exception { runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.kt"); diff --git a/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/psi/PsiVisualizerForRawFirDataGenerated.java b/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/psi/PsiVisualizerForRawFirDataGenerated.java index 191001114f5..793fbfa41a1 100644 --- a/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/psi/PsiVisualizerForRawFirDataGenerated.java +++ b/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/psi/PsiVisualizerForRawFirDataGenerated.java @@ -248,6 +248,11 @@ public class PsiVisualizerForRawFirDataGenerated extends AbstractPsiVisualizer { runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/init.kt"); } + @TestMetadata("labelForInfix.kt") + public void testLabelForInfix() throws Exception { + runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/labelForInfix.kt"); + } + @TestMetadata("lambda.kt") public void testLambda() throws Exception { runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.kt");