FIR: Add preliminary support for context receivers in resolution

This commit is contained in:
Denis.Zharkov
2022-03-09 14:36:20 +03:00
committed by teamcity
parent 588dd23fd9
commit ef84dddc88
39 changed files with 688 additions and 133 deletions
@@ -335,14 +335,14 @@ internal class KtFirCallResolver(
// Implicit invoke (e.g., `x()`) will have a different callee symbol (e.g., `x`) than the candidate (e.g., `invoke`). // Implicit invoke (e.g., `x()`) will have a different callee symbol (e.g., `x`) than the candidate (e.g., `invoke`).
createKtPartiallyAppliedSymbolForImplicitInvoke( createKtPartiallyAppliedSymbolForImplicitInvoke(
candidate.dispatchReceiverValue?.receiverExpression ?: FirNoReceiverExpression, candidate.dispatchReceiverValue?.receiverExpression ?: FirNoReceiverExpression,
candidate.extensionReceiverValue?.receiverExpression ?: FirNoReceiverExpression, candidate.chosenExtensionReceiverValue?.receiverExpression ?: FirNoReceiverExpression,
candidate.explicitReceiverKind candidate.explicitReceiverKind
) )
} else { } else {
KtPartiallyAppliedSymbol( KtPartiallyAppliedSymbol(
unsubstitutedKtSignature.substitute(substitutor), unsubstitutedKtSignature.substitute(substitutor),
candidate.dispatchReceiverValue?.receiverExpression?.toKtReceiverValue(), candidate.dispatchReceiverValue?.receiverExpression?.toKtReceiverValue(),
candidate.extensionReceiverValue?.receiverExpression?.toKtReceiverValue(), candidate.chosenExtensionReceiverValue?.receiverExpression?.toKtReceiverValue(),
) )
} }
} else if (fir is FirQualifiedAccess) { } else if (fir is FirQualifiedAccess) {
@@ -1608,6 +1608,32 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, token,
) )
} }
add(FirErrors.NO_CONTEXT_RECEIVER) { firDiagnostic ->
NoContextReceiverImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER) { firDiagnostic ->
MultipleArgumentsApplicableForContextReceiverImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER) { firDiagnostic ->
AmbiguousCallWithImplicitContextReceiverImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL) { firDiagnostic ->
UnsupportedContextualDeclarationCallImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.RECURSION_IN_IMPLICIT_TYPES) { firDiagnostic -> add(FirErrors.RECURSION_IN_IMPLICIT_TYPES) { firDiagnostic ->
RecursionInImplicitTypesImpl( RecursionInImplicitTypesImpl(
firDiagnostic as KtPsiDiagnostic, firDiagnostic as KtPsiDiagnostic,
@@ -1145,6 +1145,24 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val candidates: List<KtSymbol> abstract val candidates: List<KtSymbol>
} }
abstract class NoContextReceiver : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = NoContextReceiver::class
abstract val contextReceiverRepresentation: KtType
}
abstract class MultipleArgumentsApplicableForContextReceiver : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = MultipleArgumentsApplicableForContextReceiver::class
abstract val contextReceiverRepresentation: KtType
}
abstract class AmbiguousCallWithImplicitContextReceiver : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = AmbiguousCallWithImplicitContextReceiver::class
}
abstract class UnsupportedContextualDeclarationCall : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = UnsupportedContextualDeclarationCall::class
}
abstract class RecursionInImplicitTypes : KtFirDiagnostic<PsiElement>() { abstract class RecursionInImplicitTypes : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = RecursionInImplicitTypes::class override val diagnosticClass get() = RecursionInImplicitTypes::class
} }
@@ -1373,6 +1373,28 @@ internal class NextAmbiguityImpl(
override val token: ValidityToken, override val token: ValidityToken,
) : KtFirDiagnostic.NextAmbiguity(), KtAbstractFirDiagnostic<PsiElement> ) : KtFirDiagnostic.NextAmbiguity(), KtAbstractFirDiagnostic<PsiElement>
internal class NoContextReceiverImpl(
override val contextReceiverRepresentation: KtType,
override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.NoContextReceiver(), KtAbstractFirDiagnostic<KtElement>
internal class MultipleArgumentsApplicableForContextReceiverImpl(
override val contextReceiverRepresentation: KtType,
override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.MultipleArgumentsApplicableForContextReceiver(), KtAbstractFirDiagnostic<KtElement>
internal class AmbiguousCallWithImplicitContextReceiverImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.AmbiguousCallWithImplicitContextReceiver(), KtAbstractFirDiagnostic<KtElement>
internal class UnsupportedContextualDeclarationCallImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.UnsupportedContextualDeclarationCall(), KtAbstractFirDiagnostic<KtElement>
internal class RecursionInImplicitTypesImpl( internal class RecursionInImplicitTypesImpl(
override val firDiagnostic: KtPsiDiagnostic, override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken, override val token: ValidityToken,
@@ -53,11 +53,12 @@ class SingleCandidateResolver(
resolutionParameters.callableSymbol, resolutionParameters.callableSymbol,
explicitReceiverKind = explicitReceiverKind, explicitReceiverKind = explicitReceiverKind,
dispatchReceiverValue = dispatchReceiverValue, dispatchReceiverValue = dispatchReceiverValue,
extensionReceiverValue = givenExtensionReceiverOptions = listOfNotNull(
if (explicitReceiverKind.isExtensionReceiver) if (explicitReceiverKind.isExtensionReceiver)
callInfo.explicitReceiver?.let { ExpressionReceiverValue(it) } callInfo.explicitReceiver?.let { ExpressionReceiverValue(it) }
else else
implicitExtensionReceiverValue, implicitExtensionReceiverValue
),
scope = null, scope = null,
) )
@@ -531,6 +531,17 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
} }
} }
val CONTEXT_RECEIVERS_RESOLUTION by object : DiagnosticGroup("Context receivers resolution") {
val NO_CONTEXT_RECEIVER by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<ConeKotlinType>("contextReceiverRepresentation")
}
val MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<ConeKotlinType>("contextReceiverRepresentation")
}
val AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED)
val UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL by error<KtElement>()
}
val TYPES_AND_TYPE_PARAMETERS by object : DiagnosticGroup("Types & type parameters") { val TYPES_AND_TYPE_PARAMETERS by object : DiagnosticGroup("Types & type parameters") {
val RECURSION_IN_IMPLICIT_TYPES by error<PsiElement>() val RECURSION_IN_IMPLICIT_TYPES by error<PsiElement>()
val INFERENCE_ERROR by error<PsiElement>() val INFERENCE_ERROR by error<PsiElement>()
@@ -355,6 +355,12 @@ object FirErrors {
val HAS_NEXT_FUNCTION_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val HAS_NEXT_FUNCTION_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val NEXT_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val NEXT_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
// Context receivers resolution
val NO_CONTEXT_RECEIVER by error1<KtElement, ConeKotlinType>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER by error1<KtElement, ConeKotlinType>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER by error0<KtElement>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL by error0<KtElement>()
// Types & type parameters // Types & type parameters
val RECURSION_IN_IMPLICIT_TYPES by error0<PsiElement>() val RECURSION_IN_IMPLICIT_TYPES by error0<PsiElement>()
val INFERENCE_ERROR by error0<PsiElement>() val INFERENCE_ERROR by error0<PsiElement>()
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPE_ALIAS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_WITHOUT_EXPECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_WITHOUT_EXPECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_ACTUALS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_ACTUALS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_ANONYMOUS_TYPE_INFERRED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_ANONYMOUS_TYPE_INFERRED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_EXPECTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_EXPECTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_SUPER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_SUPER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ARGUMENT_KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ARGUMENT_KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR
@@ -294,6 +295,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISPLACED_TYPE_PA
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_STDLIB_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_STDLIB_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_VARARG_PARAMETERS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_VARARG_PARAMETERS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT
@@ -336,6 +338,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_YET_SUPPORTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_FOR_EXPECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_FOR_EXPECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_COMPANION_OBJECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_COMPANION_OBJECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_CONTEXT_RECEIVER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ELSE_IN_WHEN import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ELSE_IN_WHEN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_EXPLICIT_RETURN_TYPE_IN_API_MODE_WARNING
@@ -517,6 +520,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_IMPLICIT_I
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_INFIX_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_INFIX_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_OPERATOR_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_OPERATOR_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_FEATURE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_FEATURE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNUSED_VARIABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNUSED_VARIABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE
@@ -974,6 +978,21 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(NEXT_AMBIGUITY, "Method ''next()'' is ambiguous for this expression: {0}", SYMBOLS) map.put(NEXT_AMBIGUITY, "Method ''next()'' is ambiguous for this expression: {0}", SYMBOLS)
map.put(NEXT_NONE_APPLICABLE, "None of the ''next()'' functions is applicable for ''iterator()'' of type ''{0}''", SYMBOLS) map.put(NEXT_NONE_APPLICABLE, "None of the ''next()'' functions is applicable for ''iterator()'' of type ''{0}''", SYMBOLS)
map.put(NO_CONTEXT_RECEIVER, "No required context receiver found: {0}", RENDER_TYPE)
map.put(
MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER,
"Multiple arguments applicable for context receiver: {0}",
RENDER_TYPE
)
map.put(
AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER,
"With implicit context receiver, call is ambiguous. Specify the receiver explicitly"
)
map.put(
UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL,
"To use contextual declarations, specify the `-Xcontext-receivers` compiler option"
)
// Ambiguity // Ambiguity
map.put(OVERLOAD_RESOLUTION_AMBIGUITY, "Overload resolution ambiguity between candidates: {0}", SYMBOLS) map.put(OVERLOAD_RESOLUTION_AMBIGUITY, "Overload resolution ambiguity between candidates: {0}", SYMBOLS)
map.put(ASSIGN_OPERATOR_AMBIGUITY, "Ambiguity between assign operator candidates: {0}", SYMBOLS) map.put(ASSIGN_OPERATOR_AMBIGUITY, "Ambiguity between assign operator candidates: {0}", SYMBOLS)
@@ -186,6 +186,7 @@ private fun mapInapplicableCandidateError(
source: KtSourceElement, source: KtSourceElement,
qualifiedAccessSource: KtSourceElement?, qualifiedAccessSource: KtSourceElement?,
): List<KtDiagnostic> { ): List<KtDiagnostic> {
val typeContext = session.typeContext
val genericDiagnostic = FirErrors.INAPPLICABLE_CANDIDATE.createOn(source, diagnostic.candidate.symbol) val genericDiagnostic = FirErrors.INAPPLICABLE_CANDIDATE.createOn(source, diagnostic.candidate.symbol)
val diagnostics = diagnostic.candidate.diagnostics.filter { it.applicability == diagnostic.applicability }.mapNotNull { rootCause -> val diagnostics = diagnostic.candidate.diagnostics.filter { it.applicability == diagnostic.applicability }.mapNotNull { rootCause ->
when (rootCause) { when (rootCause) {
@@ -197,7 +198,6 @@ private fun mapInapplicableCandidateError(
rootCause.forbiddenNamedArgumentsTarget rootCause.forbiddenNamedArgumentsTarget
) )
is ArgumentTypeMismatch -> { is ArgumentTypeMismatch -> {
val typeContext = session.typeContext
FirErrors.ARGUMENT_TYPE_MISMATCH.createOn( FirErrors.ARGUMENT_TYPE_MISMATCH.createOn(
rootCause.argument.source ?: source, rootCause.argument.source ?: source,
rootCause.expectedType.removeTypeVariableTypes(typeContext), rootCause.expectedType.removeTypeVariableTypes(typeContext),
@@ -205,6 +205,18 @@ private fun mapInapplicableCandidateError(
rootCause.isMismatchDueToNullability rootCause.isMismatchDueToNullability
) )
} }
is MultipleContextReceiversApplicableForExtensionReceivers ->
FirErrors.AMBIGUOUS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER.createOn(qualifiedAccessSource ?: source)
is NoApplicableValueForContextReceiver ->
FirErrors.NO_CONTEXT_RECEIVER.createOn(
qualifiedAccessSource ?: source,
rootCause.expectedContextReceiverType.removeTypeVariableTypes(typeContext)
)
is AmbiguousValuesForContextReceiverParameter ->
FirErrors.MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER.createOn(
qualifiedAccessSource ?: source,
rootCause.expectedContextReceiverType.removeTypeVariableTypes(typeContext)
)
is NullForNotNullType -> FirErrors.NULL_FOR_NONNULL_TYPE.createOn( is NullForNotNullType -> FirErrors.NULL_FOR_NONNULL_TYPE.createOn(
rootCause.argument.source ?: source rootCause.argument.source ?: source
) )
@@ -22,8 +22,12 @@ import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.ConeErrorType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.SmartcastStability import org.jetbrains.kotlin.types.SmartcastStability
interface Receiver interface Receiver
@@ -79,6 +83,8 @@ sealed class ImplicitReceiverValue<S : FirBasedSymbol<*>>(
final override var type: ConeKotlinType = type final override var type: ConeKotlinType = type
private set private set
abstract val isContextReceiver: Boolean
val originalType: ConeKotlinType = type val originalType: ConeKotlinType = type
var implicitScope: FirTypeScope? = type.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing) var implicitScope: FirTypeScope? = type.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing)
@@ -144,6 +150,9 @@ class ImplicitDispatchReceiverValue(
override fun createSnapshot(): ImplicitReceiverValue<FirClassSymbol<*>> { override fun createSnapshot(): ImplicitReceiverValue<FirClassSymbol<*>> {
return ImplicitDispatchReceiverValue(boundSymbol, type, useSiteSession, scopeSession, false) return ImplicitDispatchReceiverValue(boundSymbol, type, useSiteSession, scopeSession, false)
} }
override val isContextReceiver: Boolean
get() = false
} }
class ImplicitExtensionReceiverValue( class ImplicitExtensionReceiverValue(
@@ -156,6 +165,9 @@ class ImplicitExtensionReceiverValue(
override fun createSnapshot(): ImplicitReceiverValue<FirCallableSymbol<*>> { override fun createSnapshot(): ImplicitReceiverValue<FirCallableSymbol<*>> {
return ImplicitExtensionReceiverValue(boundSymbol, type, useSiteSession, scopeSession, false) return ImplicitExtensionReceiverValue(boundSymbol, type, useSiteSession, scopeSession, false)
} }
override val isContextReceiver: Boolean
get() = false
} }
@@ -169,4 +181,54 @@ class InaccessibleImplicitReceiverValue(
override fun createSnapshot(): ImplicitReceiverValue<FirClassSymbol<*>> { override fun createSnapshot(): ImplicitReceiverValue<FirClassSymbol<*>> {
return InaccessibleImplicitReceiverValue(boundSymbol, type, useSiteSession, scopeSession, false) return InaccessibleImplicitReceiverValue(boundSymbol, type, useSiteSession, scopeSession, false)
} }
override val isContextReceiver: Boolean
get() = false
}
sealed class ContextReceiverValue<S : FirBasedSymbol<*>>(
boundSymbol: S,
type: ConeKotlinType,
val labelName: Name?,
useSiteSession: FirSession,
scopeSession: ScopeSession,
mutable: Boolean = true,
) : ImplicitReceiverValue<S>(
boundSymbol, type, useSiteSession, scopeSession, mutable
) {
abstract override fun createSnapshot(): ContextReceiverValue<S>
}
class ContextReceiverValueForCallable(
boundSymbol: FirCallableSymbol<*>,
type: ConeKotlinType,
labelName: Name?,
useSiteSession: FirSession,
scopeSession: ScopeSession,
mutable: Boolean = true,
) : ContextReceiverValue<FirCallableSymbol<*>>(
boundSymbol, type, labelName, useSiteSession, scopeSession, mutable
) {
override fun createSnapshot(): ContextReceiverValue<FirCallableSymbol<*>> =
ContextReceiverValueForCallable(boundSymbol, type, labelName, useSiteSession, scopeSession, mutable = false)
override val isContextReceiver: Boolean
get() = true
}
class ContextReceiverValueForClass(
boundSymbol: FirClassSymbol<*>,
type: ConeKotlinType,
labelName: Name?,
useSiteSession: FirSession,
scopeSession: ScopeSession,
mutable: Boolean = true,
) : ContextReceiverValue<FirClassSymbol<*>>(
boundSymbol, type, labelName, useSiteSession, scopeSession, mutable
) {
override fun createSnapshot(): ContextReceiverValue<FirClassSymbol<*>> =
ContextReceiverValueForClass(boundSymbol, type, labelName, useSiteSession, scopeSession, mutable = false)
override val isContextReceiver: Boolean
get() = true
} }
@@ -218,7 +218,9 @@ private fun ConeTypeProjection.typeOrDefault(default: ConeKotlinType): ConeKotli
fun ConeKotlinType.receiverType(session: FirSession): ConeKotlinType? { fun ConeKotlinType.receiverType(session: FirSession): ConeKotlinType? {
if (!isBuiltinFunctionalType(session) || !isExtensionFunctionType(session)) return null if (!isBuiltinFunctionalType(session) || !isExtensionFunctionType(session)) return null
return fullyExpandedType(session).typeArguments.first().typeOrDefault(session.builtinTypes.nothingType.type) return fullyExpandedType(session).let { expanded ->
expanded.typeArguments[expanded.contextReceiversNumberForFunctionType].typeOrDefault(session.builtinTypes.nothingType.type)
}
} }
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType { fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType {
@@ -119,7 +119,7 @@ class FirCallResolver(
functionCall.copyAsImplicitInvokeCall { functionCall.copyAsImplicitInvokeCall {
explicitReceiver = candidate.callInfo.explicitReceiver explicitReceiver = candidate.callInfo.explicitReceiver
dispatchReceiver = candidate.dispatchReceiverExpression() dispatchReceiver = candidate.dispatchReceiverExpression()
extensionReceiver = candidate.extensionReceiverExpression() extensionReceiver = candidate.chosenExtensionReceiverExpression()
argumentList = candidate.callInfo.argumentList argumentList = candidate.callInfo.argumentList
} }
} else { } else {
@@ -381,7 +381,7 @@ class FirCallResolver(
if (reducedCandidates.size == 1) { if (reducedCandidates.size == 1) {
val candidate = reducedCandidates.single() val candidate = reducedCandidates.single()
resultExpression = resultExpression.transformDispatchReceiver(StoreReceiver, candidate.dispatchReceiverExpression()) resultExpression = resultExpression.transformDispatchReceiver(StoreReceiver, candidate.dispatchReceiverExpression())
resultExpression = resultExpression.transformExtensionReceiver(StoreReceiver, candidate.extensionReceiverExpression()) resultExpression = resultExpression.transformExtensionReceiver(StoreReceiver, candidate.chosenExtensionReceiverExpression())
} }
if (resultExpression is FirExpression) transformer.storeTypeFromCallee(resultExpression) if (resultExpression is FirExpression) transformer.storeTypeFromCallee(resultExpression)
return resultExpression return resultExpression
@@ -47,9 +47,10 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
import org.jetbrains.kotlin.types.ConstantValueKind
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
import org.jetbrains.kotlin.types.ConstantValueKind
import org.jetbrains.kotlin.types.SmartcastStability import org.jetbrains.kotlin.types.SmartcastStability
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract import kotlin.contracts.contract
@@ -73,7 +74,10 @@ fun FirFunction.constructFunctionalType(isSuspend: Boolean = false): ConeLookupT
} }
val rawReturnType = (this as FirCallableDeclaration).returnTypeRef.coneType val rawReturnType = (this as FirCallableDeclaration).returnTypeRef.coneType
return createFunctionalType(parameters, receiverTypeRef?.coneType, rawReturnType, isSuspend = isSuspend) return createFunctionalType(
parameters, receiverTypeRef?.coneType, rawReturnType, isSuspend = isSuspend,
contextReceivers = contextReceivers.map { it.typeRef.coneType }
)
} }
fun FirFunction.constructFunctionalTypeRef(isSuspend: Boolean = false): FirResolvedTypeRef { fun FirFunction.constructFunctionalTypeRef(isSuspend: Boolean = false): FirResolvedTypeRef {
@@ -88,9 +92,16 @@ fun createFunctionalType(
receiverType: ConeKotlinType?, receiverType: ConeKotlinType?,
rawReturnType: ConeKotlinType, rawReturnType: ConeKotlinType,
isSuspend: Boolean, isSuspend: Boolean,
contextReceivers: List<ConeKotlinType> = emptyList(),
isKFunctionType: Boolean = false isKFunctionType: Boolean = false
): ConeLookupTagBasedType { ): ConeLookupTagBasedType {
val receiverAndParameterTypes = listOfNotNull(receiverType) + parameters + listOf(rawReturnType) val receiverAndParameterTypes =
buildList {
addAll(contextReceivers)
addIfNotNull(receiverType)
addAll(parameters)
add(rawReturnType)
}
val kind = if (isSuspend) { val kind = if (isSuspend) {
if (isKFunctionType) FunctionClassKind.KSuspendFunction else FunctionClassKind.SuspendFunction if (isKFunctionType) FunctionClassKind.KSuspendFunction else FunctionClassKind.SuspendFunction
@@ -99,7 +110,18 @@ fun createFunctionalType(
} }
val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(receiverAndParameterTypes.size - 1)) val functionalTypeId = ClassId(kind.packageFqName, kind.numberedClassName(receiverAndParameterTypes.size - 1))
val attributes = if (receiverType != null) ConeAttributes.WithExtensionFunctionType else ConeAttributes.Empty val attributes = when {
contextReceivers.isNotEmpty() -> ConeAttributes.create(
buildList {
add(CompilerConeAttributes.ContextFunctionTypeParams(contextReceivers.size))
if (receiverType != null) {
add(CompilerConeAttributes.ExtensionFunctionType)
}
}
)
receiverType != null -> ConeAttributes.WithExtensionFunctionType
else -> ConeAttributes.Empty
}
return ConeClassLikeTypeImpl( return ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(functionalTypeId), ConeClassLikeLookupTagImpl(functionalTypeId),
receiverAndParameterTypes.toTypedArray(), receiverAndParameterTypes.toTypedArray(),
@@ -16,6 +16,7 @@ sealed class CallKind(vararg resolutionSequence: ResolutionStage) {
CollectTypeVariableUsagesInfo, CollectTypeVariableUsagesInfo,
CheckDispatchReceiver, CheckDispatchReceiver,
CheckExtensionReceiver, CheckExtensionReceiver,
CheckContextReceivers,
CheckDslScopeViolation, CheckDslScopeViolation,
CheckLowPriorityInOverloadResolution, CheckLowPriorityInOverloadResolution,
PostponedVariablesInitializerResolutionStage, PostponedVariablesInitializerResolutionStage,
@@ -43,6 +44,7 @@ sealed class CallKind(vararg resolutionSequence: ResolutionStage) {
CollectTypeVariableUsagesInfo, CollectTypeVariableUsagesInfo,
CheckDispatchReceiver, CheckDispatchReceiver,
CheckExtensionReceiver, CheckExtensionReceiver,
CheckContextReceivers,
CheckDslScopeViolation, CheckDslScopeViolation,
CheckArguments, CheckArguments,
CheckCallModifiers, CheckCallModifiers,
@@ -113,6 +115,7 @@ class ResolutionSequenceBuilder(
var mapTypeArguments: Boolean = false, var mapTypeArguments: Boolean = false,
var resolveCallableReferenceArguments: Boolean = false, var resolveCallableReferenceArguments: Boolean = false,
var checkCallableReferenceExpectedType: Boolean = false, var checkCallableReferenceExpectedType: Boolean = false,
val checkContextReceivers: Boolean = false,
) { ) {
fun build(): CallKind { fun build(): CallKind {
val stages = mutableListOf<ResolutionStage>().apply { val stages = mutableListOf<ResolutionStage>().apply {
@@ -125,6 +128,7 @@ class ResolutionSequenceBuilder(
if (checkDispatchReceiver) add(CheckDispatchReceiver) if (checkDispatchReceiver) add(CheckDispatchReceiver)
if (checkExtensionReceiver) add(CheckExtensionReceiver) if (checkExtensionReceiver) add(CheckExtensionReceiver)
if (checkArguments) add(CheckArguments) if (checkArguments) add(CheckArguments)
if (checkContextReceivers) add(CheckContextReceivers)
if (resolveCallableReferenceArguments) add(EagerResolveOfCallableReferences) if (resolveCallableReferenceArguments) add(EagerResolveOfCallableReferences)
if (checkLowPriorityInOverloadResolution) add(CheckLowPriorityInOverloadResolution) if (checkLowPriorityInOverloadResolution) add(CheckLowPriorityInOverloadResolution)
if (initializePostponedVariables) add(PostponedVariablesInitializerResolutionStage) if (initializePostponedVariables) add(PostponedVariablesInitializerResolutionStage)
@@ -28,9 +28,11 @@ import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
class Candidate( class Candidate(
override val symbol: FirBasedSymbol<*>, override val symbol: FirBasedSymbol<*>,
override val dispatchReceiverValue: ReceiverValue?, override val dispatchReceiverValue: ReceiverValue?,
override val extensionReceiverValue: ReceiverValue?, // In most cases, it contains zero or single element
// More than one, only in case of context receiver group
val givenExtensionReceiverOptions: List<ReceiverValue>,
override val explicitReceiverKind: ExplicitReceiverKind, override val explicitReceiverKind: ExplicitReceiverKind,
val constraintSystemFactory: InferenceComponents.ConstraintSystemFactory, private val constraintSystemFactory: InferenceComponents.ConstraintSystemFactory,
private val baseSystem: ConstraintStorage, private val baseSystem: ConstraintStorage,
override val callInfo: CallInfo, override val callInfo: CallInfo,
val originScope: FirScope?, val originScope: FirScope?,
@@ -73,6 +75,10 @@ class Candidate(
var currentApplicability = CandidateApplicability.RESOLVED var currentApplicability = CandidateApplicability.RESOLVED
private set private set
override var chosenExtensionReceiverValue: ReceiverValue? = givenExtensionReceiverOptions.singleOrNull()
var contextReceiverArguments: List<FirExpression>? = null
override val applicability: CandidateApplicability override val applicability: CandidateApplicability
get() = currentApplicability get() = currentApplicability
@@ -95,8 +101,8 @@ class Candidate(
fun dispatchReceiverExpression(): FirExpression = fun dispatchReceiverExpression(): FirExpression =
dispatchReceiverValue?.receiverExpression?.takeIf { it !is FirExpressionStub } ?: FirNoReceiverExpression dispatchReceiverValue?.receiverExpression?.takeIf { it !is FirExpressionStub } ?: FirNoReceiverExpression
fun extensionReceiverExpression(): FirExpression = fun chosenExtensionReceiverExpression(): FirExpression =
extensionReceiverValue?.receiverExpression?.takeIf { it !is FirExpressionStub } ?: FirNoReceiverExpression chosenExtensionReceiverValue?.receiverExpression?.takeIf { it !is FirExpressionStub } ?: FirNoReceiverExpression
var hasVisibleBackingField = false var hasVisibleBackingField = false
@@ -49,19 +49,20 @@ class CandidateFactory private constructor(
explicitReceiverKind: ExplicitReceiverKind, explicitReceiverKind: ExplicitReceiverKind,
scope: FirScope?, scope: FirScope?,
dispatchReceiverValue: ReceiverValue? = null, dispatchReceiverValue: ReceiverValue? = null,
extensionReceiverValue: ReceiverValue? = null, givenExtensionReceiverOptions: List<ReceiverValue> = emptyList(),
objectsByName: Boolean = false objectsByName: Boolean = false
): Candidate { ): Candidate {
@Suppress("NAME_SHADOWING") @Suppress("NAME_SHADOWING")
val symbol = symbol.unwrapIntegerOperatorSymbolIfNeeded(callInfo) val symbol = symbol.unwrapIntegerOperatorSymbolIfNeeded(callInfo)
val result = Candidate( val result = Candidate(
symbol, dispatchReceiverValue, extensionReceiverValue, symbol, dispatchReceiverValue, givenExtensionReceiverOptions,
explicitReceiverKind, context.inferenceComponents.constraintSystemFactory, baseSystem, explicitReceiverKind, context.inferenceComponents.constraintSystemFactory, baseSystem,
callInfo, callInfo,
scope, scope,
isFromCompanionObjectTypeScope = when (explicitReceiverKind) { isFromCompanionObjectTypeScope = when (explicitReceiverKind) {
ExplicitReceiverKind.EXTENSION_RECEIVER -> extensionReceiverValue.isCandidateFromCompanionObjectTypeScope() ExplicitReceiverKind.EXTENSION_RECEIVER ->
givenExtensionReceiverOptions.singleOrNull().isCandidateFromCompanionObjectTypeScope()
ExplicitReceiverKind.DISPATCH_RECEIVER -> dispatchReceiverValue.isCandidateFromCompanionObjectTypeScope() ExplicitReceiverKind.DISPATCH_RECEIVER -> dispatchReceiverValue.isCandidateFromCompanionObjectTypeScope()
// The following cases are not applicable for companion objects. // The following cases are not applicable for companion objects.
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> false ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> false
@@ -121,7 +122,7 @@ class CandidateFactory private constructor(
return Candidate( return Candidate(
symbol, symbol,
dispatchReceiverValue = null, dispatchReceiverValue = null,
extensionReceiverValue = null, givenExtensionReceiverOptions = emptyList(),
explicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, explicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
context.inferenceComponents.constraintSystemFactory, context.inferenceComponents.constraintSystemFactory,
baseSystem, baseSystem,
@@ -34,6 +34,8 @@ import org.jetbrains.kotlin.fir.visibilityChecker
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.inference.isSubtypeConstraintCompatible
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.* import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue
@@ -76,18 +78,43 @@ internal object CheckExplicitReceiverConsistency : ResolutionStage() {
object CheckExtensionReceiver : ResolutionStage() { object CheckExtensionReceiver : ResolutionStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val expectedReceiverType = candidate.getReceiverType(context) ?: return val expectedReceiverType = candidate.getReceiverType(context) ?: return
val argumentExtensionReceiverValue = candidate.extensionReceiverValue ?: return
val expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type) val expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type)
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(
argumentType = argumentExtensionReceiverValue.type, // Probably, we should add an assertion here since we check consistency on the level of scope tower levels
expectedType = expectedType, if (candidate.givenExtensionReceiverOptions.isEmpty()) return
session = context.session
) val preparedReceivers = candidate.givenExtensionReceiverOptions.map {
candidate.prepareReceivers(it, expectedType, context)
}
if (preparedReceivers.size == 1) {
resolveExtensionReceiver(preparedReceivers, candidate, expectedType, sink, context)
return
}
val successfulReceivers = preparedReceivers.filter {
candidate.system.isSubtypeConstraintCompatible(it.type, expectedType, SimpleConstraintSystemConstraintPosition)
}
when (successfulReceivers.size) {
0 -> sink.yieldDiagnostic(InapplicableWrongReceiver())
1 -> resolveExtensionReceiver(successfulReceivers, candidate, expectedType, sink, context)
else -> sink.yieldDiagnostic(MultipleContextReceiversApplicableForExtensionReceivers())
}
}
private suspend fun resolveExtensionReceiver(
receivers: List<ReceiverDescription>,
candidate: Candidate,
expectedType: ConeKotlinType,
sink: CheckerSink,
context: ResolutionContext
) {
val receiver = receivers.single()
candidate.resolvePlainArgumentType( candidate.resolvePlainArgumentType(
candidate.csBuilder, candidate.csBuilder,
argumentExtensionReceiverValue.receiverExpression, receiver.expression,
argumentType = argumentType, argumentType = receiver.type,
expectedType = expectedType, expectedType = expectedType,
sink = sink, sink = sink,
context = context, context = context,
@@ -109,6 +136,25 @@ object CheckExtensionReceiver : ResolutionStage() {
} }
} }
private fun Candidate.prepareReceivers(
argumentExtensionReceiverValue: ReceiverValue,
expectedType: ConeKotlinType,
context: ResolutionContext,
): ReceiverDescription {
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(
argumentType = argumentExtensionReceiverValue.type,
expectedType = expectedType,
session = context.session
).let { prepareCapturedType(it, context) }
return ReceiverDescription(argumentExtensionReceiverValue.receiverExpression, argumentType)
}
private class ReceiverDescription(
val expression: FirExpression,
val type: ConeKotlinType,
)
object CheckDispatchReceiver : ResolutionStage() { object CheckDispatchReceiver : ResolutionStage() {
@OptIn(SymbolInternals::class) @OptIn(SymbolInternals::class)
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
@@ -156,6 +202,58 @@ object CheckDispatchReceiver : ResolutionStage() {
} }
} }
object CheckContextReceivers : ResolutionStage() {
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val contextReceiverExpectedTypes = (candidate.symbol as? FirCallableSymbol<*>)?.fir?.contextReceivers?.map {
candidate.substitutor.substituteOrSelf(it.typeRef.coneType)
}?.takeUnless { it.isEmpty() } ?: return
val receiverGroups: List<List<ImplicitReceiverValue<*>>> =
context.bodyResolveContext.towerDataContext.towerDataElements.mapNotNull { towerDataElement ->
towerDataElement.implicitReceiver?.let(::listOf) ?: towerDataElement.contextReceiverGroup
}
val resultingContextReceiverArguments = mutableListOf<FirExpression>()
for (expectedType in contextReceiverExpectedTypes) {
val matchingReceivers = candidate.findClosestMatchingReceivers(expectedType, receiverGroups, context)
when (matchingReceivers.size) {
0 -> {
sink.reportDiagnostic(NoApplicableValueForContextReceiver(expectedType))
return
}
1 -> {
val matchingReceiver = matchingReceivers.single()
resultingContextReceiverArguments.add(matchingReceiver.expression)
candidate.system.addSubtypeConstraint(matchingReceiver.type, expectedType, SimpleConstraintSystemConstraintPosition)
}
else -> {
sink.reportDiagnostic(AmbiguousValuesForContextReceiverParameter(expectedType))
return
}
}
}
candidate.contextReceiverArguments = resultingContextReceiverArguments
}
}
private fun Candidate.findClosestMatchingReceivers(
expectedType: ConeKotlinType,
receiverGroups: List<List<ImplicitReceiverValue<*>>>,
context: ResolutionContext,
): List<ReceiverDescription> {
for (receiverGroup in receiverGroups) {
val currentResult =
receiverGroup
.map { prepareReceivers(it, expectedType, context) }
.filter { system.isSubtypeConstraintCompatible(it.type, expectedType, SimpleConstraintSystemConstraintPosition) }
if (currentResult.isNotEmpty()) return currentResult
}
return emptyList()
}
/** /**
* See https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-dsl-marker/ for more details and * See https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-dsl-marker/ for more details and
* /compiler/testData/diagnostics/tests/resolve/dslMarker for the test files. * /compiler/testData/diagnostics/tests/resolve/dslMarker for the test files.
@@ -176,7 +274,7 @@ object CheckDslScopeViolation : ResolutionStage() {
} }
} }
checkReceiverValue(candidate.dispatchReceiverValue) checkReceiverValue(candidate.dispatchReceiverValue)
checkReceiverValue(candidate.extensionReceiverValue) checkReceiverValue(candidate.chosenExtensionReceiverValue)
// For value of builtin functional type with implicit extension receiver, the receiver is passed as the first argument rather than // For value of builtin functional type with implicit extension receiver, the receiver is passed as the first argument rather than
// an extension receiver of the `invoke` call. Hence, we need to specially handle this case. // an extension receiver of the `invoke` call. Hence, we need to specially handle this case.
@@ -162,7 +162,7 @@ internal class FirInvokeResolveTowerExtension(
continue continue
} }
val extensionReceiverExpression = invokeReceiverCandidate.extensionReceiverExpression() val extensionReceiverExpression = invokeReceiverCandidate.chosenExtensionReceiverExpression()
val useImplicitReceiverAsBuiltinInvokeArgument = val useImplicitReceiverAsBuiltinInvokeArgument =
!invokeBuiltinExtensionMode && isExtensionFunctionType && !invokeBuiltinExtensionMode && isExtensionFunctionType &&
invokeReceiverCandidate.explicitReceiverKind == ExplicitReceiverKind.NO_EXPLICIT_RECEIVER invokeReceiverCandidate.explicitReceiverKind == ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
@@ -391,6 +391,13 @@ private class InvokeFunctionResolveTask(
info, group.Member, info, group.Member,
ExplicitReceiverKind.EXTENSION_RECEIVER ExplicitReceiverKind.EXTENSION_RECEIVER
) )
},
onContextReceiverGroup = { contextReceiverGroup, towerGroup ->
processLevelForRegularInvoke(
contextReceiverGroup.toMemberScopeTowerLevel(extensionReceiver = invokeReceiverValue),
info, towerGroup.Member,
ExplicitReceiverKind.EXTENSION_RECEIVER
)
} }
) )
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.resolve.calls.tower package org.jetbrains.kotlin.fir.resolve.calls.tower
import org.jetbrains.kotlin.fir.declarations.ContextReceiverGroup
import org.jetbrains.kotlin.fir.declarations.FirTowerDataContext import org.jetbrains.kotlin.fir.declarations.FirTowerDataContext
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
@@ -47,6 +48,12 @@ internal class TowerDataElementsForName(
} }
} }
val contextReceiverGroups by lazy(LazyThreadSafetyMode.NONE) {
nonLocalTowerDataElements.mapIndexedNotNull { index, towerDataElement ->
towerDataElement.contextReceiverGroup?.let { receiver -> IndexedValue(index, receiver) }
}
}
val emptyScopes = mutableSetOf<FirScope>() val emptyScopes = mutableSetOf<FirScope>()
val implicitReceiverValuesWithEmptyScopes = mutableSetOf<ImplicitReceiverValue<*>>() val implicitReceiverValuesWithEmptyScopes = mutableSetOf<ImplicitReceiverValue<*>>()
} }
@@ -81,22 +88,34 @@ internal abstract class FirBaseTowerResolveTask(
extensionReceiver: ReceiverValue? = null, extensionReceiver: ReceiverValue? = null,
withHideMembersOnly: Boolean = false, withHideMembersOnly: Boolean = false,
includeInnerConstructors: Boolean = extensionReceiver != null, includeInnerConstructors: Boolean = extensionReceiver != null,
contextReceiverGroup: ContextReceiverGroup? = null,
): ScopeTowerLevel = ScopeTowerLevel( ): ScopeTowerLevel = ScopeTowerLevel(
components, this, components, this,
extensionReceiver, withHideMembersOnly, includeInnerConstructors givenExtensionReceiverOptions = contextReceiverGroup ?: listOfNotNull(extensionReceiver),
withHideMembersOnly, includeInnerConstructors
) )
protected fun ReceiverValue.toMemberScopeTowerLevel( protected fun ReceiverValue.toMemberScopeTowerLevel(
extensionReceiver: ReceiverValue? = null extensionReceiver: ReceiverValue? = null,
contextReceiverGroup: ContextReceiverGroup? = null,
) = MemberScopeTowerLevel( ) = MemberScopeTowerLevel(
components, this, components, this,
extensionReceiver, givenExtensionReceiverOptions = contextReceiverGroup ?: listOfNotNull(extensionReceiver),
)
protected fun ContextReceiverGroup.toMemberScopeTowerLevel(
extensionReceiver: ReceiverValue? = null,
otherContextReceiverGroup: ContextReceiverGroup? = null,
) = ContextReceiverGroupMemberScopeTowerLevel(
components, this,
givenExtensionReceiverOptions = otherContextReceiverGroup ?: listOfNotNull(extensionReceiver),
) )
protected inline fun enumerateTowerLevels( protected inline fun enumerateTowerLevels(
parentGroup: TowerGroup = TowerGroup.EmptyRoot, parentGroup: TowerGroup = TowerGroup.EmptyRoot,
onScope: (FirScope, TowerGroup) -> Unit, onScope: (FirScope, TowerGroup) -> Unit,
onImplicitReceiver: (ImplicitReceiverValue<*>, TowerGroup) -> Unit, onImplicitReceiver: (ImplicitReceiverValue<*>, TowerGroup) -> Unit,
onContextReceiverGroup: (ContextReceiverGroup, TowerGroup) -> Unit,
) { ) {
for ((index, localScope) in towerDataElementsForName.reversedFilteredLocalScopes) { for ((index, localScope) in towerDataElementsForName.reversedFilteredLocalScopes) {
onScope(localScope, parentGroup.Local(index)) onScope(localScope, parentGroup.Local(index))
@@ -118,6 +137,10 @@ internal abstract class FirBaseTowerResolveTask(
onImplicitReceiver(receiver, parentGroup.Implicit(depth)) onImplicitReceiver(receiver, parentGroup.Implicit(depth))
} }
} }
for ((depth, contextReceiverGroup) in towerDataElementsForName.contextReceiverGroups) {
onContextReceiverGroup(contextReceiverGroup, parentGroup.ContextReceiverGroup(depth))
}
} }
/** /**
@@ -243,7 +266,17 @@ internal open class FirTowerResolveTask(
) )
}, },
onImplicitReceiver = { implicitReceiverValue, group -> onImplicitReceiver = { implicitReceiverValue, group ->
processCombinationOfReceivers(implicitReceiverValue, explicitReceiverValue, info, group) // Member extensions
processLevel(
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = explicitReceiverValue),
info, group.Member, ExplicitReceiverKind.EXTENSION_RECEIVER
)
},
onContextReceiverGroup = { contextReceiverGroup, towerGroup ->
processLevel(
contextReceiverGroup.toMemberScopeTowerLevel(extensionReceiver = explicitReceiverValue),
info, towerGroup, ExplicitReceiverKind.EXTENSION_RECEIVER,
)
} }
) )
} }
@@ -277,7 +310,13 @@ internal open class FirTowerResolveTask(
implicitReceiverValuesWithEmptyScopes, implicitReceiverValuesWithEmptyScopes,
emptyScopes emptyScopes
) )
} },
onContextReceiverGroup = { contextReceiverGroup, towerGroup ->
processCandidatesWithGivenContextReceiverGroup(
contextReceiverGroup,
info, towerGroup,
)
},
) )
} }
@@ -308,6 +347,7 @@ internal open class FirTowerResolveTask(
ExplicitReceiverKind.EXTENSION_RECEIVER, parentGroup ExplicitReceiverKind.EXTENSION_RECEIVER, parentGroup
) )
} else { } else {
// context?
for ((depth, implicitReceiverValue) in towerDataElementsForName.implicitReceivers) { for ((depth, implicitReceiverValue) in towerDataElementsForName.implicitReceivers) {
processHideMembersLevel( processHideMembersLevel(
implicitReceiverValue, topLevelScope, info, index, depth, implicitReceiverValue, topLevelScope, info, index, depth,
@@ -331,19 +371,6 @@ internal open class FirTowerResolveTask(
} }
private suspend fun processCombinationOfReceivers(
implicitReceiverValue: ImplicitReceiverValue<*>,
explicitReceiverValue: ExpressionReceiverValue,
info: CallInfo,
parentGroup: TowerGroup
) {
// Member extensions
processLevel(
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = explicitReceiverValue),
info, parentGroup.Member, ExplicitReceiverKind.EXTENSION_RECEIVER
)
}
private suspend fun processCandidatesWithGivenImplicitReceiverAsValue( private suspend fun processCandidatesWithGivenImplicitReceiverAsValue(
receiver: ImplicitReceiverValue<*>, receiver: ImplicitReceiverValue<*>,
info: CallInfo, info: CallInfo,
@@ -377,11 +404,49 @@ internal open class FirTowerResolveTask(
implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = receiver), implicitReceiverValue.toMemberScopeTowerLevel(extensionReceiver = receiver),
info, group info, group
) )
} },
onContextReceiverGroup = { contextReceiverGroup, towerGroup ->
processLevel(
contextReceiverGroup.toMemberScopeTowerLevel(extensionReceiver = receiver),
info, towerGroup
)
},
) )
} }
private suspend fun processCandidatesWithGivenContextReceiverGroup(
contextReceiverGroup: ContextReceiverGroup,
info: CallInfo,
parentGroup: TowerGroup,
) {
processLevel(
contextReceiverGroup.toMemberScopeTowerLevel(), info, parentGroup.Member,
)
enumerateTowerLevels(
parentGroup,
onScope = { scope, towerGroup ->
processLevel(
scope.toScopeTowerLevel(contextReceiverGroup = contextReceiverGroup),
info, towerGroup,
)
},
onImplicitReceiver = { implicitReceiverValue, towerGroup ->
processLevel(
implicitReceiverValue.toMemberScopeTowerLevel(contextReceiverGroup = contextReceiverGroup),
info, towerGroup
)
},
onContextReceiverGroup = { otherContextReceiverGroup, towerGroup ->
processLevel(
contextReceiverGroup.toMemberScopeTowerLevel(otherContextReceiverGroup = otherContextReceiverGroup),
info, towerGroup,
)
}
)
}
private suspend fun processHideMembersLevel( private suspend fun processHideMembersLevel(
receiverValue: ReceiverValue, receiverValue: ReceiverValue,
topLevelScope: FirScope, topLevelScope: FirScope,
@@ -116,7 +116,7 @@ class FirTowerResolver(
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
scope, scope,
dispatchReceiver, dispatchReceiver,
extensionReceiverValue = null givenExtensionReceiverOptions = emptyList()
), ),
context context
) )
@@ -40,9 +40,11 @@ sealed class TowerGroupKind(val index: Byte) : Comparable<TowerGroupKind> {
class ImplicitOrNonLocal(depth: Int, val kindForDebugSake: String) : WithDepth(6, depth) class ImplicitOrNonLocal(depth: Int, val kindForDebugSake: String) : WithDepth(6, depth)
object InvokeExtension : TowerGroupKind(7) class ContextReceiverGroup(depth: Int) : WithDepth(7, depth)
object QualifierValue : TowerGroupKind(8) object InvokeExtension : TowerGroupKind(8)
object QualifierValue : TowerGroupKind(9)
class UnqualifiedEnum(depth: Int) : WithDepth(9, depth) class UnqualifiedEnum(depth: Int) : WithDepth(9, depth)
@@ -166,6 +168,8 @@ private constructor(
fun Implicit(depth: Int) = kindOf(TowerGroupKind.Implicit(depth)) fun Implicit(depth: Int) = kindOf(TowerGroupKind.Implicit(depth))
fun NonLocal(depth: Int) = kindOf(TowerGroupKind.NonLocal(depth)) fun NonLocal(depth: Int) = kindOf(TowerGroupKind.NonLocal(depth))
fun ContextReceiverGroup(depth: Int) = kindOf(TowerGroupKind.ContextReceiverGroup(depth))
fun TopPrioritized(depth: Int) = kindOf(TowerGroupKind.TopPrioritized(depth)) fun TopPrioritized(depth: Int) = kindOf(TowerGroupKind.TopPrioritized(depth))
val Last = kindOf(TowerGroupKind.Last) val Last = kindOf(TowerGroupKind.Last)
@@ -180,6 +184,8 @@ private constructor(
fun Implicit(depth: Int) = kindOf(TowerGroupKind.Implicit(depth)) fun Implicit(depth: Int) = kindOf(TowerGroupKind.Implicit(depth))
fun NonLocal(depth: Int) = kindOf(TowerGroupKind.NonLocal(depth)) fun NonLocal(depth: Int) = kindOf(TowerGroupKind.NonLocal(depth))
fun ContextReceiverGroup(depth: Int) = kindOf(TowerGroupKind.ContextReceiverGroup(depth))
val InvokeExtension get() = kindOf(TowerGroupKind.InvokeExtension) val InvokeExtension get() = kindOf(TowerGroupKind.InvokeExtension)
fun TopPrioritized(depth: Int) = kindOf(TowerGroupKind.TopPrioritized(depth)) fun TopPrioritized(depth: Int) = kindOf(TowerGroupKind.TopPrioritized(depth))
@@ -45,7 +45,7 @@ internal class TowerLevelHandler {
CallKind.VariableAccess -> { CallKind.VariableAccess -> {
processResult += towerLevel.processPropertiesByName(info, processor) processResult += towerLevel.processPropertiesByName(info, processor)
if (!collector.isSuccess() && towerLevel is ScopeTowerLevel && towerLevel.extensionReceiver == null) { if (!collector.isSuccess() && towerLevel is ScopeTowerLevel && !towerLevel.areThereExtensionReceiverOptions()) {
processResult += towerLevel.processObjectsByName(info, processor) processResult += towerLevel.processObjectsByName(info, processor)
} }
} }
@@ -74,7 +74,7 @@ private class TowerScopeLevelProcessor(
override fun consumeCandidate( override fun consumeCandidate(
symbol: FirBasedSymbol<*>, symbol: FirBasedSymbol<*>,
dispatchReceiverValue: ReceiverValue?, dispatchReceiverValue: ReceiverValue?,
extensionReceiverValue: ReceiverValue?, givenExtensionReceiverOptions: List<ReceiverValue>,
scope: FirScope, scope: FirScope,
objectsByName: Boolean objectsByName: Boolean
) { ) {
@@ -85,7 +85,7 @@ private class TowerScopeLevelProcessor(
explicitReceiverKind, explicitReceiverKind,
scope, scope,
dispatchReceiverValue, dispatchReceiverValue,
extensionReceiverValue, givenExtensionReceiverOptions,
objectsByName objectsByName
), candidateFactory.context ), candidateFactory.context
) )
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.resolve.calls.tower package org.jetbrains.kotlin.fir.resolve.calls.tower
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.ContextReceiverGroup
import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
import org.jetbrains.kotlin.fir.declarations.utils.isInner import org.jetbrains.kotlin.fir.declarations.utils.isInner
@@ -56,7 +57,7 @@ abstract class TowerScopeLevel {
fun consumeCandidate( fun consumeCandidate(
symbol: T, symbol: T,
dispatchReceiverValue: ReceiverValue?, dispatchReceiverValue: ReceiverValue?,
extensionReceiverValue: ReceiverValue?, givenExtensionReceiverOptions: List<ReceiverValue>,
scope: FirScope, scope: FirScope,
objectsByName: Boolean = false objectsByName: Boolean = false
) )
@@ -73,7 +74,7 @@ abstract class TowerScopeLevel {
class MemberScopeTowerLevel( class MemberScopeTowerLevel(
private val bodyResolveComponents: BodyResolveComponents, private val bodyResolveComponents: BodyResolveComponents,
val dispatchReceiverValue: ReceiverValue, val dispatchReceiverValue: ReceiverValue,
private val extensionReceiver: ReceiverValue? = null, private val givenExtensionReceiverOptions: List<ReceiverValue>,
) : TowerScopeLevel() { ) : TowerScopeLevel() {
private val scopeSession: ScopeSession get() = bodyResolveComponents.scopeSession private val scopeSession: ScopeSession get() = bodyResolveComponents.scopeSession
private val session: FirSession get() = bodyResolveComponents.session private val session: FirSession get() = bodyResolveComponents.session
@@ -86,11 +87,11 @@ class MemberScopeTowerLevel(
var (empty, candidates) = scope.collectCandidates(processScopeMembers) var (empty, candidates) = scope.collectCandidates(processScopeMembers)
consumeCandidates(output, candidates.map { scope to it }) consumeCandidates(output, candidates.map { scope to it })
if (extensionReceiver == null) { if (givenExtensionReceiverOptions.isEmpty()) {
val withSynthetic = FirSyntheticPropertiesScope(session, scope) val withSynthetic = FirSyntheticPropertiesScope(session, scope)
withSynthetic.processScopeMembers { symbol -> withSynthetic.processScopeMembers { symbol ->
empty = false empty = false
output.consumeCandidate(symbol, dispatchReceiverValue, null, scope) output.consumeCandidate(symbol, dispatchReceiverValue, givenExtensionReceiverOptions = emptyList(), scope)
} }
} }
return if (empty) ProcessResult.SCOPE_EMPTY else ProcessResult.FOUND return if (empty) ProcessResult.SCOPE_EMPTY else ProcessResult.FOUND
@@ -103,7 +104,7 @@ class MemberScopeTowerLevel(
val result = mutableListOf<T>() val result = mutableListOf<T>()
processScopeMembers { candidate -> processScopeMembers { candidate ->
empty = false empty = false
if (candidate is FirCallableSymbol<*> && candidate.hasConsistentExtensionReceiver(extensionReceiver)) { if (candidate is FirCallableSymbol<*> && candidate.hasConsistentExtensionReceiver(givenExtensionReceiverOptions)) {
val fir = candidate.fir val fir = candidate.fir
if ((fir as? FirConstructor)?.isInner == false) { if ((fir as? FirConstructor)?.isInner == false) {
return@processScopeMembers return@processScopeMembers
@@ -121,14 +122,14 @@ class MemberScopeTowerLevel(
candidatesWithScope: List<Pair<FirScope, T>> candidatesWithScope: List<Pair<FirScope, T>>
) { ) {
for ((scope, candidate) in candidatesWithScope) { for ((scope, candidate) in candidatesWithScope) {
if (candidate is FirCallableSymbol<*> && candidate.hasConsistentExtensionReceiver(extensionReceiver)) { if (candidate is FirCallableSymbol<*> && candidate.hasConsistentExtensionReceiver(givenExtensionReceiverOptions)) {
output.consumeCandidate( output.consumeCandidate(
candidate, dispatchReceiverValue, candidate, dispatchReceiverValue,
extensionReceiverValue = extensionReceiver, givenExtensionReceiverOptions,
scope scope
) )
} else if (candidate is FirClassLikeSymbol<*>) { } else if (candidate is FirClassLikeSymbol<*>) {
output.consumeCandidate(candidate, null, extensionReceiver, scope) output.consumeCandidate(candidate, null, givenExtensionReceiverOptions, scope)
} }
} }
} }
@@ -201,8 +202,30 @@ class MemberScopeTowerLevel(
} }
} }
private fun FirCallableSymbol<*>.hasConsistentExtensionReceiver(extensionReceiver: Receiver?): Boolean { private fun FirCallableSymbol<*>.hasConsistentExtensionReceiver(givenExtensionReceivers: List<ReceiverValue>): Boolean {
return (extensionReceiver != null) == hasExtensionReceiver() return givenExtensionReceivers.isNotEmpty() == hasExtensionReceiver()
}
}
class ContextReceiverGroupMemberScopeTowerLevel(
bodyResolveComponents: BodyResolveComponents,
contextReceiverGroup: ContextReceiverGroup,
givenExtensionReceiverOptions: List<ReceiverValue> = emptyList(),
) : TowerScopeLevel() {
private val memberScopeLevels = contextReceiverGroup.map {
MemberScopeTowerLevel(bodyResolveComponents, it, givenExtensionReceiverOptions)
}
override fun processFunctionsByName(info: CallInfo, processor: TowerScopeLevelProcessor<FirFunctionSymbol<*>>): ProcessResult {
return memberScopeLevels.minOf { it.processFunctionsByName(info, processor) }
}
override fun processPropertiesByName(info: CallInfo, processor: TowerScopeLevelProcessor<FirVariableSymbol<*>>): ProcessResult {
return memberScopeLevels.minOf { it.processPropertiesByName(info, processor) }
}
override fun processObjectsByName(info: CallInfo, processor: TowerScopeLevelProcessor<FirBasedSymbol<*>>): ProcessResult {
return memberScopeLevels.minOf { it.processObjectsByName(info, processor) }
} }
} }
@@ -216,12 +239,14 @@ class MemberScopeTowerLevel(
class ScopeTowerLevel( class ScopeTowerLevel(
private val bodyResolveComponents: BodyResolveComponents, private val bodyResolveComponents: BodyResolveComponents,
val scope: FirScope, val scope: FirScope,
val extensionReceiver: ReceiverValue?, private val givenExtensionReceiverOptions: List<ReceiverValue>,
private val withHideMembersOnly: Boolean, private val withHideMembersOnly: Boolean,
private val includeInnerConstructors: Boolean private val includeInnerConstructors: Boolean
) : TowerScopeLevel() { ) : TowerScopeLevel() {
private val session: FirSession get() = bodyResolveComponents.session private val session: FirSession get() = bodyResolveComponents.session
fun areThereExtensionReceiverOptions(): Boolean = givenExtensionReceiverOptions.isNotEmpty()
private fun dispatchReceiverValue(candidate: FirCallableSymbol<*>): ReceiverValue? { private fun dispatchReceiverValue(candidate: FirCallableSymbol<*>): ReceiverValue? {
candidate.fir.importedFromObjectData?.let { data -> candidate.fir.importedFromObjectData?.let { data ->
val objectClassId = data.objectClassId val objectClassId = data.objectClassId
@@ -257,26 +282,25 @@ class ScopeTowerLevel(
private fun shouldSkipCandidateWithInconsistentExtensionReceiver(candidate: FirCallableSymbol<*>): Boolean { private fun shouldSkipCandidateWithInconsistentExtensionReceiver(candidate: FirCallableSymbol<*>): Boolean {
// Pre-check explicit extension receiver for default package top-level members // Pre-check explicit extension receiver for default package top-level members
if (scope is FirDefaultStarImportingScope && extensionReceiver != null) { if (scope !is FirDefaultStarImportingScope || !areThereExtensionReceiverOptions()) return false
val declarationReceiverType = candidate.resolvedReceiverTypeRef?.coneType as? ConeClassLikeType ?: return false
val startProjectedDeclarationReceiverType = declarationReceiverType.lookupTag.constructClassType(
declarationReceiverType.typeArguments.map { ConeStarProjection }.toTypedArray(),
isNullable = true
)
return givenExtensionReceiverOptions.none { extensionReceiver ->
val extensionReceiverType = extensionReceiver.type val extensionReceiverType = extensionReceiver.type
if (extensionReceiverType is ConeClassLikeType) { // If some receiver is non class like, we should not skip it
val declarationReceiverType = candidate.resolvedReceiverTypeRef?.coneType if (extensionReceiverType !is ConeClassLikeType) return@none true
if (declarationReceiverType is ConeClassLikeType) {
if (!AbstractTypeChecker.isSubtypeOf( AbstractTypeChecker.isSubtypeOf(
session.typeContext, session.typeContext,
extensionReceiverType, extensionReceiverType,
declarationReceiverType.lookupTag.constructClassType( startProjectedDeclarationReceiverType
declarationReceiverType.typeArguments.map { ConeStarProjection }.toTypedArray(), )
isNullable = true
)
)
) {
return true
}
}
}
} }
return false
} }
private fun <T : FirBasedSymbol<*>> consumeCallableCandidate( private fun <T : FirBasedSymbol<*>> consumeCallableCandidate(
@@ -287,7 +311,7 @@ class ScopeTowerLevel(
if (withHideMembersOnly && candidate.getAnnotationByClassId(HidesMembers) == null) { if (withHideMembersOnly && candidate.getAnnotationByClassId(HidesMembers) == null) {
return return
} }
val receiverExpected = withHideMembersOnly || extensionReceiver != null val receiverExpected = withHideMembersOnly || areThereExtensionReceiverOptions()
if (candidateReceiverTypeRef == null == receiverExpected) return if (candidateReceiverTypeRef == null == receiverExpected) return
val dispatchReceiverValue = dispatchReceiverValue(candidate) val dispatchReceiverValue = dispatchReceiverValue(candidate)
if (dispatchReceiverValue == null && shouldSkipCandidateWithInconsistentExtensionReceiver(candidate)) { if (dispatchReceiverValue == null && shouldSkipCandidateWithInconsistentExtensionReceiver(candidate)) {
@@ -297,7 +321,7 @@ class ScopeTowerLevel(
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
processor.consumeCandidate( processor.consumeCandidate(
unwrappedCandidate as T, dispatchReceiverValue, unwrappedCandidate as T, dispatchReceiverValue,
extensionReceiverValue = extensionReceiver, givenExtensionReceiverOptions,
scope scope
) )
} }
@@ -343,7 +367,7 @@ class ScopeTowerLevel(
empty = false empty = false
processor.consumeCandidate( processor.consumeCandidate(
it, dispatchReceiverValue = null, it, dispatchReceiverValue = null,
extensionReceiverValue = null, givenExtensionReceiverOptions = emptyList(),
scope = scope, scope = scope,
objectsByName = true objectsByName = true
) )
@@ -64,7 +64,7 @@ class FirBuilderInferenceSession(
} }
private fun Candidate.isSuitableForBuilderInference(): Boolean { private fun Candidate.isSuitableForBuilderInference(): Boolean {
val extensionReceiver = extensionReceiverValue val extensionReceiver = chosenExtensionReceiverValue
val dispatchReceiver = dispatchReceiverValue val dispatchReceiver = dispatchReceiverValue
return when { return when {
extensionReceiver == null && dispatchReceiver == null -> false extensionReceiver == null && dispatchReceiver == null -> false
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.builder.buildContextReceiver
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.ResolutionMode
@@ -28,6 +29,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
import org.jetbrains.kotlin.fir.resolve.typeFromCallee import org.jetbrains.kotlin.fir.resolve.typeFromCallee
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -259,6 +261,7 @@ class FirCallCompleter(
override fun analyzeAndGetLambdaReturnArguments( override fun analyzeAndGetLambdaReturnArguments(
lambdaAtom: ResolvedLambdaAtom, lambdaAtom: ResolvedLambdaAtom,
receiverType: ConeKotlinType?, receiverType: ConeKotlinType?,
contextReceivers: List<ConeKotlinType>,
parameters: List<ConeKotlinType>, parameters: List<ConeKotlinType>,
expectedReturnType: ConeKotlinType?, expectedReturnType: ConeKotlinType?,
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>, stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>,
@@ -307,6 +310,18 @@ class FirCallCompleter(
} }
) )
if (contextReceivers.isNotEmpty()) {
lambdaArgument.replaceContextReceivers(
contextReceivers.map { contextReceiverType ->
buildContextReceiver {
typeRef = buildResolvedTypeRef {
type = contextReceiverType
}
}
}
)
}
val lookupTracker = session.lookupTracker val lookupTracker = session.lookupTracker
val fileSource = components.file.source val fileSource = components.file.source
lambdaArgument.valueParameters.forEachIndexed { index, parameter -> lambdaArgument.valueParameters.forEachIndexed { index, parameter ->
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubsti
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode
import org.jetbrains.kotlin.resolve.calls.inference.model.BuilderInferencePosition import org.jetbrains.kotlin.resolve.calls.inference.model.BuilderInferencePosition
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.registerTypeVariableIfNotPresent import org.jetbrains.kotlin.resolve.calls.inference.registerTypeVariableIfNotPresent
@@ -74,7 +73,7 @@ class FirDelegatedPropertyInferenceSession(
if (callee.candidate.system.hasContradiction) return true if (callee.candidate.system.hasContradiction) return true
val hasStubType = val hasStubType =
callee.candidate.extensionReceiverValue?.type?.containsStubType() ?: false callee.candidate.chosenExtensionReceiverValue?.type?.containsStubType() ?: false
|| callee.candidate.dispatchReceiverValue?.type?.containsStubType() ?: false || callee.candidate.dispatchReceiverValue?.type?.containsStubType() ?: false
if (!hasStubType) { if (!hasStubType) {
@@ -51,10 +51,16 @@ fun extractLambdaInfoFromFunctionalType(
// For lambdas, the existence of the receiver is always implied by the expected type, and a value parameter // For lambdas, the existence of the receiver is always implied by the expected type, and a value parameter
// can never fill its role. // can never fill its role.
val receiverType = if (argument.isLambda) expectedType.receiverType(session) else argument.receiverType val receiverType = if (argument.isLambda) expectedType.receiverType(session) else argument.receiverType
val contextReceiversNumber =
if (argument.isLambda) expectedType.contextReceiversNumberForFunctionType else argument.contextReceivers.size
val valueParametersTypesIncludingReceiver = expectedType.valueParameterTypesIncludingReceiver(session) val valueParametersTypesIncludingReceiver = expectedType.valueParameterTypesIncludingReceiver(session)
val isExtensionFunctionType = expectedType.isExtensionFunctionType(session) val isExtensionFunctionType = expectedType.isExtensionFunctionType(session)
val expectedParameters = valueParametersTypesIncludingReceiver.let { val expectedParameters = valueParametersTypesIncludingReceiver.let {
if (receiverType != null && isExtensionFunctionType) it.drop(1) else it val forExtension = if (receiverType != null && isExtensionFunctionType) 1 else 0
val toDrop = forExtension + contextReceiversNumber
if (toDrop > 0) it.drop(toDrop) else it
} }
var coerceFirstParameterToExtensionReceiver = false var coerceFirstParameterToExtensionReceiver = false
@@ -84,11 +90,19 @@ fun extractLambdaInfoFromFunctionalType(
} }
} }
val contextReceivers =
when {
contextReceiversNumber == 0 -> emptyList()
argument.isLambda -> valueParametersTypesIncludingReceiver.subList(0, contextReceiversNumber)
else -> argument.contextReceivers.map { it.typeRef.coneType }
}
return ResolvedLambdaAtom( return ResolvedLambdaAtom(
argument, argument,
expectedType, expectedType,
expectedType.isSuspendFunctionType(session), expectedType.isSuspendFunctionType(session),
receiverType, receiverType,
contextReceivers,
parameters, parameters,
returnType, returnType,
typeVariableForLambdaReturnType = returnTypeVariable, typeVariableForLambdaReturnType = returnTypeVariable,
@@ -66,7 +66,8 @@ fun Candidate.preprocessLambdaArgument(
if (resolvedArgument.coerceFirstParameterToExtensionReceiver) parameters.drop(1) else parameters, if (resolvedArgument.coerceFirstParameterToExtensionReceiver) parameters.drop(1) else parameters,
resolvedArgument.receiver, resolvedArgument.receiver,
resolvedArgument.returnType, resolvedArgument.returnType,
isSuspend = resolvedArgument.isSuspend isSuspend = resolvedArgument.isSuspend,
contextReceivers = resolvedArgument.contextReceivers,
) )
val position = ConeArgumentConstraintPosition(resolvedArgument.atom) val position = ConeArgumentConstraintPosition(resolvedArgument.atom)
@@ -124,6 +125,10 @@ private fun extractLambdaInfo(
it.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: nothingType it.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: nothingType
} }
val contextReceivers = argument.contextReceivers.map {
it.typeRef.coneTypeSafe<ConeKotlinType>() ?: nothingType
}
val newTypeVariableUsed = returnType == typeVariable.defaultType val newTypeVariableUsed = returnType == typeVariable.defaultType
if (newTypeVariableUsed) csBuilder.registerVariable(typeVariable) if (newTypeVariableUsed) csBuilder.registerVariable(typeVariable)
@@ -132,6 +137,7 @@ private fun extractLambdaInfo(
expectedType, expectedType,
isSuspend, isSuspend,
receiverType, receiverType,
contextReceivers,
parameters, parameters,
returnType, returnType,
typeVariable.takeIf { newTypeVariableUsed }, typeVariable.takeIf { newTypeVariableUsed },
@@ -37,6 +37,7 @@ interface LambdaAnalyzer {
fun analyzeAndGetLambdaReturnArguments( fun analyzeAndGetLambdaReturnArguments(
lambdaAtom: ResolvedLambdaAtom, lambdaAtom: ResolvedLambdaAtom,
receiverType: ConeKotlinType?, receiverType: ConeKotlinType?,
contextReceivers: List<ConeKotlinType>,
parameters: List<ConeKotlinType>, parameters: List<ConeKotlinType>,
expectedReturnType: ConeKotlinType?, // null means, that return type is not proper i.e. it depends on some type variables expectedReturnType: ConeKotlinType?, // null means, that return type is not proper i.e. it depends on some type variables
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>, stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>,
@@ -122,6 +123,7 @@ class PostponedArgumentsAnalyzer(
fun substitute(type: ConeKotlinType) = currentSubstitutor.safeSubstitute(c, type) as ConeKotlinType fun substitute(type: ConeKotlinType) = currentSubstitutor.safeSubstitute(c, type) as ConeKotlinType
val receiver = lambda.receiver?.let(::substitute) val receiver = lambda.receiver?.let(::substitute)
val contextReceivers = lambda.contextReceivers.map(::substitute)
val parameters = lambda.parameters.map(::substitute) val parameters = lambda.parameters.map(::substitute)
val rawReturnType = lambda.returnType val rawReturnType = lambda.returnType
@@ -137,6 +139,7 @@ class PostponedArgumentsAnalyzer(
val results = lambdaAnalyzer.analyzeAndGetLambdaReturnArguments( val results = lambdaAnalyzer.analyzeAndGetLambdaReturnArguments(
lambda, lambda,
receiver, receiver,
contextReceivers,
parameters, parameters,
expectedTypeForReturnArguments, expectedTypeForReturnArguments,
stubsForPostponedVariables, stubsForPostponedVariables,
@@ -41,6 +41,7 @@ class ResolvedLambdaAtom(
expectedType: ConeKotlinType?, expectedType: ConeKotlinType?,
val isSuspend: Boolean, val isSuspend: Boolean,
val receiver: ConeKotlinType?, val receiver: ConeKotlinType?,
val contextReceivers: List<ConeKotlinType>,
val parameters: List<ConeKotlinType>, val parameters: List<ConeKotlinType>,
var returnType: ConeKotlinType, var returnType: ConeKotlinType,
typeVariableForLambdaReturnType: ConeTypeVariableForLambdaReturnType?, typeVariableForLambdaReturnType: ConeTypeVariableForLambdaReturnType?,
@@ -467,8 +467,8 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
private fun createFunctionalType(typeRef: FirFunctionTypeRef): ConeClassLikeType { private fun createFunctionalType(typeRef: FirFunctionTypeRef): ConeClassLikeType {
val parameters = val parameters =
listOfNotNull(typeRef.receiverTypeRef?.coneType) + typeRef.contextReceiverTypeRefs.map { it.coneType } +
typeRef.contextReceiverTypeRefs.map { it.coneType } + listOfNotNull(typeRef.receiverTypeRef?.coneType) +
typeRef.valueParameters.map { it.returnTypeRef.coneType.withParameterNameAnnotation(it) } + typeRef.valueParameters.map { it.returnTypeRef.coneType.withParameterNameAnnotation(it) } +
listOf(typeRef.returnTypeRef.coneType) listOf(typeRef.returnTypeRef.coneType)
val classId = if (typeRef.isSuspend) { val classId = if (typeRef.isSuspend) {
@@ -550,7 +550,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
override val dispatchReceiverValue: ReceiverValue? override val dispatchReceiverValue: ReceiverValue?
get() = null get() = null
override val extensionReceiverValue: ReceiverValue? override val chosenExtensionReceiverValue: ReceiverValue?
get() = null get() = null
override val explicitReceiverKind: ExplicitReceiverKind override val explicitReceiverKind: ExplicitReceiverKind
@@ -131,7 +131,7 @@ class FirCallCompletionResultsWriterTransformer(
} }
var dispatchReceiver = subCandidate.dispatchReceiverExpression() var dispatchReceiver = subCandidate.dispatchReceiverExpression()
var extensionReceiver = subCandidate.extensionReceiverExpression() var extensionReceiver = subCandidate.chosenExtensionReceiverExpression()
if (!declaration.isWrappedIntegerOperator()) { if (!declaration.isWrappedIntegerOperator()) {
val expectedDispatchReceiverType = (declaration as? FirCallableDeclaration)?.dispatchReceiverType val expectedDispatchReceiverType = (declaration as? FirCallableDeclaration)?.dispatchReceiverType
val expectedExtensionReceiverType = (declaration as? FirCallableDeclaration)?.receiverTypeRef?.coneType val expectedExtensionReceiverType = (declaration as? FirCallableDeclaration)?.receiverTypeRef?.coneType
@@ -403,7 +403,7 @@ class FirCallCompletionResultsWriterTransformer(
StoreCalleeReference, StoreCalleeReference,
resolvedReference, resolvedReference,
).transformDispatchReceiver(StoreReceiver, subCandidate.dispatchReceiverExpression()) ).transformDispatchReceiver(StoreReceiver, subCandidate.dispatchReceiverExpression())
.transformExtensionReceiver(StoreReceiver, subCandidate.extensionReceiverExpression()) .transformExtensionReceiver(StoreReceiver, subCandidate.chosenExtensionReceiverExpression())
} }
override fun transformVariableAssignment( override fun transformVariableAssignment(
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
import org.jetbrains.kotlin.fir.declarations.utils.isInner import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.declarations.primaryConstructorIfAny
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.*
@@ -228,6 +227,8 @@ class BodyResolveContext(
holder: SessionHolder, holder: SessionHolder,
f: () -> T f: () -> T
): T = withTowerDataCleanup { ): T = withTowerDataCleanup {
replaceTowerDataContext(towerDataContext.addContextReceiverGroup(owner.createContextReceiverValues(holder)))
if (type != null) { if (type != null) {
val receiver = ImplicitExtensionReceiverValue( val receiver = ImplicitExtensionReceiverValue(
owner.symbol, owner.symbol,
@@ -450,6 +451,7 @@ class BodyResolveContext(
val forMembersResolution = val forMembersResolution =
staticsAndCompanion staticsAndCompanion
.addReceiver(labelName, towerElementsForClass.thisReceiver) .addReceiver(labelName, towerElementsForClass.thisReceiver)
.addContextReceiverGroup(towerElementsForClass.contextReceivers)
.addNonLocalScopeIfNotNull(typeParameterScope) .addNonLocalScopeIfNotNull(typeParameterScope)
val scopeForConstructorHeader = val scopeForConstructorHeader =
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunctionCopy import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunctionCopy
import org.jetbrains.kotlin.fir.declarations.builder.buildContextReceiver
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
@@ -34,7 +35,6 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeLocalVariableNoTypeOrIni
import org.jetbrains.kotlin.fir.resolve.inference.FirStubTypeTransformer import org.jetbrains.kotlin.fir.resolve.inference.FirStubTypeTransformer
import org.jetbrains.kotlin.fir.resolve.inference.ResolvedLambdaAtom import org.jetbrains.kotlin.fir.resolve.inference.ResolvedLambdaAtom
import org.jetbrains.kotlin.fir.resolve.inference.extractLambdaInfoFromFunctionalType import org.jetbrains.kotlin.fir.resolve.inference.extractLambdaInfoFromFunctionalType
import org.jetbrains.kotlin.fir.types.isSuspendFunctionType
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor
import org.jetbrains.kotlin.fir.resolve.transformers.* import org.jetbrains.kotlin.fir.resolve.transformers.*
@@ -809,6 +809,19 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
lambda = buildAnonymousFunctionCopy(lambda) { lambda = buildAnonymousFunctionCopy(lambda) {
receiverTypeRef = lambda.receiverTypeRef?.takeIf { it !is FirImplicitTypeRef } receiverTypeRef = lambda.receiverTypeRef?.takeIf { it !is FirImplicitTypeRef }
?: resolvedLambdaAtom?.receiver?.let { lambda.receiverTypeRef?.resolvedTypeFromPrototype(it) } ?: resolvedLambdaAtom?.receiver?.let { lambda.receiverTypeRef?.resolvedTypeFromPrototype(it) }
contextReceivers.clear()
contextReceivers.addAll(
lambda.contextReceivers.takeIf { it.isNotEmpty() }
?: resolvedLambdaAtom?.contextReceivers?.map { receiverType ->
buildContextReceiver {
this.typeRef = buildResolvedTypeRef {
type = receiverType
}
}
}.orEmpty()
)
this.valueParameters.clear() this.valueParameters.clear()
this.valueParameters.addAll(valueParameters) this.valueParameters.addAll(valueParameters)
returnTypeRef = (lambda.returnTypeRef as? FirResolvedTypeRef) returnTypeRef = (lambda.returnTypeRef as? FirResolvedTypeRef)
@@ -8,14 +8,14 @@ package org.jetbrains.kotlin.fir.declarations
import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList import kotlinx.collections.immutable.toPersistentList
import org.jetbrains.kotlin.fir.labelName
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitExtensionReceiverValue
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
import org.jetbrains.kotlin.fir.scopes.impl.wrapNestedClassifierScopeWithSubstitutionForSuperType import org.jetbrains.kotlin.fir.scopes.impl.wrapNestedClassifierScopeWithSubstitutionForSuperType
import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
@@ -23,32 +23,39 @@ fun SessionHolder.collectImplicitReceivers(
type: ConeKotlinType?, type: ConeKotlinType?,
owner: FirDeclaration owner: FirDeclaration
): ImplicitReceivers { ): ImplicitReceivers {
if (type == null) return ImplicitReceivers(null, emptyList())
val implicitCompanionValues = mutableListOf<ImplicitReceiverValue<*>>() val implicitCompanionValues = mutableListOf<ImplicitReceiverValue<*>>()
val contextReceiverValues = mutableListOf<ContextReceiverValue<*>>()
val implicitReceiverValue = when (owner) { val implicitReceiverValue = when (owner) {
is FirClass -> { is FirClass -> {
val towerElementsForClass = collectTowerDataElementsForClass(owner, type) val towerElementsForClass = collectTowerDataElementsForClass(owner, type!!)
implicitCompanionValues.addAll(towerElementsForClass.implicitCompanionValues) implicitCompanionValues.addAll(towerElementsForClass.implicitCompanionValues)
contextReceiverValues.addAll(towerElementsForClass.contextReceivers)
towerElementsForClass.thisReceiver towerElementsForClass.thisReceiver
} }
is FirFunction -> { is FirFunction -> {
ImplicitExtensionReceiverValue(owner.symbol, type, session, scopeSession) contextReceiverValues.addAll(owner.createContextReceiverValues(this))
type?.let { ImplicitExtensionReceiverValue(owner.symbol, type, session, scopeSession) }
} }
is FirVariable -> { is FirVariable -> {
ImplicitExtensionReceiverValue(owner.symbol, type, session, scopeSession) contextReceiverValues.addAll(owner.createContextReceiverValues(this))
type?.let { ImplicitExtensionReceiverValue(owner.symbol, type, session, scopeSession) }
} }
else -> { else -> {
throw IllegalArgumentException("Incorrect label & receiver owner: ${owner.javaClass}") if (type != null) {
throw IllegalArgumentException("Incorrect label & receiver owner: ${owner.javaClass}")
}
null
} }
} }
return ImplicitReceivers(implicitReceiverValue, implicitCompanionValues) return ImplicitReceivers(implicitReceiverValue, implicitCompanionValues, contextReceiverValues)
} }
data class ImplicitReceivers( data class ImplicitReceivers(
val implicitReceiverValue: ImplicitReceiverValue<*>?, val implicitReceiverValue: ImplicitReceiverValue<*>?,
val implicitCompanionValues: List<ImplicitReceiverValue<*>> val implicitCompanionValues: List<ImplicitReceiverValue<*>>,
val contextReceivers: List<ContextReceiverValue<*>>,
) )
fun SessionHolder.collectTowerDataElementsForClass(owner: FirClass, defaultType: ConeKotlinType): TowerElementsForClass { fun SessionHolder.collectTowerDataElementsForClass(owner: FirClass, defaultType: ConeKotlinType): TowerElementsForClass {
@@ -83,9 +90,15 @@ fun SessionHolder.collectTowerDataElementsForClass(owner: FirClass, defaultType:
} }
val thisReceiver = ImplicitDispatchReceiverValue(owner.symbol, defaultType, session, scopeSession) val thisReceiver = ImplicitDispatchReceiverValue(owner.symbol, defaultType, session, scopeSession)
val contextReceivers = (owner as? FirRegularClass)?.contextReceivers?.map {
ContextReceiverValueForClass(
owner.symbol, it.typeRef.coneType, it.labelName, session, scopeSession,
)
}.orEmpty()
return TowerElementsForClass( return TowerElementsForClass(
thisReceiver, thisReceiver,
contextReceivers,
owner.staticScope(this), owner.staticScope(this),
companionReceiver, companionReceiver,
companionObject?.staticScope(this), companionObject?.staticScope(this),
@@ -96,6 +109,7 @@ fun SessionHolder.collectTowerDataElementsForClass(owner: FirClass, defaultType:
class TowerElementsForClass( class TowerElementsForClass(
val thisReceiver: ImplicitReceiverValue<*>, val thisReceiver: ImplicitReceiverValue<*>,
val contextReceivers: List<ContextReceiverValueForClass>,
val staticScope: FirScope?, val staticScope: FirScope?,
val companionReceiver: ImplicitReceiverValue<*>?, val companionReceiver: ImplicitReceiverValue<*>?,
val companionStaticScope: FirScope?, val companionStaticScope: FirScope?,
@@ -137,7 +151,9 @@ class FirTowerDataContext private constructor(
fun addNonLocalTowerDataElements(newElements: List<FirTowerDataElement>): FirTowerDataContext { fun addNonLocalTowerDataElements(newElements: List<FirTowerDataElement>): FirTowerDataContext {
return FirTowerDataContext( return FirTowerDataContext(
towerDataElements.addAll(newElements), towerDataElements.addAll(newElements),
implicitReceiverStack.addAll(newElements.mapNotNull { it.implicitReceiver }), implicitReceiverStack
.addAll(newElements.mapNotNull { it.implicitReceiver })
.addAllContextReceivers(newElements.flatMap { it.contextReceiverGroup.orEmpty() }),
localScopes, localScopes,
nonLocalTowerDataElements.addAll(newElements) nonLocalTowerDataElements.addAll(newElements)
) )
@@ -162,6 +178,18 @@ class FirTowerDataContext private constructor(
) )
} }
fun addContextReceiverGroup(contextReceiverGroup: ContextReceiverGroup): FirTowerDataContext {
if (contextReceiverGroup.isEmpty()) return this
val element = contextReceiverGroup.asTowerDataElement()
return FirTowerDataContext(
towerDataElements.add(element),
contextReceiverGroup.fold(implicitReceiverStack, PersistentImplicitReceiverStack::addContextReceiver),
localScopes,
nonLocalTowerDataElements.add(element)
)
}
fun addNonLocalScopeIfNotNull(scope: FirScope?): FirTowerDataContext { fun addNonLocalScopeIfNotNull(scope: FirScope?): FirTowerDataContext {
if (scope == null) return this if (scope == null) return this
return addNonLocalScope(scope) return addNonLocalScope(scope)
@@ -179,23 +207,47 @@ class FirTowerDataContext private constructor(
fun createSnapshot(): FirTowerDataContext { fun createSnapshot(): FirTowerDataContext {
return FirTowerDataContext( return FirTowerDataContext(
towerDataElements.map { FirTowerDataElement(it.scope, it.implicitReceiver?.createSnapshot(), it.isLocal) }.toPersistentList(), towerDataElements.map(FirTowerDataElement::createSnapshot).toPersistentList(),
implicitReceiverStack.createSnapshot(), implicitReceiverStack.createSnapshot(),
localScopes.toPersistentList(), localScopes.toPersistentList(),
nonLocalTowerDataElements.map { FirTowerDataElement(it.scope, it.implicitReceiver?.createSnapshot(), it.isLocal) } nonLocalTowerDataElements.map(FirTowerDataElement::createSnapshot).toPersistentList()
.toPersistentList()
) )
} }
} }
class FirTowerDataElement(val scope: FirScope?, val implicitReceiver: ImplicitReceiverValue<*>?, val isLocal: Boolean) class FirTowerDataElement(
val scope: FirScope?,
val implicitReceiver: ImplicitReceiverValue<*>?,
val contextReceiverGroup: ContextReceiverGroup? = null,
val isLocal: Boolean,
) {
fun createSnapshot(): FirTowerDataElement =
FirTowerDataElement(
scope,
implicitReceiver?.createSnapshot(),
contextReceiverGroup?.map { it.createSnapshot() },
isLocal,
)
}
fun ImplicitReceiverValue<*>.asTowerDataElement(): FirTowerDataElement = fun ImplicitReceiverValue<*>.asTowerDataElement(): FirTowerDataElement =
FirTowerDataElement(scope = null, this, isLocal = false) FirTowerDataElement(scope = null, implicitReceiver = this, isLocal = false)
fun ContextReceiverGroup.asTowerDataElement(): FirTowerDataElement =
FirTowerDataElement(scope = null, implicitReceiver = null, contextReceiverGroup = this, isLocal = false)
fun FirScope.asTowerDataElement(isLocal: Boolean): FirTowerDataElement = fun FirScope.asTowerDataElement(isLocal: Boolean): FirTowerDataElement =
FirTowerDataElement(this, implicitReceiver = null, isLocal) FirTowerDataElement(scope = this, implicitReceiver = null, isLocal = isLocal)
fun FirClass.staticScope(sessionHolder: SessionHolder) = fun FirClass.staticScope(sessionHolder: SessionHolder) =
scopeProvider.getStaticScope(this, sessionHolder.session, sessionHolder.scopeSession) scopeProvider.getStaticScope(this, sessionHolder.session, sessionHolder.scopeSession)
typealias ContextReceiverGroup = List<ContextReceiverValue<*>>
typealias FirLocalScopes = PersistentList<FirLocalScope> typealias FirLocalScopes = PersistentList<FirLocalScope>
fun FirCallableDeclaration.createContextReceiverValues(
sessionHolder: SessionHolder,
): List<ContextReceiverValueForCallable> =
contextReceivers.map {
ContextReceiverValueForCallable(symbol, it.typeRef.coneType, it.labelName, sessionHolder.session, sessionHolder.scopeSession)
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.resolve package org.jetbrains.kotlin.fir.resolve
import kotlinx.collections.immutable.* import kotlinx.collections.immutable.*
import org.jetbrains.kotlin.fir.resolve.calls.ContextReceiverValue
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
@@ -16,7 +17,7 @@ import org.jetbrains.kotlin.name.Name
class PersistentImplicitReceiverStack private constructor( class PersistentImplicitReceiverStack private constructor(
private val stack: PersistentList<ImplicitReceiverValue<*>>, private val stack: PersistentList<ImplicitReceiverValue<*>>,
// This multi-map holds indexes of the stack ^ // This multi-map holds indexes of the stack ^
private val indexesPerLabel: PersistentSetMultimap<Name, Int>, private val receiversPerLabel: PersistentSetMultimap<Name, ImplicitReceiverValue<*>>,
private val indexesPerSymbol: PersistentMap<FirBasedSymbol<*>, Int>, private val indexesPerSymbol: PersistentMap<FirBasedSymbol<*>, Int>,
private val originalTypes: PersistentList<ConeKotlinType>, private val originalTypes: PersistentList<ConeKotlinType>,
) : ImplicitReceiverStack(), Iterable<ImplicitReceiverValue<*>> { ) : ImplicitReceiverStack(), Iterable<ImplicitReceiverValue<*>> {
@@ -33,16 +34,42 @@ class PersistentImplicitReceiverStack private constructor(
return receivers.fold(this) { acc, value -> acc.add(name = null, value) } return receivers.fold(this) { acc, value -> acc.add(name = null, value) }
} }
fun add(name: Name?, value: ImplicitReceiverValue<*>): PersistentImplicitReceiverStack { fun addAllContextReceivers(receivers: List<ContextReceiverValue<*>>): PersistentImplicitReceiverStack {
return receivers.fold(this) { acc, value -> acc.addContextReceiver(value) }
}
fun add(name: Name?, value: ImplicitReceiverValue<*>, aliasLabel: Name? = null): PersistentImplicitReceiverStack {
val stack = stack.add(value) val stack = stack.add(value)
val originalTypes = originalTypes.add(value.originalType) val originalTypes = originalTypes.add(value.originalType)
val index = stack.size - 1 val index = stack.size - 1
val indexesPerLabel = name?.let { indexesPerLabel.put(it, index) } ?: indexesPerLabel val receiversPerLabel = name?.let { receiversPerLabel.put(it, value) } ?: receiversPerLabel
val indexesPerSymbol = indexesPerSymbol.put(value.boundSymbol, index) val indexesPerSymbol = indexesPerSymbol.put(value.boundSymbol, index)
return PersistentImplicitReceiverStack( return PersistentImplicitReceiverStack(
stack, stack,
indexesPerLabel, receiversPerLabel,
indexesPerSymbol,
originalTypes
)
}
fun addContextReceiver(value: ContextReceiverValue<*>): PersistentImplicitReceiverStack {
val labelName = value.labelName ?: return this
val receiversPerLabel = receiversPerLabel.put(labelName, value)
return PersistentImplicitReceiverStack(
stack,
receiversPerLabel,
indexesPerSymbol,
originalTypes
)
}
fun addReceiverLabelAlias(aliasLabel: Name, value: ImplicitReceiverValue<*>): PersistentImplicitReceiverStack {
val receiversPerLabel = receiversPerLabel.put(aliasLabel, value)
return PersistentImplicitReceiverStack(
stack,
receiversPerLabel,
indexesPerSymbol, indexesPerSymbol,
originalTypes originalTypes
) )
@@ -50,7 +77,7 @@ class PersistentImplicitReceiverStack private constructor(
override operator fun get(name: String?): ImplicitReceiverValue<*>? { override operator fun get(name: String?): ImplicitReceiverValue<*>? {
if (name == null) return stack.lastOrNull() if (name == null) return stack.lastOrNull()
return indexesPerLabel[Name.identifier(name)].lastOrNull()?.let { stack[it] } return receiversPerLabel[Name.identifier(name)].lastOrNull()
} }
override fun lastDispatchReceiver(): ImplicitDispatchReceiverValue? { override fun lastDispatchReceiver(): ImplicitDispatchReceiverValue? {
@@ -85,7 +112,7 @@ class PersistentImplicitReceiverStack private constructor(
fun createSnapshot(): PersistentImplicitReceiverStack { fun createSnapshot(): PersistentImplicitReceiverStack {
return PersistentImplicitReceiverStack( return PersistentImplicitReceiverStack(
stack.map { it.createSnapshot() }.toPersistentList(), stack.map { it.createSnapshot() }.toPersistentList(),
indexesPerLabel, receiversPerLabel,
indexesPerSymbol, indexesPerSymbol,
originalTypes originalTypes
) )
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
abstract class AbstractCandidate { abstract class AbstractCandidate {
abstract val symbol: FirBasedSymbol<*> abstract val symbol: FirBasedSymbol<*>
abstract val dispatchReceiverValue: ReceiverValue? abstract val dispatchReceiverValue: ReceiverValue?
abstract val extensionReceiverValue: ReceiverValue? abstract val chosenExtensionReceiverValue: ReceiverValue?
abstract val explicitReceiverKind: ExplicitReceiverKind abstract val explicitReceiverKind: ExplicitReceiverKind
abstract val callInfo: AbstractCallInfo abstract val callInfo: AbstractCallInfo
abstract val diagnostics: List<ResolutionDiagnostic> abstract val diagnostics: List<ResolutionDiagnostic>
@@ -82,7 +82,8 @@ object LowerPriorityToPreserveCompatibilityDiagnostic : ResolutionDiagnostic(RES
object CandidateChosenUsingOverloadResolutionByLambdaAnnotation : ResolutionDiagnostic(RESOLVED) object CandidateChosenUsingOverloadResolutionByLambdaAnnotation : ResolutionDiagnostic(RESOLVED)
class UnstableSmartCast(val argument: FirExpressionWithSmartcast, val targetType: ConeKotlinType, val isCastToNotNull: Boolean) : ResolutionDiagnostic(UNSTABLE_SMARTCAST) class UnstableSmartCast(val argument: FirExpressionWithSmartcast, val targetType: ConeKotlinType, val isCastToNotNull: Boolean) :
ResolutionDiagnostic(UNSTABLE_SMARTCAST)
class ArgumentTypeMismatch( class ArgumentTypeMismatch(
val expectedType: ConeKotlinType, val expectedType: ConeKotlinType,
@@ -107,4 +108,14 @@ class Unsupported(val message: String, val source: KtSourceElement? = null) : Re
object PropertyAsOperator : ResolutionDiagnostic(PROPERTY_AS_OPERATOR) object PropertyAsOperator : ResolutionDiagnostic(PROPERTY_AS_OPERATOR)
class DslScopeViolation(val calleeSymbol: FirBasedSymbol<*>) : ResolutionDiagnostic(DSL_SCOPE_VIOLATION) class DslScopeViolation(val calleeSymbol: FirBasedSymbol<*>) : ResolutionDiagnostic(DSL_SCOPE_VIOLATION)
class MultipleContextReceiversApplicableForExtensionReceivers : ResolutionDiagnostic(INAPPLICABLE)
class NoApplicableValueForContextReceiver(
val expectedContextReceiverType: ConeKotlinType
) : ResolutionDiagnostic(INAPPLICABLE)
class AmbiguousValuesForContextReceiverParameter(
val expectedContextReceiverType: ConeKotlinType,
) : ResolutionDiagnostic(INAPPLICABLE)
@@ -81,9 +81,9 @@ val FirTypeRef.isMarkedNullable: Boolean?
val FirFunctionTypeRef.parametersCount: Int val FirFunctionTypeRef.parametersCount: Int
get() = if (receiverTypeRef != null) get() = if (receiverTypeRef != null)
valueParameters.size + 1 valueParameters.size + contextReceiverTypeRefs.size + 1
else else
valueParameters.size valueParameters.size + contextReceiverTypeRefs.size
val EXTENSION_FUNCTION_ANNOTATION = ClassId.fromString("kotlin/ExtensionFunctionType") val EXTENSION_FUNCTION_ANNOTATION = ClassId.fromString("kotlin/ExtensionFunctionType")