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)
This commit is contained in:
Denis Zharkov
2020-07-17 19:13:57 +03:00
parent 628b8b56b7
commit 376d3385d0
2 changed files with 63 additions and 43 deletions
@@ -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 <reified Q : FirQualifiedAccess> 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<Candidate>,
)
@@ -161,7 +175,7 @@ class FirCallResolver(
qualifiedResolver.initProcessingQualifiedAccess(callee)
@Suppress("NAME_SHADOWING")
val qualifiedAccess = qualifiedAccess.transformExplicitReceiver(transformer, ResolutionMode.ContextIndependent)
val qualifiedAccess = qualifiedAccess.transformExplicitReceiver<FirQualifiedAccess>()
qualifiedResolver.replacedQualifier(qualifiedAccess)?.let { resolvedQualifierPart ->
return resolvedQualifierPart
}
@@ -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
}