K2: Fix internal error in FIR2IR caused by PCLA + String interpolation

There's an implicit contract in PCLA that the statement-level call
should be postponed iff it has something to be postponed inside.

And that contract didn't work well for string interpolation containing
some postponed calls.

Thus, we haven't run a completion results writing for them properly,
thus leaving type parameters (K from synthetic call) for expression
types instead of an inferred substituted type.

In this commit, the contract was reversed to explicitly enumerate
the cases when it's safe to resolve the candidate outside PCLA session.

See the comments at `mightBeAnalyzedAndCompletedIndependently`.

^KT-65341 Fixed
This commit is contained in:
Denis.Zharkov
2024-01-29 15:17:04 +01:00
committed by Space Team
parent 3ba8256b8d
commit 66d8f471d9
27 changed files with 346 additions and 147 deletions
@@ -0,0 +1,10 @@
MODULE main
CLASS Kt65341Kt$nodeTransformer$1.class
K1
---
K2
invoke(LNodeTransformer1;)Lkotlin/Unit; [public, final]
K1
invoke(LNodeTransformer1;)V [public, final]
K2
---
@@ -0,0 +1,24 @@
// TARGET_BACKEND: JVM
// ISSUE: KT-65341
// JVM_ABI_K1_K2_DIFF: KT-65386
val nodeTransformer =
single {
fun getConstructorParameterValue(kParameter: String) {
if (true) {
throw java.lang.IllegalStateException("${kParameter!!}")
}
}
}
fun <Output> single(
singleConstructor: (NodeTransformer1<Output>) -> Output?
) {
}
class NodeTransformer1<Output>
fun box(): String {
// Just making sure that for the original case the whole compiler pipeline is successfully completed
return "OK"
}
@@ -0,0 +1,44 @@
// ISSUE: KT-65341
class Controller<K> {
fun yield(k: K) {}
}
fun <T> generate(lambda: Controller<T>.() -> Unit) {}
fun bar(x: String) {}
var v: String = "OK"
fun foo0(x: String?) {
generate {
bar("$v abc${x!!}")
yield("")
}
}
fun foo1(x: String?) {
generate {
bar("$v abc${when { x != null -> x else -> null}}")
yield("")
}
}
fun <E> id(e: E): E = e
fun foo2(x: String?) {
generate {
bar("$v abc${id(this)}")
yield("")
}
}
fun box(): String {
foo0(null)
foo1(null)
foo2(null)
return "OK"
}
@@ -1,54 +0,0 @@
FILE fqName:<root> fileName:/posptonedPCLACallInsideStringInterpolation.kt
CLASS CLASS name:Controller modality:FINAL visibility:public superTypes:[kotlin.Any]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.Controller<K of <root>.Controller>
TYPE_PARAMETER name:K index:0 variance: superTypes:[kotlin.Any?] reified:false
CONSTRUCTOR visibility:public <> () returnType:<root>.Controller<K of <root>.Controller> [primary]
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () declared in kotlin.Any'
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Controller modality:FINAL visibility:public superTypes:[kotlin.Any]'
FUN name:yield visibility:public modality:FINAL <> ($this:<root>.Controller<K of <root>.Controller>, k:K of <root>.Controller) returnType:kotlin.Unit
$this: VALUE_PARAMETER name:<this> type:<root>.Controller<K of <root>.Controller>
VALUE_PARAMETER name:k index:0 type:K of <root>.Controller
BLOCK_BODY
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
overridden:
public open fun toString (): kotlin.String declared in kotlin.Any
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN name:generate visibility:public modality:FINAL <T> (lambda:@[ExtensionFunctionType] kotlin.Function1<<root>.Controller<T of <root>.generate>, kotlin.Unit>) returnType:kotlin.Unit
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] reified:false
VALUE_PARAMETER name:lambda index:0 type:@[ExtensionFunctionType] kotlin.Function1<<root>.Controller<T of <root>.generate>, kotlin.Unit>
BLOCK_BODY
FUN name:id visibility:public modality:FINAL <E> (e:E of <root>.id) returnType:E of <root>.id
TYPE_PARAMETER name:E index:0 variance: superTypes:[kotlin.Any?] reified:false
VALUE_PARAMETER name:e index:0 type:E of <root>.id
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun id <E> (e: E of <root>.id): E of <root>.id declared in <root>'
GET_VAR 'e: E of <root>.id declared in <root>.id' type=E of <root>.id origin=null
FUN name:bar visibility:public modality:FINAL <> (s:kotlin.String) returnType:kotlin.Unit
VALUE_PARAMETER name:s index:0 type:kotlin.String
BLOCK_BODY
FUN name:foo visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
CALL 'public final fun generate <T> (lambda: @[ExtensionFunctionType] kotlin.Function1<<root>.Controller<T of <root>.generate>, kotlin.Unit>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
<T>: kotlin.String
lambda: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<<root>.Controller<kotlin.String>, kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> ($receiver:<root>.Controller<kotlin.String>) returnType:kotlin.Unit
$receiver: VALUE_PARAMETER name:$this$generate type:<root>.Controller<kotlin.String>
BLOCK_BODY
CALL 'public final fun bar (s: kotlin.String): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
s: STRING_CONCATENATION type=kotlin.String
CALL 'public final fun id <E> (e: E of <root>.id): E of <root>.id declared in <root>' type=E of <root>.id origin=null
<E>: IrErrorType(null)
e: GET_VAR '$this$generate: <root>.Controller<kotlin.String> declared in <root>.foo.<anonymous>' type=<root>.Controller<kotlin.String> origin=null
CALL 'public final fun yield (k: K of <root>.Controller): kotlin.Unit declared in <root>.Controller' type=kotlin.Unit origin=null
$this: GET_VAR '$this$generate: <root>.Controller<kotlin.String> declared in <root>.foo.<anonymous>' type=<root>.Controller<kotlin.String> origin=null
k: CONST String type=kotlin.String value=""
@@ -1,29 +0,0 @@
class Controller<K : Any?> {
constructor() /* primary */ {
super/*Any*/()
/* <init>() */
}
fun yield(k: K) {
}
}
fun <T : Any?> generate(lambda: @ExtensionFunctionType Function1<Controller<T>, Unit>) {
}
fun <E : Any?> id(e: E): E {
return e
}
fun bar(s: String) {
}
fun foo() {
generate<String>(lambda = local fun Controller<String>.<anonymous>() {
bar(s = id<ErrorType>(e = $this$generate))
$this$generate.yield(k = "")
}
)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// ISSUE: KT-65341
class Controller<K> {
fun yield(k: K) {}