FIR resolve: integrate receiverExpression inside ReceiverValue

This commit is contained in:
Mikhail Glukhikh
2019-08-29 16:21:21 +03:00
parent 0962755fde
commit 8bb539ce19
3 changed files with 28 additions and 27 deletions
@@ -11,13 +11,10 @@ import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirThisReceiverExpressionImpl
import org.jetbrains.kotlin.fir.references.FirImplicitThisReference
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.types.FirTypeProjection import org.jetbrains.kotlin.fir.types.FirTypeProjection
import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
@@ -68,19 +65,11 @@ class Candidate(
fun dispatchReceiverExpression(): FirExpression = when (explicitReceiverKind) { fun dispatchReceiverExpression(): FirExpression = when (explicitReceiverKind) {
ExplicitReceiverKind.DISPATCH_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> callInfo.explicitReceiver!! ExplicitReceiverKind.DISPATCH_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> callInfo.explicitReceiver!!
else -> dispatchReceiverValue?.let { else -> dispatchReceiverValue?.receiverExpression ?: FirNoReceiverExpression
FirThisReceiverExpressionImpl(null, FirImplicitThisReference(it.klassSymbol)).apply {
typeRef = FirResolvedTypeRefImpl(null, it.type)
}
} ?: FirNoReceiverExpression
} }
fun extensionReceiverExpression(): FirExpression = when (explicitReceiverKind) { fun extensionReceiverExpression(): FirExpression = when (explicitReceiverKind) {
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> callInfo.explicitReceiver!! ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> callInfo.explicitReceiver!!
else -> implicitExtensionReceiverValue?.let { else -> implicitExtensionReceiverValue?.receiverExpression ?: FirNoReceiverExpression
FirThisReceiverExpressionImpl(null, FirImplicitThisReference(it.boundSymbol)).apply {
typeRef = FirResolvedTypeRefImpl(null, it.type)
}
} ?: FirNoReceiverExpression
} }
} }
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.classId import org.jetbrains.kotlin.fir.declarations.classId
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirThisReceiverExpressionImpl
import org.jetbrains.kotlin.fir.references.FirImplicitThisReference
import org.jetbrains.kotlin.fir.renderWithType import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
@@ -18,20 +20,30 @@ 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.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
interface ReceiverValue { interface ReceiverValue {
val type: ConeKotlinType val type: ConeKotlinType
val receiverExpression: FirExpression
fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirScope? = fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirScope? =
type.scope(useSiteSession, scopeSession) type.scope(useSiteSession, scopeSession)
} }
private fun receiverExpression(symbol: AbstractFirBasedSymbol<*>, type: ConeKotlinType): FirExpression =
FirThisReceiverExpressionImpl(null, FirImplicitThisReference(symbol)).apply {
typeRef = FirResolvedTypeRefImpl(null, type)
}
class ClassDispatchReceiverValue(val klassSymbol: FirClassSymbol) : ReceiverValue { class ClassDispatchReceiverValue(val klassSymbol: FirClassSymbol) : ReceiverValue {
override val type: ConeKotlinType = ConeClassTypeImpl( override val type: ConeKotlinType = ConeClassTypeImpl(
klassSymbol.toLookupTag(), klassSymbol.toLookupTag(),
klassSymbol.fir.typeParameters.map { ConeStarProjection }.toTypedArray(), klassSymbol.fir.typeParameters.map { ConeStarProjection }.toTypedArray(),
isNullable = false isNullable = false
) )
override val receiverExpression: FirExpression = receiverExpression(klassSymbol, type)
} }
class ExpressionReceiverValue( class ExpressionReceiverValue(
@@ -41,6 +53,9 @@ class ExpressionReceiverValue(
override val type: ConeKotlinType override val type: ConeKotlinType
get() = typeProvider(explicitReceiverExpression)?.coneTypeSafe() get() = typeProvider(explicitReceiverExpression)?.coneTypeSafe()
?: ConeKotlinErrorType("No type calculated for: ${explicitReceiverExpression.renderWithType()}") // TODO: assert here ?: ConeKotlinErrorType("No type calculated for: ${explicitReceiverExpression.renderWithType()}") // TODO: assert here
override val receiverExpression: FirExpression
get() = explicitReceiverExpression
} }
abstract class ImplicitReceiverValue<S : AbstractFirBasedSymbol<*>>( abstract class ImplicitReceiverValue<S : AbstractFirBasedSymbol<*>>(
@@ -52,6 +67,8 @@ abstract class ImplicitReceiverValue<S : AbstractFirBasedSymbol<*>>(
val implicitScope: FirScope? = type.scope(useSiteSession, scopeSession) val implicitScope: FirScope? = type.scope(useSiteSession, scopeSession)
override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirScope? = implicitScope override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirScope? = implicitScope
override val receiverExpression: FirExpression = receiverExpression(boundSymbol, type)
} }
class ImplicitDispatchReceiverValue( class ImplicitDispatchReceiverValue(
@@ -60,8 +60,8 @@ internal sealed class CheckReceivers : ResolutionStage() {
return this == DISPATCH_RECEIVER || this == BOTH_RECEIVERS return this == DISPATCH_RECEIVER || this == BOTH_RECEIVERS
} }
override fun Candidate.getReceiverValue(): ReceiverValue? { override fun Candidate.getReceiverType(): ConeKotlinType? {
return dispatchReceiverValue return dispatchReceiverValue?.type
} }
} }
@@ -74,35 +74,30 @@ internal sealed class CheckReceivers : ResolutionStage() {
return this == EXTENSION_RECEIVER || this == BOTH_RECEIVERS return this == EXTENSION_RECEIVER || this == BOTH_RECEIVERS
} }
override fun Candidate.getReceiverValue(): ReceiverValue? { override fun Candidate.getReceiverType(): ConeKotlinType? {
val callableSymbol = symbol as? FirCallableSymbol<*> ?: return null val callableSymbol = symbol as? FirCallableSymbol<*> ?: return null
val callable = callableSymbol.fir val callable = callableSymbol.fir
val type = (callable.receiverTypeRef as FirResolvedTypeRef?)?.type ?: return null return (callable.receiverTypeRef as FirResolvedTypeRef?)?.type
return object : ReceiverValue {
override val type: ConeKotlinType
get() = type
}
} }
} }
abstract fun Candidate.getReceiverValue(): ReceiverValue? abstract fun Candidate.getReceiverType(): ConeKotlinType?
abstract fun ExplicitReceiverKind.shouldBeCheckedAgainstExplicit(): Boolean abstract fun ExplicitReceiverKind.shouldBeCheckedAgainstExplicit(): Boolean
abstract fun ExplicitReceiverKind.shouldBeCheckedAgainstImplicit(): Boolean abstract fun ExplicitReceiverKind.shouldBeCheckedAgainstImplicit(): Boolean
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
val expectedReceiverParameterValue = candidate.getReceiverValue() val expectedReceiverType = candidate.getReceiverType()
val explicitReceiverExpression = callInfo.explicitReceiver val explicitReceiverExpression = callInfo.explicitReceiver
val explicitReceiverKind = candidate.explicitReceiverKind val explicitReceiverKind = candidate.explicitReceiverKind
if (expectedReceiverParameterValue != null) { if (expectedReceiverType != null) {
if (explicitReceiverExpression != null && explicitReceiverKind.shouldBeCheckedAgainstExplicit()) { if (explicitReceiverExpression != null && explicitReceiverKind.shouldBeCheckedAgainstExplicit()) {
resolveArgumentExpression( resolveArgumentExpression(
candidate.csBuilder, candidate.csBuilder,
argument = explicitReceiverExpression, argument = explicitReceiverExpression,
expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverParameterValue.type), expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType),
expectedTypeRef = explicitReceiverExpression.typeRef, expectedTypeRef = explicitReceiverExpression.typeRef,
sink = sink, sink = sink,
isReceiver = true, isReceiver = true,
@@ -117,7 +112,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
resolvePlainArgumentType( resolvePlainArgumentType(
candidate.csBuilder, candidate.csBuilder,
argumentType = argumentExtensionReceiverValue.type, argumentType = argumentExtensionReceiverValue.type,
expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverParameterValue.type), expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type),
sink = sink, sink = sink,
isReceiver = true, isReceiver = true,
isSafeCall = callInfo.isSafeCall isSafeCall = callInfo.isSafeCall