From 1222449dc8311480e405b6197fec8a8b169dc545 Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Tue, 25 Jun 2019 16:03:12 +0300 Subject: [PATCH] FIR resolve: perform inference completion for property access --- .../transformers/FirBodyResolveTransformer.kt | 26 +++++++++++++---- .../FirCallCompleterTransformer.kt | 28 +++++++++++++++++++ .../irText/expressions/classReference.fir.txt | 5 ++-- .../expressions/genericPropertyRef.fir.txt | 11 ++++---- .../expressions/objectClassReference.fir.txt | 3 +- .../expressions/useImportedMember.fir.txt | 4 +-- 6 files changed, 59 insertions(+), 18 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt index 508536669d4..747764cd3ed 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt @@ -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().typeParameters.isEmpty()) -> + FirResolvedCallableReferenceImpl(firSession, psi, name, coneSymbol) + else -> FirNamedReferenceWithCandidate(firSession, psi, name, candidate) } } else -> FirErrorNamedReference( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompleterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompleterTransformer.kt index c47badd88bc..251849e23d5 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompleterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompleterTransformer.kt @@ -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 { + 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? diff --git a/compiler/testData/ir/irText/expressions/classReference.fir.txt b/compiler/testData/ir/irText/expressions/classReference.fir.txt index b81c6721e7f..2a1ee4da480 100644 --- a/compiler/testData/ir/irText/expressions/classReference.fir.txt +++ b/compiler/testData/ir/irText/expressions/classReference.fir.txt @@ -24,6 +24,5 @@ FILE fqName: 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<.A> CONSTRUCTOR_CALL 'public constructor () [primary] declared in .A' type=.A origin=null - ERROR_CALL 'No getter found for R|kotlin/jvm/java|' type=java.lang.Class> - ERROR_CALL 'No getter found for R|kotlin/jvm/java|' type=java.lang.Class> - + ERROR_CALL 'No getter found for R|kotlin/jvm/java|' type=java.lang.Class<.A> + ERROR_CALL 'No getter found for R|kotlin/jvm/java|' type=java.lang.Class<.A> diff --git a/compiler/testData/ir/irText/expressions/genericPropertyRef.fir.txt b/compiler/testData/ir/irText/expressions/genericPropertyRef.fir.txt index 5ee65610981..5a8099aef50 100644 --- a/compiler/testData/ir/irText/expressions/genericPropertyRef.fir.txt +++ b/compiler/testData/ir/irText/expressions/genericPropertyRef.fir.txt @@ -161,12 +161,11 @@ FILE fqName: 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 declared in .' type=T of origin=null PROPERTY name:barRef visibility:public modality:FINAL [val] - FIELD PROPERTY_BACKING_FIELD name:barRef type:T of visibility:public [final,static] + FIELD PROPERTY_BACKING_FIELD name:barRef type:kotlin.String.Companion visibility:public [final,static] EXPRESSION_BODY - CALL 'public final fun (): T of declared in ' type=T of origin=null - FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> () returnType:T of + CALL 'public final fun (): T of declared in ' type=kotlin.String.Companion origin=null + FUN DEFAULT_PROPERTY_ACCESSOR name: 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 (): T of declared in ' - GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:barRef type:T of visibility:public [final,static] ' type=T of origin=null - + RETURN type=kotlin.Nothing from='public final fun (): kotlin.String.Companion declared in ' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:barRef type:kotlin.String.Companion visibility:public [final,static] ' type=kotlin.String.Companion origin=null diff --git a/compiler/testData/ir/irText/expressions/objectClassReference.fir.txt b/compiler/testData/ir/irText/expressions/objectClassReference.fir.txt index 554975dd7c7..4b513538cc2 100644 --- a/compiler/testData/ir/irText/expressions/objectClassReference.fir.txt +++ b/compiler/testData/ir/irText/expressions/objectClassReference.fir.txt @@ -22,5 +22,4 @@ FILE fqName: fileName:/objectClassReference.kt BLOCK_BODY GET_CLASS type=kotlin.reflect.KClass<.A> GET_OBJECT 'CLASS OBJECT name:A modality:FINAL visibility:public superTypes:[kotlin.Any]' type=.A - ERROR_CALL 'No getter found for R|kotlin/jvm/java|' type=java.lang.Class> - + ERROR_CALL 'No getter found for R|kotlin/jvm/java|' type=java.lang.Class<.A> diff --git a/compiler/testData/ir/irText/expressions/useImportedMember.fir.txt b/compiler/testData/ir/irText/expressions/useImportedMember.fir.txt index e416e0b36bd..b6beeac7ee3 100644 --- a/compiler/testData/ir/irText/expressions/useImportedMember.fir.txt +++ b/compiler/testData/ir/irText/expressions/useImportedMember.fir.txt @@ -208,7 +208,7 @@ FILE fqName: 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 (): T of declared in .C' type=T of origin=null + arg0: CALL 'public final fun (): T of declared in .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 ' @@ -225,7 +225,7 @@ FILE fqName: 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 (): T of declared in .BaseClass' type=T of origin=null + arg0: CALL 'public final fun (): T of declared in .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 '