diff --git a/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/destructuringDeclarationInLambda.txt b/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/destructuringDeclarationInLambda.txt index b595982e8ce..b9b4a6a0c73 100644 --- a/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/destructuringDeclarationInLambda.txt +++ b/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/destructuringDeclarationInLambda.txt @@ -31,7 +31,10 @@ FILE: [ResolvedTo(IMPORTS)] destructuringDeclarationInLambda.kt R|/x|( = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1] x@fun ([ResolvedTo(BODY_RESOLVE)] : R|X|): R|kotlin/Unit| { [ResolvedTo(BODY_RESOLVE)] lval a: R|kotlin/Int| = R|/|.R|/X.component1|() [ResolvedTo(BODY_RESOLVE)] lval b: R|kotlin/Int| = R|/|.R|/X.component2|() - ^@x Unit + { + ^@x Unit + } + } ) } \ No newline at end of file diff --git a/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/destructuringDeclarationParameterInLambda.txt b/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/destructuringDeclarationParameterInLambda.txt index d350f57f025..14499203747 100644 --- a/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/destructuringDeclarationParameterInLambda.txt +++ b/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/destructuringDeclarationParameterInLambda.txt @@ -31,7 +31,10 @@ FILE: [ResolvedTo(IMPORTS)] destructuringDeclarationParameterInLambda.kt R|/x|( = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function2] x@fun ([ResolvedTo(BODY_RESOLVE)] : R|X|, [ResolvedTo(BODY_RESOLVE)] i: R|kotlin/Int|): R|kotlin/Unit| { [ResolvedTo(BODY_RESOLVE)] lval a: R|kotlin/Int| = R|/|.R|/X.component1|() [ResolvedTo(BODY_RESOLVE)] lval b: R|kotlin/Int| = R|/|.R|/X.component2|() - ^@x Unit + { + ^@x Unit + } + } ) } \ No newline at end of file diff --git a/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryInDestructuringDeclarationParameterInLambda.txt b/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryInDestructuringDeclarationParameterInLambda.txt index 76300270676..0e6554429d7 100644 --- a/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryInDestructuringDeclarationParameterInLambda.txt +++ b/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryInDestructuringDeclarationParameterInLambda.txt @@ -31,7 +31,10 @@ FILE: [ResolvedTo(IMPORTS)] entryInDestructuringDeclarationParameterInLambda.kt R|/x|( = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1] x@fun ([ResolvedTo(BODY_RESOLVE)] : R|X|): R|kotlin/Unit| { [ResolvedTo(BODY_RESOLVE)] lval a: R|kotlin/Int| = R|/|.R|/X.component1|() [ResolvedTo(BODY_RESOLVE)] lval b: R|kotlin/Int| = R|/|.R|/X.component2|() - ^@x Unit + { + ^@x Unit + } + } ) } \ No newline at end of file diff --git a/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryUnderscoreInDestructuringDeclarationParameterInLambda.txt b/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryUnderscoreInDestructuringDeclarationParameterInLambda.txt index c984dee6119..f837e104d60 100644 --- a/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryUnderscoreInDestructuringDeclarationParameterInLambda.txt +++ b/analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryUnderscoreInDestructuringDeclarationParameterInLambda.txt @@ -31,7 +31,10 @@ FILE: [ResolvedTo(IMPORTS)] entryUnderscoreInDestructuringDeclarationParameterIn R|/x|( = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1] x@fun ([ResolvedTo(BODY_RESOLVE)] : R|X|): R|kotlin/Unit| { [ResolvedTo(BODY_RESOLVE)] lval : R|kotlin/Int| = R|/|.R|/X.component1|() [ResolvedTo(BODY_RESOLVE)] lval b: R|kotlin/Int| = R|/|.R|/X.component2|() - ^@x Unit + { + ^@x Unit + } + } ) } \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolve/arguments/destructuring.fir.txt b/compiler/fir/analysis-tests/testData/resolve/arguments/destructuring.fir.txt index 3d2f7967602..1bae69d65a9 100644 --- a/compiler/fir/analysis-tests/testData/resolve/arguments/destructuring.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/arguments/destructuring.fir.txt @@ -27,19 +27,28 @@ FILE: destructuring.kt R|/foo1|( = foo1@fun (: R|C|): R|kotlin/Unit| { lval x: R|kotlin/Int| = R|/|.R|/C.component1|() lval y: R|kotlin/String| = R|/|.R|/C.component2|() - R|/C.C|(R|/x|, R|/y|) + { + R|/C.C|(R|/x|, R|/y|) + } + } ) R|/foo1|( = foo1@fun (: R|C|): R|kotlin/Unit| { lval x: R|kotlin/Int| = R|/|.R|/C.component1|() lval y: R|kotlin/String| = R|/|.R|/C.component2|() - R|/C.C|(R|/x|, R|/y|) + { + R|/C.C|(R|/x|, R|/y|) + } + } ) R|/foo1|( = foo1@fun (: R|C|): R|kotlin/Unit| { lval x: R|kotlin/String| = R|/|.R|/C.component1#|() lval y: R|kotlin/Int| = R|/|.R|/C.component2#|() - R|/C.C#|(R|/x|, R|/y|) + { + R|/C.C#|(R|/x|, R|/y|) + } + } ) R|/foo2|( = foo2@fun (: R|C|, : R|C|): R|kotlin/Unit| { @@ -47,7 +56,10 @@ FILE: destructuring.kt lval y: R|kotlin/String| = R|/|.R|/C.component2|() lval z: R|kotlin/Int| = R|/|.R|/C.component1|() lval w: R|kotlin/String| = R|/|.R|/C.component2|() - R|/C.C|(R|/x|.R|kotlin/Int.plus|(R|/z|), R|/y|.R|kotlin/String.plus|(R|/w|)) + { + R|/C.C|(R|/x|.R|kotlin/Int.plus|(R|/z|), R|/y|.R|kotlin/String.plus|(R|/w|)) + } + } ) R|/foo2|( = foo2@fun (: R|C|, : R|C|): R|kotlin/Unit| { @@ -55,7 +67,10 @@ FILE: destructuring.kt lval y: R|kotlin/String| = R|/|.R|/C.component2|() lval z: R|kotlin/Int| = R|/|.R|/C.component1|() lval w: R|kotlin/String| = R|/|.R|/C.component2|() - R|/C.C|(R|/x|.R|kotlin/Int.plus|(R|/z|), R|/y|.R|kotlin/String.plus|(R|/w|)) + { + R|/C.C|(R|/x|.R|kotlin/Int.plus|(R|/z|), R|/y|.R|kotlin/String.plus|(R|/w|)) + } + } ) R|/foo2|( = foo2@fun (: R|C|, : R|C|): R|kotlin/Unit| { @@ -63,7 +78,10 @@ FILE: destructuring.kt lval y: R|kotlin/Int| = R|/|.R|/C.component2#|() lval z: R|kotlin/String| = R|/|.R|/C.component1#|() lval w: R|kotlin/Int| = R|/|.R|/C.component2#|() - R|/C.C#|(R|/x|.R|kotlin/String.plus|(R|/z|), R|/y|.R|kotlin/Int.plus|(R|/w|)) + { + R|/C.C#|(R|/x|.R|kotlin/String.plus|(R|/z|), R|/y|.R|kotlin/Int.plus|(R|/w|)) + } + } ) } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/components.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/components.fir.txt index 4bbe80b6601..608840b227c 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/components.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/components.fir.txt @@ -37,8 +37,11 @@ FILE: components.kt R|/list|.R|kotlin/collections/forEach|( = forEach@fun (: R|D|): R|kotlin/Unit| { lval x: R|kotlin/Int| = R|/|.R|/D.component1|() lval y: R|kotlin/String| = R|/|.R|/D.component2|() - R|kotlin/io/println|(R|/x|) - R|kotlin/io/println|(R|/y|) + { + R|kotlin/io/println|(R|/x|) + R|kotlin/io/println|(R|/y|) + } + } ) } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/inference/problems/buildListLazy.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/inference/problems/buildListLazy.fir.txt index 7865e005f3f..2c4abf85735 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/inference/problems/buildListLazy.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/inference/problems/buildListLazy.fir.txt @@ -25,7 +25,10 @@ FILE: buildListLazy.kt R|/getEnv|().R|kotlin/collections/forEach|( = forEach@fun (: R|NameAndSafeValue|): R|kotlin/Unit| { lval name: R|kotlin/String| = R|/|.R|/NameAndSafeValue.component1|() lval value: R|kotlin/Int| = R|/|.R|/NameAndSafeValue.component2|() - this@R|special/anonymous|.R|kotlin/collections/plusAssign|(R|/NameAndSafeValue.NameAndSafeValue|(R|/name|, R|/value|)) + { + this@R|special/anonymous|.R|kotlin/collections/plusAssign|(R|/NameAndSafeValue.NameAndSafeValue|(R|/name|, R|/value|)) + } + } ) this@R|special/anonymous|.R|kotlin/collections/sortBy|( = sortBy@fun (it: R|NameAndSafeValue|): R|kotlin/String?| { diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/MyMap.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/MyMap.fir.txt index 0ed3fe7f221..d11ffb5d3ea 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/MyMap.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/MyMap.fir.txt @@ -15,9 +15,12 @@ FILE: test.kt R|/map|.R|kotlin/collections/forEach|( = forEach@fun (: R|kotlin/collections/Map.Entry|): R|kotlin/Unit| { lval key: R|kotlin/String!| = R|/|.R|kotlin/collections/component1|() lval value: R|kotlin/String!| = R|/|.R|kotlin/collections/component2|() - R|kotlin/io/println|((R|/key|, String(: ), R|/value|)) - R|/key|.R|kotlin/String.length| - R|/value|.R|kotlin/String.length| + { + R|kotlin/io/println|((R|/key|, String(: ), R|/value|)) + R|/key|.R|kotlin/String.length| + R|/value|.R|kotlin/String.length| + } + } ) } @@ -37,9 +40,12 @@ FILE: test.kt R|/map|.R|kotlin/collections/forEach|( = forEach@fun (: R|kotlin/collections/Map.Entry|): R|kotlin/Unit| { lval key: R|kotlin/String| = R|/|.R|kotlin/collections/component1|() lval value: R|kotlin/String| = R|/|.R|kotlin/collections/component2|() - R|kotlin/io/println|((R|/key|, String(: ), R|/value|)) - R|/key|.R|kotlin/String.length| - R|/value|.R|kotlin/String.length| + { + R|kotlin/io/println|((R|/key|, String(: ), R|/value|)) + R|/key|.R|kotlin/String.length| + R|/value|.R|kotlin/String.length| + } + } ) } diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt index 261fb7f8975..f8c130dbd44 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildProperty import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.builder.FirCallBuilder import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList import org.jetbrains.kotlin.fir.expressions.builder.buildBlock @@ -82,30 +83,39 @@ fun generateDestructuringBlock( tmpVariable: Boolean ): FirBlock { return buildBlock { - if (tmpVariable) { - statements += container - } - val isVar = multiDeclaration.isVar - for ((index, entry) in multiDeclaration.entries.withIndex()) { - if (entry == null) continue - statements += buildProperty { - this.moduleData = moduleData - origin = FirDeclarationOrigin.Source - returnTypeRef = entry.returnTypeRef - name = entry.name - initializer = buildComponentCall { - val componentCallSource = entry.source?.fakeElement(KtFakeSourceElementKind.DesugaredComponentFunctionCall) - source = componentCallSource - explicitReceiver = generateResolvedAccessExpression(componentCallSource, container) - componentIndex = index + 1 - } - this.isVar = isVar - symbol = FirPropertySymbol(entry.name) // TODO? - source = entry.source - isLocal = true - status = FirDeclarationStatusImpl(Visibilities.Local, Modality.FINAL) - annotations += entry.annotations + statements.addDestructuringStatements(moduleData, multiDeclaration, container, tmpVariable) + } +} + +internal fun MutableList.addDestructuringStatements( + moduleData: FirModuleData, + multiDeclaration: DestructuringDeclaration, + container: FirVariable, + tmpVariable: Boolean, +) { + if (tmpVariable) { + this += container + } + val isVar = multiDeclaration.isVar + for ((index, entry) in multiDeclaration.entries.withIndex()) { + if (entry == null) continue + this += buildProperty { + this.moduleData = moduleData + origin = FirDeclarationOrigin.Source + returnTypeRef = entry.returnTypeRef + name = entry.name + initializer = buildComponentCall { + val componentCallSource = entry.source?.fakeElement(KtFakeSourceElementKind.DesugaredComponentFunctionCall) + source = componentCallSource + explicitReceiver = generateResolvedAccessExpression(componentCallSource, container) + componentIndex = index + 1 } + this.isVar = isVar + symbol = FirPropertySymbol(entry.name) // TODO? + source = entry.source + isLocal = true + status = FirDeclarationStatusImpl(Visibilities.Local, Modality.FINAL) + annotations += entry.annotations } } } diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt index b091cbab311..6343d870ebe 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt @@ -133,7 +133,7 @@ class LightTreeRawFirDeclarationBuilder( return convertBlockExpressionWithoutBuilding(block).build() } - fun convertBlockExpressionWithoutBuilding(block: LighterASTNode): FirBlockBuilder { + fun convertBlockExpressionWithoutBuilding(block: LighterASTNode, kind: KtFakeSourceElementKind? = null): FirBlockBuilder { val firStatements = block.forEachChildrenReturnList { node, container -> @Suppress("RemoveRedundantQualifierName") when (node.tokenType) { @@ -147,7 +147,7 @@ class LightTreeRawFirDeclarationBuilder( } } return FirBlockBuilder().apply { - source = block.toFirSourceElement() + source = block.toFirSourceElement(kind) firStatements.forEach { firStatement -> val isForLoopBlock = firStatement is FirBlock && firStatement.source?.kind == KtFakeSourceElementKind.DesugaredForLoop if (firStatement !is FirBlock || isForLoopBlock || firStatement.annotations.isNotEmpty()) { diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirExpressionBuilder.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirExpressionBuilder.kt index 8934eb68eb6..c21a21a01fe 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirExpressionBuilder.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirExpressionBuilder.kt @@ -8,16 +8,13 @@ package org.jetbrains.kotlin.fir.lightTree.converter import com.intellij.lang.LighterASTNode import com.intellij.psi.TokenType import com.intellij.util.diff.FlyweightCapableTreeStructure +import org.jetbrains.kotlin.* import org.jetbrains.kotlin.ElementTypeUtils.getOperationSymbol import org.jetbrains.kotlin.ElementTypeUtils.isExpression -import org.jetbrains.kotlin.KtFakeSourceElementKind -import org.jetbrains.kotlin.KtLightSourceElement import org.jetbrains.kotlin.KtNodeTypes.* -import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.descriptors.EffectiveVisibility import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.fakeElement import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.builder.* import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin @@ -53,6 +50,7 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType import org.jetbrains.kotlin.psi.stubs.elements.KtNameReferenceExpressionElementType import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.util.OperatorNameConventions +import org.jetbrains.kotlin.utils.addToStdlib.runIf class LightTreeRawFirExpressionBuilder( session: FirSession, @@ -176,12 +174,12 @@ class LightTreeRawFirExpressionBuilder( isNoinline = false isVararg = false } - destructuringStatements += generateDestructuringBlock( + destructuringStatements.addDestructuringStatements( baseModuleData, multiDeclaration, multiParameter, tmpVariable = false - ).statements + ) multiParameter } else { valueParameter.firValueParameter @@ -190,7 +188,10 @@ class LightTreeRawFirExpressionBuilder( body = withForcedLocalContext { if (block != null) { - declarationBuilder.convertBlockExpressionWithoutBuilding(block!!).apply { + val kind = runIf(destructuringStatements.isNotEmpty()) { + KtFakeSourceElementKind.LambdaDestructuringBlock + } + val bodyBlock = declarationBuilder.convertBlockExpressionWithoutBuilding(block!!, kind).apply { statements.firstOrNull()?.let { if (it.isContractBlockFirCheck()) { this@buildAnonymousFunction.contractDescription = it.toLegacyRawContractDescription() @@ -209,8 +210,18 @@ class LightTreeRawFirExpressionBuilder( } ) } - statements.addAll(0, destructuringStatements) }.build() + + if (destructuringStatements.isNotEmpty()) { + // Destructured variables must be in a separate block so that they can be shadowed. + buildBlock { + source = bodyBlock.source?.realElement() + statements.addAll(destructuringStatements) + statements.add(bodyBlock) + } + } else { + bodyBlock + } } else { buildSingleExpressionBlock(buildErrorExpression(null, ConeSyntaxDiagnostic("Lambda has no body"))) } diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiConversionUtils.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiConversionUtils.kt index 440d553f5b8..ab3f0656b04 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiConversionUtils.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiConversionUtils.kt @@ -131,35 +131,55 @@ internal fun generateDestructuringBlock( ): FirBlock { return buildBlock { source = multiDeclaration.toKtPsiSourceElement() - if (tmpVariable) { - statements += container + statements.addDestructuringStatements( + moduleData, + multiDeclaration, + container, + tmpVariable, + localEntries, + extractAnnotationsTo, + toFirOrImplicitTypeRef + ) + } +} + +internal fun MutableList.addDestructuringStatements( + moduleData: FirModuleData, + multiDeclaration: KtDestructuringDeclaration, + container: FirVariable, + tmpVariable: Boolean, + localEntries: Boolean, + extractAnnotationsTo: KtAnnotated.(FirAnnotationContainerBuilder) -> Unit, + toFirOrImplicitTypeRef: KtTypeReference?.() -> FirTypeRef, +) { + if (tmpVariable) { + this += container + } + val isVar = multiDeclaration.isVar + for ((index, entry) in multiDeclaration.entries.withIndex()) { + val name = if (entry.nameIdentifier?.text == "_") { + SpecialNames.UNDERSCORE_FOR_UNUSED_VAR + } else { + entry.nameAsSafeName } - val isVar = multiDeclaration.isVar - for ((index, entry) in multiDeclaration.entries.withIndex()) { - val name = if (entry.nameIdentifier?.text == "_") { - SpecialNames.UNDERSCORE_FOR_UNUSED_VAR - } else { - entry.nameAsSafeName - } - val entrySource = entry.toKtPsiSourceElement() - statements += buildProperty { - source = entrySource - this.moduleData = moduleData - origin = FirDeclarationOrigin.Source - returnTypeRef = entry.typeReference.toFirOrImplicitTypeRef() - this.name = name - initializer = buildComponentCall { - val componentCallSource = entrySource.fakeElement(KtFakeSourceElementKind.DesugaredComponentFunctionCall) - source = componentCallSource - explicitReceiver = generateResolvedAccessExpression(componentCallSource, container) - componentIndex = index + 1 - } - this.isVar = isVar - isLocal = localEntries - status = FirDeclarationStatusImpl(if (localEntries) Visibilities.Local else Visibilities.Public, Modality.FINAL) - symbol = FirPropertySymbol(name) - entry.extractAnnotationsTo(this) + val entrySource = entry.toKtPsiSourceElement() + this += buildProperty { + source = entrySource + this.moduleData = moduleData + origin = FirDeclarationOrigin.Source + returnTypeRef = entry.typeReference.toFirOrImplicitTypeRef() + this.name = name + initializer = buildComponentCall { + val componentCallSource = entrySource.fakeElement(KtFakeSourceElementKind.DesugaredComponentFunctionCall) + source = componentCallSource + explicitReceiver = generateResolvedAccessExpression(componentCallSource, container) + componentIndex = index + 1 } + this.isVar = isVar + isLocal = localEntries + status = FirDeclarationStatusImpl(if (localEntries) Visibilities.Local else Visibilities.Public, Modality.FINAL) + symbol = FirPropertySymbol(name) + entry.extractAnnotationsTo(this) } } } diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt index 69e04887ec4..56fbfb9e50a 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiRawFirBuilder.kt @@ -1738,14 +1738,14 @@ open class PsiRawFirBuilder( isNoinline = false isVararg = false } - destructuringStatements += generateDestructuringBlock( + destructuringStatements.addDestructuringStatements( baseModuleData, multiDeclaration, multiParameter, tmpVariable = false, localEntries = true, extractAnnotationsTo = { extractAnnotationsTo(it) }, - ) { toFirOrImplicitType() }.statements + ) { toFirOrImplicitType() } multiParameter } else { val typeRef = valueParameter.typeReference?.convertSafe() ?: FirImplicitTypeRefImplWithoutSource @@ -1768,7 +1768,10 @@ open class PsiRawFirBuilder( val errorExpression = buildErrorExpression(source, ConeSyntaxDiagnostic("Lambda has no body")) FirSingleExpressionBlock(errorExpression.toReturn()) } else { - configureBlockWithoutBuilding(ktBody).apply { + val kind = runIf(destructuringStatements.isNotEmpty()) { + KtFakeSourceElementKind.LambdaDestructuringBlock + } + val bodyBlock = configureBlockWithoutBuilding(ktBody, kind).apply { statements.firstOrNull()?.let { if (it.isContractBlockFirCheck()) { this@buildAnonymousFunction.contractDescription = it.toLegacyRawContractDescription() @@ -1787,8 +1790,18 @@ open class PsiRawFirBuilder( } ) } - statements.addAll(0, destructuringStatements) }.build() + + if (destructuringStatements.isNotEmpty()) { + // Destructured variables must be in a separate block so that they can be shadowed. + buildBlock { + source = bodyBlock.source?.realElement() + statements.addAll(destructuringStatements) + statements.add(bodyBlock) + } + } else { + bodyBlock + } } } context.firFunctionTargets.removeLast() @@ -2244,9 +2257,9 @@ open class PsiRawFirBuilder( return configureBlockWithoutBuilding(expression).build() } - private fun configureBlockWithoutBuilding(expression: KtBlockExpression): FirBlockBuilder { + private fun configureBlockWithoutBuilding(expression: KtBlockExpression, kind: KtFakeSourceElementKind? = null): FirBlockBuilder { return FirBlockBuilder().apply { - source = expression.toFirSourceElement() + source = expression.toFirSourceElement(kind) for (statement in expression.statements) { val firStatement = statement.toFirStatement { "Statement expected: ${statement.text}" } val isForLoopBlock = 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 cb082909a3c..e656315d6a2 100644 --- a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.txt +++ b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/lambda.txt @@ -30,7 +30,10 @@ FILE: lambda.kt use#( = use@fun .(: ): { lval x: = R|/|.component1#() lval y: = R|/|.component2#() - x#.plus#(y#) + { + x#.plus#(y#) + } + } ) ^foo use#( = use@fun .(): { diff --git a/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt b/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt index 1bfb1d2a94e..594e139b756 100644 --- a/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt +++ b/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt @@ -220,6 +220,10 @@ sealed class KtFakeSourceElementKind(final override val shouldSkipErrorTypeRepor // where `it` parameter declaration has fake source object ItLambdaParameter : KtFakeSourceElementKind() + // { (a, b) -> foo() } -> { x -> val (a, b) = x; { foo() } } + // where the inner block { foo() } has fake source + object LambdaDestructuringBlock : KtFakeSourceElementKind() + // for java annotations implicit constructor is generated // with a fake source which refers to containing class object ImplicitJavaAnnotationConstructor : KtFakeSourceElementKind() diff --git a/compiler/testData/diagnostics/tests/shadowing/ShadowLambdaParameter.fir.kt b/compiler/testData/diagnostics/tests/shadowing/ShadowLambdaParameter.fir.kt index 611cba7c02b..d97c8ef794d 100644 --- a/compiler/testData/diagnostics/tests/shadowing/ShadowLambdaParameter.fir.kt +++ b/compiler/testData/diagnostics/tests/shadowing/ShadowLambdaParameter.fir.kt @@ -6,8 +6,12 @@ fun foo3(i: (Pair) -> Unit) {} fun bar(x: Int, y: Int) { foo1 { x -> x } - foo2 { x: Int, y: Int -> x + y } - foo3 { (x, y) -> x + y } + foo2 { x: Int, y: Int -> + val x = x + } + foo3 { (x, y) -> + val x = x + } } data class Pair(val a: Int, val b: Int) \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/shadowing/ShadowLambdaParameter.kt b/compiler/testData/diagnostics/tests/shadowing/ShadowLambdaParameter.kt index 3292820bf36..e39cf40b411 100644 --- a/compiler/testData/diagnostics/tests/shadowing/ShadowLambdaParameter.kt +++ b/compiler/testData/diagnostics/tests/shadowing/ShadowLambdaParameter.kt @@ -6,8 +6,12 @@ fun foo3(i: (Pair) -> Unit) {} fun bar(x: Int, y: Int) { foo1 { x -> x } - foo2 { x: Int, y: Int -> x + y } - foo3 { (x, y) -> x + y } + foo2 { x: Int, y: Int -> + val x = x + } + foo3 { (x, y) -> + val x = x + } } data class Pair(val a: Int, val b: Int) diff --git a/compiler/testData/diagnostics/tests/shadowing/ShadowVariableInFor.fir.kt b/compiler/testData/diagnostics/tests/shadowing/ShadowVariableInFor.fir.kt index 20a792522e8..57e4602d823 100644 --- a/compiler/testData/diagnostics/tests/shadowing/ShadowVariableInFor.fir.kt +++ b/compiler/testData/diagnostics/tests/shadowing/ShadowVariableInFor.fir.kt @@ -1,6 +1,13 @@ +// WITH_STDLIB + fun ff(): Int { var i = 1 for (i in 0..10) { } + + for ((i, j) in listOf(Pair(1,2))) { + val i = i + } + return i } diff --git a/compiler/testData/diagnostics/tests/shadowing/ShadowVariableInFor.kt b/compiler/testData/diagnostics/tests/shadowing/ShadowVariableInFor.kt index b62b6d0ea30..32467ddf999 100644 --- a/compiler/testData/diagnostics/tests/shadowing/ShadowVariableInFor.kt +++ b/compiler/testData/diagnostics/tests/shadowing/ShadowVariableInFor.kt @@ -1,6 +1,13 @@ +// WITH_STDLIB + fun ff(): Int { var i = 1 for (i in 0..10) { } + + for ((i, j) in listOf(Pair(1,2))) { + val i = i + } + return i }