FIR resolve: perform inference completion for property access

This commit is contained in:
Simon Ogorodnik
2019-06-25 16:03:12 +03:00
committed by Mikhail Glukhikh
parent 99680a2ad7
commit 1222449dc8
6 changed files with 59 additions and 18 deletions
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl
import org.jetbrains.kotlin.fir.references.FirBackingFieldReferenceImpl
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.resolve.*
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.symbols.*
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.types.*
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 type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName")
qualifiedAccessExpression.resultType = FirResolvedTypeRefImpl(session, null, type, emptyList())
return qualifiedAccessExpression.compose()
}
is FirSuperReference -> {
if (callee.superTypeRef is FirResolvedTypeRef) {
@@ -397,14 +401,23 @@ open class FirBodyResolveTransformer(
qualifiedAccessExpression.resultType = superTypeRef
callee.replaceSuperTypeRef(superTypeRef)
}
return qualifiedAccessExpression.compose()
}
is FirResolvedCallableReference -> {
if (qualifiedAccessExpression.typeRef !is FirResolvedTypeRef) {
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(
@@ -774,10 +787,13 @@ open class FirBodyResolveTransformer(
}
candidates.size == 1 -> {
val candidate = candidates.single()
if (candidate.symbol is FirBackingFieldSymbol) {
FirBackingFieldReferenceImpl(firSession, psi, candidate.symbol)
} else {
FirNamedReferenceWithCandidate(firSession, psi, name, candidate)
val coneSymbol = candidate.symbol
when {
coneSymbol is FirBackingFieldSymbol -> FirBackingFieldReferenceImpl(firSession, psi, coneSymbol)
coneSymbol is FirVariableSymbol &&
(coneSymbol !is FirPropertySymbol || coneSymbol.firUnsafe<FirMemberDeclaration>().typeParameters.isEmpty()) ->
FirResolvedCallableReferenceImpl(firSession, psi, name, coneSymbol)
else -> FirNamedReferenceWithCandidate(firSession, psi, name, candidate)
}
}
else -> FirErrorNamedReference(
@@ -10,6 +10,7 @@ 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.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
@@ -33,6 +34,33 @@ class FirCallCompleterTransformer(
private val typeCalculator: ReturnTypeCalculator
) : 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(
variableAssignment: FirVariableAssignment,
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_CLASS type=kotlin.reflect.KClass<<root>.A>
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<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<<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
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]
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
CALL 'public final fun <get-bar> (): T of <uninitialized parent> declared in <root>' type=T of <uninitialized parent> origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-barRef> visibility:public modality:FINAL <> () returnType:T of <uninitialized parent>
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:kotlin.String.Companion
correspondingProperty: PROPERTY name:barRef visibility:public modality:FINAL [val]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-barRef> (): T of <uninitialized parent> 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
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: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
GET_CLASS type=kotlin.reflect.KClass<<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
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
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"
arg1: CONST String type=kotlin.String value="8"
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
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
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"
arg1: CONST String type=kotlin.String value="10"
then: RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in <root>'