[FIR] Introduce inference session

This commit is contained in:
Dmitriy Novozhilov
2020-02-26 11:10:14 +03:00
parent dfa6dfa960
commit 1003b81c93
9 changed files with 160 additions and 65 deletions
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.calls.ResolutionStageRunner
import org.jetbrains.kotlin.fir.resolve.dfa.FirDataFlowAnalyzer
import org.jetbrains.kotlin.fir.resolve.inference.FirCallCompleter
import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents
import org.jetbrains.kotlin.fir.resolve.transformers.*
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
@@ -34,6 +35,7 @@ interface BodyResolveComponents : SessionHolder {
val scopeSession: ScopeSession
val samResolver: FirSamResolver
val callResolver: FirCallResolver
val callCompleter: FirCallCompleter
val doubleColonExpressionResolver: FirDoubleColonExpressionResolver
val syntheticCallGenerator: FirSyntheticCallGenerator
val dataFlowAnalyzer: FirDataFlowAnalyzer<*>
@@ -6,12 +6,9 @@
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionWithSmartcast
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype
import org.jetbrains.kotlin.fir.returnExpressions
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
@@ -28,6 +25,7 @@ class CandidateFactory private constructor(
callInfo.arguments.forEach {
system.addSubsystemFromExpression(it)
}
system.addOtherSystem(bodyResolveComponents.inferenceComponents.inferenceSession.currentConstraintSystem)
return system.asReadOnlyStorage()
}
}
@@ -13,10 +13,10 @@ import org.jetbrains.kotlin.fir.expressions.FirResolvable
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.calls.candidate
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.transformers.*
import org.jetbrains.kotlin.fir.resolve.transformers.MapArguments
import org.jetbrains.kotlin.fir.resolve.transformers.FirCallCompletionResultsWriterTransformer
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.FirBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
@@ -30,9 +30,8 @@ import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.types.model.StubTypeMarker
@@ -42,7 +41,9 @@ class FirCallCompleter(
private val transformer: FirBodyResolveTransformer,
components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents
) : BodyResolveComponents by components {
private val completer = ConstraintSystemCompleter(components.inferenceComponents)
val completer = ConstraintSystemCompleter(components.inferenceComponents)
private val inferenceSession
get() = inferenceComponents.inferenceSession
fun <T> completeCall(call: T, expectedTypeRef: FirTypeRef?): T
where T : FirResolvable, T : FirStatement {
@@ -51,7 +52,7 @@ class FirCallCompleter(
if (call is FirExpression) {
call.resultType = typeRef
}
return if (call is FirFunctionCall) {
val errorCall = if (call is FirFunctionCall) {
call.transformArguments(
transformer,
ResolutionMode.WithExpectedType(typeRef.resolvedTypeFromPrototype(session.builtinTypes.nullableAnyType.type))
@@ -59,7 +60,10 @@ class FirCallCompleter(
} else {
call
}
inferenceSession.addErrorCall(errorCall)
return errorCall
}
val candidate = call.candidate() ?: return call
val initialSubstitutor = candidate.substitutor
@@ -75,31 +79,50 @@ class FirCallCompleter(
val completionMode = candidate.computeCompletionMode(inferenceComponents, expectedTypeRef, initialType)
val analyzer =
PostponedArgumentsAnalyzer(
LambdaAnalyzerImpl(), inferenceComponents, candidate,
transformer.components.callResolver
)
val analyzer = createPostponedArgumentsAnalyzer()
call.transformSingle(InvocationKindTransformer, null)
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(call), initialType) {
analyzer.analyze(candidate.system.asPostponedArgumentsAnalyzerContext(), it)
}
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
val finalSubstitutor =
candidate.system.asReadOnlyStorage().buildAbstractResultingSubstitutor(inferenceComponents.ctx) as ConeSubstitutor
return call.transformSingle(
FirCallCompletionResultsWriterTransformer(
session, finalSubstitutor, returnTypeCalculator,
inferenceComponents.approximator,
integerOperatorsTypeUpdater,
integerLiteralTypeApproximator
),
null
)
return when (completionMode) {
ConstraintSystemCompletionMode.FULL -> {
if (inferenceSession.shouldRunCompletion(candidate)) {
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(call), initialType) {
analyzer.analyze(candidate.system.asPostponedArgumentsAnalyzerContext(), it, candidate)
}
val finalSubstitutor =
candidate.system.asReadOnlyStorage().buildAbstractResultingSubstitutor(inferenceComponents.ctx) as ConeSubstitutor
val completedCall = call.transformSingle(
FirCallCompletionResultsWriterTransformer(
session, finalSubstitutor, returnTypeCalculator,
inferenceComponents.approximator,
integerOperatorsTypeUpdater,
integerLiteralTypeApproximator
),
null
)
inferenceSession.addCompetedCall(completedCall)
completedCall
} else {
inferenceSession.addPartiallyResolvedCall(call)
call
}
}
ConstraintSystemCompletionMode.PARTIAL -> {
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(call), initialType) {
analyzer.analyze(candidate.system.asPostponedArgumentsAnalyzerContext(), it, candidate)
}
val approximatedCall = call.transformSingle(integerOperatorsTypeUpdater, null)
inferenceSession.addPartiallyResolvedCall(approximatedCall)
approximatedCall
}
}
return call.transformSingle(integerOperatorsTypeUpdater, null)
}
fun createPostponedArgumentsAnalyzer(): PostponedArgumentsAnalyzer {
return PostponedArgumentsAnalyzer(
LambdaAnalyzerImpl(), inferenceComponents,
transformer.components.callResolver
)
}
private inner class LambdaAnalyzerImpl : LambdaAnalyzer {
@@ -111,8 +134,7 @@ class FirCallCompleter(
expectedReturnType: ConeKotlinType?,
rawReturnType: ConeKotlinType,
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>
): Pair<List<FirStatement>, InferenceSession> {
): ReturnArgumentsAnalysisResult {
val needItParam = lambdaArgument.valueParameters.isEmpty() && parameters.size == 1
val itParam = when {
@@ -153,7 +175,9 @@ class FirCallCompleter(
lambdaArgument.transformSingle(transformer, ResolutionMode.LambdaResolution(expectedReturnTypeRef))
val returnArguments = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(lambdaArgument)
return returnArguments to InferenceSession.default
// TODO: add detecting of coroutine inference session
return ReturnArgumentsAnalysisResult(returnArguments, null)
}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve.inference
import org.jetbrains.kotlin.fir.expressions.FirResolvable
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeVariableTypeConstructor
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
abstract class FirInferenceSession {
companion object {
val DEFAULT: FirInferenceSession = object : FirInferenceSession() {
override fun shouldRunCompletion(candidate: Candidate): Boolean = true
override val currentConstraintSystem: ConstraintStorage
get() = ConstraintStorage.Empty
override fun <T> addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement {}
override fun <T> addErrorCall(call: T) where T : FirResolvable, T : FirStatement {}
override fun <T> addCompetedCall(call: T) where T : FirResolvable, T : FirStatement {}
override fun inferPostponedVariables(
lambda: ResolvedLambdaAtom,
initialStorage: ConstraintStorage
): Map<ConeTypeVariableTypeConstructor, ConeKotlinType> = emptyMap()
override fun <T> callCompleted(call: T): Boolean where T : FirResolvable, T : FirStatement = false
override fun <T> shouldCompleteResolvedSubAtomsOf(call: T): Boolean where T : FirResolvable, T : FirStatement = true
}
}
abstract fun shouldRunCompletion(candidate: Candidate): Boolean
abstract val currentConstraintSystem: ConstraintStorage
abstract fun <T> addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement
abstract fun <T> addErrorCall(call: T) where T : FirResolvable, T : FirStatement
abstract fun <T> addCompetedCall(call: T) where T : FirResolvable, T : FirStatement
abstract fun inferPostponedVariables(
lambda: ResolvedLambdaAtom,
initialStorage: ConstraintStorage,
// TODO: diagnostic holder
): Map<ConeTypeVariableTypeConstructor, ConeKotlinType>
// TODO: do we need this?
// abstract fun writeOnlyStubs(): Boolean
abstract fun <T> callCompleted(call: T): Boolean where T : FirResolvable, T : FirStatement
abstract fun <T> shouldCompleteResolvedSubAtomsOf(call: T): Boolean where T : FirResolvable, T : FirStatement
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.resolve.inference
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.PrivateForInline
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
@@ -37,6 +38,20 @@ class InferenceComponents(
private val injector = ConstraintInjector(incorporator, approximator, KotlinTypeRefiner.Default)
val resultTypeResolver = ResultTypeResolver(approximator, trivialConstraintTypeInferenceOracle)
@set:PrivateForInline
var inferenceSession: FirInferenceSession = FirInferenceSession.DEFAULT
@UseExperimental(PrivateForInline::class)
inline fun <R> withInferenceSession(inferenceSession: FirInferenceSession, block: () -> R): R {
val oldSession = this.inferenceSession
this.inferenceSession = inferenceSession
return try {
block()
} finally {
this.inferenceSession = oldSession
}
}
fun createConstraintSystem(): NewConstraintSystemImpl {
return NewConstraintSystemImpl(injector, ctx)
}
@@ -14,9 +14,10 @@ import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.diagnostics.FirUnresolvedReferenceError
import org.jetbrains.kotlin.fir.resolve.transformers.StoreNameReference
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeVariable
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
import org.jetbrains.kotlin.resolve.calls.inference.model.CoroutinePosition
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
import org.jetbrains.kotlin.types.model.StubTypeMarker
@@ -24,6 +25,11 @@ import org.jetbrains.kotlin.types.model.TypeVariableMarker
import org.jetbrains.kotlin.types.model.freshTypeConstructor
import org.jetbrains.kotlin.types.model.safeSubstitute
data class ReturnArgumentsAnalysisResult(
val returnArguments: List<FirStatement>,
val inferenceSession: FirInferenceSession?
)
interface LambdaAnalyzer {
fun analyzeAndGetLambdaReturnArguments(
lambdaArgument: FirAnonymousFunction,
@@ -33,33 +39,33 @@ interface LambdaAnalyzer {
expectedReturnType: ConeKotlinType?, // null means, that return type is not proper i.e. it depends on some type variables
rawReturnType: ConeKotlinType,
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>
): Pair<List<FirStatement>, InferenceSession>
): ReturnArgumentsAnalysisResult
}
class PostponedArgumentsAnalyzer(
private val lambdaAnalyzer: LambdaAnalyzer,
private val components: InferenceComponents,
private val candidate: Candidate,
private val callResolver: FirCallResolver
) {
fun analyze(
c: PostponedArgumentsAnalyzer.Context,
// resolutionCallbacks: KotlinResolutionCallbacks,
argument: PostponedResolvedAtomMarker
argument: PostponedResolvedAtomMarker,
candidate: Candidate
//diagnosticsHolder: KotlinDiagnosticsHolder
) {
when (argument) {
is ResolvedLambdaAtom ->
analyzeLambda(c, argument/*, diagnosticsHolder*/)
analyzeLambda(c, argument, candidate/*, diagnosticsHolder*/)
// is LambdaWithTypeVariableAsExpectedTypeAtom ->
// analyzeLambda(
// c, resolutionCallbacks, argument.transformToResolvedLambda(c.getBuilder()), diagnosticsHolder
// )
is ResolvedCallableReferenceAtom -> processCallableReference(argument)
is ResolvedCallableReferenceAtom -> processCallableReference(argument, candidate)
//
// is ResolvedCollectionLiteralAtom -> TODO("Not supported")
@@ -67,7 +73,7 @@ class PostponedArgumentsAnalyzer(
}
}
private fun processCallableReference(atom: ResolvedCallableReferenceAtom) {
private fun processCallableReference(atom: ResolvedCallableReferenceAtom, candidate: Candidate) {
if (atom.postponed) {
callResolver.resolveCallableReference(candidate.csBuilder, atom)
}
@@ -98,7 +104,8 @@ class PostponedArgumentsAnalyzer(
private fun analyzeLambda(
c: PostponedArgumentsAnalyzer.Context,
lambda: ResolvedLambdaAtom//,
lambda: ResolvedLambdaAtom,
candidate: Candidate
//diagnosticHolder: KotlinDiagnosticsHolder
) {
val unitType = components.session.builtinTypes.unitType.type//Unit(components.session.firSymbolProvider).constructType(emptyArray(), false)
@@ -136,7 +143,6 @@ class PostponedArgumentsAnalyzer(
val subResolvedKtPrimitives = returnArguments.map {
if (it !is FirExpression) return@map
var atom: PostponedResolvedAtomMarker? = null
candidate.resolveArgumentExpression(
c.getBuilder(),
it,
@@ -153,7 +159,6 @@ class PostponedArgumentsAnalyzer(
}
if (returnArguments.isEmpty()) {
// val unitType =
val lambdaReturnType = lambda.returnType.let(::substitute)
c.getBuilder().addSubtypeConstraint(
lambdaReturnType,
@@ -169,21 +174,20 @@ class PostponedArgumentsAnalyzer(
lambda.analyzed = true
lambda.returnStatements = returnArguments
//lambda.setAnalyzedResults(returnArguments, subResolvedKtPrimitives)
// if (inferenceSession != null) {
// val storageSnapshot = c.getBuilder().currentStorage()
//
// val postponedVariables = inferenceSession.inferPostponedVariables(lambda, storageSnapshot)
//
// for ((constructor, resultType) in postponedVariables) {
// val variableWithConstraints = storageSnapshot.notFixedTypeVariables[constructor] ?: continue
// val variable = variableWithConstraints.typeVariable
//
// c.getBuilder().unmarkPostponedVariable(variable)
// c.getBuilder().addEqualityConstraint(variable.defaultType(c), resultType, CoroutinePosition())
// }
// }
if (inferenceSession != null) {
val storageSnapshot = c.getBuilder().currentStorage()
val postponedVariables = inferenceSession.inferPostponedVariables(lambda, storageSnapshot)
for ((constructor, resultType) in postponedVariables) {
val variableWithConstraints = storageSnapshot.notFixedTypeVariables[constructor] ?: continue
val variable = variableWithConstraints.typeVariable as ConeTypeVariable
c.getBuilder().unmarkPostponedVariable(variable)
c.getBuilder().addEqualityConstraint(variable.defaultType, resultType, CoroutinePosition())
}
}
}
}
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.fir.references.impl.FirStubReference
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.diagnostics.FirUnresolvedNameError
import org.jetbrains.kotlin.fir.resolve.inference.FirCallCompleter
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.SyntheticCallableId
@@ -41,8 +40,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.types.Variance
class FirSyntheticCallGenerator(
private val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents,
private val callCompleter: FirCallCompleter
private val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents
) : BodyResolveComponents by components {
private val whenSelectFunction: FirSimpleFunction = generateSyntheticSelectFunction(SyntheticCallableId.WHEN)
private val trySelectFunction: FirSimpleFunction = generateSyntheticSelectFunction(SyntheticCallableId.TRY)
@@ -73,6 +73,7 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb
protected inline val resolutionStageRunner: ResolutionStageRunner get() = components.resolutionStageRunner
protected inline val samResolver: FirSamResolver get() = components.samResolver
protected inline val typeResolverTransformer: FirSpecificTypeResolverTransformer get() = components.typeResolverTransformer
protected inline val callResolver: FirCallResolver get() = components.callResolver
protected inline val callCompleter: FirCallCompleter get() = components.callCompleter
protected inline val dataFlowAnalyzer: FirDataFlowAnalyzer<*> get() = components.dataFlowAnalyzer
protected inline val scopeSession: ScopeSession get() = components.scopeSession
@@ -121,9 +122,9 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb
val typeResolverTransformer = FirSpecificTypeResolverTransformer(
FirTypeResolveScopeForBodyResolve(topLevelScopes, implicitReceiverStack, localScopes), session
)
val callCompleter: FirCallCompleter = FirCallCompleter(transformer, this)
override val callCompleter: FirCallCompleter = FirCallCompleter(transformer, this)
override val dataFlowAnalyzer: FirDataFlowAnalyzer<*> = FirDataFlowAnalyzer.createFirDataFlowAnalyzer(this)
override val syntheticCallGenerator: FirSyntheticCallGenerator = FirSyntheticCallGenerator(this, callCompleter)
override val syntheticCallGenerator: FirSyntheticCallGenerator = FirSyntheticCallGenerator(this)
override val integerLiteralTypeApproximator: IntegerLiteralTypeApproximationTransformer =
IntegerLiteralTypeApproximationTransformer(symbolProvider, inferenceComponents.ctx)
override val integerOperatorsTypeUpdater: IntegerOperatorsTypeUpdater = IntegerOperatorsTypeUpdater(integerLiteralTypeApproximator)
@@ -43,7 +43,6 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : FirPartialBodyResolveTransformer(transformer) {
private val callResolver: FirCallResolver get() = components.callResolver
private inline val builtinTypes: BuiltinTypes get() = session.builtinTypes
init {