K2: generate Unit conversion for indexed assignment at raw FIR stage

#KT-59748 Fixed
This commit is contained in:
Mikhail Glukhikh
2023-07-24 22:11:30 +02:00
committed by Space Team
parent 1832413a02
commit f20e2dec31
33 changed files with 160 additions and 16 deletions
@@ -8,6 +8,7 @@ FILE: setWithTrailingLambda.kt
^ Unit
}
)
Unit
}
public final data class EditorData : R|kotlin/Any| {
public constructor(meta: R|MyMap<EditorData, kotlin/Any>|): R|EditorData| {
@@ -46,10 +46,13 @@ FILE: arraySet.kt
}
public final fun test_1(a: R|A<B>|): R|kotlin/Unit| {
R|<local>/a|.R|SubstitutionOverride</A.set: R|kotlin/Unit|>|(Int(0), R|/B.B|())
Unit
}
public final fun test_2(a: R|A<C>|): R|kotlin/Unit| {
R|<local>/a|.R|SubstitutionOverride</A.set: R|kotlin/Unit|>|(Int(0), R|/C.C|())
Unit
}
public final fun test_3(a: R|A<D>|): R|kotlin/Unit| {
R|<local>/a|.R|SubstitutionOverride</A.set: R|kotlin/Unit|>|(Int(0), R|/D.D|())
Unit
}
@@ -26,6 +26,7 @@ FILE: notUselessCast_3.kt
}
)
R|<local>/cards|.R|SubstitutionOverride<kotlin/collections/List.get: R|kotlin/collections/List<kotlin/collections/MutableList<Square>>|>|(Int(0)).R|SubstitutionOverride<kotlin/collections/List.get: R|kotlin/collections/MutableList<Square>|>|(Int(0)).R|SubstitutionOverride<kotlin/collections/MutableList.set: R|Square|>|(Int(0), Q|MARKED|)
Unit
}
public final fun test_2(): R|kotlin/Unit| {
lval lines: R|kotlin/collections/List<kotlin/String>| = R|kotlin/collections/listOf|<R|kotlin/String|>()
@@ -40,4 +41,5 @@ FILE: notUselessCast_3.kt
}
)
R|<local>/cards|.R|SubstitutionOverride<kotlin/collections/List.get: R|kotlin/collections/List<kotlin/collections/MutableList<UNMARKED>>|>|(Int(0)).R|SubstitutionOverride<kotlin/collections/List.get: R|kotlin/collections/MutableList<UNMARKED>|>|(Int(0)).R|SubstitutionOverride<kotlin/collections/MutableList.set: R|UNMARKED|><Inapplicable(INAPPLICABLE): kotlin/collections/MutableList.set>#|(Int(0), Q|MARKED|)
Unit
}
@@ -12,6 +12,7 @@ FILE: typeAliasWithForEach.kt
lval result: R|java/util/HashMap<kotlin/String, ArgsInfo>| = R|java/util/HashMap.HashMap|<R|kotlin/String|, R|ArgsInfo|>()
this@R|/deepCopy|.R|SubstitutionOverride<kotlin/collections/Map.forEach: R|kotlin/Unit|>|(<L> = forEach@fun <anonymous>(key: R|@EnhancedNullability kotlin/String|, value: R|@EnhancedNullability ArgsInfo|): R|kotlin/Unit| <inline=NoInline> {
R|<local>/result|.R|kotlin/collections/set|<R|kotlin/String|, R|ArgsInfo|>(R|<local>/key|, R|/ArgsInfoImpl.ArgsInfoImpl|(R|<local>/value|))
Unit
}
)
^deepCopy R|<local>/result|
@@ -88,7 +88,7 @@ object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() {
)
}
}
} else if (resultExpression.source?.kind == KtFakeSourceElementKind.ImplicitUnit && !functionReturnType.isUnit) {
} else if (resultExpression.source?.kind is KtFakeSourceElementKind.ImplicitUnit && !functionReturnType.isUnit) {
reporter.reportOn(
resultExpression.source,
RETURN_TYPE_MISMATCH,
@@ -56,6 +56,7 @@ import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
class Fir2IrVisitor(
private val components: Fir2IrComponents,
@@ -758,7 +759,9 @@ class Fir2IrVisitor(
private fun FirStatement.toIrStatement(): IrStatement? {
if (this is FirTypeAlias) return null
if (this is FirUnitExpression) return convertToIrExpression(this)
if (this is FirUnitExpression) return runUnless(source?.kind is KtFakeSourceElementKind.ImplicitUnit.IndexedAssignmentCoercion) {
convertToIrExpression(this)
}
if (this is FirContractCallBlock) return null
if (this is FirBlock) return convertToIrExpression(this)
return accept(this@Fir2IrVisitor, null) as IrStatement
@@ -18587,6 +18587,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/fir/linkViaSignatures.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -18587,6 +18587,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/fir/linkViaSignatures.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -203,7 +203,7 @@ class LightTreeRawFirExpressionBuilder(
source = expressionSource.fakeElement(KtFakeSourceElementKind.ImplicitReturn.FromExpressionBody)
this.target = target
result = buildUnitExpression {
source = expressionSource.fakeElement(KtFakeSourceElementKind.ImplicitUnit)
source = expressionSource.fakeElement(KtFakeSourceElementKind.ImplicitUnit.LambdaCoercion)
}
}
)
@@ -1391,7 +1391,7 @@ class LightTreeRawFirExpressionBuilder(
}
val calculatedFirExpression = firExpression ?: buildUnitExpression {
source = returnExpression.toFirSourceElement(KtFakeSourceElementKind.ImplicitUnit)
source = returnExpression.toFirSourceElement(KtFakeSourceElementKind.ImplicitUnit.Return)
}
return calculatedFirExpression.toReturn(
baseSource = returnExpression.toFirSourceElement(),
@@ -1752,7 +1752,7 @@ open class PsiRawFirBuilder(
source = expressionSource.fakeElement(KtFakeSourceElementKind.ImplicitReturn.FromExpressionBody)
this.target = target
result = buildUnitExpression {
source = expressionSource.fakeElement(KtFakeSourceElementKind.ImplicitUnit)
source = expressionSource.fakeElement(KtFakeSourceElementKind.ImplicitUnit.LambdaCoercion)
}
}
)
@@ -2269,7 +2269,7 @@ open class PsiRawFirBuilder(
}
override fun visitReturnExpression(expression: KtReturnExpression, data: FirElement?): FirElement {
val source = expression.toFirSourceElement(KtFakeSourceElementKind.ImplicitUnit)
val source = expression.toFirSourceElement(KtFakeSourceElementKind.ImplicitUnit.Return)
val result = expression.returnedExpression?.toFirExpression("Incorrect return expression")
?: buildUnitExpression { this.source = source }
return result.toReturn(source, expression.getTargetLabel()?.getReferencedName(), fromKtReturnExpression = true)
@@ -2,10 +2,12 @@ FILE: arrayAssignment.kt
public? final? fun test(): R|kotlin/Unit| {
lval x: <implicit> = intArrayOf#(IntegerLiteral(1), IntegerLiteral(2), IntegerLiteral(3))
x#.set#(IntegerLiteral(1), IntegerLiteral(0))
Unit
}
public? final? fun foo(): <implicit> {
^foo IntegerLiteral(1)
}
public? final? fun test2(): R|kotlin/Unit| {
intArrayOf#(IntegerLiteral(1), IntegerLiteral(2), IntegerLiteral(3)).set#(foo#(), IntegerLiteral(1))
Unit
}
@@ -4,10 +4,16 @@ FILE: safeCallsWithAssignment.kt
a#?.{ $subj$.b# }?.{ $subj$.c# = IntegerLiteral(1) }
a#?.{ $subj$.b# }.c# = IntegerLiteral(1)
a#?.{ $subj$.b#.set#(IntegerLiteral(0), IntegerLiteral(1)) }
Unit
a#?.{ $subj$.b# }?.{ $subj$.c#.set#(IntegerLiteral(0), IntegerLiteral(1)) }
Unit
a#?.{ $subj$.b# }.c#.set#(IntegerLiteral(0), IntegerLiteral(1))
Unit
a#?.{ $subj$.b#.get#(IntegerLiteral(0)).set#(IntegerLiteral(0), IntegerLiteral(1)) }
Unit
a#?.{ $subj$.b# }?.{ $subj$.c#.get#(IntegerLiteral(0)).set#(IntegerLiteral(0), IntegerLiteral(1)) }
Unit
a#?.{ $subj$.b# }.c#.get#(IntegerLiteral(0)).set#(IntegerLiteral(0), IntegerLiteral(1))
Unit
a#?.{ $subj$.b# }.d#() = IntegerLiteral(1)
}
@@ -749,7 +749,13 @@ abstract class AbstractRawFirBuilder<T>(val baseSession: FirSession, val context
return if (operation == FirOperation.ASSIGN) {
val result = unwrappedLhs.convert()
result.replaceAnnotations(result.annotations.smartPlus(annotations))
result.pullUpSafeCallIfNecessary()
buildBlock {
source = result.source
statements += result.pullUpSafeCallIfNecessary()
statements += buildUnitExpression {
source = result.source?.fakeElement(KtFakeSourceElementKind.ImplicitUnit.IndexedAssignmentCoercion)
}
}
} else {
val receiver = unwrappedLhs.convert()
@@ -86,9 +86,19 @@ sealed class KtFakeSourceElementKind(final override val shouldSkipErrorTypeRepor
object FromLastStatement : ImplicitReturn()
}
// return expression in procedures -> return Unit
// with a fake sources which refers to the return statement
object ImplicitUnit : KtFakeSourceElementKind()
sealed class ImplicitUnit : KtFakeSourceElementKind() {
// this source is used for implicit returns from empty lambdas {}
// fake source refers to the lambda expression
object LambdaCoercion : ImplicitUnit()
// this source is used for 'return' without given value converted to 'return Unit'
// fake source refers to the return statement
object Return : ImplicitUnit()
// this source is used for 'a[i] = b' converted to { a[i] = b; Unit }
// fake source refers to the assignment statement
object IndexedAssignmentCoercion : ImplicitUnit()
}
// delegates are wrapped into FirWrappedDelegateExpression
// with a fake sources which refers to delegated expression
@@ -0,0 +1,14 @@
// ISSUE: KT-59748
// WITH_STDLIB
fun foo(list: MutableList<Any?>, condition: Boolean): Unit = when {
condition -> list[0] = "OK"
else -> Unit
}
fun box(): String {
val list = mutableListOf<Any?>("FAIL")
foo(list, true)
foo(list, false)
return list[0] as String
}
@@ -5,7 +5,7 @@ package kt235
fun main() {
val array = MyArray()
val f: () -> String = <!INITIALIZER_TYPE_MISMATCH!>{
<!TYPE_MISMATCH!>array[2] = 23<!> //error: Type mismatch: inferred type is Int (!!!) but String was expected
array[2] = 23 //error: Type mismatch: inferred type is Int (!!!) but String was expected
}<!>
val g: () -> String = <!INITIALIZER_TYPE_MISMATCH!>{
var x = 1
@@ -17,11 +17,11 @@ fun main() {
}<!>
val array1 = MyArray1()
val i: () -> String = <!INITIALIZER_TYPE_MISMATCH!>{
<!TYPE_MISMATCH!>array1[2] = 23<!>
array1[2] = 23
}<!>
val fi: () -> String = <!INITIALIZER_TYPE_MISMATCH!>{
<!TYPE_MISMATCH!>array[2] = 23<!>
array[2] = 23
}<!>
val gi: () -> String = <!INITIALIZER_TYPE_MISMATCH!>{
var x = 1
@@ -7,6 +7,7 @@ FILE: setOperatorOnDynamic.fir.kt
)
lval x3: R|kotlin/Any| = R|kotlin/arrayOf|<R|kotlin/String|>().R|kotlin/collections/fold|<R|kotlin/String|, R|dynamic|>(R|kotlin/js/js|(String(({}))), <L> = fold@fun <anonymous>(res: R|dynamic|, key: R|kotlin/String|): R|dynamic| <inline=Inline, kind=UNKNOWN> {
R|<local>/res|.R|<dynamic>/set|(vararg(R|<local>/key|, String(hello)))
Unit
^ R|<local>/res|
}
)
@@ -29,6 +29,7 @@ FILE: unsafeAssignmentExtra.fir.kt
public final fun main(arg: R|kotlin/Any|, condition: R|kotlin/Boolean|): R|kotlin/Unit| {
lval value: R|Foo<kotlin/Int>| = R|/myBuilder|<R|kotlin/Int|>(<L> = myBuilder@fun R|Foo<kotlin/Int>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|SubstitutionOverride</Foo.b: R|kotlin/Array<Stub (chain inference): TypeVariable(T)>|>|.R|SubstitutionOverride<kotlin/Array.set: R|kotlin/Unit|>|(Int(0), Int(123))
Unit
this@R|special/anonymous|.R|SubstitutionOverride</Foo.a: R|Stub (chain inference): TypeVariable(T)|>| = Int(45)
{
lval <unary>: R|kotlin/Int| = this@R|special/anonymous|.R|SubstitutionOverride</Foo.a: R|Stub (chain inference): TypeVariable(T)|>|
@@ -103,6 +104,7 @@ FILE: unsafeAssignmentExtra.fir.kt
this@R|special/anonymous|.R|SubstitutionOverride</Foo.accept: R|kotlin/Unit|>|(String())
this@R|special/anonymous|.R|SubstitutionOverride</Foo.a: R|Stub (chain inference): TypeVariable(T)|>| = Int(45)
this@R|special/anonymous|.R|SubstitutionOverride</Foo.b: R|kotlin/Array<Stub (chain inference): TypeVariable(T)>|>|.R|SubstitutionOverride<kotlin/Array.set: R|kotlin/Unit|>|(Int(0), Int(123))
Unit
R|<local>/baz|(this@R|special/anonymous|.R|SubstitutionOverride</Foo.a: R|Stub (chain inference): TypeVariable(T)|>|)
}
)
@@ -1,10 +1,10 @@
// ISSUE: KT-59748
// FIR_DUMP
fun foo(list: MutableList<Any?>, condition: Boolean): Unit = <!RETURN_TYPE_MISMATCH!>when {
fun foo(list: MutableList<Any?>, condition: Boolean): Unit = when {
condition -> list[0] = ""
else -> Unit
}<!>
}
fun bar(list: MutableList<Any?>, condition: Boolean): Unit = <!RETURN_TYPE_MISMATCH!>when {
condition -> list.set(0, "")
@@ -2,7 +2,11 @@ FILE: listAssignmentInWhen.fir.kt
public final fun foo(list: R|kotlin/collections/MutableList<kotlin/Any?>|, condition: R|kotlin/Boolean|): R|kotlin/Unit| {
^foo when () {
R|<local>/condition| -> {
R|<local>/list|.R|SubstitutionOverride<kotlin/collections/MutableList.set: R|kotlin/Any?|>|(Int(0), String())
{
R|<local>/list|.R|SubstitutionOverride<kotlin/collections/MutableList.set: R|kotlin/Any?|>|(Int(0), String())
Unit
}
}
else -> {
Q|kotlin/Unit|
@@ -17711,6 +17711,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/fir/KotlinDocumentationProvider.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -18587,6 +18587,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/fir/linkViaSignatures.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -18587,6 +18587,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
runTest("compiler/testData/codegen/box/fir/linkViaSignatures.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -15440,6 +15440,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/fir/linkViaSignatures.kt");
}
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
runTest("compiler/testData/codegen/box/fir/localInvokeExtension.kt");
@@ -13679,6 +13679,12 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -13679,6 +13679,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -13679,6 +13679,12 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -14785,6 +14785,12 @@ public class FirNativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTe
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -15133,6 +15133,12 @@ public class FirNativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenB
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -14612,6 +14612,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -14786,6 +14786,12 @@ public class NativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenBoxT
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -13655,6 +13655,12 @@ public class FirWasmCodegenBoxTestGenerated extends AbstractFirWasmCodegenBoxTes
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {
@@ -13655,6 +13655,12 @@ public class K1WasmCodegenBoxTestGenerated extends AbstractK1WasmCodegenBoxTest
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
}
@Test
@TestMetadata("listAssignmentInWhen.kt")
public void testListAssignmentInWhen() throws Exception {
runTest("compiler/testData/codegen/box/fir/listAssignmentInWhen.kt");
}
@Test
@TestMetadata("localInvokeExtension.kt")
public void testLocalInvokeExtension() throws Exception {