[FIR] Store expressions of receivers inside candidates instead of ReceiverValue
This is needed because of mutable nature of receiver values: implicit receiver values can be modified because of smartcasts, but in candidate we need to store snapshot of receiver in the form it was at the beginning of the resolution ^KT-58823 Fixed
This commit is contained in:
committed by
Space Team
parent
b564260a33
commit
6409bf2fe8
+4
-4
@@ -447,15 +447,15 @@ 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.dispatchReceiver ?: FirNoReceiverExpression,
|
||||||
candidate.chosenExtensionReceiverValue?.receiverExpression ?: FirNoReceiverExpression,
|
candidate.chosenExtensionReceiver ?: FirNoReceiverExpression,
|
||||||
candidate.explicitReceiverKind
|
candidate.explicitReceiverKind
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
KtPartiallyAppliedSymbol(
|
KtPartiallyAppliedSymbol(
|
||||||
with(analysisSession) { unsubstitutedKtSignature.substitute(substitutor) },
|
with(analysisSession) { unsubstitutedKtSignature.substitute(substitutor) },
|
||||||
candidate.dispatchReceiverValue?.receiverExpression?.toKtReceiverValue(),
|
candidate.dispatchReceiver?.toKtReceiverValue(),
|
||||||
candidate.chosenExtensionReceiverValue?.receiverExpression?.toKtReceiverValue(),
|
candidate.chosenExtensionReceiver?.toKtReceiverValue(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else if (fir is FirImplicitInvokeCall) {
|
} else if (fir is FirImplicitInvokeCall) {
|
||||||
|
|||||||
+1
-3
@@ -57,9 +57,7 @@ internal class KtFirVisibilityChecker(
|
|||||||
|
|
||||||
val dispatchReceiverCanBeExplicit = candidateSymbol is KtCallableSymbol && !candidateSymbol.isExtension
|
val dispatchReceiverCanBeExplicit = candidateSymbol is KtCallableSymbol && !candidateSymbol.isExtension
|
||||||
val explicitDispatchReceiver = runIf(dispatchReceiverCanBeExplicit) {
|
val explicitDispatchReceiver = runIf(dispatchReceiverCanBeExplicit) {
|
||||||
receiverExpression
|
receiverExpression?.getOrBuildFirSafe<FirExpression>(analysisSession.firResolveSession)
|
||||||
?.getOrBuildFirSafe<FirExpression>(analysisSession.firResolveSession)
|
|
||||||
?.let { ExpressionReceiverValue(it) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val candidateFirSymbol = candidateSymbol.firSymbol.fir as FirMemberDeclaration
|
val candidateFirSymbol = candidateSymbol.firSymbol.fir as FirMemberDeclaration
|
||||||
|
|||||||
+3
-3
@@ -53,12 +53,12 @@ class SingleCandidateResolver(
|
|||||||
callInfo,
|
callInfo,
|
||||||
resolutionParameters.callableSymbol,
|
resolutionParameters.callableSymbol,
|
||||||
explicitReceiverKind = explicitReceiverKind,
|
explicitReceiverKind = explicitReceiverKind,
|
||||||
dispatchReceiverValue = dispatchReceiverValue,
|
dispatchReceiver = dispatchReceiverValue?.receiverExpression,
|
||||||
givenExtensionReceiverOptions = listOfNotNull(
|
givenExtensionReceiverOptions = listOfNotNull(
|
||||||
if (explicitReceiverKind.isExtensionReceiver)
|
if (explicitReceiverKind.isExtensionReceiver)
|
||||||
callInfo.explicitReceiver?.let { ExpressionReceiverValue(it) }
|
callInfo.explicitReceiver
|
||||||
else
|
else
|
||||||
implicitExtensionReceiverValue
|
implicitExtensionReceiverValue?.receiverExpression
|
||||||
),
|
),
|
||||||
scope = null,
|
scope = null,
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-2
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
|||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
|
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
|
||||||
import org.jetbrains.kotlin.fir.references.*
|
import org.jetbrains.kotlin.fir.references.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDiagnosticWithCandidates
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDiagnosticWithCandidates
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
||||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||||
@@ -51,7 +50,7 @@ object FirReassignmentAndInvisibleSetterChecker : FirVariableAssignmentChecker()
|
|||||||
context.session,
|
context.session,
|
||||||
context.findClosest()!!,
|
context.findClosest()!!,
|
||||||
context.containingDeclarations,
|
context.containingDeclarations,
|
||||||
ExpressionReceiverValue(expression.dispatchReceiver),
|
expression.dispatchReceiver,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.declarations.FirFile
|
|||||||
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
|
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.resolve.SupertypeSupplier
|
import org.jetbrains.kotlin.fir.resolve.SupertypeSupplier
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirSimpleSyntheticPropertySymbol
|
import org.jetbrains.kotlin.fir.resolve.calls.FirSimpleSyntheticPropertySymbol
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
|
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
|
||||||
@@ -30,7 +31,7 @@ object FirJavaVisibilityChecker : FirVisibilityChecker() {
|
|||||||
symbol: FirBasedSymbol<*>,
|
symbol: FirBasedSymbol<*>,
|
||||||
useSiteFile: FirFile,
|
useSiteFile: FirFile,
|
||||||
containingDeclarations: List<FirDeclaration>,
|
containingDeclarations: List<FirDeclaration>,
|
||||||
dispatchReceiver: ReceiverValue?,
|
dispatchReceiver: FirExpression?,
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
isCallToPropertySetter: Boolean,
|
isCallToPropertySetter: Boolean,
|
||||||
supertypeSupplier: SupertypeSupplier
|
supertypeSupplier: SupertypeSupplier
|
||||||
|
|||||||
@@ -12,13 +12,12 @@ import org.jetbrains.kotlin.fir.declarations.*
|
|||||||
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
|
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
|
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
|
import org.jetbrains.kotlin.fir.expressions.toReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirThisReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.getContainingFile
|
import org.jetbrains.kotlin.fir.resolve.providers.getContainingFile
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||||
@@ -54,7 +53,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
symbol: FirBasedSymbol<*>,
|
symbol: FirBasedSymbol<*>,
|
||||||
useSiteFile: FirFile,
|
useSiteFile: FirFile,
|
||||||
containingDeclarations: List<FirDeclaration>,
|
containingDeclarations: List<FirDeclaration>,
|
||||||
dispatchReceiver: ReceiverValue?,
|
dispatchReceiver: FirExpression?,
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
isCallToPropertySetter: Boolean,
|
isCallToPropertySetter: Boolean,
|
||||||
supertypeSupplier: SupertypeSupplier
|
supertypeSupplier: SupertypeSupplier
|
||||||
@@ -95,7 +94,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
session: FirSession,
|
session: FirSession,
|
||||||
useSiteFile: FirFile,
|
useSiteFile: FirFile,
|
||||||
containingDeclarations: List<FirDeclaration>,
|
containingDeclarations: List<FirDeclaration>,
|
||||||
dispatchReceiver: ReceiverValue?,
|
dispatchReceiver: FirExpression?,
|
||||||
isCallToPropertySetter: Boolean = false,
|
isCallToPropertySetter: Boolean = false,
|
||||||
staticQualifierClassForCallable: FirRegularClass? = null,
|
staticQualifierClassForCallable: FirRegularClass? = null,
|
||||||
// There's no need to check if containing class is visible in case we check if a member might be overridden in a subclass
|
// There's no need to check if containing class is visible in case we check if a member might be overridden in a subclass
|
||||||
@@ -172,16 +171,16 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
|
|
||||||
private fun FirMemberDeclaration.containingNonLocalClass(
|
private fun FirMemberDeclaration.containingNonLocalClass(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
dispatchReceiverValue: ReceiverValue?,
|
dispatchReceiver: FirExpression?,
|
||||||
containingUseSiteDeclarations: List<FirDeclaration>,
|
containingUseSiteDeclarations: List<FirDeclaration>,
|
||||||
supertypeSupplier: SupertypeSupplier
|
supertypeSupplier: SupertypeSupplier
|
||||||
): FirClassLikeDeclaration? {
|
): FirClassLikeDeclaration? {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is FirCallableDeclaration -> {
|
is FirCallableDeclaration -> {
|
||||||
if (dispatchReceiverValue != null) {
|
if (dispatchReceiver != null) {
|
||||||
val baseReceiverType = dispatchReceiverClassTypeOrNull()
|
val baseReceiverType = dispatchReceiverClassTypeOrNull()
|
||||||
if (baseReceiverType != null) {
|
if (baseReceiverType != null) {
|
||||||
dispatchReceiverValue.type.findClassRepresentation(baseReceiverType, session)?.toSymbol(session)?.fir?.let {
|
dispatchReceiver.typeRef.coneType.findClassRepresentation(baseReceiverType, session)?.toSymbol(session)?.fir?.let {
|
||||||
return it
|
return it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,7 +219,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
session: FirSession,
|
session: FirSession,
|
||||||
useSiteFile: FirFile,
|
useSiteFile: FirFile,
|
||||||
containingDeclarations: List<FirDeclaration>,
|
containingDeclarations: List<FirDeclaration>,
|
||||||
dispatchReceiver: ReceiverValue?,
|
dispatchReceiver: FirExpression?,
|
||||||
isCallToPropertySetter: Boolean = false,
|
isCallToPropertySetter: Boolean = false,
|
||||||
supertypeSupplier: SupertypeSupplier
|
supertypeSupplier: SupertypeSupplier
|
||||||
): Boolean {
|
): Boolean {
|
||||||
@@ -288,7 +287,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
symbol: FirBasedSymbol<*>,
|
symbol: FirBasedSymbol<*>,
|
||||||
useSiteFile: FirFile,
|
useSiteFile: FirFile,
|
||||||
containingDeclarations: List<FirDeclaration>,
|
containingDeclarations: List<FirDeclaration>,
|
||||||
dispatchReceiver: ReceiverValue?,
|
dispatchReceiver: FirExpression?,
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
isCallToPropertySetter: Boolean,
|
isCallToPropertySetter: Boolean,
|
||||||
supertypeSupplier: SupertypeSupplier
|
supertypeSupplier: SupertypeSupplier
|
||||||
@@ -304,7 +303,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
symbol: FirBasedSymbol<*>,
|
symbol: FirBasedSymbol<*>,
|
||||||
containingDeclarationOfUseSite: List<FirDeclaration>,
|
containingDeclarationOfUseSite: List<FirDeclaration>,
|
||||||
ownerLookupTag: ConeClassLikeLookupTag,
|
ownerLookupTag: ConeClassLikeLookupTag,
|
||||||
dispatchReceiver: ReceiverValue?,
|
dispatchReceiver: FirExpression?,
|
||||||
isVariableOrNamedFunction: Boolean,
|
isVariableOrNamedFunction: Boolean,
|
||||||
session: FirSession
|
session: FirSession
|
||||||
): Boolean {
|
): Boolean {
|
||||||
@@ -332,7 +331,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
|
|
||||||
val dispatchReceiverParameterClassLookupTag = dispatchReceiverParameterClassSymbol.toLookupTag()
|
val dispatchReceiverParameterClassLookupTag = dispatchReceiverParameterClassSymbol.toLookupTag()
|
||||||
val dispatchReceiverValueOwnerLookupTag =
|
val dispatchReceiverValueOwnerLookupTag =
|
||||||
dispatchReceiver.type.findClassRepresentation(
|
dispatchReceiver.typeRef.coneType.findClassRepresentation(
|
||||||
dispatchReceiverParameterClassLookupTag.constructClassType(
|
dispatchReceiverParameterClassLookupTag.constructClassType(
|
||||||
Array(dispatchReceiverParameterClassSymbol.fir.typeParameters.size) { ConeStarProjection },
|
Array(dispatchReceiverParameterClassSymbol.fir.typeParameters.size) { ConeStarProjection },
|
||||||
isNullable = true
|
isNullable = true
|
||||||
@@ -342,21 +341,13 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
|
|
||||||
if (dispatchReceiverParameterClassLookupTag != dispatchReceiverValueOwnerLookupTag) return false
|
if (dispatchReceiverParameterClassLookupTag != dispatchReceiverValueOwnerLookupTag) return false
|
||||||
if (fir.visibility == Visibilities.PrivateToThis) {
|
if (fir.visibility == Visibilities.PrivateToThis) {
|
||||||
when (dispatchReceiver) {
|
when (val dispatchReceiverReference = dispatchReceiver.toReference()) {
|
||||||
is ExpressionReceiverValue -> {
|
is FirThisReference -> {
|
||||||
val explicitReceiver = dispatchReceiver.explicitReceiver
|
if (dispatchReceiverReference.boundSymbol != dispatchReceiverParameterClassSymbol) {
|
||||||
if (explicitReceiver !is FirThisReceiverExpression) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (explicitReceiver.calleeReference.boundSymbol != dispatchReceiverParameterClassSymbol) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is ImplicitReceiverValue<*> -> {
|
|
||||||
if (dispatchReceiver.boundSymbol != dispatchReceiverParameterClassSymbol) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else -> return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -385,7 +376,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
|
|
||||||
private fun canSeeProtectedMemberOf(
|
private fun canSeeProtectedMemberOf(
|
||||||
containingUseSiteClass: FirClass,
|
containingUseSiteClass: FirClass,
|
||||||
dispatchReceiver: ReceiverValue?,
|
dispatchReceiver: FirExpression?,
|
||||||
ownerLookupTag: ConeClassLikeLookupTag,
|
ownerLookupTag: ConeClassLikeLookupTag,
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
isVariableOrNamedFunction: Boolean,
|
isVariableOrNamedFunction: Boolean,
|
||||||
@@ -410,20 +401,17 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun doesReceiverFitForProtectedVisibility(
|
private fun doesReceiverFitForProtectedVisibility(
|
||||||
dispatchReceiver: ReceiverValue?,
|
dispatchReceiver: FirExpression?,
|
||||||
containingUseSiteClass: FirClass,
|
containingUseSiteClass: FirClass,
|
||||||
ownerLookupTag: ConeClassLikeLookupTag,
|
ownerLookupTag: ConeClassLikeLookupTag,
|
||||||
isSyntheticProperty: Boolean,
|
isSyntheticProperty: Boolean,
|
||||||
session: FirSession
|
session: FirSession
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (dispatchReceiver == null) return true
|
if (dispatchReceiver == null) return true
|
||||||
var dispatchReceiverType = dispatchReceiver.type
|
var dispatchReceiverType = dispatchReceiver.typeRef.coneType
|
||||||
if (dispatchReceiver is ExpressionReceiverValue) {
|
if (dispatchReceiver is FirPropertyAccessExpression && dispatchReceiver.calleeReference is FirSuperReference) {
|
||||||
val explicitReceiver = dispatchReceiver.explicitReceiver
|
// Special 'super' case: type of this, not of super, should be taken for the check below
|
||||||
if (explicitReceiver is FirPropertyAccessExpression && explicitReceiver.calleeReference is FirSuperReference) {
|
dispatchReceiverType = dispatchReceiver.dispatchReceiver.typeRef.coneType
|
||||||
// Special 'super' case: type of this, not of super, should be taken for the check below
|
|
||||||
dispatchReceiverType = explicitReceiver.dispatchReceiver.typeRef.coneType
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val typeCheckerState = session.typeContext.newTypeCheckerState(
|
val typeCheckerState = session.typeContext.newTypeCheckerState(
|
||||||
errorTypesEqualToAnything = false,
|
errorTypesEqualToAnything = false,
|
||||||
@@ -448,8 +436,9 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ReceiverValue?.ownerIfCompanion(session: FirSession): ConeClassLikeLookupTag? =
|
private fun FirExpression?.ownerIfCompanion(session: FirSession): ConeClassLikeLookupTag? =
|
||||||
(this?.type as? ConeClassLikeType)?.lookupTag?.ownerIfCompanion(session)
|
// TODO: what if there is an intersection type from smartcast?
|
||||||
|
(this?.typeRef?.coneType as? ConeClassLikeType)?.lookupTag?.ownerIfCompanion(session)
|
||||||
|
|
||||||
// monitorEnter/monitorExit are the only functions which are accessed "illegally" (see kotlin/util/Synchronized.kt).
|
// monitorEnter/monitorExit are the only functions which are accessed "illegally" (see kotlin/util/Synchronized.kt).
|
||||||
// Since they are intrinsified in the codegen, FIR should treat it as visible.
|
// Since they are intrinsified in the codegen, FIR should treat it as visible.
|
||||||
@@ -464,7 +453,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
protected fun canSeeProtectedMemberOf(
|
protected fun canSeeProtectedMemberOf(
|
||||||
usedSymbol: FirBasedSymbol<*>,
|
usedSymbol: FirBasedSymbol<*>,
|
||||||
containingDeclarationOfUseSite: List<FirDeclaration>,
|
containingDeclarationOfUseSite: List<FirDeclaration>,
|
||||||
dispatchReceiver: ReceiverValue?,
|
dispatchReceiver: FirExpression?,
|
||||||
ownerLookupTag: ConeClassLikeLookupTag,
|
ownerLookupTag: ConeClassLikeLookupTag,
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
isVariableOrNamedFunction: Boolean,
|
isVariableOrNamedFunction: Boolean,
|
||||||
|
|||||||
@@ -36,9 +36,7 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
import org.jetbrains.kotlin.types.SmartcastStability
|
import org.jetbrains.kotlin.types.SmartcastStability
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
|
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
|
||||||
|
|
||||||
interface Receiver
|
interface ReceiverValue {
|
||||||
|
|
||||||
interface ReceiverValue : Receiver {
|
|
||||||
val type: ConeKotlinType
|
val type: ConeKotlinType
|
||||||
|
|
||||||
val receiverExpression: FirExpression
|
val receiverExpression: FirExpression
|
||||||
@@ -51,8 +49,7 @@ interface ReceiverValue : Receiver {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should inherit just Receiver, not ReceiverValue
|
abstract class AbstractExplicitReceiver<E : FirExpression> {
|
||||||
abstract class AbstractExplicitReceiver<E : FirExpression> : Receiver {
|
|
||||||
abstract val explicitReceiver: FirExpression
|
abstract val explicitReceiver: FirExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,11 +59,11 @@ abstract class AbstractExplicitReceiverValue<E : FirExpression> : AbstractExplic
|
|||||||
get() = explicitReceiver.typeRef.coneTypeSafe()
|
get() = explicitReceiver.typeRef.coneTypeSafe()
|
||||||
?: ConeErrorType(ConeIntermediateDiagnostic("No type calculated for: ${explicitReceiver.renderWithType()}")) // TODO: assert here
|
?: ConeErrorType(ConeIntermediateDiagnostic("No type calculated for: ${explicitReceiver.renderWithType()}")) // TODO: assert here
|
||||||
|
|
||||||
override val receiverExpression: FirExpression
|
final override val receiverExpression: FirExpression
|
||||||
get() = explicitReceiver
|
get() = explicitReceiver
|
||||||
}
|
}
|
||||||
|
|
||||||
open class ExpressionReceiverValue(
|
class ExpressionReceiverValue(
|
||||||
override val explicitReceiver: FirExpression
|
override val explicitReceiver: FirExpression
|
||||||
) : AbstractExplicitReceiverValue<FirExpression>(), ReceiverValue {
|
) : AbstractExplicitReceiverValue<FirExpression>(), ReceiverValue {
|
||||||
override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirTypeScope? {
|
override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirTypeScope? {
|
||||||
@@ -121,10 +118,46 @@ sealed class ImplicitReceiverValue<S : FirBasedSymbol<*>>(
|
|||||||
|
|
||||||
override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirTypeScope? = implicitScope
|
override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirTypeScope? = implicitScope
|
||||||
|
|
||||||
private val originalReceiverExpression: FirExpression =
|
private var receiverIsSmartcasted: Boolean = false
|
||||||
|
private var originalReceiverExpression: FirExpression =
|
||||||
receiverExpression(boundSymbol, type, contextReceiverNumber, inaccessibleReceiver)
|
receiverExpression(boundSymbol, type, contextReceiverNumber, inaccessibleReceiver)
|
||||||
final override var receiverExpression: FirExpression = originalReceiverExpression
|
private var _receiverExpression: FirExpression? = null
|
||||||
private set
|
|
||||||
|
private fun computeReceiverExpression(): FirExpression {
|
||||||
|
_receiverExpression?.let { return it }
|
||||||
|
val actualReceiverExpression = if (receiverIsSmartcasted) {
|
||||||
|
buildSmartCastExpression {
|
||||||
|
originalExpression = originalReceiverExpression
|
||||||
|
this.source = originalExpression.source?.fakeElement(KtFakeSourceElementKind.SmartCastExpression)
|
||||||
|
smartcastType = buildResolvedTypeRef {
|
||||||
|
source = originalReceiverExpression.typeRef.source?.fakeElement(KtFakeSourceElementKind.SmartCastedTypeRef)
|
||||||
|
type = this@ImplicitReceiverValue.type
|
||||||
|
}
|
||||||
|
typesFromSmartCast = listOf(type)
|
||||||
|
smartcastStability = SmartcastStability.STABLE_VALUE
|
||||||
|
typeRef = smartcastType.copyWithNewSourceKind(KtFakeSourceElementKind.ImplicitTypeRef)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
originalReceiverExpression
|
||||||
|
}
|
||||||
|
_receiverExpression = actualReceiverExpression
|
||||||
|
return actualReceiverExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The idea of receiver expression for implicit receivers is following:
|
||||||
|
* - Implicit receivers are mutable because of smartcasts
|
||||||
|
* - Expression of implicit receiver may be used during call resolution and then stored for later. This implies necesserity
|
||||||
|
* to keep receiver expression independent of state of corresponding implicit value
|
||||||
|
* - In the same time we don't want to create new receiver expression for each access in sake of performance
|
||||||
|
* All those statements lead to the current implementation:
|
||||||
|
* - original receiver expression (without smartcast) always stored inside receiver value and can not be changed (TODO: except builder inference)
|
||||||
|
* - we keep information about was there smartcast or not in [receiverIsSmartcasted] field
|
||||||
|
* - we cache computed receiver expression in [_receiverExpression] field
|
||||||
|
* - if type of receiver value was changed this cache is dropped
|
||||||
|
*/
|
||||||
|
final override val receiverExpression: FirExpression
|
||||||
|
get() = computeReceiverExpression()
|
||||||
|
|
||||||
@RequiresOptIn
|
@RequiresOptIn
|
||||||
annotation class ImplicitReceiverInternals
|
annotation class ImplicitReceiverInternals
|
||||||
@@ -132,7 +165,8 @@ sealed class ImplicitReceiverValue<S : FirBasedSymbol<*>>(
|
|||||||
@Deprecated(level = DeprecationLevel.ERROR, message = "Builder inference should not modify implicit receivers. KT-54708")
|
@Deprecated(level = DeprecationLevel.ERROR, message = "Builder inference should not modify implicit receivers. KT-54708")
|
||||||
fun updateTypeInBuilderInference(type: ConeKotlinType) {
|
fun updateTypeInBuilderInference(type: ConeKotlinType) {
|
||||||
this.type = type
|
this.type = type
|
||||||
receiverExpression = receiverExpression(boundSymbol, type, contextReceiverNumber, inaccessibleReceiver)
|
originalReceiverExpression = receiverExpression(boundSymbol, type, contextReceiverNumber, inaccessibleReceiver)
|
||||||
|
_receiverExpression = null
|
||||||
implicitScope = type.scope(
|
implicitScope = type.scope(
|
||||||
useSiteSession = useSiteSession,
|
useSiteSession = useSiteSession,
|
||||||
scopeSession = scopeSession,
|
scopeSession = scopeSession,
|
||||||
@@ -147,24 +181,10 @@ sealed class ImplicitReceiverValue<S : FirBasedSymbol<*>>(
|
|||||||
@ImplicitReceiverInternals
|
@ImplicitReceiverInternals
|
||||||
fun updateTypeFromSmartcast(type: ConeKotlinType) {
|
fun updateTypeFromSmartcast(type: ConeKotlinType) {
|
||||||
if (type == this.type) return
|
if (type == this.type) return
|
||||||
if (!mutable) throw IllegalStateException("Cannot mutate an immutable ImplicitReceiverValue")
|
if (!mutable) error("Cannot mutate an immutable ImplicitReceiverValue")
|
||||||
this.type = type
|
this.type = type
|
||||||
receiverExpression = if (type == originalReceiverExpression.typeRef.coneType) {
|
receiverIsSmartcasted = type != this.originalType
|
||||||
originalReceiverExpression
|
_receiverExpression = null
|
||||||
} else {
|
|
||||||
buildSmartCastExpression {
|
|
||||||
originalExpression = originalReceiverExpression
|
|
||||||
this.source = originalExpression.source?.fakeElement(KtFakeSourceElementKind.SmartCastExpression)
|
|
||||||
smartcastType = buildResolvedTypeRef {
|
|
||||||
source = originalReceiverExpression.typeRef.source?.fakeElement(KtFakeSourceElementKind.SmartCastedTypeRef)
|
|
||||||
this.type = type
|
|
||||||
}
|
|
||||||
typesFromSmartCast = listOf(type)
|
|
||||||
smartcastStability = SmartcastStability.STABLE_VALUE
|
|
||||||
typeRef = smartcastType.copyWithNewSourceKind(KtFakeSourceElementKind.ImplicitTypeRef)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
implicitScope = type.scope(
|
implicitScope = type.scope(
|
||||||
useSiteSession = useSiteSession,
|
useSiteSession = useSiteSession,
|
||||||
scopeSession = scopeSession,
|
scopeSession = scopeSession,
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ class Candidate(
|
|||||||
// - in case a use-site receiver is explicit
|
// - in case a use-site receiver is explicit
|
||||||
// - in some cases with static entities, no matter is a use-site receiver explicit or not
|
// - in some cases with static entities, no matter is a use-site receiver explicit or not
|
||||||
// OR we may have here a kind of ImplicitReceiverValue (non-statics only)
|
// OR we may have here a kind of ImplicitReceiverValue (non-statics only)
|
||||||
override var dispatchReceiverValue: ReceiverValue?,
|
override var dispatchReceiver: FirExpression?,
|
||||||
// In most cases, it contains zero or single element
|
// In most cases, it contains zero or single element
|
||||||
// More than one, only in case of context receiver group
|
// More than one, only in case of context receiver group
|
||||||
val givenExtensionReceiverOptions: List<ReceiverValue>,
|
val givenExtensionReceiverOptions: List<FirExpression>,
|
||||||
override val explicitReceiverKind: ExplicitReceiverKind,
|
override val explicitReceiverKind: ExplicitReceiverKind,
|
||||||
private val constraintSystemFactory: InferenceComponents.ConstraintSystemFactory,
|
private val constraintSystemFactory: InferenceComponents.ConstraintSystemFactory,
|
||||||
private val baseSystem: ConstraintStorage,
|
private val baseSystem: ConstraintStorage,
|
||||||
@@ -44,7 +44,7 @@ class Candidate(
|
|||||||
val isFromOriginalTypeInPresenceOfSmartCast: Boolean = false,
|
val isFromOriginalTypeInPresenceOfSmartCast: Boolean = false,
|
||||||
) : AbstractCandidate() {
|
) : AbstractCandidate() {
|
||||||
|
|
||||||
var systemInitialized: Boolean = false
|
private var systemInitialized: Boolean = false
|
||||||
val system: NewConstraintSystemImpl by lazy(LazyThreadSafetyMode.NONE) {
|
val system: NewConstraintSystemImpl by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
val system = constraintSystemFactory.createConstraintSystem()
|
val system = constraintSystemFactory.createConstraintSystem()
|
||||||
system.addOtherSystem(baseSystem)
|
system.addOtherSystem(baseSystem)
|
||||||
@@ -80,7 +80,7 @@ class Candidate(
|
|||||||
var currentApplicability = CandidateApplicability.RESOLVED
|
var currentApplicability = CandidateApplicability.RESOLVED
|
||||||
private set
|
private set
|
||||||
|
|
||||||
override var chosenExtensionReceiverValue: ReceiverValue? = givenExtensionReceiverOptions.singleOrNull()
|
override var chosenExtensionReceiver: FirExpression? = givenExtensionReceiverOptions.singleOrNull()
|
||||||
|
|
||||||
var contextReceiverArguments: List<FirExpression>? = null
|
var contextReceiverArguments: List<FirExpression>? = null
|
||||||
|
|
||||||
@@ -103,11 +103,13 @@ class Candidate(
|
|||||||
|
|
||||||
var passedStages: Int = 0
|
var passedStages: Int = 0
|
||||||
|
|
||||||
|
// FirExpressionStub can be located here in case of callable reference resolution
|
||||||
fun dispatchReceiverExpression(): FirExpression =
|
fun dispatchReceiverExpression(): FirExpression =
|
||||||
dispatchReceiverValue?.receiverExpression?.takeIf { it !is FirExpressionStub } ?: FirNoReceiverExpression
|
dispatchReceiver?.takeIf { it !is FirExpressionStub } ?: FirNoReceiverExpression
|
||||||
|
|
||||||
|
// FirExpressionStub can be located here in case of callable reference resolution
|
||||||
fun chosenExtensionReceiverExpression(): FirExpression =
|
fun chosenExtensionReceiverExpression(): FirExpression =
|
||||||
chosenExtensionReceiverValue?.receiverExpression?.takeIf { it !is FirExpressionStub } ?: FirNoReceiverExpression
|
chosenExtensionReceiver?.takeIf { it !is FirExpressionStub } ?: FirNoReceiverExpression
|
||||||
|
|
||||||
fun contextReceiverArguments(): List<FirExpression> =
|
fun contextReceiverArguments(): List<FirExpression> =
|
||||||
contextReceiverArguments ?: emptyList()
|
contextReceiverArguments ?: emptyList()
|
||||||
|
|||||||
+12
-7
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.originalForWrappedIntegerOperator
|
|||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.classId
|
import org.jetbrains.kotlin.fir.types.classId
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzerContext
|
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzerContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
@@ -54,8 +55,8 @@ class CandidateFactory private constructor(
|
|||||||
symbol: FirBasedSymbol<*>,
|
symbol: FirBasedSymbol<*>,
|
||||||
explicitReceiverKind: ExplicitReceiverKind,
|
explicitReceiverKind: ExplicitReceiverKind,
|
||||||
scope: FirScope?,
|
scope: FirScope?,
|
||||||
dispatchReceiverValue: ReceiverValue? = null,
|
dispatchReceiver: FirExpression? = null,
|
||||||
givenExtensionReceiverOptions: List<ReceiverValue> = emptyList(),
|
givenExtensionReceiverOptions: List<FirExpression> = emptyList(),
|
||||||
objectsByName: Boolean = false,
|
objectsByName: Boolean = false,
|
||||||
isFromOriginalTypeInPresenceOfSmartCast: Boolean = false,
|
isFromOriginalTypeInPresenceOfSmartCast: Boolean = false,
|
||||||
): Candidate {
|
): Candidate {
|
||||||
@@ -64,7 +65,7 @@ class CandidateFactory private constructor(
|
|||||||
|
|
||||||
val result = Candidate(
|
val result = Candidate(
|
||||||
symbol,
|
symbol,
|
||||||
dispatchReceiverValue,
|
dispatchReceiver,
|
||||||
givenExtensionReceiverOptions,
|
givenExtensionReceiverOptions,
|
||||||
explicitReceiverKind,
|
explicitReceiverKind,
|
||||||
context.inferenceComponents.constraintSystemFactory,
|
context.inferenceComponents.constraintSystemFactory,
|
||||||
@@ -74,7 +75,7 @@ class CandidateFactory private constructor(
|
|||||||
isFromCompanionObjectTypeScope = when (explicitReceiverKind) {
|
isFromCompanionObjectTypeScope = when (explicitReceiverKind) {
|
||||||
ExplicitReceiverKind.EXTENSION_RECEIVER ->
|
ExplicitReceiverKind.EXTENSION_RECEIVER ->
|
||||||
givenExtensionReceiverOptions.singleOrNull().isCandidateFromCompanionObjectTypeScope()
|
givenExtensionReceiverOptions.singleOrNull().isCandidateFromCompanionObjectTypeScope()
|
||||||
ExplicitReceiverKind.DISPATCH_RECEIVER -> dispatchReceiverValue.isCandidateFromCompanionObjectTypeScope()
|
ExplicitReceiverKind.DISPATCH_RECEIVER -> dispatchReceiver.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
|
||||||
},
|
},
|
||||||
@@ -117,8 +118,12 @@ class CandidateFactory private constructor(
|
|||||||
|
|
||||||
private fun ReceiverValue?.isCandidateFromCompanionObjectTypeScope(): Boolean {
|
private fun ReceiverValue?.isCandidateFromCompanionObjectTypeScope(): Boolean {
|
||||||
val expressionReceiverValue = this as? ExpressionReceiverValue ?: return false
|
val expressionReceiverValue = this as? ExpressionReceiverValue ?: return false
|
||||||
val resolvedQualifier = (expressionReceiverValue.explicitReceiver as? FirResolvedQualifier) ?: return false
|
return expressionReceiverValue.explicitReceiver.isCandidateFromCompanionObjectTypeScope()
|
||||||
val originClassOfCandidate = expressionReceiverValue.type.classId ?: return false
|
}
|
||||||
|
|
||||||
|
private fun FirExpression?.isCandidateFromCompanionObjectTypeScope(): Boolean {
|
||||||
|
val resolvedQualifier = this as? FirResolvedQualifier ?: return false
|
||||||
|
val originClassOfCandidate = this.typeRef.coneType.classId ?: return false
|
||||||
return (resolvedQualifier.symbol?.fir as? FirRegularClass)?.companionObjectSymbol?.classId == originClassOfCandidate
|
return (resolvedQualifier.symbol?.fir as? FirRegularClass)?.companionObjectSymbol?.classId == originClassOfCandidate
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +139,7 @@ class CandidateFactory private constructor(
|
|||||||
}
|
}
|
||||||
return Candidate(
|
return Candidate(
|
||||||
symbol,
|
symbol,
|
||||||
dispatchReceiverValue = null,
|
dispatchReceiver = null,
|
||||||
givenExtensionReceiverOptions = emptyList(),
|
givenExtensionReceiverOptions = emptyList(),
|
||||||
explicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
explicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||||
context.inferenceComponents.constraintSystemFactory,
|
context.inferenceComponents.constraintSystemFactory,
|
||||||
|
|||||||
+41
-27
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.expressions.*
|
|||||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.fir.matchingParameterFunctionType
|
import org.jetbrains.kotlin.fir.matchingParameterFunctionType
|
||||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirThisReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.directExpansionType
|
import org.jetbrains.kotlin.fir.resolve.directExpansionType
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable
|
import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable
|
||||||
@@ -25,10 +26,8 @@ import org.jetbrains.kotlin.fir.resolve.inference.csBuilder
|
|||||||
import org.jetbrains.kotlin.fir.resolve.inference.hasBuilderInferenceAnnotation
|
import org.jetbrains.kotlin.fir.resolve.inference.hasBuilderInferenceAnnotation
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExplicitTypeParameterConstraintPosition
|
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExplicitTypeParameterConstraintPosition
|
||||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
import org.jetbrains.kotlin.fir.scopes.*
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirUnstableSmartcastTypeScope
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
|
||||||
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
|
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||||
@@ -135,17 +134,17 @@ object CheckExtensionReceiver : ResolutionStage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun Candidate.prepareReceivers(
|
private fun Candidate.prepareReceivers(
|
||||||
argumentExtensionReceiverValue: ReceiverValue,
|
argumentExtensionReceiver: FirExpression,
|
||||||
expectedType: ConeKotlinType,
|
expectedType: ConeKotlinType,
|
||||||
context: ResolutionContext,
|
context: ResolutionContext,
|
||||||
): ReceiverDescription {
|
): ReceiverDescription {
|
||||||
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(
|
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(
|
||||||
argumentType = argumentExtensionReceiverValue.type,
|
argumentType = argumentExtensionReceiver.typeRef.coneType,
|
||||||
expectedType = expectedType,
|
expectedType = expectedType,
|
||||||
session = context.session
|
session = context.session
|
||||||
).let { prepareCapturedType(it, context) }
|
).let { prepareCapturedType(it, context) }
|
||||||
|
|
||||||
return ReceiverDescription(argumentExtensionReceiverValue.receiverExpression, argumentType)
|
return ReceiverDescription(argumentExtensionReceiver, argumentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ReceiverDescription(
|
private class ReceiverDescription(
|
||||||
@@ -163,7 +162,7 @@ object CheckDispatchReceiver : ResolutionStage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val dispatchReceiverValueType = candidate.dispatchReceiverValue?.type ?: return
|
val dispatchReceiverValueType = candidate.dispatchReceiver?.typeRef?.coneType ?: return
|
||||||
val isReceiverNullable = !AbstractNullabilityChecker.isSubtypeOfAny(context.session.typeContext, dispatchReceiverValueType)
|
val isReceiverNullable = !AbstractNullabilityChecker.isSubtypeOfAny(context.session.typeContext, dispatchReceiverValueType)
|
||||||
|
|
||||||
val isCandidateFromUnstableSmartcast =
|
val isCandidateFromUnstableSmartcast =
|
||||||
@@ -205,9 +204,10 @@ object CheckContextReceivers : ResolutionStage() {
|
|||||||
candidate.substitutor.substituteOrSelf(it.typeRef.coneType)
|
candidate.substitutor.substituteOrSelf(it.typeRef.coneType)
|
||||||
}?.takeUnless { it.isEmpty() } ?: return
|
}?.takeUnless { it.isEmpty() } ?: return
|
||||||
|
|
||||||
val receiverGroups: List<List<ImplicitReceiverValue<*>>> =
|
val receiverGroups: List<List<FirExpression>> =
|
||||||
context.bodyResolveContext.towerDataContext.towerDataElements.asReversed().mapNotNull { towerDataElement ->
|
context.bodyResolveContext.towerDataContext.towerDataElements.asReversed().mapNotNull { towerDataElement ->
|
||||||
towerDataElement.implicitReceiver?.let(::listOf) ?: towerDataElement.contextReceiverGroup
|
towerDataElement.implicitReceiver?.receiverExpression?.let(::listOf)
|
||||||
|
?: towerDataElement.contextReceiverGroup?.map { it.receiverExpression }
|
||||||
}
|
}
|
||||||
|
|
||||||
val resultingContextReceiverArguments = mutableListOf<FirExpression>()
|
val resultingContextReceiverArguments = mutableListOf<FirExpression>()
|
||||||
@@ -236,7 +236,7 @@ object CheckContextReceivers : ResolutionStage() {
|
|||||||
|
|
||||||
private fun Candidate.findClosestMatchingReceivers(
|
private fun Candidate.findClosestMatchingReceivers(
|
||||||
expectedType: ConeKotlinType,
|
expectedType: ConeKotlinType,
|
||||||
receiverGroups: List<List<ImplicitReceiverValue<*>>>,
|
receiverGroups: List<List<FirExpression>>,
|
||||||
context: ResolutionContext,
|
context: ResolutionContext,
|
||||||
): List<ReceiverDescription> {
|
): List<ReceiverDescription> {
|
||||||
for (receiverGroup in receiverGroups) {
|
for (receiverGroup in receiverGroups) {
|
||||||
@@ -259,18 +259,24 @@ object CheckDslScopeViolation : ResolutionStage() {
|
|||||||
private val dslMarkerClassId = ClassId.fromString("kotlin/DslMarker")
|
private val dslMarkerClassId = ClassId.fromString("kotlin/DslMarker")
|
||||||
|
|
||||||
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
|
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
|
||||||
fun checkReceiverValue(receiverValue: ReceiverValue?) {
|
fun checkReceiver(receiver: FirExpression?) {
|
||||||
if (receiverValue is ImplicitReceiverValue<*>) {
|
val thisReference = receiver?.toReference() as? FirThisReference ?: return
|
||||||
receiverValue.checkImpl(
|
if (thisReference.isImplicit) {
|
||||||
|
checkImpl(
|
||||||
candidate,
|
candidate,
|
||||||
sink,
|
sink,
|
||||||
context,
|
context,
|
||||||
{ receiverValue.getDslMarkersOfImplicitReceiver(context) }
|
{ getDslMarkersOfImplicitReceiver(thisReference.boundSymbol, receiver.typeRef.coneType, context) }
|
||||||
) { a, b -> a == b }
|
) {
|
||||||
|
// TODO: is there better alternative?
|
||||||
|
// Here we rely on the fact that receiver expression of implicit receiver value can not be changed
|
||||||
|
// during resolution of one single call
|
||||||
|
it.receiverExpression == receiver
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkReceiverValue(candidate.dispatchReceiverValue)
|
checkReceiver(candidate.dispatchReceiver)
|
||||||
checkReceiverValue(candidate.chosenExtensionReceiverValue)
|
checkReceiver(candidate.chosenExtensionReceiver)
|
||||||
|
|
||||||
// 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.
|
||||||
@@ -299,31 +305,31 @@ object CheckDslScopeViolation : ResolutionStage() {
|
|||||||
// ```
|
// ```
|
||||||
// `useX()` is a call to `invoke` with `useX` as the dispatch receiver. In the FIR tree, extension receiver is represented as an
|
// `useX()` is a call to `invoke` with `useX` as the dispatch receiver. In the FIR tree, extension receiver is represented as an
|
||||||
// implicit `this` expression passed as the first argument.
|
// implicit `this` expression passed as the first argument.
|
||||||
if (candidate.dispatchReceiverValue?.type?.fullyExpandedType(context.session)?.isSomeFunctionType(context.session) == true &&
|
if (candidate.dispatchReceiver?.typeRef?.coneType?.fullyExpandedType(context.session)?.isSomeFunctionType(context.session) == true &&
|
||||||
(candidate.symbol as? FirNamedFunctionSymbol)?.name == OperatorNameConventions.INVOKE
|
(candidate.symbol as? FirNamedFunctionSymbol)?.name == OperatorNameConventions.INVOKE
|
||||||
) {
|
) {
|
||||||
val firstArg = candidate.argumentMapping?.keys?.firstOrNull() as? FirThisReceiverExpression ?: return
|
val firstArg = candidate.argumentMapping?.keys?.firstOrNull() as? FirThisReceiverExpression ?: return
|
||||||
if (!firstArg.isImplicit) return
|
if (!firstArg.isImplicit) return
|
||||||
firstArg.checkImpl(
|
checkImpl(
|
||||||
candidate,
|
candidate,
|
||||||
sink,
|
sink,
|
||||||
context,
|
context,
|
||||||
{ firstArg.getDslMarkersOfThisReceiverExpression(context) }
|
{ firstArg.getDslMarkersOfThisReceiverExpression(context) }
|
||||||
) { receiver, thisExpression -> receiver.boundSymbol == thisExpression.calleeReference.boundSymbol }
|
) { it.boundSymbol == firstArg.calleeReference.boundSymbol }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the implicit receiver (represented as an object of type `T`) violates DSL scope rules.
|
* Checks whether the implicit receiver (represented as an object of type `T`) violates DSL scope rules.
|
||||||
*/
|
*/
|
||||||
private fun <T> T.checkImpl(
|
private fun checkImpl(
|
||||||
candidate: Candidate,
|
candidate: Candidate,
|
||||||
sink: CheckerSink,
|
sink: CheckerSink,
|
||||||
context: ResolutionContext,
|
context: ResolutionContext,
|
||||||
dslMarkersProvider: () -> Set<ClassId>,
|
dslMarkersProvider: () -> Set<ClassId>,
|
||||||
isImplicitReceiverMatching: (ImplicitReceiverValue<*>, T) -> Boolean,
|
isImplicitReceiverMatching: (ImplicitReceiverValue<*>) -> Boolean,
|
||||||
) {
|
) {
|
||||||
val resolvedReceiverIndex = context.bodyResolveContext.implicitReceiverStack.indexOfFirst { isImplicitReceiverMatching(it, this) }
|
val resolvedReceiverIndex = context.bodyResolveContext.implicitReceiverStack.indexOfFirst { isImplicitReceiverMatching(it) }
|
||||||
if (resolvedReceiverIndex == -1) return
|
if (resolvedReceiverIndex == -1) return
|
||||||
val closerReceivers = context.bodyResolveContext.implicitReceiverStack.drop(resolvedReceiverIndex + 1)
|
val closerReceivers = context.bodyResolveContext.implicitReceiverStack.drop(resolvedReceiverIndex + 1)
|
||||||
if (closerReceivers.isEmpty()) return
|
if (closerReceivers.isEmpty()) return
|
||||||
@@ -335,6 +341,14 @@ object CheckDslScopeViolation : ResolutionStage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ImplicitReceiverValue<*>.getDslMarkersOfImplicitReceiver(context: ResolutionContext): Set<ClassId> {
|
private fun ImplicitReceiverValue<*>.getDslMarkersOfImplicitReceiver(context: ResolutionContext): Set<ClassId> {
|
||||||
|
return CheckDslScopeViolation.getDslMarkersOfImplicitReceiver(boundSymbol, type, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDslMarkersOfImplicitReceiver(
|
||||||
|
boundSymbol: FirBasedSymbol<*>?,
|
||||||
|
type: ConeKotlinType,
|
||||||
|
context: ResolutionContext,
|
||||||
|
): Set<ClassId> {
|
||||||
return buildSet {
|
return buildSet {
|
||||||
(boundSymbol as? FirAnonymousFunctionSymbol)?.fir?.matchingParameterFunctionType?.let {
|
(boundSymbol as? FirAnonymousFunctionSymbol)?.fir?.matchingParameterFunctionType?.let {
|
||||||
// collect annotations in the function type at declaration site. For example, the `@A` and `@B` in the following code.
|
// collect annotations in the function type at declaration site. For example, the `@A` and `@B` in the following code.
|
||||||
@@ -550,7 +564,7 @@ internal object CheckVisibility : CheckerStage() {
|
|||||||
val visible = visibilityChecker.isVisible(
|
val visible = visibilityChecker.isVisible(
|
||||||
declaration,
|
declaration,
|
||||||
candidate.callInfo,
|
candidate.callInfo,
|
||||||
dispatchReceiverValue = null
|
dispatchReceiver = null
|
||||||
)
|
)
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
sink.yieldDiagnostic(VisibilityError)
|
sink.yieldDiagnostic(VisibilityError)
|
||||||
@@ -696,8 +710,8 @@ private val DYNAMIC_EXTENSION_ANNOTATION_CLASS_ID: ClassId = ClassId.topLevel(DY
|
|||||||
internal object ProcessDynamicExtensionAnnotation : ResolutionStage() {
|
internal object ProcessDynamicExtensionAnnotation : 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) {
|
||||||
if (candidate.symbol.origin === FirDeclarationOrigin.DynamicScope) return
|
if (candidate.symbol.origin === FirDeclarationOrigin.DynamicScope) return
|
||||||
val extensionReceiver = candidate.chosenExtensionReceiverValue ?: return
|
val extensionReceiver = candidate.chosenExtensionReceiver ?: return
|
||||||
val argumentIsDynamic = extensionReceiver.type is ConeDynamicType
|
val argumentIsDynamic = extensionReceiver.typeRef.coneType is ConeDynamicType
|
||||||
val parameterIsDynamic = (candidate.symbol as? FirCallableSymbol)?.resolvedReceiverTypeRef?.type is ConeDynamicType
|
val parameterIsDynamic = (candidate.symbol as? FirCallableSymbol)?.resolvedReceiverTypeRef?.type is ConeDynamicType
|
||||||
if (parameterIsDynamic != argumentIsDynamic ||
|
if (parameterIsDynamic != argumentIsDynamic ||
|
||||||
parameterIsDynamic && !candidate.symbol.hasAnnotation(DYNAMIC_EXTENSION_ANNOTATION_CLASS_ID, context.session)
|
parameterIsDynamic && !candidate.symbol.hasAnnotation(DYNAMIC_EXTENSION_ANNOTATION_CLASS_ID, context.session)
|
||||||
|
|||||||
+30
-19
@@ -13,10 +13,9 @@ import org.jetbrains.kotlin.fir.declarations.*
|
|||||||
import org.jetbrains.kotlin.fir.declarations.utils.getExplicitBackingField
|
import org.jetbrains.kotlin.fir.declarations.utils.getExplicitBackingField
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.buildSmartCastExpression
|
import org.jetbrains.kotlin.fir.expressions.builder.buildSmartCastExpression
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirThisReference
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousObjectSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousObjectSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||||
@@ -30,14 +29,18 @@ import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
|||||||
fun FirVisibilityChecker.isVisible(
|
fun FirVisibilityChecker.isVisible(
|
||||||
declaration: FirMemberDeclaration,
|
declaration: FirMemberDeclaration,
|
||||||
callInfo: CallInfo,
|
callInfo: CallInfo,
|
||||||
dispatchReceiverValue: ReceiverValue?
|
dispatchReceiver: FirExpression?
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val staticQualifierForCallable = runIf(declaration is FirCallableDeclaration && declaration.isStatic) {
|
val staticQualifierForCallable = runIf(
|
||||||
val explicitReceiver = (dispatchReceiverValue as? ExpressionReceiverValue)?.explicitReceiver
|
declaration is FirCallableDeclaration &&
|
||||||
when (val classLikeSymbol = (explicitReceiver as? FirResolvedQualifier)?.symbol) {
|
declaration.isStatic &&
|
||||||
|
isExplicitReceiverExpression(dispatchReceiver)
|
||||||
|
) {
|
||||||
|
when (val classLikeSymbol = (dispatchReceiver as? FirResolvedQualifier)?.symbol) {
|
||||||
is FirRegularClassSymbol -> classLikeSymbol.fir
|
is FirRegularClassSymbol -> classLikeSymbol.fir
|
||||||
is FirTypeAliasSymbol -> classLikeSymbol.fullyExpandedClass(callInfo.session)?.fir
|
is FirTypeAliasSymbol -> classLikeSymbol.fullyExpandedClass(callInfo.session)?.fir
|
||||||
is FirAnonymousObjectSymbol, null -> null
|
is FirAnonymousObjectSymbol,
|
||||||
|
null -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isVisible(
|
return isVisible(
|
||||||
@@ -45,7 +48,7 @@ fun FirVisibilityChecker.isVisible(
|
|||||||
callInfo.session,
|
callInfo.session,
|
||||||
callInfo.containingFile,
|
callInfo.containingFile,
|
||||||
callInfo.containingDeclarations,
|
callInfo.containingDeclarations,
|
||||||
dispatchReceiverValue,
|
dispatchReceiver,
|
||||||
staticQualifierClassForCallable = staticQualifierForCallable,
|
staticQualifierClassForCallable = staticQualifierForCallable,
|
||||||
isCallToPropertySetter = callInfo.callSite is FirVariableAssignment
|
isCallToPropertySetter = callInfo.callSite is FirVariableAssignment
|
||||||
)
|
)
|
||||||
@@ -57,28 +60,29 @@ fun FirVisibilityChecker.isVisible(
|
|||||||
): Boolean {
|
): Boolean {
|
||||||
val callInfo = candidate.callInfo
|
val callInfo = candidate.callInfo
|
||||||
|
|
||||||
if (!isVisible(declaration, callInfo, candidate.dispatchReceiverValue)) {
|
if (!isVisible(declaration, callInfo, candidate.dispatchReceiver)) {
|
||||||
val dispatchReceiverWithoutSmartCastType =
|
val dispatchReceiverWithoutSmartCastType =
|
||||||
removeSmartCastTypeForAttemptToFitVisibility(candidate.dispatchReceiverValue, candidate.callInfo.session) ?: return false
|
removeSmartCastTypeForAttemptToFitVisibility(candidate.dispatchReceiver, candidate.callInfo.session) ?: return false
|
||||||
|
|
||||||
if (!isVisible(declaration, callInfo, dispatchReceiverWithoutSmartCastType)) return false
|
if (!isVisible(declaration, callInfo, dispatchReceiverWithoutSmartCastType)) return false
|
||||||
|
|
||||||
candidate.dispatchReceiverValue = dispatchReceiverWithoutSmartCastType
|
candidate.dispatchReceiver = dispatchReceiverWithoutSmartCastType
|
||||||
}
|
}
|
||||||
|
|
||||||
val backingField = declaration.getBackingFieldIfApplicable()
|
val backingField = declaration.getBackingFieldIfApplicable()
|
||||||
if (backingField != null) {
|
if (backingField != null) {
|
||||||
candidate.hasVisibleBackingField = isVisible(backingField, callInfo, candidate.dispatchReceiverValue)
|
candidate.hasVisibleBackingField = isVisible(backingField, callInfo, candidate.dispatchReceiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSmartCastTypeForAttemptToFitVisibility(dispatchReceiverValue: ReceiverValue?, session: FirSession): ReceiverValue? {
|
private fun removeSmartCastTypeForAttemptToFitVisibility(dispatchReceiver: FirExpression?, session: FirSession): FirExpression? {
|
||||||
val expressionWithSmartcastIfStable =
|
val expressionWithSmartcastIfStable =
|
||||||
(dispatchReceiverValue?.receiverExpression as? FirSmartCastExpression)?.takeIf { it.isStable } ?: return null
|
(dispatchReceiver as? FirSmartCastExpression)?.takeIf { it.isStable } ?: return null
|
||||||
|
|
||||||
if (dispatchReceiverValue.type.isNullableNothing) return null
|
val receiverType = dispatchReceiver.typeRef.coneType
|
||||||
|
if (receiverType.isNullableNothing) return null
|
||||||
|
|
||||||
val originalExpression = expressionWithSmartcastIfStable.originalExpression
|
val originalExpression = expressionWithSmartcastIfStable.originalExpression
|
||||||
val originalType = originalExpression.typeRef.coneType
|
val originalType = originalExpression.typeRef.coneType
|
||||||
@@ -87,11 +91,11 @@ private fun removeSmartCastTypeForAttemptToFitVisibility(dispatchReceiverValue:
|
|||||||
|
|
||||||
// Basically, this `if` is just for sake of optimizaton
|
// Basically, this `if` is just for sake of optimizaton
|
||||||
// We have only nullability enhancement, here, so return initial smart cast receiver value
|
// We have only nullability enhancement, here, so return initial smart cast receiver value
|
||||||
if (originalTypeNotNullable == dispatchReceiverValue.type) return null
|
if (originalTypeNotNullable == receiverType) return null
|
||||||
|
|
||||||
val expressionForReceiver = with(session.typeContext) {
|
val expressionForReceiver = with(session.typeContext) {
|
||||||
when {
|
when {
|
||||||
originalType.isNullableType() && !dispatchReceiverValue.type.isNullableType() ->
|
originalType.isNullableType() && !receiverType.isNullableType() ->
|
||||||
buildSmartCastExpression {
|
buildSmartCastExpression {
|
||||||
source = originalExpression.source?.fakeElement(KtFakeSourceElementKind.SmartCastExpression)
|
source = originalExpression.source?.fakeElement(KtFakeSourceElementKind.SmartCastExpression)
|
||||||
this.originalExpression = originalExpression
|
this.originalExpression = originalExpression
|
||||||
@@ -107,7 +111,7 @@ private fun removeSmartCastTypeForAttemptToFitVisibility(dispatchReceiverValue:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExpressionReceiverValue(expressionForReceiver)
|
return expressionForReceiver
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,3 +127,10 @@ private fun FirMemberDeclaration.getBackingFieldIfApplicable(): FirBackingField?
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isExplicitReceiverExpression(receiverExpression: FirExpression?): Boolean {
|
||||||
|
if (receiverExpression == null) return false
|
||||||
|
// Only FirThisReference may be a reference in implicit receiver
|
||||||
|
val thisReference = receiverExpression.toReference() as? FirThisReference ?: return true
|
||||||
|
return !thisReference.isImplicit
|
||||||
|
}
|
||||||
|
|||||||
+20
-7
@@ -90,11 +90,13 @@ internal abstract class FirBaseTowerResolveTask(
|
|||||||
includeInnerConstructors: Boolean = extensionReceiver != null,
|
includeInnerConstructors: Boolean = extensionReceiver != null,
|
||||||
contextReceiverGroup: ContextReceiverGroup? = null,
|
contextReceiverGroup: ContextReceiverGroup? = null,
|
||||||
dispatchReceiverForStatics: ExpressionReceiverValue? = null
|
dispatchReceiverForStatics: ExpressionReceiverValue? = null
|
||||||
): ScopeTowerLevel = ScopeTowerLevel(
|
): ScopeTowerLevel {
|
||||||
components, this,
|
return ScopeTowerLevel(
|
||||||
givenExtensionReceiverOptions = contextReceiverGroup ?: listOfNotNull(extensionReceiver),
|
components, this,
|
||||||
withHideMembersOnly, includeInnerConstructors, dispatchReceiverForStatics
|
givenExtensionReceiverOptions = createExtensionReceiverOptions(contextReceiverGroup, extensionReceiver),
|
||||||
)
|
withHideMembersOnly, includeInnerConstructors, dispatchReceiverForStatics
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
protected fun FirScope.toScopeTowerLevelForStaticWithImplicitDispatchReceiver(
|
protected fun FirScope.toScopeTowerLevelForStaticWithImplicitDispatchReceiver(
|
||||||
staticOwnerOwnerSymbol: FirRegularClassSymbol? = null,
|
staticOwnerOwnerSymbol: FirRegularClassSymbol? = null,
|
||||||
@@ -123,7 +125,7 @@ internal abstract class FirBaseTowerResolveTask(
|
|||||||
skipSynthetics: Boolean = false,
|
skipSynthetics: Boolean = false,
|
||||||
) = MemberScopeTowerLevel(
|
) = MemberScopeTowerLevel(
|
||||||
components, this,
|
components, this,
|
||||||
givenExtensionReceiverOptions = contextReceiverGroup ?: listOfNotNull(extensionReceiver),
|
givenExtensionReceiverOptions = createExtensionReceiverOptions(contextReceiverGroup, extensionReceiver),
|
||||||
skipSynthetics = skipSynthetics,
|
skipSynthetics = skipSynthetics,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -132,9 +134,20 @@ internal abstract class FirBaseTowerResolveTask(
|
|||||||
otherContextReceiverGroup: ContextReceiverGroup? = null,
|
otherContextReceiverGroup: ContextReceiverGroup? = null,
|
||||||
) = ContextReceiverGroupMemberScopeTowerLevel(
|
) = ContextReceiverGroupMemberScopeTowerLevel(
|
||||||
components, this,
|
components, this,
|
||||||
givenExtensionReceiverOptions = otherContextReceiverGroup ?: listOfNotNull(extensionReceiver),
|
givenExtensionReceiverOptions = createExtensionReceiverOptions(otherContextReceiverGroup, extensionReceiver),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun createExtensionReceiverOptions(
|
||||||
|
contextReceiverGroup: ContextReceiverGroup?,
|
||||||
|
extensionReceiverValue: ReceiverValue?,
|
||||||
|
): List<FirExpression> {
|
||||||
|
return when {
|
||||||
|
contextReceiverGroup != null -> contextReceiverGroup.map { it.receiverExpression }
|
||||||
|
extensionReceiverValue != null -> listOf(extensionReceiverValue.receiverExpression)
|
||||||
|
else -> emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected inline fun enumerateTowerLevels(
|
protected inline fun enumerateTowerLevels(
|
||||||
parentGroup: TowerGroup = TowerGroup.EmptyRoot,
|
parentGroup: TowerGroup = TowerGroup.EmptyRoot,
|
||||||
onScope: (FirScope, FirRegularClassSymbol?, TowerGroup) -> Unit,
|
onScope: (FirScope, FirRegularClassSymbol?, TowerGroup) -> Unit,
|
||||||
|
|||||||
+1
-1
@@ -117,7 +117,7 @@ class FirTowerResolver(
|
|||||||
it,
|
it,
|
||||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||||
scope,
|
scope,
|
||||||
dispatchReceiver,
|
dispatchReceiver?.receiverExpression,
|
||||||
givenExtensionReceiverOptions = emptyList()
|
givenExtensionReceiverOptions = emptyList()
|
||||||
),
|
),
|
||||||
context
|
context
|
||||||
|
|||||||
+5
-4
@@ -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.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
@@ -78,11 +79,11 @@ private class TowerScopeLevelProcessor(
|
|||||||
) : TowerScopeLevel.TowerScopeLevelProcessor<FirBasedSymbol<*>> {
|
) : TowerScopeLevel.TowerScopeLevelProcessor<FirBasedSymbol<*>> {
|
||||||
override fun consumeCandidate(
|
override fun consumeCandidate(
|
||||||
symbol: FirBasedSymbol<*>,
|
symbol: FirBasedSymbol<*>,
|
||||||
dispatchReceiverValue: ReceiverValue?,
|
dispatchReceiver: FirExpression?,
|
||||||
givenExtensionReceiverOptions: List<ReceiverValue>,
|
givenExtensionReceiverOptions: List<FirExpression>,
|
||||||
scope: FirScope,
|
scope: FirScope,
|
||||||
objectsByName: Boolean,
|
objectsByName: Boolean,
|
||||||
isFromOriginalTypeInPresenceOfSmartCast: Boolean
|
isFromOriginalTypeInPresenceOfSmartCast: Boolean,
|
||||||
) {
|
) {
|
||||||
resultCollector.consumeCandidate(
|
resultCollector.consumeCandidate(
|
||||||
group, candidateFactory.createCandidate(
|
group, candidateFactory.createCandidate(
|
||||||
@@ -90,7 +91,7 @@ private class TowerScopeLevelProcessor(
|
|||||||
symbol,
|
symbol,
|
||||||
explicitReceiverKind,
|
explicitReceiverKind,
|
||||||
scope,
|
scope,
|
||||||
dispatchReceiverValue,
|
dispatchReceiver,
|
||||||
givenExtensionReceiverOptions,
|
givenExtensionReceiverOptions,
|
||||||
objectsByName,
|
objectsByName,
|
||||||
isFromOriginalTypeInPresenceOfSmartCast
|
isFromOriginalTypeInPresenceOfSmartCast
|
||||||
|
|||||||
+13
-12
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.*
|
|||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression
|
import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedQualifier
|
import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedQualifier
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
@@ -55,8 +56,8 @@ abstract class TowerScopeLevel {
|
|||||||
interface TowerScopeLevelProcessor<in T : FirBasedSymbol<*>> {
|
interface TowerScopeLevelProcessor<in T : FirBasedSymbol<*>> {
|
||||||
fun consumeCandidate(
|
fun consumeCandidate(
|
||||||
symbol: T,
|
symbol: T,
|
||||||
dispatchReceiverValue: ReceiverValue?,
|
dispatchReceiver: FirExpression?,
|
||||||
givenExtensionReceiverOptions: List<ReceiverValue>,
|
givenExtensionReceiverOptions: List<FirExpression>,
|
||||||
scope: FirScope,
|
scope: FirScope,
|
||||||
objectsByName: Boolean = false,
|
objectsByName: Boolean = false,
|
||||||
isFromOriginalTypeInPresenceOfSmartCast: Boolean = false,
|
isFromOriginalTypeInPresenceOfSmartCast: Boolean = false,
|
||||||
@@ -74,7 +75,7 @@ abstract class TowerScopeLevel {
|
|||||||
class MemberScopeTowerLevel(
|
class MemberScopeTowerLevel(
|
||||||
private val bodyResolveComponents: BodyResolveComponents,
|
private val bodyResolveComponents: BodyResolveComponents,
|
||||||
val dispatchReceiverValue: ReceiverValue,
|
val dispatchReceiverValue: ReceiverValue,
|
||||||
private val givenExtensionReceiverOptions: List<ReceiverValue>,
|
private val givenExtensionReceiverOptions: List<FirExpression>,
|
||||||
private val skipSynthetics: Boolean,
|
private val skipSynthetics: Boolean,
|
||||||
) : TowerScopeLevel() {
|
) : TowerScopeLevel() {
|
||||||
private val scopeSession: ScopeSession get() = bodyResolveComponents.scopeSession
|
private val scopeSession: ScopeSession get() = bodyResolveComponents.scopeSession
|
||||||
@@ -156,7 +157,7 @@ class MemberScopeTowerLevel(
|
|||||||
empty = false
|
empty = false
|
||||||
output.consumeCandidate(
|
output.consumeCandidate(
|
||||||
symbol,
|
symbol,
|
||||||
dispatchReceiverValue,
|
dispatchReceiverValue.receiverExpression,
|
||||||
givenExtensionReceiverOptions = emptyList(),
|
givenExtensionReceiverOptions = emptyList(),
|
||||||
scope
|
scope
|
||||||
)
|
)
|
||||||
@@ -198,8 +199,8 @@ class MemberScopeTowerLevel(
|
|||||||
|
|
||||||
val dispatchReceiverToUse = when {
|
val dispatchReceiverToUse = when {
|
||||||
isFromOriginalTypeInPresenceOfSmartCast ->
|
isFromOriginalTypeInPresenceOfSmartCast ->
|
||||||
getOriginalReceiverExpressionIfStableSmartCast()?.let(::ExpressionReceiverValue)
|
getOriginalReceiverExpressionIfStableSmartCast()
|
||||||
else -> dispatchReceiverValue
|
else -> dispatchReceiverValue.receiverExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
output.consumeCandidate(
|
output.consumeCandidate(
|
||||||
@@ -283,7 +284,7 @@ class MemberScopeTowerLevel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirCallableSymbol<*>.hasConsistentExtensionReceiver(givenExtensionReceivers: List<ReceiverValue>): Boolean {
|
private fun FirCallableSymbol<*>.hasConsistentExtensionReceiver(givenExtensionReceivers: List<FirExpression>): Boolean {
|
||||||
return givenExtensionReceivers.isNotEmpty() == hasExtensionReceiver()
|
return givenExtensionReceivers.isNotEmpty() == hasExtensionReceiver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,7 +292,7 @@ class MemberScopeTowerLevel(
|
|||||||
class ContextReceiverGroupMemberScopeTowerLevel(
|
class ContextReceiverGroupMemberScopeTowerLevel(
|
||||||
bodyResolveComponents: BodyResolveComponents,
|
bodyResolveComponents: BodyResolveComponents,
|
||||||
contextReceiverGroup: ContextReceiverGroup,
|
contextReceiverGroup: ContextReceiverGroup,
|
||||||
givenExtensionReceiverOptions: List<ReceiverValue> = emptyList(),
|
givenExtensionReceiverOptions: List<FirExpression> = emptyList(),
|
||||||
) : TowerScopeLevel() {
|
) : TowerScopeLevel() {
|
||||||
private val memberScopeLevels = contextReceiverGroup.map {
|
private val memberScopeLevels = contextReceiverGroup.map {
|
||||||
MemberScopeTowerLevel(bodyResolveComponents, it, givenExtensionReceiverOptions, false)
|
MemberScopeTowerLevel(bodyResolveComponents, it, givenExtensionReceiverOptions, false)
|
||||||
@@ -320,7 +321,7 @@ class ContextReceiverGroupMemberScopeTowerLevel(
|
|||||||
class ScopeTowerLevel(
|
class ScopeTowerLevel(
|
||||||
private val bodyResolveComponents: BodyResolveComponents,
|
private val bodyResolveComponents: BodyResolveComponents,
|
||||||
val scope: FirScope,
|
val scope: FirScope,
|
||||||
private val givenExtensionReceiverOptions: List<ReceiverValue>,
|
private val givenExtensionReceiverOptions: List<FirExpression>,
|
||||||
private val withHideMembersOnly: Boolean,
|
private val withHideMembersOnly: Boolean,
|
||||||
private val includeInnerConstructors: Boolean,
|
private val includeInnerConstructors: Boolean,
|
||||||
private val dispatchReceiverForStatics: ExpressionReceiverValue?
|
private val dispatchReceiverForStatics: ExpressionReceiverValue?
|
||||||
@@ -383,7 +384,7 @@ class ScopeTowerLevel(
|
|||||||
)
|
)
|
||||||
|
|
||||||
return givenExtensionReceiverOptions.none { extensionReceiver ->
|
return givenExtensionReceiverOptions.none { extensionReceiver ->
|
||||||
val extensionReceiverType = extensionReceiver.type
|
val extensionReceiverType = extensionReceiver.resultType.coneType
|
||||||
// If some receiver is non class like, we should not skip it
|
// If some receiver is non class like, we should not skip it
|
||||||
if (extensionReceiverType !is ConeClassLikeType) return@none true
|
if (extensionReceiverType !is ConeClassLikeType) return@none true
|
||||||
|
|
||||||
@@ -417,7 +418,7 @@ class ScopeTowerLevel(
|
|||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
processor.consumeCandidate(
|
processor.consumeCandidate(
|
||||||
unwrappedCandidate as T,
|
unwrappedCandidate as T,
|
||||||
dispatchReceiverValue,
|
dispatchReceiverValue?.receiverExpression,
|
||||||
givenExtensionReceiverOptions,
|
givenExtensionReceiverOptions,
|
||||||
scope
|
scope
|
||||||
)
|
)
|
||||||
@@ -463,7 +464,7 @@ class ScopeTowerLevel(
|
|||||||
scope.processClassifiersByName(info.name) {
|
scope.processClassifiersByName(info.name) {
|
||||||
empty = false
|
empty = false
|
||||||
processor.consumeCandidate(
|
processor.consumeCandidate(
|
||||||
it, dispatchReceiverValue = null,
|
it, dispatchReceiver = null,
|
||||||
givenExtensionReceiverOptions = emptyList(),
|
givenExtensionReceiverOptions = emptyList(),
|
||||||
scope = scope,
|
scope = scope,
|
||||||
objectsByName = true
|
objectsByName = true
|
||||||
|
|||||||
+25
-11
@@ -10,14 +10,16 @@ import org.jetbrains.kotlin.fir.FirSession
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
|
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirResolvable
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
import org.jetbrains.kotlin.fir.render
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitExtensionReceiverValue
|
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitExtensionReceiverValue
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext
|
import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.candidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor
|
import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.replaceStubsAndTypeVariablesToErrors
|
import org.jetbrains.kotlin.fir.resolve.substitution.replaceStubsAndTypeVariablesToErrors
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.FirCallCompletionResultsWriterTransformer
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
|
import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
|
||||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||||
@@ -72,12 +74,12 @@ class FirBuilderInferenceSession(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun Candidate.isSuitableForBuilderInference(): Boolean {
|
private fun Candidate.isSuitableForBuilderInference(): Boolean {
|
||||||
val extensionReceiver = chosenExtensionReceiverValue
|
val extensionReceiver = chosenExtensionReceiver
|
||||||
val dispatchReceiver = dispatchReceiverValue
|
val dispatchReceiver = dispatchReceiver
|
||||||
return when {
|
return when {
|
||||||
extensionReceiver == null && dispatchReceiver == null -> false
|
extensionReceiver == null && dispatchReceiver == null -> false
|
||||||
dispatchReceiver?.type?.containsStubType() == true -> true
|
dispatchReceiver?.typeRef?.coneType?.containsStubType() == true -> true
|
||||||
extensionReceiver?.type?.containsStubType() == true -> symbol.fir.hasBuilderInferenceAnnotation(session)
|
extensionReceiver?.typeRef?.coneType?.containsStubType() == true -> symbol.fir.hasBuilderInferenceAnnotation(session)
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +253,6 @@ class FirBuilderInferenceSession(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: support diagnostics, see [CoroutineInferenceSession#updateCalls]
|
// TODO: support diagnostics, see [CoroutineInferenceSession#updateCalls]
|
||||||
|
|
||||||
val completionResultsWriter = components.callCompleter.createCompletionResultsWriter(substitutor)
|
val completionResultsWriter = components.callCompleter.createCompletionResultsWriter(substitutor)
|
||||||
for ((call, _) in partiallyResolvedCalls) {
|
for ((call, _) in partiallyResolvedCalls) {
|
||||||
call.transformSingle(completionResultsWriter, null)
|
call.transformSingle(completionResultsWriter, null)
|
||||||
@@ -260,19 +261,32 @@ class FirBuilderInferenceSession(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FirStubTypeTransformer(
|
class FirStubTypeTransformer(private val substitutor: ConeSubstitutor) : FirDefaultTransformer<Nothing?>() {
|
||||||
private val substitutor: ConeSubstitutor
|
|
||||||
) : FirDefaultTransformer<Nothing?>() {
|
|
||||||
|
|
||||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): E {
|
override fun <E : FirElement> transformElement(element: E, data: Nothing?): E {
|
||||||
|
// All resolvable nodes should be implemented separately to cover substitution of receivers in the candidate
|
||||||
|
if (element is FirResolvable) {
|
||||||
|
element.candidate()?.let { processCandidate(it) }
|
||||||
|
}
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return (element.transformChildren(this, data) as E)
|
return element.transformChildren(this, data = null) as E
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transformResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: Nothing?): FirTypeRef =
|
override fun transformResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: Nothing?): FirTypeRef =
|
||||||
substitutor.substituteOrNull(resolvedTypeRef.type)?.let {
|
substitutor.substituteOrNull(resolvedTypeRef.type)?.let {
|
||||||
resolvedTypeRef.withReplacedConeType(it)
|
resolvedTypeRef.withReplacedConeType(it)
|
||||||
} ?: resolvedTypeRef
|
} ?: resolvedTypeRef
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We should manually update all receivers in the all not completed candidates, because not all calls with candidates
|
||||||
|
* contained in partiallyResolvedCalls and candidate stores not receiver values, which are updated, (TODO: remove this comment after removal of updating values)
|
||||||
|
* and receivers of candidates are not direct FIR children of calls, so they won't be visited during regular transformChildren
|
||||||
|
*/
|
||||||
|
private fun processCandidate(candidate: Candidate) {
|
||||||
|
candidate.dispatchReceiver = candidate.dispatchReceiver?.transform(this, data = null)
|
||||||
|
candidate.chosenExtensionReceiver = candidate.chosenExtensionReceiver?.transform(this, data = null)
|
||||||
|
candidate.contextReceiverArguments = candidate.contextReceiverArguments?.map { it.transform(this, data = null) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val BUILDER_INFERENCE_ANNOTATION_CLASS_ID: ClassId = ClassId.topLevel(BUILDER_INFERENCE_ANNOTATION_FQ_NAME)
|
private val BUILDER_INFERENCE_ANNOTATION_CLASS_ID: ClassId = ClassId.topLevel(BUILDER_INFERENCE_ANNOTATION_FQ_NAME)
|
||||||
|
|||||||
+2
-3
@@ -72,8 +72,8 @@ class FirDelegatedPropertyInferenceSession(
|
|||||||
if (callee.candidate.system.hasContradiction) return true
|
if (callee.candidate.system.hasContradiction) return true
|
||||||
|
|
||||||
val hasStubType =
|
val hasStubType =
|
||||||
callee.candidate.chosenExtensionReceiverValue?.type?.containsStubType() ?: false
|
callee.candidate.chosenExtensionReceiver?.typeRef?.coneType?.containsStubType() ?: false
|
||||||
|| callee.candidate.dispatchReceiverValue?.type?.containsStubType() ?: false
|
|| callee.candidate.dispatchReceiver?.typeRef?.coneType?.containsStubType() ?: false
|
||||||
|
|
||||||
if (!hasStubType) {
|
if (!hasStubType) {
|
||||||
return true
|
return true
|
||||||
@@ -165,7 +165,6 @@ class FirDelegatedPropertyInferenceSession(
|
|||||||
fun completeCandidates(): List<FirResolvable> {
|
fun completeCandidates(): List<FirResolvable> {
|
||||||
val commonSystem = components.session.inferenceComponents.createConstraintSystem()
|
val commonSystem = components.session.inferenceComponents.createConstraintSystem()
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
val notCompletedCalls = partiallyResolvedCalls.mapNotNull { partiallyResolvedCall ->
|
val notCompletedCalls = partiallyResolvedCalls.mapNotNull { partiallyResolvedCall ->
|
||||||
partiallyResolvedCall.first.takeIf { resolvable ->
|
partiallyResolvedCall.first.takeIf { resolvable ->
|
||||||
resolvable.candidate() != null
|
resolvable.candidate() != null
|
||||||
|
|||||||
+3
-3
@@ -13,10 +13,10 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef
|
|||||||
import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass
|
import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.*
|
import org.jetbrains.kotlin.fir.diagnostics.*
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.AbstractCallInfo
|
import org.jetbrains.kotlin.fir.resolve.calls.AbstractCallInfo
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.AbstractCandidate
|
import org.jetbrains.kotlin.fir.resolve.calls.AbstractCandidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ResolutionDiagnostic
|
import org.jetbrains.kotlin.fir.resolve.calls.ResolutionDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
@@ -538,10 +538,10 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
|||||||
override val applicability: CandidateApplicability
|
override val applicability: CandidateApplicability
|
||||||
) : AbstractCandidate() {
|
) : AbstractCandidate() {
|
||||||
|
|
||||||
override val dispatchReceiverValue: ReceiverValue?
|
override val dispatchReceiver: FirExpression?
|
||||||
get() = null
|
get() = null
|
||||||
|
|
||||||
override val chosenExtensionReceiverValue: ReceiverValue?
|
override val chosenExtensionReceiver: FirExpression?
|
||||||
get() = null
|
get() = null
|
||||||
|
|
||||||
override val explicitReceiverKind: ExplicitReceiverKind
|
override val explicitReceiverKind: ExplicitReceiverKind
|
||||||
|
|||||||
+1
@@ -9,6 +9,7 @@ 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.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.labelName
|
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.*
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
|
|||||||
+3
-2
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.calls
|
package org.jetbrains.kotlin.fir.resolve.calls
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintSystemError
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintSystemError
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
@@ -12,8 +13,8 @@ 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 dispatchReceiver: FirExpression?
|
||||||
abstract val chosenExtensionReceiverValue: ReceiverValue?
|
abstract val chosenExtensionReceiver: FirExpression?
|
||||||
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>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ abstract class FirThisReference : FirReference() {
|
|||||||
abstract val labelName: String?
|
abstract val labelName: String?
|
||||||
abstract val boundSymbol: FirBasedSymbol<*>?
|
abstract val boundSymbol: FirBasedSymbol<*>?
|
||||||
abstract val contextReceiverNumber: Int
|
abstract val contextReceiverNumber: Int
|
||||||
|
abstract val isImplicit: Boolean
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitThisReference(this, data)
|
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitThisReference(this, data)
|
||||||
|
|
||||||
|
|||||||
+1
@@ -23,6 +23,7 @@ internal class FirExplicitThisReference(
|
|||||||
override var contextReceiverNumber: Int,
|
override var contextReceiverNumber: Int,
|
||||||
) : FirThisReference() {
|
) : FirThisReference() {
|
||||||
override var boundSymbol: FirBasedSymbol<*>? = null
|
override var boundSymbol: FirBasedSymbol<*>? = null
|
||||||
|
override val isImplicit: Boolean = false
|
||||||
|
|
||||||
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {}
|
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -23,6 +23,7 @@ internal class FirImplicitThisReference(
|
|||||||
) : FirThisReference() {
|
) : FirThisReference() {
|
||||||
override val source: KtSourceElement? get() = null
|
override val source: KtSourceElement? get() = null
|
||||||
override val labelName: String? get() = null
|
override val labelName: String? get() = null
|
||||||
|
override val isImplicit: Boolean = true
|
||||||
|
|
||||||
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {}
|
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -484,6 +484,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
value = "null"
|
value = "null"
|
||||||
isMutable = true
|
isMutable = true
|
||||||
}
|
}
|
||||||
|
defaultFalse("isImplicit")
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(thisReference, "FirImplicitThisReference") {
|
impl(thisReference, "FirImplicitThisReference") {
|
||||||
@@ -495,6 +496,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
default("boundSymbol") {
|
default("boundSymbol") {
|
||||||
isMutable = false
|
isMutable = false
|
||||||
}
|
}
|
||||||
|
defaultTrue("isImplicit")
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(superReference, "FirExplicitSuperReference")
|
impl(superReference, "FirExplicitSuperReference")
|
||||||
|
|||||||
+1
@@ -687,6 +687,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
|||||||
+stringField("labelName", nullable = true)
|
+stringField("labelName", nullable = true)
|
||||||
+field("boundSymbol", firBasedSymbolType, "*", nullable = true, withReplace = true)
|
+field("boundSymbol", firBasedSymbolType, "*", nullable = true, withReplace = true)
|
||||||
+intField("contextReceiverNumber", withReplace = true)
|
+intField("contextReceiverNumber", withReplace = true)
|
||||||
|
+booleanField("isImplicit")
|
||||||
}
|
}
|
||||||
|
|
||||||
typeRef.configure {
|
typeRef.configure {
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// IGNORE_BACKEND_K2: JVM_IR
|
|
||||||
// ISSUE: KT-58823
|
// ISSUE: KT-58823
|
||||||
// FILE: Base.java
|
// FILE: Base.java
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user