FIR: support type inference for assignments, fix related lambda inference
This commit is contained in:
@@ -5,9 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWrappedArgumentExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
@@ -49,9 +47,8 @@ fun PostponedArgumentsAnalyzer.Context.addSubsystemFromExpression(expression: Fi
|
||||
}
|
||||
}
|
||||
|
||||
internal fun FirFunctionCall.candidate(): Candidate? {
|
||||
val callee = this.calleeReference
|
||||
return when (callee) {
|
||||
internal fun FirQualifiedAccess.candidate(): Candidate? {
|
||||
return when (val callee = this.calleeReference) {
|
||||
is FirNamedReferenceWithCandidate -> return callee.candidate
|
||||
else -> null
|
||||
}
|
||||
|
||||
+5
-4
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWrappedArgumentExpression
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
@@ -92,7 +93,7 @@ class ConstraintSystemCompleter(val components: InferenceComponents) {
|
||||
fun complete(
|
||||
c: KotlinConstraintSystemCompleter.Context,
|
||||
completionMode: KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode,
|
||||
topLevelAtoms: List<FirExpression>,
|
||||
topLevelAtoms: List<FirStatement>,
|
||||
candidateReturnType: ConeKotlinType,
|
||||
analyze: (PostponedResolvedAtomMarker) -> Unit
|
||||
) {
|
||||
@@ -159,7 +160,7 @@ class ConstraintSystemCompleter(val components: InferenceComponents) {
|
||||
|
||||
private fun analyzePostponeArgumentIfPossible(
|
||||
c: KotlinConstraintSystemCompleter.Context,
|
||||
topLevelAtoms: List<FirExpression>,
|
||||
topLevelAtoms: List<FirStatement>,
|
||||
analyze: (PostponedResolvedAtomMarker) -> Unit
|
||||
): Boolean {
|
||||
for (argument in getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)) {
|
||||
@@ -171,8 +172,8 @@ class ConstraintSystemCompleter(val components: InferenceComponents) {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List<FirExpression>): List<PostponedResolvedAtomMarker> {
|
||||
fun FirExpression.process(to: MutableList<PostponedResolvedAtomMarker>) {
|
||||
private fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List<FirStatement>): List<PostponedResolvedAtomMarker> {
|
||||
fun FirStatement.process(to: MutableList<PostponedResolvedAtomMarker>) {
|
||||
when (this) {
|
||||
is FirFunctionCall -> {
|
||||
val candidate = (this.calleeReference as? FirNamedReferenceWithCandidate)?.candidate
|
||||
|
||||
+31
-14
@@ -198,7 +198,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
access.resultType = typeFromCallee(access)
|
||||
}
|
||||
|
||||
private fun <T> typeFromCallee(access: T): FirResolvedTypeRef where T : FirQualifiedAccess, T : FirExpression {
|
||||
private fun <T> typeFromCallee(access: T): FirResolvedTypeRef where T : FirQualifiedAccess {
|
||||
return when (val newCallee = access.calleeReference) {
|
||||
is FirErrorNamedReference ->
|
||||
FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason)
|
||||
@@ -232,6 +232,12 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
error("WTF ! $symbol")
|
||||
}
|
||||
}
|
||||
is FirThisReference -> {
|
||||
val labelName = newCallee.labelName
|
||||
val types = if (labelName == null) labels.values() else labels[Name.identifier(labelName)]
|
||||
val type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName")
|
||||
FirResolvedTypeRefImpl(session, null, type, emptyList())
|
||||
}
|
||||
else -> error("Failed to extract type from: $newCallee")
|
||||
}
|
||||
}
|
||||
@@ -402,8 +408,15 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
variableAssignment: FirVariableAssignment,
|
||||
data: Any?
|
||||
): CompositeTransformResult<FirStatement> {
|
||||
val variableAssignment = variableAssignment.transformRValue(this, null)
|
||||
return transformCallee(variableAssignment).compose()
|
||||
val resolvedAssignment = transformCallee(variableAssignment)
|
||||
return if (resolvedAssignment is FirVariableAssignment) {
|
||||
val completeAssignment = completeTypeInference(resolvedAssignment, noExpectedType)
|
||||
val expectedType = typeFromCallee(completeAssignment)
|
||||
completeAssignment.transformRValue(this, expectedType).compose()
|
||||
} else {
|
||||
// This can happen in erroneous code only
|
||||
resolvedAssignment.compose()
|
||||
}
|
||||
}
|
||||
|
||||
override fun transformAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: Any?): CompositeTransformResult<FirDeclaration> {
|
||||
@@ -592,13 +605,15 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
|
||||
data class LambdaResolution(val expectedReturnTypeRef: FirResolvedTypeRef?)
|
||||
|
||||
private fun completeTypeInference(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?): FirFunctionCall {
|
||||
val typeRef = typeFromCallee(functionCall)
|
||||
private fun <T : FirQualifiedAccess> completeTypeInference(qualifiedAccess: T, expectedTypeRef: FirTypeRef?): T {
|
||||
val typeRef = typeFromCallee(qualifiedAccess)
|
||||
if (typeRef.type is ConeKotlinErrorType) {
|
||||
functionCall.resultType = typeRef
|
||||
return functionCall
|
||||
if (qualifiedAccess is FirExpression) {
|
||||
qualifiedAccess.resultType = typeRef
|
||||
}
|
||||
return qualifiedAccess
|
||||
}
|
||||
val candidate = functionCall.candidate() ?: return functionCall
|
||||
val candidate = qualifiedAccess.candidate() ?: return qualifiedAccess
|
||||
val initialSubstitutor = candidate.substitutor
|
||||
|
||||
val initialType = initialSubstitutor.substituteOrSelf(typeRef.type)
|
||||
@@ -637,16 +652,18 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
val expectedReturnTypeRef = expectedReturnType?.let { lambdaArgument.returnTypeRef.resolvedTypeFromPrototype(it) }
|
||||
|
||||
val newLambdaExpression = lambdaArgument.copy(
|
||||
receiverTypeRef = receiverType?.let { lambdaArgument.receiverTypeRef!!.resolvedTypeFromPrototype(it) },
|
||||
valueParameters = lambdaArgument.valueParameters.mapIndexed { index, parameter ->
|
||||
parameter.transformReturnTypeRef(StoreType, parameter.returnTypeRef.resolvedTypeFromPrototype(parameters[index]))
|
||||
parameter
|
||||
} + listOfNotNull(itParam),
|
||||
returnTypeRef = lambdaArgument.returnTypeRef.resolvedTypeFromPrototype(rawReturnType)
|
||||
returnTypeRef = expectedReturnTypeRef ?: noExpectedType
|
||||
)
|
||||
|
||||
val expectedReturnTypeRef = expectedReturnType?.let { newLambdaExpression.returnTypeRef.resolvedTypeFromPrototype(it) }
|
||||
replacements[lambdaArgument] =
|
||||
newLambdaExpression.transformSingle(this@FirBodyResolveTransformer, LambdaResolution(expectedReturnTypeRef))
|
||||
|
||||
@@ -656,7 +673,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
|
||||
}, { it.resultType }, inferenceComponents)
|
||||
|
||||
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(functionCall), initialType) {
|
||||
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(qualifiedAccess), initialType) {
|
||||
analyzer.analyze(
|
||||
candidate.system.asPostponedArgumentsAnalyzerContext(),
|
||||
it
|
||||
@@ -664,18 +681,18 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
)
|
||||
}
|
||||
|
||||
functionCall.transformChildren(ReplaceInArguments, replacements.toMap())
|
||||
qualifiedAccess.transformChildren(ReplaceInArguments, replacements.toMap())
|
||||
|
||||
|
||||
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
|
||||
val finalSubstitutor =
|
||||
candidate.system.asReadOnlyStorage().buildAbstractResultingSubstitutor(inferenceComponents.ctx) as ConeSubstitutor
|
||||
return functionCall.transformSingle(
|
||||
return qualifiedAccess.transformSingle(
|
||||
FirCallCompleterTransformer(session, finalSubstitutor, jump),
|
||||
null
|
||||
)
|
||||
}
|
||||
return functionCall
|
||||
return qualifiedAccess
|
||||
}
|
||||
|
||||
override fun transformTryExpression(tryExpression: FirTryExpression, data: Any?): CompositeTransformResult<FirStatement> {
|
||||
|
||||
+32
-2
@@ -5,13 +5,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.transformers
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.copy
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||
import org.jetbrains.kotlin.fir.resolve.constructFunctionalTypeRef
|
||||
@@ -23,15 +23,45 @@ import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirTypeProjectionWithVarianceImpl
|
||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.compose
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
object StoreCalleeReference : FirTransformer<FirResolvedCallableReference>() {
|
||||
override fun <E : FirElement> transformElement(element: E, data: FirResolvedCallableReference): CompositeTransformResult<E> {
|
||||
return element.compose()
|
||||
}
|
||||
|
||||
override fun transformResolvedCallableReference(
|
||||
resolvedCallableReference: FirResolvedCallableReference,
|
||||
data: FirResolvedCallableReference
|
||||
): CompositeTransformResult<FirNamedReference> {
|
||||
return data.compose()
|
||||
}
|
||||
}
|
||||
|
||||
class FirCallCompleterTransformer(
|
||||
val session: FirSession,
|
||||
private val finalSubstitutor: ConeSubstitutor,
|
||||
private val typeCalculator: ReturnTypeCalculator
|
||||
) : FirAbstractTreeTransformer() {
|
||||
|
||||
override fun transformVariableAssignment(
|
||||
variableAssignment: FirVariableAssignment,
|
||||
data: Nothing?
|
||||
): CompositeTransformResult<FirStatement> {
|
||||
val calleeReference = variableAssignment.calleeReference as? FirNamedReferenceWithCandidate
|
||||
?: return variableAssignment.compose()
|
||||
return variableAssignment.transformCalleeReference(
|
||||
StoreCalleeReference,
|
||||
FirResolvedCallableReferenceImpl(
|
||||
calleeReference.session,
|
||||
calleeReference.psi,
|
||||
calleeReference.name,
|
||||
calleeReference.coneSymbol
|
||||
)
|
||||
).compose()
|
||||
}
|
||||
|
||||
override fun transformFunctionCall(functionCall: FirFunctionCall, data: Nothing?): CompositeTransformResult<FirStatement> {
|
||||
val calleeReference = functionCall.calleeReference as? FirNamedReferenceWithCandidate ?: return functionCall.compose()
|
||||
|
||||
@@ -7,7 +7,14 @@ var b: MutableSet<String>? = null
|
||||
field = HashSet()
|
||||
}
|
||||
|
||||
var <T> MutableSet<T>.d: T? get() = null
|
||||
set(_) {}
|
||||
|
||||
fun <T> produce(): T = TODO()
|
||||
|
||||
fun foo() {
|
||||
var c: MutableSet<String>? = null
|
||||
c = HashSet()
|
||||
|
||||
c!!.d = produce()
|
||||
}
|
||||
+20
-2
@@ -4,9 +4,27 @@ FILE: hashSet.kt
|
||||
public final var b: R|kotlin/collections/MutableSet<kotlin/String>|? = Null(null)
|
||||
public get(): R|kotlin/collections/MutableSet<kotlin/String>|?
|
||||
public set(_: R|kotlin/collections/MutableSet<kotlin/String>|?): R|kotlin/Unit| {
|
||||
F|/b| = R|java/util/HashSet.HashSet|()
|
||||
F|/b| = R|java/util/HashSet.HashSet|<R|kotlin/String|>()
|
||||
}
|
||||
public final var <T> R|kotlin/collections/MutableSet<T>|.d: R|T|?
|
||||
public get(): R|T|? {
|
||||
^ Null(null)
|
||||
}
|
||||
public set(_: R|T|?): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun <T> produce(): R|T| {
|
||||
^produce R|kotlin/TODO|()
|
||||
}
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
lvar c: R|kotlin/collections/MutableSet<kotlin/String>|? = Null(null)
|
||||
R|<local>/c| = R|java/util/HashSet.HashSet|()
|
||||
R|<local>/c| = R|java/util/HashSet.HashSet|<R|kotlin/String|>()
|
||||
when (lval <bangbang>: R|kotlin/collections/MutableSet<kotlin/String>|? = R|<local>/c|) {
|
||||
==($subj$, Null(null)) -> {
|
||||
throw R|kotlin/KotlinNullPointerException.KotlinNullPointerException|()
|
||||
}
|
||||
else -> {
|
||||
R|<local>/<bangbang>|!
|
||||
}
|
||||
}
|
||||
.R|/d| = R|/produce|<R|T|?>()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user