[RAW FIR] Put destructuring statements outside of main lambda block
This fixes a false positive REDECLARATION when you want to shadow a destructured lambda parameter inside the lambda. #KT-60771 Fixed
This commit is contained in:
committed by
Space Team
parent
6a9c50325e
commit
8de36c416e
analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/destructuringDeclarationInLambda.txt
Vendored
+4
-1
@@ -31,7 +31,10 @@ FILE: [ResolvedTo(IMPORTS)] destructuringDeclarationInLambda.kt
|
||||
R|/x|(<L> = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1<X, kotlin/Unit>] x@fun <anonymous>([ResolvedTo(BODY_RESOLVE)] <destruct>: R|X|): R|kotlin/Unit| <inline=NoInline> {
|
||||
[ResolvedTo(BODY_RESOLVE)] lval a: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component1|()
|
||||
[ResolvedTo(BODY_RESOLVE)] lval b: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component2|()
|
||||
^@x Unit
|
||||
{
|
||||
^@x Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
+4
-1
@@ -31,7 +31,10 @@ FILE: [ResolvedTo(IMPORTS)] destructuringDeclarationParameterInLambda.kt
|
||||
R|/x|(<L> = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function2<X, kotlin/Int, kotlin/Unit>] x@fun <anonymous>([ResolvedTo(BODY_RESOLVE)] <destruct>: R|X|, [ResolvedTo(BODY_RESOLVE)] i: R|kotlin/Int|): R|kotlin/Unit| <inline=NoInline> {
|
||||
[ResolvedTo(BODY_RESOLVE)] lval a: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component1|()
|
||||
[ResolvedTo(BODY_RESOLVE)] lval b: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component2|()
|
||||
^@x Unit
|
||||
{
|
||||
^@x Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
+4
-1
@@ -31,7 +31,10 @@ FILE: [ResolvedTo(IMPORTS)] entryInDestructuringDeclarationParameterInLambda.kt
|
||||
R|/x|(<L> = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1<X, kotlin/Unit>] x@fun <anonymous>([ResolvedTo(BODY_RESOLVE)] <destruct>: R|X|): R|kotlin/Unit| <inline=NoInline> {
|
||||
[ResolvedTo(BODY_RESOLVE)] lval a: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component1|()
|
||||
[ResolvedTo(BODY_RESOLVE)] lval b: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component2|()
|
||||
^@x Unit
|
||||
{
|
||||
^@x Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
+4
-1
@@ -31,7 +31,10 @@ FILE: [ResolvedTo(IMPORTS)] entryUnderscoreInDestructuringDeclarationParameterIn
|
||||
R|/x|(<L> = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1<X, kotlin/Unit>] x@fun <anonymous>([ResolvedTo(BODY_RESOLVE)] <destruct>: R|X|): R|kotlin/Unit| <inline=NoInline> {
|
||||
[ResolvedTo(BODY_RESOLVE)] lval <unused var>: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component1|()
|
||||
[ResolvedTo(BODY_RESOLVE)] lval b: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component2|()
|
||||
^@x Unit
|
||||
{
|
||||
^@x Unit
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
+24
-6
@@ -27,19 +27,28 @@ FILE: destructuring.kt
|
||||
R|/foo1|(<L> = foo1@fun <anonymous>(<destruct>: R|C|): R|kotlin/Unit| <inline=NoInline> {
|
||||
lval x: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component1|()
|
||||
lval y: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component2|()
|
||||
R|/C.C|(R|<local>/x|, R|<local>/y|)
|
||||
{
|
||||
R|/C.C|(R|<local>/x|, R|<local>/y|)
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/foo1|(<L> = foo1@fun <anonymous>(<destruct>: R|C|): R|kotlin/Unit| <inline=NoInline> {
|
||||
lval x: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component1|()
|
||||
lval y: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component2|()
|
||||
R|/C.C|(R|<local>/x|, R|<local>/y|)
|
||||
{
|
||||
R|/C.C|(R|<local>/x|, R|<local>/y|)
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/foo1|(<L> = foo1@fun <anonymous>(<destruct>: R|C|): R|kotlin/Unit| <inline=NoInline> {
|
||||
lval x: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component1<CS errors: /C.component1>#|()
|
||||
lval y: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component2<CS errors: /C.component2>#|()
|
||||
R|/C.C<Inapplicable(INAPPLICABLE): /C.C>#|(R|<local>/x|, R|<local>/y|)
|
||||
{
|
||||
R|/C.C<Inapplicable(INAPPLICABLE): /C.C>#|(R|<local>/x|, R|<local>/y|)
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/foo2|(<L> = foo2@fun <anonymous>(<destruct>: R|C|, <destruct>: R|C|): R|kotlin/Unit| <inline=NoInline> {
|
||||
@@ -47,7 +56,10 @@ FILE: destructuring.kt
|
||||
lval y: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component2|()
|
||||
lval z: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component1|()
|
||||
lval w: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component2|()
|
||||
R|/C.C|(R|<local>/x|.R|kotlin/Int.plus|(R|<local>/z|), R|<local>/y|.R|kotlin/String.plus|(R|<local>/w|))
|
||||
{
|
||||
R|/C.C|(R|<local>/x|.R|kotlin/Int.plus|(R|<local>/z|), R|<local>/y|.R|kotlin/String.plus|(R|<local>/w|))
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/foo2|(<L> = foo2@fun <anonymous>(<destruct>: R|C|, <destruct>: R|C|): R|kotlin/Unit| <inline=NoInline> {
|
||||
@@ -55,7 +67,10 @@ FILE: destructuring.kt
|
||||
lval y: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component2|()
|
||||
lval z: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component1|()
|
||||
lval w: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component2|()
|
||||
R|/C.C|(R|<local>/x|.R|kotlin/Int.plus|(R|<local>/z|), R|<local>/y|.R|kotlin/String.plus|(R|<local>/w|))
|
||||
{
|
||||
R|/C.C|(R|<local>/x|.R|kotlin/Int.plus|(R|<local>/z|), R|<local>/y|.R|kotlin/String.plus|(R|<local>/w|))
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
R|/foo2|(<L> = foo2@fun <anonymous>(<destruct>: R|C|, <destruct>: R|C|): R|kotlin/Unit| <inline=NoInline> {
|
||||
@@ -63,7 +78,10 @@ FILE: destructuring.kt
|
||||
lval y: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component2<CS errors: /C.component2>#|()
|
||||
lval z: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component1<CS errors: /C.component1>#|()
|
||||
lval w: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component2<CS errors: /C.component2>#|()
|
||||
R|/C.C<Inapplicable(INAPPLICABLE): /C.C>#|(R|<local>/x|.R|kotlin/String.plus|(R|<local>/z|), R|<local>/y|.R|kotlin/Int.plus|(R|<local>/w|))
|
||||
{
|
||||
R|/C.C<Inapplicable(INAPPLICABLE): /C.C>#|(R|<local>/x|.R|kotlin/String.plus|(R|<local>/z|), R|<local>/y|.R|kotlin/Int.plus|(R|<local>/w|))
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -37,8 +37,11 @@ FILE: components.kt
|
||||
R|<local>/list|.R|kotlin/collections/forEach|<R|D|>(<L> = forEach@fun <anonymous>(<destruct>: R|D|): R|kotlin/Unit| <inline=Inline, kind=UNKNOWN> {
|
||||
lval x: R|kotlin/Int| = R|<local>/<destruct>|.R|/D.component1|()
|
||||
lval y: R|kotlin/String| = R|<local>/<destruct>|.R|/D.component2|()
|
||||
R|kotlin/io/println|(R|<local>/x|)
|
||||
R|kotlin/io/println|(R|<local>/y|)
|
||||
{
|
||||
R|kotlin/io/println|(R|<local>/x|)
|
||||
R|kotlin/io/println|(R|<local>/y|)
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Vendored
+4
-1
@@ -25,7 +25,10 @@ FILE: buildListLazy.kt
|
||||
R|/getEnv|().R|kotlin/collections/forEach|<R|NameAndSafeValue|>(<L> = forEach@fun <anonymous>(<destruct>: R|NameAndSafeValue|): R|kotlin/Unit| <inline=Inline, kind=UNKNOWN> {
|
||||
lval name: R|kotlin/String| = R|<local>/<destruct>|.R|/NameAndSafeValue.component1|()
|
||||
lval value: R|kotlin/Int| = R|<local>/<destruct>|.R|/NameAndSafeValue.component2|()
|
||||
this@R|special/anonymous|.R|kotlin/collections/plusAssign|<R|NameAndSafeValue|>(R|/NameAndSafeValue.NameAndSafeValue|(R|<local>/name|, R|<local>/value|))
|
||||
{
|
||||
this@R|special/anonymous|.R|kotlin/collections/plusAssign|<R|NameAndSafeValue|>(R|/NameAndSafeValue.NameAndSafeValue|(R|<local>/name|, R|<local>/value|))
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
this@R|special/anonymous|.R|kotlin/collections/sortBy|<R|NameAndSafeValue|, R|kotlin/String|>(<L> = sortBy@fun <anonymous>(it: R|NameAndSafeValue|): R|kotlin/String?| <inline=CrossInline> {
|
||||
|
||||
@@ -15,9 +15,12 @@ FILE: test.kt
|
||||
R|<local>/map|.R|kotlin/collections/forEach|<R|kotlin/String!|, R|kotlin/String!|>(<L> = forEach@fun <anonymous>(<destruct>: R|kotlin/collections/Map.Entry<kotlin/String!, kotlin/String!>|): R|kotlin/Unit| <inline=Inline, kind=UNKNOWN> {
|
||||
lval key: R|kotlin/String!| = R|<local>/<destruct>|.R|kotlin/collections/component1|<R|kotlin/String!|, R|kotlin/String!|>()
|
||||
lval value: R|kotlin/String!| = R|<local>/<destruct>|.R|kotlin/collections/component2|<R|kotlin/String!|, R|kotlin/String!|>()
|
||||
R|kotlin/io/println|(<strcat>(R|<local>/key|, String(: ), R|<local>/value|))
|
||||
R|<local>/key|.R|kotlin/String.length|
|
||||
R|<local>/value|.R|kotlin/String.length|
|
||||
{
|
||||
R|kotlin/io/println|(<strcat>(R|<local>/key|, String(: ), R|<local>/value|))
|
||||
R|<local>/key|.R|kotlin/String.length|
|
||||
R|<local>/value|.R|kotlin/String.length|
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -37,9 +40,12 @@ FILE: test.kt
|
||||
R|<local>/map|.R|kotlin/collections/forEach|<R|kotlin/String|, R|kotlin/String|>(<L> = forEach@fun <anonymous>(<destruct>: R|kotlin/collections/Map.Entry<kotlin/String, kotlin/String>|): R|kotlin/Unit| <inline=Inline, kind=UNKNOWN> {
|
||||
lval key: R|kotlin/String| = R|<local>/<destruct>|.R|kotlin/collections/component1|<R|kotlin/String|, R|kotlin/String|>()
|
||||
lval value: R|kotlin/String| = R|<local>/<destruct>|.R|kotlin/collections/component2|<R|kotlin/String|, R|kotlin/String|>()
|
||||
R|kotlin/io/println|(<strcat>(R|<local>/key|, String(: ), R|<local>/value|))
|
||||
R|<local>/key|.R|kotlin/String.length|
|
||||
R|<local>/value|.R|kotlin/String.length|
|
||||
{
|
||||
R|kotlin/io/println|(<strcat>(R|<local>/key|, String(: ), R|<local>/value|))
|
||||
R|<local>/key|.R|kotlin/String.length|
|
||||
R|<local>/value|.R|kotlin/String.length|
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
+33
-23
@@ -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<FirStatement>.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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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<FirStatement> { 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()) {
|
||||
|
||||
+19
-8
@@ -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")))
|
||||
}
|
||||
|
||||
+47
-27
@@ -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<FirStatement>.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
-6
@@ -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 =
|
||||
|
||||
@@ -30,7 +30,10 @@ FILE: lambda.kt
|
||||
use#(<L> = use@fun <implicit>.<anonymous>(<destruct>: <implicit>): <implicit> <inline=Unknown> {
|
||||
lval x: <implicit> = R|<local>/<destruct>|.component1#()
|
||||
lval y: <implicit> = R|<local>/<destruct>|.component2#()
|
||||
x#.plus#(y#)
|
||||
{
|
||||
x#.plus#(y#)
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
^foo use#(<L> = use@fun <implicit>.<anonymous>(): <implicit> <inline=Unknown> {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
@@ -6,8 +6,12 @@ fun foo3(i: (Pair) -> Unit) {}
|
||||
|
||||
fun bar(x: Int, y: Int) {
|
||||
foo1 { <!NAME_SHADOWING!>x<!> -> x }
|
||||
foo2 { <!NAME_SHADOWING!>x<!>: Int, <!NAME_SHADOWING!>y<!>: Int -> x + y }
|
||||
foo3 { (x, y) -> x + y }
|
||||
foo2 { <!NAME_SHADOWING!>x<!>: Int, <!NAME_SHADOWING!>y<!>: Int ->
|
||||
val <!NAME_SHADOWING!>x<!> = x
|
||||
}
|
||||
foo3 { (x, y) ->
|
||||
val <!NAME_SHADOWING!>x<!> = x
|
||||
}
|
||||
}
|
||||
|
||||
data class Pair(val a: Int, val b: Int)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
fun ff(): Int {
|
||||
var i = 1
|
||||
for (<!NAME_SHADOWING!>i<!> in 0..10) {
|
||||
}
|
||||
|
||||
for ((<!NAME_SHADOWING!>i<!>, j) in listOf(Pair(1,2))) {
|
||||
val <!NAME_SHADOWING!>i<!> = i
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user