Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.fir.resolve.calls.ResolutionStages.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.inference.*
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
import org.jetbrains.kotlin.types.AbstractNullabilityChecker
abstract class ResolutionStage {
abstract suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext)
}
abstract class CheckerStage : ResolutionStage()
internal object CheckExplicitReceiverConsistency : ResolutionStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val receiverKind = candidate.explicitReceiverKind
val explicitReceiver = callInfo.explicitReceiver
// TODO: add invoke cases
when (receiverKind) {
NO_EXPLICIT_RECEIVER -> {
if (explicitReceiver != null && explicitReceiver !is FirResolvedQualifier && !explicitReceiver.isSuperReferenceExpression()) {
return sink.yieldDiagnostic(InapplicableWrongReceiver)
}
}
EXTENSION_RECEIVER, DISPATCH_RECEIVER -> {
if (explicitReceiver == null) {
return sink.yieldDiagnostic(InapplicableWrongReceiver)
}
}
BOTH_RECEIVERS -> {
if (explicitReceiver == null) {
return sink.yieldDiagnostic(InapplicableWrongReceiver)
}
// Here we should also check additional invoke receiver
}
}
}
}
object CheckExtensionReceiver : ResolutionStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val expectedReceiverType = candidate.getReceiverType(context) ?: return
val argumentExtensionReceiverValue = candidate.extensionReceiverValue ?: return
val expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type)
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(
argumentType = argumentExtensionReceiverValue.type,
expectedType = expectedType,
session = context.session
)
candidate.resolvePlainArgumentType(
candidate.csBuilder,
argumentType = argumentType,
expectedType = expectedType,
sink = sink,
context = context,
isReceiver = true,
isDispatch = false,
)
sink.yieldIfNeed()
}
private fun Candidate.getReceiverType(context: ResolutionContext): ConeKotlinType? {
val callableSymbol = symbol as? FirCallableSymbol<*> ?: return null
val callable = callableSymbol.fir
val receiverType = callable.receiverTypeRef?.coneType
if (receiverType != null) return receiverType
val returnTypeRef = callable.returnTypeRef as? FirResolvedTypeRef ?: return null
if (!returnTypeRef.type.isExtensionFunctionType(context.session)) return null
return (returnTypeRef.type.typeArguments.firstOrNull() as? ConeKotlinTypeProjection)?.type
}
}
object CheckDispatchReceiver : ResolutionStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val explicitReceiverExpression = callInfo.explicitReceiver
if (explicitReceiverExpression.isSuperCall()) {
val status = candidate.symbol.fir as? FirMemberDeclaration
if (status?.modality == Modality.ABSTRACT) {
sink.reportDiagnostic(ResolvedWithLowPriority)
}
}
val dispatchReceiverValueType = candidate.dispatchReceiverValue?.type ?: return
if (!AbstractNullabilityChecker.isSubtypeOfAny(context.session.typeContext, dispatchReceiverValueType)) {
sink.yieldDiagnostic(InapplicableWrongReceiver)
}
}
}
private fun FirExpression?.isSuperCall(): Boolean {
if (this !is FirQualifiedAccessExpression) return false
return calleeReference is FirSuperReference
}
private fun FirExpression.isSuperReferenceExpression(): Boolean {
return if (this is FirQualifiedAccessExpression) {
val calleeReference = calleeReference
calleeReference is FirSuperReference
} else false
}
internal object MapArguments : ResolutionStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val symbol = candidate.symbol as? FirFunctionSymbol<*> ?: return sink.reportDiagnostic(HiddenCandidate)
val function = symbol.fir
val mapping = context.bodyResolveComponents.mapArguments(callInfo.arguments, function, candidate.originScope)
candidate.argumentMapping = mapping.toArgumentToParameterMapping()
candidate.numDefaults = mapping.numDefaults()
mapping.diagnostics.forEach(sink::reportDiagnostic)
sink.yieldIfNeed()
}
}
internal object CheckArguments : CheckerStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val argumentMapping =
candidate.argumentMapping ?: error("Argument should be already mapped while checking arguments!")
for (argument in callInfo.arguments) {
val parameter = argumentMapping[argument]
candidate.resolveArgument(
argument,
parameter,
isReceiver = false,
sink = sink,
context = context
)
if (candidate.system.hasContradiction) {
sink.yieldDiagnostic(InapplicableCandidate)
}
sink.yieldIfNeed()
}
}
}
internal object EagerResolveOfCallableReferences : CheckerStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
if (candidate.postponedAtoms.isEmpty()) return
for (atom in candidate.postponedAtoms) {
if (atom is ResolvedCallableReferenceAtom) {
if (!context.bodyResolveComponents.callResolver.resolveCallableReference(candidate.csBuilder, atom)) {
sink.yieldDiagnostic(InapplicableCandidate)
}
}
}
}
}
internal object DiscriminateSynthetics : CheckerStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
if (candidate.symbol is SyntheticSymbol) {
sink.reportDiagnostic(ResolvedWithLowPriority)
}
}
}
internal object CheckVisibility : CheckerStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val visibilityChecker = callInfo.session.visibilityChecker
val symbol = candidate.symbol
val declaration = symbol.fir
if (declaration is FirMemberDeclaration) {
if (!checkVisibility(declaration, sink, candidate, visibilityChecker)) {
return
}
}
if (declaration is FirConstructor) {
// TODO: Should be some other form
val classSymbol = declaration.returnTypeRef.coneTypeUnsafe().lookupTag.toSymbol(declaration.session)
if (classSymbol is FirRegularClassSymbol) {
if (classSymbol.fir.classKind.isSingleton) {
sink.yieldDiagnostic(HiddenCandidate)
}
checkVisibility(classSymbol.fir, sink, candidate, visibilityChecker)
}
}
}
private suspend fun checkVisibility(
declaration: T,
sink: CheckerSink,
candidate: Candidate,
visibilityChecker: FirVisibilityChecker
): Boolean where T : FirMemberDeclaration, T : FirSymbolOwner<*> {
if (!visibilityChecker.isVisible(declaration, candidate)) {
sink.yieldDiagnostic(HiddenCandidate)
return false
}
return true
}
}
internal object CheckLowPriorityInOverloadResolution : CheckerStage() {
private val LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_CLASS_ID: ClassId =
ClassId(FqName("kotlin.internal"), Name.identifier("LowPriorityInOverloadResolution"))
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val annotations = when (val fir = candidate.symbol.fir) {
is FirSimpleFunction -> fir.annotations
is FirProperty -> fir.annotations
else -> return
}
val hasLowPriorityAnnotation = annotations.any {
val lookupTag = it.annotationTypeRef.coneTypeSafe()?.lookupTag ?: return@any false
lookupTag.classId == LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_CLASS_ID
}
if (hasLowPriorityAnnotation) {
sink.reportDiagnostic(ResolvedWithLowPriority)
}
}
}
internal object PostponedVariablesInitializerResolutionStage : ResolutionStage() {
private val BUILDER_INFERENCE_CLASS_ID: ClassId = ClassId.fromString("kotlin/BuilderInference")
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val argumentMapping = candidate.argumentMapping ?: return
// TODO: convert type argument mapping to map [FirTypeParameterSymbol, FirTypedProjection?]
if (candidate.typeArgumentMapping is TypeArgumentMapping.Mapped) return
for (parameter in argumentMapping.values) {
if (!parameter.hasBuilderInferenceMarker()) continue
val type = parameter.returnTypeRef.coneType
val receiverType = type.receiverType(callInfo.session) ?: continue
for (freshVariable in candidate.freshVariables) {
if (candidate.csBuilder.isPostponedTypeVariable(freshVariable)) continue
if (freshVariable !is TypeParameterBasedTypeVariable) continue
val typeParameterSymbol = freshVariable.typeParameterSymbol
val typeHasVariable = receiverType.contains {
(it as? ConeTypeParameterType)?.lookupTag?.typeParameterSymbol == typeParameterSymbol
}
if (typeHasVariable) {
candidate.csBuilder.markPostponedVariable(freshVariable)
}
}
}
}
private fun FirValueParameter.hasBuilderInferenceMarker(): Boolean {
return this.hasAnnotation(BUILDER_INFERENCE_CLASS_ID)
}
}