FIR resolve: perform inference completion for property access
This commit is contained in:
committed by
Mikhail Glukhikh
parent
99680a2ad7
commit
1222449dc8
+21
-5
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.expressions.*
|
|||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl
|
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl
|
||||||
import org.jetbrains.kotlin.fir.references.FirBackingFieldReferenceImpl
|
import org.jetbrains.kotlin.fir.references.FirBackingFieldReferenceImpl
|
||||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
||||||
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
|
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
@@ -26,6 +27,8 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope
|
|||||||
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
||||||
import org.jetbrains.kotlin.fir.symbols.*
|
import org.jetbrains.kotlin.fir.symbols.*
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.*
|
import org.jetbrains.kotlin.fir.types.impl.*
|
||||||
@@ -386,6 +389,7 @@ open class FirBodyResolveTransformer(
|
|||||||
val types = if (labelName == null) labels.values() else labels[Name.identifier(labelName)]
|
val types = if (labelName == null) labels.values() else labels[Name.identifier(labelName)]
|
||||||
val type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName")
|
val type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName")
|
||||||
qualifiedAccessExpression.resultType = FirResolvedTypeRefImpl(session, null, type, emptyList())
|
qualifiedAccessExpression.resultType = FirResolvedTypeRefImpl(session, null, type, emptyList())
|
||||||
|
return qualifiedAccessExpression.compose()
|
||||||
}
|
}
|
||||||
is FirSuperReference -> {
|
is FirSuperReference -> {
|
||||||
if (callee.superTypeRef is FirResolvedTypeRef) {
|
if (callee.superTypeRef is FirResolvedTypeRef) {
|
||||||
@@ -397,14 +401,23 @@ open class FirBodyResolveTransformer(
|
|||||||
qualifiedAccessExpression.resultType = superTypeRef
|
qualifiedAccessExpression.resultType = superTypeRef
|
||||||
callee.replaceSuperTypeRef(superTypeRef)
|
callee.replaceSuperTypeRef(superTypeRef)
|
||||||
}
|
}
|
||||||
|
return qualifiedAccessExpression.compose()
|
||||||
}
|
}
|
||||||
is FirResolvedCallableReference -> {
|
is FirResolvedCallableReference -> {
|
||||||
if (qualifiedAccessExpression.typeRef !is FirResolvedTypeRef) {
|
if (qualifiedAccessExpression.typeRef !is FirResolvedTypeRef) {
|
||||||
storeTypeFromCallee(qualifiedAccessExpression)
|
storeTypeFromCallee(qualifiedAccessExpression)
|
||||||
}
|
}
|
||||||
|
return qualifiedAccessExpression.compose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return transformCallee(qualifiedAccessExpression).compose()
|
val transformedCallee = transformCallee(qualifiedAccessExpression)
|
||||||
|
// NB: here we can get raw expression because of dropped qualifiers (see transform callee),
|
||||||
|
// so candidate existence must be checked before calling completion
|
||||||
|
return if (transformedCallee is FirQualifiedAccessExpression && transformedCallee.candidate() != null) {
|
||||||
|
completeTypeInference(transformedCallee, data as? FirTypeRef).compose()
|
||||||
|
} else {
|
||||||
|
transformedCallee.compose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transformVariableAssignment(
|
override fun transformVariableAssignment(
|
||||||
@@ -774,10 +787,13 @@ open class FirBodyResolveTransformer(
|
|||||||
}
|
}
|
||||||
candidates.size == 1 -> {
|
candidates.size == 1 -> {
|
||||||
val candidate = candidates.single()
|
val candidate = candidates.single()
|
||||||
if (candidate.symbol is FirBackingFieldSymbol) {
|
val coneSymbol = candidate.symbol
|
||||||
FirBackingFieldReferenceImpl(firSession, psi, candidate.symbol)
|
when {
|
||||||
} else {
|
coneSymbol is FirBackingFieldSymbol -> FirBackingFieldReferenceImpl(firSession, psi, coneSymbol)
|
||||||
FirNamedReferenceWithCandidate(firSession, psi, name, candidate)
|
coneSymbol is FirVariableSymbol &&
|
||||||
|
(coneSymbol !is FirPropertySymbol || coneSymbol.firUnsafe<FirMemberDeclaration>().typeParameters.isEmpty()) ->
|
||||||
|
FirResolvedCallableReferenceImpl(firSession, psi, name, coneSymbol)
|
||||||
|
else -> FirNamedReferenceWithCandidate(firSession, psi, name, candidate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> FirErrorNamedReference(
|
else -> FirErrorNamedReference(
|
||||||
|
|||||||
+28
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
||||||
@@ -33,6 +34,33 @@ class FirCallCompleterTransformer(
|
|||||||
private val typeCalculator: ReturnTypeCalculator
|
private val typeCalculator: ReturnTypeCalculator
|
||||||
) : FirAbstractTreeTransformer() {
|
) : FirAbstractTreeTransformer() {
|
||||||
|
|
||||||
|
override fun transformQualifiedAccessExpression(
|
||||||
|
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
||||||
|
data: Nothing?
|
||||||
|
): CompositeTransformResult<FirStatement> {
|
||||||
|
val calleeReference =
|
||||||
|
qualifiedAccessExpression.calleeReference as? FirNamedReferenceWithCandidate ?: return qualifiedAccessExpression.compose()
|
||||||
|
calleeReference.candidate.substitutor
|
||||||
|
|
||||||
|
val typeRef = typeCalculator.tryCalculateReturnType(calleeReference.coneSymbol.firUnsafe())
|
||||||
|
|
||||||
|
val initialType = calleeReference.candidate.substitutor.substituteOrNull(typeRef.type)
|
||||||
|
val finalType = finalSubstitutor.substituteOrNull(initialType)
|
||||||
|
|
||||||
|
val resultType = typeRef.withReplacedConeType(session, finalType)
|
||||||
|
qualifiedAccessExpression.replaceTypeRef(resultType)
|
||||||
|
|
||||||
|
return qualifiedAccessExpression.transformCalleeReference(
|
||||||
|
StoreCalleeReference,
|
||||||
|
FirResolvedCallableReferenceImpl(
|
||||||
|
calleeReference.session,
|
||||||
|
calleeReference.psi,
|
||||||
|
calleeReference.name,
|
||||||
|
calleeReference.coneSymbol
|
||||||
|
)
|
||||||
|
).compose()
|
||||||
|
}
|
||||||
|
|
||||||
override fun transformVariableAssignment(
|
override fun transformVariableAssignment(
|
||||||
variableAssignment: FirVariableAssignment,
|
variableAssignment: FirVariableAssignment,
|
||||||
data: Nothing?
|
data: Nothing?
|
||||||
|
|||||||
@@ -24,6 +24,5 @@ FILE fqName:<root> fileName:/classReference.kt
|
|||||||
GET_OBJECT 'CLASS CLASS name:A modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
|
GET_OBJECT 'CLASS CLASS name:A modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
|
||||||
GET_CLASS type=kotlin.reflect.KClass<<root>.A>
|
GET_CLASS type=kotlin.reflect.KClass<<root>.A>
|
||||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.A' type=<root>.A origin=null
|
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.A' type=<root>.A origin=null
|
||||||
ERROR_CALL 'No getter found for R|kotlin/jvm/java|' type=java.lang.Class<T of <uninitialized parent>>
|
ERROR_CALL 'No getter found for R|kotlin/jvm/java|' type=java.lang.Class<<root>.A>
|
||||||
ERROR_CALL 'No getter found for R|kotlin/jvm/java|' type=java.lang.Class<T of <uninitialized parent>>
|
ERROR_CALL 'No getter found for R|kotlin/jvm/java|' type=java.lang.Class<<root>.A>
|
||||||
|
|
||||||
|
|||||||
@@ -161,12 +161,11 @@ FILE fqName:<root> fileName:/genericPropertyRef.kt
|
|||||||
SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:value2 type:kotlin.Any? visibility:public [static] ' type=kotlin.Any? origin=null
|
SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:value2 type:kotlin.Any? visibility:public [static] ' type=kotlin.Any? origin=null
|
||||||
value: GET_VAR 'value: T of <uninitialized parent> declared in <root>.<set-bar>' type=T of <uninitialized parent> origin=null
|
value: GET_VAR 'value: T of <uninitialized parent> declared in <root>.<set-bar>' type=T of <uninitialized parent> origin=null
|
||||||
PROPERTY name:barRef visibility:public modality:FINAL [val]
|
PROPERTY name:barRef visibility:public modality:FINAL [val]
|
||||||
FIELD PROPERTY_BACKING_FIELD name:barRef type:T of <uninitialized parent> visibility:public [final,static]
|
FIELD PROPERTY_BACKING_FIELD name:barRef type:kotlin.String.Companion visibility:public [final,static]
|
||||||
EXPRESSION_BODY
|
EXPRESSION_BODY
|
||||||
CALL 'public final fun <get-bar> (): T of <uninitialized parent> declared in <root>' type=T of <uninitialized parent> origin=null
|
CALL 'public final fun <get-bar> (): T of <uninitialized parent> declared in <root>' type=kotlin.String.Companion origin=null
|
||||||
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-barRef> visibility:public modality:FINAL <> () returnType:T of <uninitialized parent>
|
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-barRef> visibility:public modality:FINAL <> () returnType:kotlin.String.Companion
|
||||||
correspondingProperty: PROPERTY name:barRef visibility:public modality:FINAL [val]
|
correspondingProperty: PROPERTY name:barRef visibility:public modality:FINAL [val]
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
RETURN type=kotlin.Nothing from='public final fun <get-barRef> (): T of <uninitialized parent> declared in <root>'
|
RETURN type=kotlin.Nothing from='public final fun <get-barRef> (): kotlin.String.Companion declared in <root>'
|
||||||
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:barRef type:T of <uninitialized parent> visibility:public [final,static] ' type=T of <uninitialized parent> origin=null
|
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:barRef type:kotlin.String.Companion visibility:public [final,static] ' type=kotlin.String.Companion origin=null
|
||||||
|
|
||||||
|
|||||||
@@ -22,5 +22,4 @@ FILE fqName:<root> fileName:/objectClassReference.kt
|
|||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
GET_CLASS type=kotlin.reflect.KClass<<root>.A>
|
GET_CLASS type=kotlin.reflect.KClass<<root>.A>
|
||||||
GET_OBJECT 'CLASS OBJECT name:A modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.A
|
GET_OBJECT 'CLASS OBJECT name:A modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.A
|
||||||
ERROR_CALL 'No getter found for R|kotlin/jvm/java|' type=java.lang.Class<T of <uninitialized parent>>
|
ERROR_CALL 'No getter found for R|kotlin/jvm/java|' type=java.lang.Class<<root>.A>
|
||||||
|
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ FILE fqName:<root> fileName:/useImportedMember.kt
|
|||||||
BRANCH
|
BRANCH
|
||||||
if: CALL 'public final fun not (): kotlin.Boolean declared in kotlin.Boolean' type=kotlin.Boolean origin=EXCLEQ
|
if: CALL 'public final fun not (): kotlin.Boolean declared in kotlin.Boolean' type=kotlin.Boolean origin=EXCLEQ
|
||||||
$this: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ
|
$this: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ
|
||||||
arg0: CALL 'public final fun <get-g2> (): T of <uninitialized parent> declared in <root>.C' type=T of <uninitialized parent> origin=null
|
arg0: CALL 'public final fun <get-g2> (): T of <uninitialized parent> declared in <root>.C' type=kotlin.String origin=null
|
||||||
$this: CONST String type=kotlin.String value="8"
|
$this: CONST String type=kotlin.String value="8"
|
||||||
arg1: CONST String type=kotlin.String value="8"
|
arg1: CONST String type=kotlin.String value="8"
|
||||||
then: RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in <root>'
|
then: RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in <root>'
|
||||||
@@ -225,7 +225,7 @@ FILE fqName:<root> fileName:/useImportedMember.kt
|
|||||||
BRANCH
|
BRANCH
|
||||||
if: CALL 'public final fun not (): kotlin.Boolean declared in kotlin.Boolean' type=kotlin.Boolean origin=EXCLEQ
|
if: CALL 'public final fun not (): kotlin.Boolean declared in kotlin.Boolean' type=kotlin.Boolean origin=EXCLEQ
|
||||||
$this: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ
|
$this: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ
|
||||||
arg0: CALL 'public final fun <get-fromClass> (): T of <uninitialized parent> declared in <root>.BaseClass' type=T of <uninitialized parent> origin=null
|
arg0: CALL 'public final fun <get-fromClass> (): T of <uninitialized parent> declared in <root>.BaseClass' type=kotlin.String origin=null
|
||||||
$this: CONST String type=kotlin.String value="10"
|
$this: CONST String type=kotlin.String value="10"
|
||||||
arg1: CONST String type=kotlin.String value="10"
|
arg1: CONST String type=kotlin.String value="10"
|
||||||
then: RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in <root>'
|
then: RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in <root>'
|
||||||
|
|||||||
Reference in New Issue
Block a user