[FIR] Safe implicit receiver stack in lambda atom for resolve of inner lambdas
#KT-36887 Fixed
This commit is contained in:
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir
|
package org.jetbrains.kotlin.fir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionStub
|
import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionStub
|
||||||
@@ -46,7 +45,6 @@ class FirCallResolver(
|
|||||||
components: BodyResolveComponents,
|
components: BodyResolveComponents,
|
||||||
topLevelScopes: List<FirScope>,
|
topLevelScopes: List<FirScope>,
|
||||||
localScopes: List<FirLocalScope>,
|
localScopes: List<FirLocalScope>,
|
||||||
override val implicitReceiverStack: ImplicitReceiverStack,
|
|
||||||
private val qualifiedResolver: FirQualifiedNameResolver,
|
private val qualifiedResolver: FirQualifiedNameResolver,
|
||||||
) : BodyResolveComponents by components {
|
) : BodyResolveComponents by components {
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -39,7 +39,8 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
fun createFirDataFlowAnalyzer(
|
fun createFirDataFlowAnalyzer(
|
||||||
components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents
|
components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents
|
||||||
): FirDataFlowAnalyzer<*> = object : FirDataFlowAnalyzer<PersistentFlow>(components) {
|
): FirDataFlowAnalyzer<*> = object : FirDataFlowAnalyzer<PersistentFlow>(components) {
|
||||||
private val receiverStack: ImplicitReceiverStackImpl = components.implicitReceiverStack as ImplicitReceiverStackImpl
|
private val receiverStack: ImplicitReceiverStackImpl
|
||||||
|
get() = components.implicitReceiverStack as ImplicitReceiverStackImpl
|
||||||
|
|
||||||
override val logicSystem: PersistentLogicSystem = object : PersistentLogicSystem(components.inferenceComponents.ctx) {
|
override val logicSystem: PersistentLogicSystem = object : PersistentLogicSystem(components.inferenceComponents.ctx) {
|
||||||
override fun processUpdatedReceiverVariable(flow: PersistentFlow, variable: RealVariable) {
|
override fun processUpdatedReceiverVariable(flow: PersistentFlow, variable: RealVariable) {
|
||||||
|
|||||||
+5
-3
@@ -140,14 +140,14 @@ class FirCallCompleter(
|
|||||||
|
|
||||||
private inner class LambdaAnalyzerImpl : LambdaAnalyzer {
|
private inner class LambdaAnalyzerImpl : LambdaAnalyzer {
|
||||||
override fun analyzeAndGetLambdaReturnArguments(
|
override fun analyzeAndGetLambdaReturnArguments(
|
||||||
lambdaArgument: FirAnonymousFunction,
|
lambdaAtom: ResolvedLambdaAtom,
|
||||||
isSuspend: Boolean,
|
|
||||||
receiverType: ConeKotlinType?,
|
receiverType: ConeKotlinType?,
|
||||||
parameters: List<ConeKotlinType>,
|
parameters: List<ConeKotlinType>,
|
||||||
expectedReturnType: ConeKotlinType?,
|
expectedReturnType: ConeKotlinType?,
|
||||||
rawReturnType: ConeKotlinType,
|
rawReturnType: ConeKotlinType,
|
||||||
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>
|
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>
|
||||||
): ReturnArgumentsAnalysisResult {
|
): ReturnArgumentsAnalysisResult {
|
||||||
|
val lambdaArgument: FirAnonymousFunction = lambdaAtom.atom
|
||||||
val needItParam = lambdaArgument.valueParameters.isEmpty() && parameters.size == 1
|
val needItParam = lambdaArgument.valueParameters.isEmpty() && parameters.size == 1
|
||||||
|
|
||||||
val itParam = when {
|
val itParam = when {
|
||||||
@@ -185,7 +185,9 @@ class FirCallCompleter(
|
|||||||
lambdaArgument.replaceValueParameters(lambdaArgument.valueParameters + listOfNotNull(itParam))
|
lambdaArgument.replaceValueParameters(lambdaArgument.valueParameters + listOfNotNull(itParam))
|
||||||
lambdaArgument.replaceReturnTypeRef(expectedReturnTypeRef ?: noExpectedType)
|
lambdaArgument.replaceReturnTypeRef(expectedReturnTypeRef ?: noExpectedType)
|
||||||
|
|
||||||
lambdaArgument.transformSingle(transformer, ResolutionMode.LambdaResolution(expectedReturnTypeRef))
|
transformer.components.withImplicitReceiverStack(lambdaAtom.implicitReceiverStack) {
|
||||||
|
lambdaArgument.transformSingle(transformer, ResolutionMode.LambdaResolution(expectedReturnTypeRef))
|
||||||
|
}
|
||||||
|
|
||||||
val returnArguments = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(lambdaArgument)
|
val returnArguments = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(lambdaArgument)
|
||||||
|
|
||||||
|
|||||||
+21
-11
@@ -9,12 +9,10 @@ import org.jetbrains.kotlin.fir.FirSession
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||||
import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.CandidateApplicability
|
import org.jetbrains.kotlin.fir.resolve.calls.CandidateApplicability
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.isExtensionFunctionType
|
import org.jetbrains.kotlin.fir.resolve.calls.isExtensionFunctionType
|
||||||
import org.jetbrains.kotlin.fir.resolve.createFunctionalType
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
@@ -36,8 +34,8 @@ fun Candidate.preprocessLambdaArgument(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val resolvedArgument =
|
val resolvedArgument =
|
||||||
extractLambdaInfoFromFunctionalType(expectedType, expectedTypeRef, argument, bodyResolveComponents.session)
|
extractLambdaInfoFromFunctionalType(expectedType, expectedTypeRef, argument, bodyResolveComponents.session, bodyResolveComponents)
|
||||||
?: extraLambdaInfo(expectedType, argument, csBuilder, bodyResolveComponents.session)
|
?: extraLambdaInfo(expectedType, argument, csBuilder, bodyResolveComponents.session, bodyResolveComponents)
|
||||||
|
|
||||||
if (expectedType != null) {
|
if (expectedType != null) {
|
||||||
// TODO: add SAM conversion processing
|
// TODO: add SAM conversion processing
|
||||||
@@ -106,7 +104,8 @@ private fun extraLambdaInfo(
|
|||||||
expectedType: ConeKotlinType?,
|
expectedType: ConeKotlinType?,
|
||||||
argument: FirAnonymousFunction,
|
argument: FirAnonymousFunction,
|
||||||
csBuilder: ConstraintSystemBuilder,
|
csBuilder: ConstraintSystemBuilder,
|
||||||
session: FirSession
|
session: FirSession,
|
||||||
|
components: BodyResolveComponents
|
||||||
): ResolvedLambdaAtom {
|
): ResolvedLambdaAtom {
|
||||||
val isSuspend = expectedType?.isSuspendFunctionType(session) ?: false
|
val isSuspend = expectedType?.isSuspendFunctionType(session) ?: false
|
||||||
|
|
||||||
@@ -130,18 +129,27 @@ private fun extraLambdaInfo(
|
|||||||
val newTypeVariableUsed = returnType == typeVariable.defaultType
|
val newTypeVariableUsed = returnType == typeVariable.defaultType
|
||||||
if (newTypeVariableUsed) csBuilder.registerVariable(typeVariable)
|
if (newTypeVariableUsed) csBuilder.registerVariable(typeVariable)
|
||||||
|
|
||||||
return ResolvedLambdaAtom(argument, isSuspend, receiverType, parameters, returnType, typeVariable.takeIf { newTypeVariableUsed })
|
return ResolvedLambdaAtom(
|
||||||
|
argument,
|
||||||
|
isSuspend,
|
||||||
|
receiverType,
|
||||||
|
parameters,
|
||||||
|
returnType,
|
||||||
|
typeVariable.takeIf { newTypeVariableUsed },
|
||||||
|
components.implicitReceiverStack.snapshot()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun extractLambdaInfoFromFunctionalType(
|
internal fun extractLambdaInfoFromFunctionalType(
|
||||||
expectedType: ConeKotlinType?,
|
expectedType: ConeKotlinType?,
|
||||||
expectedTypeRef: FirTypeRef,
|
expectedTypeRef: FirTypeRef,
|
||||||
argument: FirAnonymousFunction,
|
argument: FirAnonymousFunction,
|
||||||
session: FirSession
|
session: FirSession,
|
||||||
|
components: BodyResolveComponents
|
||||||
): ResolvedLambdaAtom? {
|
): ResolvedLambdaAtom? {
|
||||||
if (expectedType == null) return null
|
if (expectedType == null) return null
|
||||||
if (expectedType is ConeFlexibleType) {
|
if (expectedType is ConeFlexibleType) {
|
||||||
return extractLambdaInfoFromFunctionalType(expectedType.lowerBound, expectedTypeRef, argument, session)
|
return extractLambdaInfoFromFunctionalType(expectedType.lowerBound, expectedTypeRef, argument, session, components)
|
||||||
}
|
}
|
||||||
if (!expectedType.isBuiltinFunctionalType(session)) return null
|
if (!expectedType.isBuiltinFunctionalType(session)) return null
|
||||||
|
|
||||||
@@ -155,7 +163,8 @@ internal fun extractLambdaInfoFromFunctionalType(
|
|||||||
receiverType,
|
receiverType,
|
||||||
parameters,
|
parameters,
|
||||||
returnType,
|
returnType,
|
||||||
typeVariableForLambdaReturnType = null
|
typeVariableForLambdaReturnType = null,
|
||||||
|
components.implicitReceiverStack.snapshot()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +208,8 @@ class ResolvedLambdaAtom(
|
|||||||
val receiver: ConeKotlinType?,
|
val receiver: ConeKotlinType?,
|
||||||
val parameters: List<ConeKotlinType>,
|
val parameters: List<ConeKotlinType>,
|
||||||
val returnType: ConeKotlinType,
|
val returnType: ConeKotlinType,
|
||||||
val typeVariableForLambdaReturnType: TypeVariableForLambdaReturnType?
|
val typeVariableForLambdaReturnType: TypeVariableForLambdaReturnType?,
|
||||||
|
val implicitReceiverStack: ImplicitReceiverStack
|
||||||
) : PostponedResolvedAtomMarker {
|
) : PostponedResolvedAtomMarker {
|
||||||
|
|
||||||
override var analyzed: Boolean = false
|
override var analyzed: Boolean = false
|
||||||
|
|||||||
+2
-5
@@ -6,7 +6,6 @@
|
|||||||
package org.jetbrains.kotlin.fir.resolve.inference
|
package org.jetbrains.kotlin.fir.resolve.inference
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.FirCallResolver
|
import org.jetbrains.kotlin.fir.FirCallResolver
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
||||||
@@ -32,8 +31,7 @@ data class ReturnArgumentsAnalysisResult(
|
|||||||
|
|
||||||
interface LambdaAnalyzer {
|
interface LambdaAnalyzer {
|
||||||
fun analyzeAndGetLambdaReturnArguments(
|
fun analyzeAndGetLambdaReturnArguments(
|
||||||
lambdaArgument: FirAnonymousFunction,
|
lambdaAtom: ResolvedLambdaAtom,
|
||||||
isSuspend: Boolean,
|
|
||||||
receiverType: ConeKotlinType?,
|
receiverType: ConeKotlinType?,
|
||||||
parameters: List<ConeKotlinType>,
|
parameters: List<ConeKotlinType>,
|
||||||
expectedReturnType: ConeKotlinType?, // null means, that return type is not proper i.e. it depends on some type variables
|
expectedReturnType: ConeKotlinType?, // null means, that return type is not proper i.e. it depends on some type variables
|
||||||
@@ -128,8 +126,7 @@ class PostponedArgumentsAnalyzer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val (returnArguments, inferenceSession) = lambdaAnalyzer.analyzeAndGetLambdaReturnArguments(
|
val (returnArguments, inferenceSession) = lambdaAnalyzer.analyzeAndGetLambdaReturnArguments(
|
||||||
lambda.atom,
|
lambda,
|
||||||
lambda.isSuspend,
|
|
||||||
receiver,
|
receiver,
|
||||||
parameters,
|
parameters,
|
||||||
expectedTypeForReturnArguments,
|
expectedTypeForReturnArguments,
|
||||||
|
|||||||
+15
-2
@@ -106,7 +106,10 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb
|
|||||||
override val symbolProvider: FirSymbolProvider = session.firSymbolProvider
|
override val symbolProvider: FirSymbolProvider = session.firSymbolProvider
|
||||||
|
|
||||||
override val returnTypeCalculator: ReturnTypeCalculator = transformer.returnTypeCalculator
|
override val returnTypeCalculator: ReturnTypeCalculator = transformer.returnTypeCalculator
|
||||||
override val implicitReceiverStack: ImplicitReceiverStack = ImplicitReceiverStackImpl()
|
|
||||||
|
@set:PrivateForInline
|
||||||
|
override var implicitReceiverStack: ImplicitReceiverStack = ImplicitReceiverStackImpl()
|
||||||
|
|
||||||
override val inferenceComponents: InferenceComponents = inferenceComponents(session, returnTypeCalculator, scopeSession)
|
override val inferenceComponents: InferenceComponents = inferenceComponents(session, returnTypeCalculator, scopeSession)
|
||||||
override val resolutionStageRunner: ResolutionStageRunner = ResolutionStageRunner(inferenceComponents)
|
override val resolutionStageRunner: ResolutionStageRunner = ResolutionStageRunner(inferenceComponents)
|
||||||
override val samResolver: FirSamResolver = FirSamResolverImpl(session, scopeSession)
|
override val samResolver: FirSamResolver = FirSamResolverImpl(session, scopeSession)
|
||||||
@@ -116,7 +119,6 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb
|
|||||||
this,
|
this,
|
||||||
topLevelScopes,
|
topLevelScopes,
|
||||||
localScopes,
|
localScopes,
|
||||||
implicitReceiverStack,
|
|
||||||
qualifiedResolver
|
qualifiedResolver
|
||||||
)
|
)
|
||||||
val typeResolverTransformer = FirSpecificTypeResolverTransformer(
|
val typeResolverTransformer = FirSpecificTypeResolverTransformer(
|
||||||
@@ -147,6 +149,17 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb
|
|||||||
containerIfAny = prevContainer
|
containerIfAny = prevContainer
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UseExperimental(PrivateForInline::class)
|
||||||
|
inline fun <T> withImplicitReceiverStack(implicitReceiverStack: ImplicitReceiverStack, f: () -> T): T {
|
||||||
|
val existedStack = this.implicitReceiverStack
|
||||||
|
this.implicitReceiverStack = implicitReceiverStack
|
||||||
|
return try {
|
||||||
|
f()
|
||||||
|
} finally {
|
||||||
|
this.implicitReceiverStack = existedStack
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -489,7 +489,7 @@ class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer)
|
|||||||
val expectedTypeRef = (data as? ResolutionMode.WithExpectedType)?.expectedTypeRef ?: buildImplicitTypeRef()
|
val expectedTypeRef = (data as? ResolutionMode.WithExpectedType)?.expectedTypeRef ?: buildImplicitTypeRef()
|
||||||
val resolvedLambdaAtom = (expectedTypeRef as? FirResolvedTypeRef)?.let {
|
val resolvedLambdaAtom = (expectedTypeRef as? FirResolvedTypeRef)?.let {
|
||||||
extractLambdaInfoFromFunctionalType(
|
extractLambdaInfoFromFunctionalType(
|
||||||
it.type, it, anonymousFunction, session
|
it.type, it, anonymousFunction, session, components
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
var af = anonymousFunction
|
var af = anonymousFunction
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ class Second {
|
|||||||
|
|
||||||
val test = with(data) {
|
val test = with(data) {
|
||||||
list.filterIsInstance<Int>().filter {
|
list.filterIsInstance<Int>().filter {
|
||||||
it == <!UNRESOLVED_REFERENCE!>member<!>
|
it == member
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -21,7 +21,7 @@ FILE: withInInitializer.kt
|
|||||||
|
|
||||||
public final val test: R|kotlin/collections/List<kotlin/Int>| = R|kotlin/with|<R|First|, R|kotlin/collections/List<kotlin/Int>|>(this@R|/Second|.R|/Second.data|, <L> = with@fun R|First|.<anonymous>(): R|kotlin/collections/List<kotlin/Int>| <kind=EXACTLY_ONCE> {
|
public final val test: R|kotlin/collections/List<kotlin/Int>| = R|kotlin/with|<R|First|, R|kotlin/collections/List<kotlin/Int>|>(this@R|/Second|.R|/Second.data|, <L> = with@fun R|First|.<anonymous>(): R|kotlin/collections/List<kotlin/Int>| <kind=EXACTLY_ONCE> {
|
||||||
^ this@R|/Second|.R|/Second.list|.R|kotlin/collections/filterIsInstance|<R|kotlin/Int|>().R|kotlin/collections/filter|<R|kotlin/Int|>(<L> = filter@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| <kind=UNKNOWN> {
|
^ this@R|/Second|.R|/Second.list|.R|kotlin/collections/filterIsInstance|<R|kotlin/Int|>().R|kotlin/collections/filter|<R|kotlin/Int|>(<L> = filter@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| <kind=UNKNOWN> {
|
||||||
^ ==(R|<local>/it|, <Unresolved name: member>#)
|
^ ==(R|<local>/it|, this@R|special/anonymous|.R|/First.member|)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Generated
+5
-5
@@ -288,6 +288,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
|
|||||||
runTest("compiler/fir/resolve/testData/resolveWithStdlib/whenAsLambdaReturnStatement.kt");
|
runTest("compiler/fir/resolve/testData/resolveWithStdlib/whenAsLambdaReturnStatement.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("withInInitializer.kt")
|
||||||
|
public void testWithInInitializer() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolveWithStdlib/withInInitializer.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/fir/resolve/testData/resolveWithStdlib/callableReferences")
|
@TestMetadata("compiler/fir/resolve/testData/resolveWithStdlib/callableReferences")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
@@ -714,11 +719,6 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
|
|||||||
public void testWeakHashMap() throws Exception {
|
public void testWeakHashMap() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolveWithStdlib/problems/weakHashMap.kt");
|
runTest("compiler/fir/resolve/testData/resolveWithStdlib/problems/weakHashMap.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("withInInitializer.kt")
|
|
||||||
public void testWithInInitializer() throws Exception {
|
|
||||||
runTest("compiler/fir/resolve/testData/resolveWithStdlib/problems/withInInitializer.kt");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/fir/resolve/testData/resolveWithStdlib/smartcasts")
|
@TestMetadata("compiler/fir/resolve/testData/resolveWithStdlib/smartcasts")
|
||||||
|
|||||||
Reference in New Issue
Block a user