diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirMetadataSerializer.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirMetadataSerializer.kt index 786fa762bb2..cf565080bca 100644 --- a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirMetadataSerializer.kt +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirMetadataSerializer.kt @@ -86,6 +86,7 @@ class FirMetadataSerializer( returnTypeRef = function.returnTypeRef.approximated(toSuper = true, typeParameterSet) receiverTypeRef = function.receiverTypeRef?.approximated(toSuper = false, typeParameterSet) isLambda = (function as? FirAnonymousFunction)?.isLambda == true + hasExplicitParameterList = (function as? FirAnonymousFunction)?.hasExplicitParameterList == true valueParameters.addAll(function.valueParameters.map { buildValueParameterCopy(it) { returnTypeRef = it.returnTypeRef.approximated(toSuper = false, typeParameterSet) diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/CopyUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/CopyUtils.kt index 8f77b730587..e79d052ab6f 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/CopyUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/CopyUtils.kt @@ -99,6 +99,7 @@ fun FirAnonymousFunction.copy( this.receiverTypeRef = receiverTypeRef symbol = this@copy.symbol isLambda = this@copy.isLambda + hasExplicitParameterList = this@copy.hasExplicitParameterList this.valueParameters.addAll(valueParameters) this.body = body this.annotations.addAll(annotations) diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index 2294cfd3518..5b43044c7f0 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -1548,6 +1548,7 @@ class DeclarationsConverter( receiverTypeRef = receiverType symbol = functionSymbol isLambda = false + hasExplicitParameterList = true label = context.getLastLabel(functionDeclaration) val labelName = label?.name ?: context.calleeNamesForLambda.lastOrNull()?.identifier target = FirFunctionTarget(labelName = labelName, isLambda = false) 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 c7d7c9d98f1..937752ea173 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 @@ -125,10 +125,12 @@ class ExpressionsConverter( private fun convertLambdaExpression(lambdaExpression: LighterASTNode): FirExpression { val valueParameterList = mutableListOf() var block: LighterASTNode? = null + var hasArrow = false lambdaExpression.getChildNodesByType(FUNCTION_LITERAL).first().forEachChildren { when (it.tokenType) { VALUE_PARAMETER_LIST -> valueParameterList += declarationsConverter.convertValueParameters(it, ValueParameterDeclaration.LAMBDA) BLOCK -> block = it + ARROW -> hasArrow = true } } @@ -142,6 +144,7 @@ class ExpressionsConverter( receiverTypeRef = implicitType symbol = FirAnonymousFunctionSymbol() isLambda = true + hasExplicitParameterList = hasArrow label = context.getLastLabel(lambdaExpression) ?: context.calleeNamesForLambda.lastOrNull()?.let { buildLabel { source = expressionSource.fakeElement(FirFakeSourceElementKind.GeneratedLambdaLabel) 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 8b053ef72a3..35a2505e38c 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 @@ -1223,6 +1223,7 @@ open class RawFirBuilder( receiverTypeRef = receiverType symbol = FirAnonymousFunctionSymbol() isLambda = false + hasExplicitParameterList = true label = context.getLastLabel(function) labelName = label?.name ?: context.calleeNamesForLambda.lastOrNull()?.identifier } @@ -1338,6 +1339,7 @@ open class RawFirBuilder( receiverTypeRef = receiverType symbol = FirAnonymousFunctionSymbol() isLambda = true + hasExplicitParameterList = expression.functionLiteral.arrow != null val destructuringStatements = mutableListOf() for (valueParameter in literal.valueParameters) { diff --git a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.kt b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.kt index 781eb68447c..62a36ba1a1c 100644 --- a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.kt +++ b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.kt @@ -31,4 +31,6 @@ fun test(list: List) { val simple = { } +val simpleWithArrow = { -> } + val another = { 42 } \ No newline at end of file diff --git a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.lazyBodies.txt b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.lazyBodies.txt index 7c646906766..056f6daf1a7 100644 --- a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.lazyBodies.txt +++ b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.lazyBodies.txt @@ -23,5 +23,7 @@ FILE: lambda.kt public? final? fun test(list: List): R|kotlin/Unit| { LAZY_BLOCK } public? final? val simple: = LAZY_EXPRESSION public? get(): + public? final? val simpleWithArrow: = LAZY_EXPRESSION + public? get(): public? final? val another: = LAZY_EXPRESSION public? get(): diff --git a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.txt b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.txt index 8eeee45ad9c..8f527962a82 100644 --- a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.txt +++ b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.txt @@ -70,6 +70,11 @@ FILE: lambda.kt ^ Unit } + public? get(): + public? final? val simpleWithArrow: = fun .()(): { + ^ Unit + } + public? get(): public? final? val another: = fun .(): { IntegerLiteral(42) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt index e432397c705..732eda6ee1b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceUtils.kt @@ -59,7 +59,7 @@ fun extractLambdaInfoFromFunctionalType( var coerceFirstParameterToExtensionReceiver = false val argumentValueParameters = argument.valueParameters - val parameters = if (argument.isLambda && argumentValueParameters.isEmpty() && expectedParameters.size < 2) { + val parameters = if (argument.isLambda && !argument.hasExplicitParameterList && expectedParameters.size < 2) { expectedParameters // Infer existence of a parameter named `it` of an appropriate type. } else { if (duringCompletion && diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/FirContractResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/FirContractResolveTransformer.kt index 194bdd5e3b7..d6013ba7ea8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/FirContractResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/FirContractResolveTransformer.kt @@ -167,6 +167,7 @@ open class FirContractResolveTransformer( receiverTypeRef = buildImplicitTypeRef() symbol = FirAnonymousFunctionSymbol() isLambda = true + hasExplicitParameterList = true body = buildBlock { contractDescription.rawEffects.forEach { diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirAnonymousFunction.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirAnonymousFunction.kt index b5687247dbc..2373e7a13cf 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirAnonymousFunction.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/FirAnonymousFunction.kt @@ -45,6 +45,7 @@ abstract class FirAnonymousFunction : FirFunction(), FirTypeParametersOwner { abstract val invocationKind: EventOccurrencesRange? abstract val inlineStatus: InlineStatus abstract val isLambda: Boolean + abstract val hasExplicitParameterList: Boolean abstract override val typeParameters: List abstract val typeRef: FirTypeRef diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirAnonymousFunctionBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirAnonymousFunctionBuilder.kt index d3fcef051ea..01c270e7e70 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirAnonymousFunctionBuilder.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirAnonymousFunctionBuilder.kt @@ -59,6 +59,7 @@ class FirAnonymousFunctionBuilder : FirFunctionBuilder, FirAnnotationContainerBu var invocationKind: EventOccurrencesRange? = null var inlineStatus: InlineStatus = InlineStatus.Unknown var isLambda: Boolean by kotlin.properties.Delegates.notNull() + var hasExplicitParameterList: Boolean by kotlin.properties.Delegates.notNull() val typeParameters: MutableList = mutableListOf() var typeRef: FirTypeRef = FirImplicitTypeRefImpl(null) @@ -82,6 +83,7 @@ class FirAnonymousFunctionBuilder : FirFunctionBuilder, FirAnnotationContainerBu invocationKind, inlineStatus, isLambda, + hasExplicitParameterList, typeParameters, typeRef, ) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirAnonymousFunctionImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirAnonymousFunctionImpl.kt index 59aecc75418..63298a24331 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirAnonymousFunctionImpl.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirAnonymousFunctionImpl.kt @@ -52,6 +52,7 @@ internal class FirAnonymousFunctionImpl( override var invocationKind: EventOccurrencesRange?, override var inlineStatus: InlineStatus, override val isLambda: Boolean, + override val hasExplicitParameterList: Boolean, override val typeParameters: MutableList, override var typeRef: FirTypeRef, ) : FirAnonymousFunction() { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt index 865bc2adde3..bb5f1209822 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt @@ -626,6 +626,12 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode = print(".") } print("") + if (anonymousFunction.valueParameters.isEmpty() && + anonymousFunction.hasExplicitParameterList && + anonymousFunction.returnTypeRef is FirImplicitTypeRef + ) { + print("()") + } anonymousFunction.valueParameters.renderParameters() print(": ") anonymousFunction.returnTypeRef.accept(this) diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt index 9c4bd6ba31b..38eb07b6655 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -282,6 +282,7 @@ object NodeConfigurator : AbstractFieldConfigurator(FirTreeBuild isMutable = true } +booleanField("isLambda") + +booleanField("hasExplicitParameterList") +typeParameters +field(typeRef, withReplace = true) } diff --git a/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.fir.kt b/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.fir.kt index 1a7f1c67f04..290e1f39012 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.fir.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/ExpectedParametersTypesMismatch.fir.kt @@ -24,9 +24,9 @@ fun test1() { foo1 { x, y -> "" } - foo1 { + foo1 { -> 42 - } + } foo2 { diff --git a/compiler/testData/diagnostics/tests/overload/EmptyArgumentListInLambda.fir.kt b/compiler/testData/diagnostics/tests/overload/EmptyArgumentListInLambda.fir.kt deleted file mode 100644 index c633afa5c9b..00000000000 --- a/compiler/testData/diagnostics/tests/overload/EmptyArgumentListInLambda.fir.kt +++ /dev/null @@ -1,8 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER - -fun foo(g: () -> Int) {} -fun foo(f: (Int) -> Int) {} - -fun test() { - foo { -> 42 } -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/overload/EmptyArgumentListInLambda.kt b/compiler/testData/diagnostics/tests/overload/EmptyArgumentListInLambda.kt index 06de4fb5a0e..b545dd431df 100644 --- a/compiler/testData/diagnostics/tests/overload/EmptyArgumentListInLambda.kt +++ b/compiler/testData/diagnostics/tests/overload/EmptyArgumentListInLambda.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER fun foo(g: () -> Int) {} diff --git a/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt b/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt index c34ec14ed4e..4a05ef61e77 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt @@ -130,7 +130,7 @@ fun test4() { // to non-extension lambda 2 } open class A(a: () -> Unit) { - constructor(f: (String) -> Unit) : this({ -> f("") }) + constructor(f: (String) -> Unit) : this({ -> f("") }) } class B: A({ s -> "1" }) diff --git a/compiler/testData/diagnostics/tests/regressions/kt352.fir.kt b/compiler/testData/diagnostics/tests/regressions/kt352.fir.kt index 293c30b4192..35c388d0c42 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt352.fir.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt352.fir.kt @@ -2,14 +2,14 @@ package kt352 -val f : (Any) -> Unit = { -> } //type mismatch +val f : (Any) -> Unit = { -> } //type mismatch fun foo() { - val f : (Any) -> Unit = { -> } //!!! no error + val f : (Any) -> Unit = { -> } //!!! no error } class A() { - val f : (Any) -> Unit = { -> } //type mismatch + val f : (Any) -> Unit = { -> } //type mismatch } //more tests @@ -25,4 +25,4 @@ val testIt : (Any) -> Unit = { if (it is String) { doSmth(it) } -} \ No newline at end of file +}