FIR resolve: add correct receiver tower scopes + check receivers
This commit is contained in:
@@ -33,7 +33,7 @@ fun resolveArgumentExpression(
|
||||
typeProvider: (FirExpression) -> FirTypeRef?
|
||||
) {
|
||||
return when (argument) {
|
||||
is FirQualifiedAccessExpression, is FirFunctionCall -> checkPlainExpressionArgument(
|
||||
is FirQualifiedAccessExpression, is FirFunctionCall -> resolvePlainExpressionArgument(
|
||||
csBuilder,
|
||||
argument,
|
||||
expectedType,
|
||||
@@ -65,11 +65,11 @@ fun resolveArgumentExpression(
|
||||
acceptLambdaAtoms,
|
||||
typeProvider
|
||||
)
|
||||
else -> checkPlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, typeProvider)
|
||||
else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, typeProvider)
|
||||
}
|
||||
}
|
||||
|
||||
fun checkPlainExpressionArgument(
|
||||
fun resolvePlainExpressionArgument(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
argument: FirExpression,
|
||||
expectedType: ConeKotlinType?,
|
||||
@@ -79,16 +79,29 @@ fun checkPlainExpressionArgument(
|
||||
) {
|
||||
if (expectedType == null) return
|
||||
val argumentType = typeProvider(argument)?.coneTypeSafe<ConeKotlinType>() ?: return
|
||||
resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver)
|
||||
}
|
||||
|
||||
fun resolvePlainArgumentType(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
argumentType: ConeKotlinType,
|
||||
expectedType: ConeKotlinType,
|
||||
sink: CheckerSink,
|
||||
isReceiver: Boolean
|
||||
) {
|
||||
val position = SimpleConstraintSystemConstraintPosition //TODO
|
||||
|
||||
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) {
|
||||
if (!isReceiver) {
|
||||
csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
|
||||
return
|
||||
}
|
||||
val nullableExpectedType = expectedType.withNullability(ConeNullability.NULLABLE)
|
||||
if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) {
|
||||
sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER) // TODO
|
||||
} else {
|
||||
csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
|
||||
sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.renderWithType
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.resolve.scope
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
|
||||
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
@@ -32,17 +33,13 @@ import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
|
||||
|
||||
|
||||
|
||||
class CallInfo(
|
||||
val callKind: CallKind,
|
||||
|
||||
val explicitReceiver: FirExpression?,
|
||||
|
||||
val arguments: List<FirExpression>,
|
||||
val typeArguments: List<FirTypeProjection>,
|
||||
|
||||
val typeArguments: List<FirTypeProjection>,
|
||||
val typeProvider: (FirExpression) -> FirTypeRef?
|
||||
) {
|
||||
val argumentCount get() = arguments.size
|
||||
@@ -63,7 +60,8 @@ class CheckerSinkImpl : CheckerSink {
|
||||
|
||||
class Candidate(
|
||||
val symbol: ConeSymbol,
|
||||
val receiverKind: ExplicitReceiverKind,
|
||||
val dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
val explicitReceiverKind: ExplicitReceiverKind,
|
||||
private val inferenceComponents: InferenceComponents,
|
||||
private val baseSystem: ConstraintStorage
|
||||
) {
|
||||
@@ -112,55 +110,87 @@ interface TowerScopeLevel {
|
||||
fun <T : ConeSymbol> processElementsByName(
|
||||
token: Token<T>,
|
||||
name: Name,
|
||||
extensionReceiver: ReceiverValueWithPossibleTypes?,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction
|
||||
|
||||
interface TowerScopeLevelProcessor<T : ConeSymbol> {
|
||||
fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction
|
||||
fun consumeCandidate(symbol: T, dispatchReceiverValue: ClassDispatchReceiverValue?): ProcessorAction
|
||||
}
|
||||
|
||||
object Empty : TowerScopeLevel {
|
||||
override fun <T : ConeSymbol> processElementsByName(
|
||||
token: Token<T>,
|
||||
name: Name,
|
||||
extensionReceiver: ReceiverValueWithPossibleTypes?,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction = ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
|
||||
interface ReceiverValue {
|
||||
val type: ConeKotlinType
|
||||
abstract class SessionBasedTowerLevel(val session: FirSession) : TowerScopeLevel {
|
||||
protected fun ConeSymbol.dispatchReceiverValue(): ClassDispatchReceiverValue? {
|
||||
return when (this) {
|
||||
is FirFunctionSymbol -> fir.dispatchReceiverValue(session)
|
||||
is FirClassSymbol -> ClassDispatchReceiverValue(fir.symbol)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
protected fun ConeCallableSymbol.hasConsistentExtensionReceiver(explicitExtensionReceiver: ExpressionReceiverValue?): Boolean {
|
||||
val hasExtensionReceiver = hasExtensionReceiver()
|
||||
return hasExtensionReceiver == (explicitExtensionReceiver != null)
|
||||
}
|
||||
}
|
||||
|
||||
interface ReceiverValueWithPossibleTypes : ReceiverValue
|
||||
|
||||
// This is more like "dispatch receiver-based tower level"
|
||||
// Here we always have an explicit or implicit dispatch receiver, and can access members of its scope
|
||||
// (which is separated from currently accessible scope, see below)
|
||||
// So: dispatch receiver = given explicit or implicit receiver
|
||||
// So: extension receiver = NONE
|
||||
class MemberScopeTowerLevel(
|
||||
val session: FirSession,
|
||||
val dispatchReceiver: ReceiverValueWithPossibleTypes
|
||||
) : TowerScopeLevel {
|
||||
|
||||
session: FirSession,
|
||||
val dispatchReceiver: ReceiverValue
|
||||
) : SessionBasedTowerLevel(session) {
|
||||
|
||||
private fun <T : ConeSymbol> processMembers(
|
||||
output: TowerScopeLevel.TowerScopeLevelProcessor<T>,
|
||||
explicitExtensionReceiver: ExpressionReceiverValue?,
|
||||
processScopeMembers: FirScope.(processor: (T) -> ProcessorAction) -> ProcessorAction
|
||||
): ProcessorAction {
|
||||
val scope = dispatchReceiver.type.scope(session, ScopeSession()) ?: return ProcessorAction.NEXT
|
||||
if (scope.processScopeMembers { output.consumeCandidate(it, dispatchReceiver) }.stop()) return ProcessorAction.STOP
|
||||
if (scope.processScopeMembers { candidate ->
|
||||
if (candidate is ConeCallableSymbol && candidate.hasConsistentExtensionReceiver(explicitExtensionReceiver)) {
|
||||
// NB: we do not check dispatchReceiverValue != null here,
|
||||
// because of objects & constructors (see comments in dispatchReceiverValue() implementation)
|
||||
output.consumeCandidate(candidate, candidate.dispatchReceiverValue())
|
||||
} else if (candidate is ConeClassLikeSymbol) {
|
||||
output.consumeCandidate(candidate, null)
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}.stop()
|
||||
) return ProcessorAction.STOP
|
||||
val withSynthetic = FirSyntheticPropertiesScope(session, scope, ReturnTypeCalculatorWithJump(session))
|
||||
return withSynthetic.processScopeMembers { output.consumeCandidate(it, dispatchReceiver) }
|
||||
return withSynthetic.processScopeMembers { symbol ->
|
||||
output.consumeCandidate(symbol, symbol.dispatchReceiverValue())
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T : ConeSymbol> processElementsByName(
|
||||
token: TowerScopeLevel.Token<T>,
|
||||
name: Name,
|
||||
extensionReceiver: ReceiverValueWithPossibleTypes?,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevel.TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction {
|
||||
val explicitExtensionReceiver = if (dispatchReceiver == explicitReceiver) null else explicitReceiver
|
||||
return when (token) {
|
||||
TowerScopeLevel.Token.Properties -> processMembers(processor) { this.processPropertiesByName(name, it.cast()) }
|
||||
TowerScopeLevel.Token.Functions -> processMembers(processor) { this.processFunctionsByName(name, it.cast()) }
|
||||
TowerScopeLevel.Token.Properties -> processMembers(processor, explicitExtensionReceiver) { symbol ->
|
||||
this.processPropertiesByName(name, symbol.cast())
|
||||
}
|
||||
TowerScopeLevel.Token.Functions -> processMembers(processor, explicitExtensionReceiver) { symbol ->
|
||||
this.processFunctionsByName(name, symbol.cast())
|
||||
}
|
||||
TowerScopeLevel.Token.Objects -> ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
@@ -169,30 +199,36 @@ class MemberScopeTowerLevel(
|
||||
|
||||
private fun ConeCallableSymbol.hasExtensionReceiver(): Boolean = (this as? FirCallableSymbol)?.fir?.receiverTypeRef != null
|
||||
|
||||
// This is more like "scope-based tower level"
|
||||
// We can access here members of currently accessible scope which is not influenced by explicit receiver
|
||||
// We can either have no explicit receiver at all, or it can be an extension receiver
|
||||
// An explicit receiver never can be a dispatch receiver at this level
|
||||
// So: dispatch receiver = strictly NONE
|
||||
// So: extension receiver = either none or explicit
|
||||
// (if explicit receiver exists, it always *should* be an extension receiver)
|
||||
class ScopeTowerLevel(
|
||||
val session: FirSession,
|
||||
session: FirSession,
|
||||
val scope: FirScope
|
||||
) : TowerScopeLevel {
|
||||
) : SessionBasedTowerLevel(session) {
|
||||
override fun <T : ConeSymbol> processElementsByName(
|
||||
token: TowerScopeLevel.Token<T>,
|
||||
name: Name,
|
||||
extensionReceiver: ReceiverValueWithPossibleTypes?,
|
||||
explicitReceiver: ExpressionReceiverValue?,
|
||||
processor: TowerScopeLevel.TowerScopeLevelProcessor<T>
|
||||
): ProcessorAction {
|
||||
return when (token) {
|
||||
|
||||
TowerScopeLevel.Token.Properties -> scope.processPropertiesByName(name) { candidate ->
|
||||
val candidateHasExtensionReceiver = candidate.hasExtensionReceiver()
|
||||
if (candidateHasExtensionReceiver == (extensionReceiver != null)) {
|
||||
processor.consumeCandidate(candidate as T, boundDispatchReceiver = null)
|
||||
if (candidate.hasConsistentExtensionReceiver(explicitReceiver) && candidate.dispatchReceiverValue() == null) {
|
||||
processor.consumeCandidate(candidate as T, dispatchReceiverValue = null)
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
TowerScopeLevel.Token.Functions -> scope.processFunctionsByName(name) { candidate ->
|
||||
val candidateHasExtensionReceiver = candidate.hasExtensionReceiver()
|
||||
if (candidateHasExtensionReceiver == (extensionReceiver != null)) {
|
||||
processor.consumeCandidate(candidate as T, boundDispatchReceiver = null)
|
||||
// TODO: fix implicit receiver
|
||||
if (candidate.hasConsistentExtensionReceiver(explicitReceiver) && candidate.dispatchReceiverValue() == null) {
|
||||
processor.consumeCandidate(candidate as T, dispatchReceiverValue = null)
|
||||
} else {
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
@@ -200,7 +236,7 @@ class ScopeTowerLevel(
|
||||
TowerScopeLevel.Token.Objects -> scope.processClassifiersByNameWithAction(name, FirPosition.OTHER) {
|
||||
processor.consumeCandidate(
|
||||
it as T,
|
||||
boundDispatchReceiver = null
|
||||
dispatchReceiverValue = null
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -212,7 +248,6 @@ class ScopeTowerLevel(
|
||||
abstract class TowerDataConsumer {
|
||||
abstract fun consume(
|
||||
kind: TowerDataKind,
|
||||
implicitReceiverType: ConeKotlinType?,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
resultCollector: CandidateCollector,
|
||||
group: Int
|
||||
@@ -282,11 +317,7 @@ fun createSimpleConsumer(
|
||||
session,
|
||||
name,
|
||||
token,
|
||||
object : ReceiverValueWithPossibleTypes {
|
||||
override val type: ConeKotlinType
|
||||
get() = callInfo.typeProvider(callInfo.explicitReceiver)?.coneTypeSafe()
|
||||
?: ConeKotlinErrorType("No type calculated for: ${callInfo.explicitReceiver.renderWithType()}") // TODO: assert here
|
||||
},
|
||||
ExpressionReceiverValue(callInfo.explicitReceiver, callInfo.typeProvider),
|
||||
factory
|
||||
)
|
||||
} else {
|
||||
@@ -301,14 +332,13 @@ class PrioritizedTowerDataConsumer(
|
||||
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
implicitReceiverType: ConeKotlinType?,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
resultCollector: CandidateCollector,
|
||||
group: Int
|
||||
): ProcessorAction {
|
||||
if (checkSkip(group, resultCollector)) return ProcessorAction.NEXT
|
||||
for ((index, consumer) in consumers.withIndex()) {
|
||||
val action = consumer.consume(kind, implicitReceiverType, towerScopeLevel, resultCollector, group * consumers.size + index)
|
||||
val action = consumer.consume(kind, towerScopeLevel, resultCollector, group * consumers.size + index)
|
||||
if (action.stop()) {
|
||||
return ProcessorAction.STOP
|
||||
}
|
||||
@@ -321,14 +351,13 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
||||
val session: FirSession,
|
||||
val name: Name,
|
||||
val token: TowerScopeLevel.Token<T>,
|
||||
val explicitReceiver: ReceiverValueWithPossibleTypes,
|
||||
val explicitReceiver: ExpressionReceiverValue,
|
||||
val candidateFactory: CandidateFactory
|
||||
) : TowerDataConsumer() {
|
||||
|
||||
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
implicitReceiverType: ConeKotlinType?,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
resultCollector: CandidateCollector,
|
||||
group: Int
|
||||
@@ -339,14 +368,14 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
||||
MemberScopeTowerLevel(session, explicitReceiver).processElementsByName(
|
||||
token,
|
||||
name,
|
||||
extensionReceiver = null,
|
||||
explicitReceiver = null,
|
||||
processor = object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
|
||||
override fun consumeCandidate(symbol: T, dispatchReceiverValue: ClassDispatchReceiverValue?): ProcessorAction {
|
||||
resultCollector.consumeCandidate(
|
||||
group,
|
||||
candidateFactory.createCandidate(
|
||||
symbol,
|
||||
boundDispatchReceiver,
|
||||
dispatchReceiverValue,
|
||||
ExplicitReceiverKind.DISPATCH_RECEIVER
|
||||
)
|
||||
)
|
||||
@@ -359,14 +388,14 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
||||
towerScopeLevel.processElementsByName(
|
||||
token,
|
||||
name,
|
||||
extensionReceiver = explicitReceiver,
|
||||
explicitReceiver = explicitReceiver,
|
||||
processor = object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
|
||||
override fun consumeCandidate(symbol: T, dispatchReceiverValue: ClassDispatchReceiverValue?): ProcessorAction {
|
||||
resultCollector.consumeCandidate(
|
||||
group,
|
||||
candidateFactory.createCandidate(
|
||||
symbol,
|
||||
boundDispatchReceiver,
|
||||
dispatchReceiverValue,
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER
|
||||
)
|
||||
)
|
||||
@@ -390,7 +419,6 @@ class NoExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
||||
|
||||
override fun consume(
|
||||
kind: TowerDataKind,
|
||||
implicitReceiverType: ConeKotlinType?,
|
||||
towerScopeLevel: TowerScopeLevel,
|
||||
resultCollector: CandidateCollector,
|
||||
group: Int
|
||||
@@ -402,12 +430,16 @@ class NoExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
|
||||
towerScopeLevel.processElementsByName(
|
||||
token,
|
||||
name,
|
||||
null,
|
||||
object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction {
|
||||
explicitReceiver = null,
|
||||
processor = object : TowerScopeLevel.TowerScopeLevelProcessor<T> {
|
||||
override fun consumeCandidate(symbol: T, dispatchReceiverValue: ClassDispatchReceiverValue?): ProcessorAction {
|
||||
resultCollector.consumeCandidate(
|
||||
group,
|
||||
candidateFactory.createCandidate(symbol, boundDispatchReceiver, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER)
|
||||
candidateFactory.createCandidate(
|
||||
symbol,
|
||||
dispatchReceiverValue,
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
|
||||
)
|
||||
)
|
||||
return ProcessorAction.NEXT
|
||||
}
|
||||
@@ -426,15 +458,40 @@ class CallResolver(val typeCalculator: ReturnTypeCalculator, val session: FirSes
|
||||
|
||||
var scopes: List<FirScope>? = null
|
||||
|
||||
fun runTowerResolver(towerDataConsumer: TowerDataConsumer): CandidateCollector {
|
||||
private fun processImplicitReceiver(
|
||||
towerDataConsumer: TowerDataConsumer,
|
||||
implicitReceiverValue: ImplicitReceiverValue,
|
||||
collector: CandidateCollector,
|
||||
oldGroup: Int
|
||||
): Int {
|
||||
var group = oldGroup
|
||||
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, MemberScopeTowerLevel(session, implicitReceiverValue), collector, group++)
|
||||
|
||||
return group
|
||||
}
|
||||
|
||||
fun runTowerResolver(towerDataConsumer: TowerDataConsumer, implicitReceiverValues: List<ImplicitReceiverValue>): CandidateCollector {
|
||||
val collector = CandidateCollector(callInfo!!)
|
||||
|
||||
var group = 0
|
||||
|
||||
towerDataConsumer.consume(TowerDataKind.EMPTY, null, TowerScopeLevel.Empty, collector, group++)
|
||||
towerDataConsumer.consume(TowerDataKind.EMPTY, TowerScopeLevel.Empty, collector, group++)
|
||||
|
||||
for (scope in scopes!!) {
|
||||
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, null, ScopeTowerLevel(session, scope), collector, group++)
|
||||
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, scope), collector, group++)
|
||||
}
|
||||
|
||||
var blockDispatchReceivers = false
|
||||
for (implicitReceiverValue in implicitReceiverValues) {
|
||||
if (implicitReceiverValue is ImplicitDispatchReceiverValue) {
|
||||
if (blockDispatchReceivers) {
|
||||
continue
|
||||
}
|
||||
if (!implicitReceiverValue.boundSymbol.fir.isInner) {
|
||||
blockDispatchReceivers = true
|
||||
}
|
||||
}
|
||||
processImplicitReceiver(towerDataConsumer, implicitReceiverValue, collector, group)
|
||||
}
|
||||
|
||||
return collector
|
||||
@@ -522,8 +579,15 @@ class CandidateCollector(val callInfo: CallInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
fun FirCallableDeclaration.dispatchReceiverType(session: FirSession): ConeKotlinType? {
|
||||
fun FirCallableDeclaration.dispatchReceiverValue(session: FirSession): ClassDispatchReceiverValue? {
|
||||
// TODO: this is not true at least for inner class constructors
|
||||
if (this is FirConstructor) return null
|
||||
val id = (this.symbol as ConeCallableSymbol).callableId.classId ?: return null
|
||||
val symbol = session.service<FirSymbolProvider>().getClassLikeSymbolByFqName(id) as? FirClassSymbol ?: return null
|
||||
return symbol.fir.defaultType()
|
||||
}
|
||||
val regularClass = symbol.fir
|
||||
|
||||
// TODO: this is also not true, but objects can be also imported
|
||||
if (regularClass.classKind == ClassKind.OBJECT) return null
|
||||
|
||||
return ClassDispatchReceiverValue(regularClass.symbol)
|
||||
}
|
||||
|
||||
@@ -29,10 +29,10 @@ class CandidateFactory(
|
||||
|
||||
fun createCandidate(
|
||||
symbol: ConeSymbol,
|
||||
boundDispatchReceiver: ReceiverValueWithPossibleTypes?,
|
||||
dispatchReceiverValue: ClassDispatchReceiverValue?,
|
||||
explicitReceiverKind: ExplicitReceiverKind
|
||||
): Candidate {
|
||||
return Candidate(symbol, explicitReceiverKind, inferenceComponents, baseSystem)
|
||||
return Candidate(symbol, dispatchReceiverValue, explicitReceiverKind, inferenceComponents, baseSystem)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.renderWithType
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||
|
||||
interface ReceiverValue {
|
||||
val type: ConeKotlinType
|
||||
}
|
||||
|
||||
class ClassDispatchReceiverValue(val klassSymbol: FirClassSymbol) : ReceiverValue {
|
||||
override val type: ConeKotlinType = ConeClassTypeImpl(
|
||||
klassSymbol.toLookupTag(),
|
||||
klassSymbol.fir.typeParameters.map { ConeStarProjection }.toTypedArray(),
|
||||
isNullable = false
|
||||
)
|
||||
}
|
||||
|
||||
class ExpressionReceiverValue(
|
||||
private val explicitReceiverExpression: FirExpression,
|
||||
val typeProvider: (FirExpression) -> FirTypeRef?
|
||||
) : ReceiverValue {
|
||||
override val type: ConeKotlinType
|
||||
get() = typeProvider(explicitReceiverExpression)?.coneTypeSafe()
|
||||
?: ConeKotlinErrorType("No type calculated for: ${explicitReceiverExpression.renderWithType()}") // TODO: assert here
|
||||
}
|
||||
|
||||
interface ImplicitReceiverValue : ReceiverValue {
|
||||
}
|
||||
|
||||
class ImplicitDispatchReceiverValue(
|
||||
val boundSymbol: FirClassSymbol,
|
||||
override val type: ConeKotlinType
|
||||
) : ImplicitReceiverValue
|
||||
|
||||
class ImplicitExtensionReceiverValue(
|
||||
override val type: ConeKotlinType
|
||||
) : ImplicitReceiverValue
|
||||
@@ -9,6 +9,8 @@ import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
|
||||
import java.lang.IllegalStateException
|
||||
@@ -22,7 +24,7 @@ abstract class CheckerStage : ResolutionStage()
|
||||
|
||||
internal object CheckExplicitReceiverConsistency : ResolutionStage() {
|
||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
val receiverKind = candidate.receiverKind
|
||||
val receiverKind = candidate.explicitReceiverKind
|
||||
val explicitReceiver = callInfo.explicitReceiver
|
||||
// TODO: add invoke cases
|
||||
when (receiverKind) {
|
||||
@@ -42,14 +44,60 @@ internal object CheckExplicitReceiverConsistency : ResolutionStage() {
|
||||
}
|
||||
|
||||
internal sealed class CheckReceivers : ResolutionStage() {
|
||||
object Dispatch : CheckReceivers()
|
||||
object Dispatch : CheckReceivers() {
|
||||
override fun ExplicitReceiverKind.shouldBeResolvedAsImplicit(): Boolean {
|
||||
return this == EXTENSION_RECEIVER || this == NO_EXPLICIT_RECEIVER
|
||||
}
|
||||
|
||||
object Extension : CheckReceivers()
|
||||
override fun ExplicitReceiverKind.shouldBeResolvedAsExplicit(): Boolean {
|
||||
return this == DISPATCH_RECEIVER || this == BOTH_RECEIVERS
|
||||
}
|
||||
|
||||
override fun Candidate.getReceiverValue(): ReceiverValue? {
|
||||
return dispatchReceiverValue
|
||||
}
|
||||
}
|
||||
|
||||
object Extension : CheckReceivers() {
|
||||
override fun ExplicitReceiverKind.shouldBeResolvedAsImplicit(): Boolean {
|
||||
return this == DISPATCH_RECEIVER || this == NO_EXPLICIT_RECEIVER
|
||||
}
|
||||
|
||||
override fun ExplicitReceiverKind.shouldBeResolvedAsExplicit(): Boolean {
|
||||
return this == EXTENSION_RECEIVER || this == BOTH_RECEIVERS
|
||||
}
|
||||
|
||||
override fun Candidate.getReceiverValue(): ReceiverValue? {
|
||||
val callableSymbol = symbol as? FirCallableSymbol ?: return null
|
||||
val callable = callableSymbol.fir
|
||||
val type = (callable.receiverTypeRef as FirResolvedTypeRef?)?.type ?: return null
|
||||
return object : ReceiverValue {
|
||||
override val type: ConeKotlinType
|
||||
get() = type
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun Candidate.getReceiverValue(): ReceiverValue?
|
||||
|
||||
abstract fun ExplicitReceiverKind.shouldBeResolvedAsExplicit(): Boolean
|
||||
|
||||
abstract fun ExplicitReceiverKind.shouldBeResolvedAsImplicit(): Boolean
|
||||
|
||||
override fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||
val callableSymbol = candidate.symbol as? FirCallableSymbol ?: return
|
||||
val callableId = callableSymbol.callableId
|
||||
val callable = callableSymbol.fir
|
||||
val receiverParameterValue = candidate.getReceiverValue()
|
||||
val explicitReceiverExpression = callInfo.explicitReceiver
|
||||
val explicitReceiverKind = candidate.explicitReceiverKind
|
||||
|
||||
if (receiverParameterValue != null) {
|
||||
if (explicitReceiverExpression != null && explicitReceiverKind.shouldBeResolvedAsExplicit()) {
|
||||
resolveArgumentExpression(
|
||||
candidate.csBuilder, explicitReceiverExpression, receiverParameterValue.type,
|
||||
sink, isReceiver = true, typeProvider = callInfo.typeProvider
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ class FirSyntheticPropertiesScope(val session: FirSession, val baseScope: FirSco
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (ConeVariableSymbol) -> ProcessorAction): ProcessorAction {
|
||||
if (name.isSpecial) return ProcessorAction.NEXT
|
||||
if (baseScope.processFunctionsByName(Name.guessByFirstCharacter("get${name.identifier.capitalize()}")) {
|
||||
checkGetAndCreateSynthetic(name, it, processor)
|
||||
}.stop()) return ProcessorAction.STOP
|
||||
|
||||
+20
-13
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
||||
import org.jetbrains.kotlin.fir.symbols.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.*
|
||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||
@@ -79,9 +80,15 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
}
|
||||
|
||||
|
||||
inline fun <T> withLabel(labelName: Name, type: ConeKotlinType, block: () -> T): T {
|
||||
private inline fun <T> withLabelAndReceiverType(labelName: Name, owner: FirElement, type: ConeKotlinType, block: () -> T): T {
|
||||
labels.put(labelName, type)
|
||||
when (owner) {
|
||||
is FirRegularClass -> implicitReceiverStack += ImplicitDispatchReceiverValue(owner.symbol, type)
|
||||
is FirFunction -> implicitReceiverStack += ImplicitExtensionReceiverValue(type)
|
||||
else -> throw IllegalArgumentException("Incorrect label & receiver owner: ${owner.javaClass}")
|
||||
}
|
||||
val result = block()
|
||||
implicitReceiverStack.removeAt(implicitReceiverStack.size - 1)
|
||||
labels.remove(labelName, type)
|
||||
return result
|
||||
}
|
||||
@@ -90,7 +97,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
return withScopeCleanup(scopes) {
|
||||
val type = regularClass.defaultType()
|
||||
scopes.addIfNotNull(type.scope(session, ScopeSession()))
|
||||
withLabel(regularClass.name, type) {
|
||||
withLabelAndReceiverType(regularClass.name, regularClass, type) {
|
||||
super.transformRegularClass(regularClass, data)
|
||||
}
|
||||
}
|
||||
@@ -136,12 +143,13 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
}
|
||||
|
||||
val scopes = mutableListOf<FirScope>()
|
||||
val localScopes = mutableListOf<FirLocalScope>()
|
||||
private val localScopes = mutableListOf<FirLocalScope>()
|
||||
|
||||
val labels = LinkedHashMultimap.create<Name, ConeKotlinType>()
|
||||
private val labels = LinkedHashMultimap.create<Name, ConeKotlinType>()
|
||||
|
||||
private val implicitReceiverStack = mutableListOf<ImplicitReceiverValue>()
|
||||
|
||||
val jump = ReturnTypeCalculatorWithJump(session)
|
||||
private val jump = ReturnTypeCalculatorWithJump(session)
|
||||
|
||||
private fun <T> storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression {
|
||||
access.resultType = typeFromCallee(access)
|
||||
@@ -168,7 +176,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
}
|
||||
}
|
||||
|
||||
val inferenceComponents = InferenceComponents(object : ConeInferenceContext, TypeSystemInferenceExtensionContextDelegate {
|
||||
private val inferenceComponents = InferenceComponents(object : ConeInferenceContext, TypeSystemInferenceExtensionContextDelegate {
|
||||
override fun findCommonIntegerLiteralTypesSuperType(explicitSupertypes: List<SimpleTypeMarker>): SimpleTypeMarker? {
|
||||
//TODO wtf
|
||||
return explicitSupertypes.firstOrNull()
|
||||
@@ -201,7 +209,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
callee.name,
|
||||
info, inferenceComponents
|
||||
)
|
||||
val result = resolver.runTowerResolver(consumer)
|
||||
val result = resolver.runTowerResolver(consumer, implicitReceiverStack.asReversed())
|
||||
|
||||
val nameReference = createResolvedNamedReference(
|
||||
callee,
|
||||
@@ -279,7 +287,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
|
||||
val label = anonymousFunction.label
|
||||
return if (label != null && receiverTypeRef != null) {
|
||||
withLabel(Name.identifier(label.name), receiverTypeRef.coneTypeUnsafe()) { transform() }
|
||||
withLabelAndReceiverType(Name.identifier(label.name), anonymousFunction, receiverTypeRef.coneTypeUnsafe()) { transform() }
|
||||
} else {
|
||||
transform()
|
||||
}
|
||||
@@ -291,18 +299,17 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
|
||||
val name = functionCall.calleeReference.name
|
||||
|
||||
val receiver = functionCall.explicitReceiver
|
||||
val explicitReceiver = functionCall.explicitReceiver
|
||||
val arguments = functionCall.arguments
|
||||
val typeArguments = functionCall.typeArguments
|
||||
|
||||
|
||||
val info = CallInfo(CallKind.Function, receiver, arguments, typeArguments) { it.resultType }
|
||||
val info = CallInfo(CallKind.Function, explicitReceiver, arguments, typeArguments) { it.resultType }
|
||||
val resolver = CallResolver(jump, session)
|
||||
resolver.callInfo = info
|
||||
resolver.scopes = (scopes + localScopes).asReversed()
|
||||
|
||||
val consumer = createFunctionConsumer(session, name, info, inferenceComponents)
|
||||
val result = resolver.runTowerResolver(consumer)
|
||||
val result = resolver.runTowerResolver(consumer, implicitReceiverStack.asReversed())
|
||||
val bestCandidates = result.bestCandidates()
|
||||
val reducedCandidates = ConeOverloadConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents)
|
||||
.chooseMaximallySpecificCandidates(bestCandidates, discriminateGenerics = false)
|
||||
@@ -598,7 +605,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
||||
}
|
||||
|
||||
return if (receiverTypeRef != null) {
|
||||
withLabel(namedFunction.name, receiverTypeRef.coneTypeUnsafe()) { transform() }
|
||||
withLabelAndReceiverType(namedFunction.name, namedFunction, receiverTypeRef.coneTypeUnsafe()) { transform() }
|
||||
} else {
|
||||
transform()
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ FILE: access.kt
|
||||
^plus String()
|
||||
}
|
||||
|
||||
public final fun R|Foo|.check(): R|kotlin/String| {
|
||||
^check R|/Foo.abc|().R|/Bar.plus|(R|/Bar.bar|())
|
||||
public final fun R|Foo|.check(): <ERROR TYPE REF: Inapplicable(INAPPLICABLE): [kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus]> {
|
||||
^check R|/Foo.abc|().<Inapplicable(INAPPLICABLE): [kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus]>#(R|/bar|())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ FILE: receiverConsistency.kt
|
||||
}
|
||||
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
R|/C.err|()
|
||||
<Unresolved name: err>#()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ FILE: simple.kt
|
||||
}
|
||||
|
||||
public final fun err(): R|kotlin/Unit| {
|
||||
R|/Owner.foo|()
|
||||
<Unresolved name: foo>#()
|
||||
this#.<Unresolved name: foo>#()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user