FIR: Get rid of replacements map during calls completion

Otherwise, it's complicated to work with nested lambdas:
outer/inner ones may be replaced independently and still refer
to the old one instances.
So in the changed test, if we don't apply the commit, will remain
implicit return and receiver types for the nested lambda

Anyway, once we decided to leave immutable semantics,
replacements are not necessary anymore
This commit is contained in:
Denis Zharkov
2020-02-04 16:23:29 +03:00
parent 8d24e0f842
commit 4f834cb16b
7 changed files with 47 additions and 57 deletions
@@ -40,7 +40,6 @@ class PostponedArgumentsAnalyzer(
private val lambdaAnalyzer: LambdaAnalyzer, private val lambdaAnalyzer: LambdaAnalyzer,
private val components: InferenceComponents, private val components: InferenceComponents,
private val candidate: Candidate, private val candidate: Candidate,
private val replacements: MutableMap<FirExpression, FirExpression>,
private val callResolver: FirCallResolver private val callResolver: FirCallResolver
) { ) {
@@ -94,8 +93,6 @@ class PostponedArgumentsAnalyzer(
replaceTypeRef(FirResolvedTypeRefImpl(null, candidate.resultingTypeForCallableReference!!)) replaceTypeRef(FirResolvedTypeRefImpl(null, candidate.resultingTypeForCallableReference!!))
} }
} }
replacements[callableReferenceAccess] = transformedCalleeReference
} }
private fun analyzeLambda( private fun analyzeLambda(
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.fir.resolve.inference package org.jetbrains.kotlin.fir.resolve.inference
import org.jetbrains.kotlin.fir.copy
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
@@ -16,8 +15,8 @@ import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.transformers.* import org.jetbrains.kotlin.fir.resolve.transformers.FirCallCompletionResultsWriterTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.MapArguments import org.jetbrains.kotlin.fir.resolve.transformers.InvocationKindTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
@@ -75,11 +74,10 @@ class FirCallCompleter(
} }
val completionMode = candidate.computeCompletionMode(inferenceComponents, expectedTypeRef, initialType) val completionMode = candidate.computeCompletionMode(inferenceComponents, expectedTypeRef, initialType)
val replacements = mutableMapOf<FirExpression, FirExpression>()
val analyzer = val analyzer =
PostponedArgumentsAnalyzer( PostponedArgumentsAnalyzer(
LambdaAnalyzerImpl(replacements), inferenceComponents, candidate, replacements, LambdaAnalyzerImpl(), inferenceComponents, candidate,
transformer.components.callResolver transformer.components.callResolver
) )
@@ -88,8 +86,6 @@ class FirCallCompleter(
analyzer.analyze(candidate.system.asPostponedArgumentsAnalyzerContext(), it) analyzer.analyze(candidate.system.asPostponedArgumentsAnalyzerContext(), it)
} }
call.transformChildren(MapArguments, replacements.toMap())
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) { if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
val finalSubstitutor = val finalSubstitutor =
candidate.system.asReadOnlyStorage().buildAbstractResultingSubstitutor(inferenceComponents.ctx) as ConeSubstitutor candidate.system.asReadOnlyStorage().buildAbstractResultingSubstitutor(inferenceComponents.ctx) as ConeSubstitutor
@@ -106,9 +102,7 @@ class FirCallCompleter(
return call.transformSingle(integerOperatorsTypeUpdater, null) return call.transformSingle(integerOperatorsTypeUpdater, null)
} }
private inner class LambdaAnalyzerImpl( private inner class LambdaAnalyzerImpl : LambdaAnalyzer {
val replacements: MutableMap<FirExpression, FirExpression>
) : LambdaAnalyzer {
override fun analyzeAndGetLambdaReturnArguments( override fun analyzeAndGetLambdaReturnArguments(
lambdaArgument: FirAnonymousFunction, lambdaArgument: FirAnonymousFunction,
isSuspend: Boolean, isSuspend: Boolean,
@@ -142,24 +136,24 @@ class FirCallCompleter(
val expectedReturnTypeRef = expectedReturnType?.let { lambdaArgument.returnTypeRef.resolvedTypeFromPrototype(it) } val expectedReturnTypeRef = expectedReturnType?.let { lambdaArgument.returnTypeRef.resolvedTypeFromPrototype(it) }
val newLambdaExpression = lambdaArgument.copy( lambdaArgument.replaceReceiverTypeRef(
receiverTypeRef = receiverType?.let { receiverType?.approximateLambdaInputType()?.let {
lambdaArgument.receiverTypeRef?.resolvedTypeFromPrototype(it.approximateLambdaInputType()) lambdaArgument.receiverTypeRef?.resolvedTypeFromPrototype(it)
}, }
valueParameters = lambdaArgument.valueParameters.mapIndexed { index, parameter ->
parameter.transformReturnTypeRef(
StoreType,
parameter.returnTypeRef.resolvedTypeFromPrototype(parameters[index].approximateLambdaInputType())
)
parameter
} + listOfNotNull(itParam),
returnTypeRef = expectedReturnTypeRef ?: noExpectedType
) )
replacements[lambdaArgument] = lambdaArgument.valueParameters.forEachIndexed { index, parameter ->
newLambdaExpression.transformSingle(transformer, ResolutionMode.LambdaResolution(expectedReturnTypeRef)) parameter.replaceReturnTypeRef(
parameter.returnTypeRef.resolvedTypeFromPrototype(parameters[index].approximateLambdaInputType())
)
}
val returnArguments = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(newLambdaExpression) lambdaArgument.replaceValueParameters(lambdaArgument.valueParameters + listOfNotNull(itParam))
lambdaArgument.replaceReturnTypeRef(expectedReturnTypeRef ?: noExpectedType)
lambdaArgument.transformSingle(transformer, ResolutionMode.LambdaResolution(expectedReturnTypeRef))
val returnArguments = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(lambdaArgument)
return returnArguments to InferenceSession.default return returnArguments to InferenceSession.default
} }
} }
@@ -2,8 +2,8 @@ FILE: postponedLambdas.kt
public final inline fun foo(vararg x: R|kotlin/Array<kotlin/Any>|): R|kotlin/Unit| { public final inline fun foo(vararg x: R|kotlin/Array<kotlin/Any>|): R|kotlin/Unit| {
} }
public final fun test(a: R|kotlin/Any|, b: R|kotlin/Any|, c: R|kotlin/Any|): R|kotlin/Unit| { public final fun test(a: R|kotlin/Any|, b: R|kotlin/Any|, c: R|kotlin/Any|): R|kotlin/Unit| {
R|/foo|(vararg(R|<local>/a|, R|<local>/b|), foo@fun <anonymous>(): R|kotlin/String| <kind=UNKNOWN> { R|/foo|(vararg(R|<local>/a|, foo@fun <anonymous>(): R|kotlin/String| <kind=UNKNOWN> {
String() String()
} }
) , R|<local>/b|))
} }
@@ -8,7 +8,7 @@ interface MyMap<K, V> {
val w: Inv<String> = TODO() val w: Inv<String> = TODO()
public fun <X, K> Inv<X>.associateBy1(keySelector: (X) -> K): MyMap<K, String> = TODO() public fun <X, K> Inv<X>.associateBy1(keySelector: (X) -> K): MyMap<K, X> = TODO()
val x = myRun { val x = myRun {
w.associateBy1 { f -> f.length } w.associateBy1 { f -> f.length }
@@ -14,7 +14,7 @@ FILE: nestedLambdas.kt
} }
public final val w: R|Inv<kotlin/String>| = R|kotlin/TODO|() public final val w: R|Inv<kotlin/String>| = R|kotlin/TODO|()
public get(): R|Inv<kotlin/String>| public get(): R|Inv<kotlin/String>|
public final fun <X, K> R|Inv<X>|.associateBy1(keySelector: R|(X) -> K|): R|MyMap<K, kotlin/String>| { public final fun <X, K> R|Inv<X>|.associateBy1(keySelector: R|(X) -> K|): R|MyMap<K, X>| {
^associateBy1 R|kotlin/TODO|() ^associateBy1 R|kotlin/TODO|()
} }
public final val x: R|MyMap<kotlin/Int, kotlin/String>| = R|/myRun|<R|MyMap<kotlin/Int, kotlin/String>|>(<L> = myRun@fun <anonymous>(): R|MyMap<kotlin/Int, kotlin/String>| { public final val x: R|MyMap<kotlin/Int, kotlin/String>| = R|/myRun|<R|MyMap<kotlin/Int, kotlin/String>|>(<L> = myRun@fun <anonymous>(): R|MyMap<kotlin/Int, kotlin/String>| {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun <T> block(block: () -> T): T = block() fun <T> block(block: () -> T): T = block()
fun foo() {} fun foo() {}
@@ -22,32 +22,32 @@ FILE fqName:<root> fileName:/samConversionInVarargs.kt
BLOCK_BODY BLOCK_BODY
FUN name:testLambda visibility:public modality:FINAL <> () returnType:kotlin.Unit FUN name:testLambda visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY BLOCK_BODY
ERROR_CALL 'Cannot bind 2 arguments to useVararg call with 1 parameters' type=kotlin.Unit CALL 'public final fun useVararg (vararg foos: <root>.IFoo): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
FUN_EXPR type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=LAMBDA foos: VARARG type=kotlin.Array<<root>.IFoo> varargElementType=<root>.IFoo
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Unit FUN_EXPR type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=LAMBDA
VALUE_PARAMETER name:it index:0 type:kotlin.Int FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Unit
BLOCK_BODY VALUE_PARAMETER name:it index:0 type:kotlin.Int
GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit BLOCK_BODY
VARARG type=kotlin.Array<<root>.IFoo> varargElementType=<root>.IFoo GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
FUN name:testSeveralLambdas visibility:public modality:FINAL <> () returnType:kotlin.Unit FUN name:testSeveralLambdas visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY BLOCK_BODY
ERROR_CALL 'Cannot bind 4 arguments to useVararg call with 1 parameters' type=kotlin.Unit CALL 'public final fun useVararg (vararg foos: <root>.IFoo): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
FUN_EXPR type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=LAMBDA foos: VARARG type=kotlin.Array<<root>.IFoo> varargElementType=<root>.IFoo
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Unit FUN_EXPR type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=LAMBDA
VALUE_PARAMETER name:it index:0 type:kotlin.Int FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Unit
BLOCK_BODY VALUE_PARAMETER name:it index:0 type:kotlin.Int
GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit BLOCK_BODY
FUN_EXPR type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=LAMBDA GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Unit FUN_EXPR type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=LAMBDA
VALUE_PARAMETER name:it index:0 type:kotlin.Int FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Unit
BLOCK_BODY VALUE_PARAMETER name:it index:0 type:kotlin.Int
GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit BLOCK_BODY
FUN_EXPR type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=LAMBDA GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Unit FUN_EXPR type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=LAMBDA
VALUE_PARAMETER name:it index:0 type:kotlin.Int FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Unit
BLOCK_BODY VALUE_PARAMETER name:it index:0 type:kotlin.Int
GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit BLOCK_BODY
VARARG type=kotlin.Array<<root>.IFoo> varargElementType=<root>.IFoo GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
FUN name:withVarargOfInt visibility:public modality:FINAL <> (xs:kotlin.IntArray) returnType:kotlin.String FUN name:withVarargOfInt visibility:public modality:FINAL <> (xs:kotlin.IntArray) returnType:kotlin.String
VALUE_PARAMETER name:xs index:0 type:kotlin.IntArray varargElementType:kotlin.Int [vararg] VALUE_PARAMETER name:xs index:0 type:kotlin.IntArray varargElementType:kotlin.Int [vararg]
BLOCK_BODY BLOCK_BODY