From 376d3385d0f8ace0b4dacb27ee8b9af67ba4147c Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 17 Jul 2020 19:13:57 +0300 Subject: [PATCH] FIR: Handle super-receiver case in a special way Before this change, it was resolved independently of containg call But in fact, the type of `super` depends on the name of the callee (see KT-39599 and KT-39070) --- .../jetbrains/kotlin/fir/FirCallResolver.kt | 18 +++- .../FirExpressionsResolveTransformer.kt | 88 ++++++++++--------- 2 files changed, 63 insertions(+), 43 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 98980e574f5..708ffe48401 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -66,7 +66,7 @@ class FirCallResolver( qualifiedResolver.reset() @Suppress("NAME_SHADOWING") val functionCall = if (needTransformArguments) { - functionCall.transformExplicitReceiver(transformer, ResolutionMode.ContextIndependent) + functionCall.transformExplicitReceiver() .also { dataFlowAnalyzer.enterQualifiedAccessExpression() functionCall.argumentList.transformArguments(transformer, ResolutionMode.ContextDependent) @@ -108,6 +108,20 @@ class FirCallResolver( return resultFunctionCall } + private inline fun Q.transformExplicitReceiver(): Q { + val explicitReceiver = + explicitReceiver as? FirQualifiedAccessExpression + ?: return transformExplicitReceiver(transformer, ResolutionMode.ContextIndependent) as Q + + val callee = + explicitReceiver.calleeReference as? FirSuperReference + ?: return transformExplicitReceiver(transformer, ResolutionMode.ContextIndependent) as Q + + transformer.transformSuperReceiver(callee, explicitReceiver) + + return this + } + private data class ResolutionResult( val info: CallInfo, val applicability: CandidateApplicability, val candidates: Collection, ) @@ -161,7 +175,7 @@ class FirCallResolver( qualifiedResolver.initProcessingQualifiedAccess(callee) @Suppress("NAME_SHADOWING") - val qualifiedAccess = qualifiedAccess.transformExplicitReceiver(transformer, ResolutionMode.ContextIndependent) + val qualifiedAccess = qualifiedAccess.transformExplicitReceiver() qualifiedResolver.replacedQualifier(qualifiedAccess)?.let { resolvedQualifierPart -> return resolvedQualifierPart } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index bec3a2e763e..db075cf81c8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.fir.references.builder.buildSimpleNamedReference import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.* -import org.jetbrains.kotlin.fir.resolve.calls.candidate import org.jetbrains.kotlin.fir.resolve.diagnostics.* import org.jetbrains.kotlin.fir.resolve.inference.FirStubInferenceSession import org.jetbrains.kotlin.fir.resolve.transformers.InvocationKindTransformer @@ -85,46 +84,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform qualifiedAccessExpression } is FirSuperReference -> { - val labelName = callee.labelName - val implicitReceiver = - if (labelName != null) implicitReceiverStack[labelName] as? ImplicitDispatchReceiverValue - else implicitReceiverStack.lastDispatchReceiver() - implicitReceiver?.receiverExpression?.let { - qualifiedAccessExpression.transformDispatchReceiver(StoreReceiver, it) - } - when (val superTypeRef = callee.superTypeRef) { - is FirResolvedTypeRef -> { - qualifiedAccessExpression.resultType = superTypeRef - } - !is FirImplicitTypeRef -> { - callee.transformChildren(transformer, ResolutionMode.ContextIndependent) - qualifiedAccessExpression.resultType = callee.superTypeRef - } - else -> { - val superTypeRefs = implicitReceiver?.boundSymbol?.phasedFir?.superTypeRefs - val resultType = when { - superTypeRefs?.isNotEmpty() != true -> { - buildErrorTypeRef { - source = qualifiedAccessExpression.source - // NB: NOT_A_SUPERTYPE is reported by a separate checker - diagnostic = ConeStubDiagnostic(ConeSimpleDiagnostic("No super type", DiagnosticKind.Other)) - } - } - superTypeRefs.size == 1 -> { - superTypeRefs.single() - } - else -> { - buildComposedSuperTypeRef { - source = qualifiedAccessExpression.source - superTypeRefs.mapTo(this.superTypeRefs) { it as FirResolvedTypeRef } - } - } - } - qualifiedAccessExpression.resultType = resultType - callee.replaceSuperTypeRef(resultType) - } - } - qualifiedAccessExpression + transformSuperReceiver(callee, qualifiedAccessExpression) } is FirDelegateFieldReference -> { val delegateFieldSymbol = callee.resolvedSymbol @@ -164,6 +124,52 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform return result.compose() } + fun transformSuperReceiver( + superReference: FirSuperReference, + superReferenceContainer: FirQualifiedAccessExpression + ): FirQualifiedAccessExpression { + val labelName = superReference.labelName + val implicitReceiver = + if (labelName != null) implicitReceiverStack[labelName] as? ImplicitDispatchReceiverValue + else implicitReceiverStack.lastDispatchReceiver() + implicitReceiver?.receiverExpression?.let { + superReferenceContainer.transformDispatchReceiver(StoreReceiver, it) + } + when (val superTypeRef = superReference.superTypeRef) { + is FirResolvedTypeRef -> { + superReferenceContainer.resultType = superTypeRef + } + !is FirImplicitTypeRef -> { + superReference.transformChildren(transformer, ResolutionMode.ContextIndependent) + superReferenceContainer.resultType = superReference.superTypeRef + } + else -> { + val superTypeRefs = implicitReceiver?.boundSymbol?.phasedFir?.superTypeRefs + val resultType = when { + superTypeRefs?.isNotEmpty() != true -> { + buildErrorTypeRef { + source = superReferenceContainer.source + // NB: NOT_A_SUPERTYPE is reported by a separate checker + diagnostic = ConeStubDiagnostic(ConeSimpleDiagnostic("No super type", DiagnosticKind.Other)) + } + } + superTypeRefs.size == 1 -> { + superTypeRefs.single() + } + else -> { + buildComposedSuperTypeRef { + source = superReferenceContainer.source + superTypeRefs.mapTo(this.superTypeRefs) { it as FirResolvedTypeRef } + } + } + } + superReferenceContainer.resultType = resultType + superReference.replaceSuperTypeRef(resultType) + } + } + return superReferenceContainer + } + protected open fun FirQualifiedAccessExpression.isAcceptableResolvedQualifiedAccess(): Boolean { return true }