FIR: substitute the whole lambda body after builder inference

This commit is contained in:
Tianyu Geng
2021-07-26 15:56:56 -07:00
committed by teamcityserver
parent f737d8002e
commit 0026560bd7
7 changed files with 30 additions and 27 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.inference
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.hasAnnotation import org.jetbrains.kotlin.fir.declarations.hasAnnotation
import org.jetbrains.kotlin.fir.expressions.FirArgumentList import org.jetbrains.kotlin.fir.expressions.FirArgumentList
import org.jetbrains.kotlin.fir.expressions.FirResolvable import org.jetbrains.kotlin.fir.expressions.FirResolvable
@@ -28,6 +29,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.BUILDER_INFERENCE_ANNOTATION_
import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.types.model.TypeConstructorMarker
class FirBuilderInferenceSession( class FirBuilderInferenceSession(
private val lambda: FirAnonymousFunction,
resolutionContext: ResolutionContext, resolutionContext: ResolutionContext,
private val stubsForPostponedVariables: Map<ConeTypeVariable, ConeStubType>, private val stubsForPostponedVariables: Map<ConeTypeVariable, ConeStubType>,
) : AbstractManyCandidatesInferenceSession(resolutionContext) { ) : AbstractManyCandidatesInferenceSession(resolutionContext) {
@@ -225,19 +227,16 @@ class FirBuilderInferenceSession(
return introducedConstraint return introducedConstraint
} }
// TODO: besides calls, perhaps use the stub type substitutor for all top-level expressions inside the lambda
private fun updateCalls(commonSystem: NewConstraintSystemImpl) { private fun updateCalls(commonSystem: NewConstraintSystemImpl) {
val nonFixedToVariablesSubstitutor = createNonFixedTypeToVariableSubstitutor() val nonFixedToVariablesSubstitutor = createNonFixedTypeToVariableSubstitutor()
val commonSystemSubstitutor = commonSystem.buildCurrentSubstitutor() as ConeSubstitutor val commonSystemSubstitutor = commonSystem.buildCurrentSubstitutor() as ConeSubstitutor
val nonFixedTypesToResultSubstitutor = ConeComposedSubstitutor(commonSystemSubstitutor, nonFixedToVariablesSubstitutor) val nonFixedTypesToResultSubstitutor = ConeComposedSubstitutor(commonSystemSubstitutor, nonFixedToVariablesSubstitutor)
val completionResultsWriter = components.callCompleter.createCompletionResultsWriter(nonFixedTypesToResultSubstitutor)
val stubTypeSubstitutor = FirStubTypeTransformer(nonFixedTypesToResultSubstitutor) val stubTypeSubstitutor = FirStubTypeTransformer(nonFixedTypesToResultSubstitutor)
for ((completedCall, _) in commonCalls) { lambda.transformSingle(stubTypeSubstitutor, null)
completedCall.transformSingle(stubTypeSubstitutor, null) // TODO: support diagnostics, see [CoroutineInferenceSession#updateCalls]
// TODO: support diagnostics, see [CoroutineInferenceSession#updateCalls]
}
val completionResultsWriter = components.callCompleter.createCompletionResultsWriter(nonFixedTypesToResultSubstitutor)
for ((call, _) in partiallyResolvedCalls) { for ((call, _) in partiallyResolvedCalls) {
call.transformSingle(completionResultsWriter, null) call.transformSingle(completionResultsWriter, null)
// TODO: support diagnostics, see [CoroutineInferenceSession#updateCalls] // TODO: support diagnostics, see [CoroutineInferenceSession#updateCalls]
@@ -272,7 +272,11 @@ class FirCallCompleter(
val builderInferenceSession = runIf(stubsForPostponedVariables.isNotEmpty()) { val builderInferenceSession = runIf(stubsForPostponedVariables.isNotEmpty()) {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
FirBuilderInferenceSession(transformer.resolutionContext, stubsForPostponedVariables as Map<ConeTypeVariable, ConeStubType>) FirBuilderInferenceSession(
lambdaArgument,
transformer.resolutionContext,
stubsForPostponedVariables as Map<ConeTypeVariable, ConeStubType>
)
} }
transformer.context.withAnonymousFunctionTowerDataContext(lambdaArgument.symbol) { transformer.context.withAnonymousFunctionTowerDataContext(lambdaArgument.symbol) {
@@ -1,7 +1,6 @@
// !LANGUAGE: +UnrestrictedBuilderInference // !LANGUAGE: +UnrestrictedBuilderInference
// !DIAGNOSTICS: -DEPRECATION -EXPERIMENTAL_IS_NOT_ENABLED // !DIAGNOSTICS: -DEPRECATION -EXPERIMENTAL_IS_NOT_ENABLED
// WITH_RUNTIME // WITH_RUNTIME
// IGNORE_BACKEND_FIR: JVM_IR
// DONT_TARGET_EXACT_BACKEND: WASM // DONT_TARGET_EXACT_BACKEND: WASM
// FILE: main.kt // FILE: main.kt
@@ -10,7 +10,7 @@ fun main() {
buildList { buildList {
add(3) add(3)
object : A { object : A {
override fun foo(): MutableList<String> = this@buildList override fun foo(): MutableList<String> = <!RETURN_TYPE_MISMATCH!>this@buildList<!>
} }
} }
buildList { buildList {
@@ -19,12 +19,12 @@ fun main() {
} }
buildList { buildList {
add("3") add("3")
val x: MutableList<Int> = this@buildList val x: MutableList<Int> = <!INITIALIZER_TYPE_MISMATCH!>this@buildList<!>
} }
buildList { buildList {
val y: CharSequence = "" val y: CharSequence = ""
add(y) add(y)
val x: MutableList<String> = this@buildList val x: MutableList<String> = <!INITIALIZER_TYPE_MISMATCH!>this@buildList<!>
} }
buildList { buildList {
add("") add("")
@@ -37,8 +37,8 @@ fun test() {
get()?.hashCode() get()?.hashCode()
get()?.<!NONE_APPLICABLE!>equals<!>(1) get()?.<!NONE_APPLICABLE!>equals<!>(1)
val x = get() val x = get()
x<!UNNECESSARY_SAFE_CALL!>?.<!>hashCode() x?.hashCode()
x<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>(1) x?.<!NONE_APPLICABLE!>equals<!>(1)
x.equals("") x.equals("")
} }
val ret3 = build { val ret3 = build {
@@ -50,20 +50,20 @@ fun test() {
get()?.hashCode() get()?.hashCode()
get()?.<!NONE_APPLICABLE!>equals<!>(1) get()?.<!NONE_APPLICABLE!>equals<!>(1)
val x = get() val x = get()
x<!UNNECESSARY_SAFE_CALL!>?.<!>hashCode() x?.hashCode()
x<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>(1) x?.<!NONE_APPLICABLE!>equals<!>(1)
if (get() == null) {} if (get() == null) {}
if (get() === null) {} if (get() === null) {}
if (x != null) { if (x != null) {
x<!UNNECESSARY_SAFE_CALL!>?.<!>hashCode() x?.hashCode()
x<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>(1) x?.<!NONE_APPLICABLE!>equals<!>(1)
x.equals("") x.equals("")
x.hashCode() x.hashCode()
x.toString() x.toString()
x.test() x.test()
x<!UNNECESSARY_SAFE_CALL!>?.<!>test2() x?.test2()
x.test2() x.test2()
} }
@@ -166,8 +166,8 @@ fun test() {
get()?.hashCode() get()?.hashCode()
get()?.<!NONE_APPLICABLE!>equals<!>(1) get()?.<!NONE_APPLICABLE!>equals<!>(1)
val x = get() val x = get()
x<!UNNECESSARY_SAFE_CALL!>?.<!>hashCode() x?.hashCode()
x<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>(1) x?.<!NONE_APPLICABLE!>equals<!>(1)
if (get() == null) {} if (get() == null) {}
if (get() === null) {} if (get() === null) {}
@@ -296,8 +296,8 @@ fun test() {
get()?.hashCode() get()?.hashCode()
get()?.<!NONE_APPLICABLE!>equals<!>(1) get()?.<!NONE_APPLICABLE!>equals<!>(1)
val x = get() val x = get()
x<!UNNECESSARY_SAFE_CALL!>?.<!>hashCode() x?.hashCode()
x<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>(1) x?.<!NONE_APPLICABLE!>equals<!>(1)
if (get() == null) {} if (get() == null) {}
if (get() === null) {} if (get() === null) {}
+2 -1
View File
@@ -19,7 +19,7 @@ fun <E : Any?, C : Base<E>> Receiver<E>.toChannel(destination: C): C {
} }
fun <R : Any?> foo(r: Receiver<R>): R { fun <R : Any?> foo(r: Receiver<R>): R {
return produce<R>(block = local fun Derived<R>.<anonymous>() { return produce<R>(block = local fun Derived<ErrorType>.<anonymous>() {
r.toChannel<R, Derived<ErrorType>>(destination = <this>) /*~> Unit */ r.toChannel<R, Derived<ErrorType>>(destination = <this>) /*~> Unit */
} }
) )
@@ -28,3 +28,4 @@ fun <R : Any?> foo(r: Receiver<R>): R {
fun box(): String { fun box(): String {
return "OK" return "OK"
} }
+4 -4
View File
@@ -72,16 +72,16 @@ FILE fqName:<root> fileName:/kt47082.kt
RETURN type=kotlin.Nothing from='public final fun foo <R> (r: <root>.Receiver<R of <root>.foo>): R of <root>.foo declared in <root>' RETURN type=kotlin.Nothing from='public final fun foo <R> (r: <root>.Receiver<R of <root>.foo>): R of <root>.foo declared in <root>'
CALL 'public final fun produce <E> (block: @[ExtensionFunctionType] kotlin.Function1<<root>.Derived<E of <root>.produce>, kotlin.Unit>): E of <root>.produce declared in <root>' type=R of <root>.foo origin=null CALL 'public final fun produce <E> (block: @[ExtensionFunctionType] kotlin.Function1<<root>.Derived<E of <root>.produce>, kotlin.Unit>): E of <root>.produce declared in <root>' type=R of <root>.foo origin=null
<E>: R of <root>.foo <E>: R of <root>.foo
block: FUN_EXPR type=kotlin.Function1<<root>.Derived<R of <root>.foo>, kotlin.Unit> origin=LAMBDA block: FUN_EXPR type=kotlin.Function1<<root>.Derived<IrErrorType(null)>, kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> ($receiver:<root>.Derived<R of <root>.foo>) returnType:kotlin.Unit FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> ($receiver:<root>.Derived<IrErrorType(null)>) returnType:kotlin.Unit
$receiver: VALUE_PARAMETER name:<this> type:<root>.Derived<R of <root>.foo> $receiver: VALUE_PARAMETER name:<this> type:<root>.Derived<IrErrorType(null)>
BLOCK_BODY BLOCK_BODY
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
CALL 'public final fun toChannel <E, C> (destination: C of <root>.toChannel): C of <root>.toChannel declared in <root>' type=<root>.Derived<IrErrorType(null)> origin=null CALL 'public final fun toChannel <E, C> (destination: C of <root>.toChannel): C of <root>.toChannel declared in <root>' type=<root>.Derived<IrErrorType(null)> origin=null
<E>: R of <root>.foo <E>: R of <root>.foo
<C>: <root>.Derived<IrErrorType(null)> <C>: <root>.Derived<IrErrorType(null)>
$receiver: GET_VAR 'r: <root>.Receiver<R of <root>.foo> declared in <root>.foo' type=<root>.Receiver<R of <root>.foo> origin=null $receiver: GET_VAR 'r: <root>.Receiver<R of <root>.foo> declared in <root>.foo' type=<root>.Receiver<R of <root>.foo> origin=null
destination: GET_VAR '<this>: <root>.Derived<R of <root>.foo> declared in <root>.foo.<anonymous>' type=<root>.Derived<IrErrorType(null)> origin=null destination: GET_VAR '<this>: <root>.Derived<IrErrorType(null)> declared in <root>.foo.<anonymous>' type=<root>.Derived<IrErrorType(null)> origin=null
FUN name:box visibility:public modality:FINAL <> () returnType:kotlin.String FUN name:box visibility:public modality:FINAL <> () returnType:kotlin.String
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in <root>' RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in <root>'