[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:
Kirill Rakhman
2023-08-18 17:35:24 +02:00
committed by Space Team
parent 6a9c50325e
commit 8de36c416e
19 changed files with 215 additions and 90 deletions
@@ -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
}
}
)
}
@@ -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
}
}
)
}
@@ -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
}
}
)
}
@@ -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
}
}
)
}
@@ -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|)
}
}
)
}
@@ -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|
}
}
)
}
@@ -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
}
}
}
@@ -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()) {
@@ -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")))
}
@@ -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)
}
}
}
@@ -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
}