FIR resolve: add correct receiver tower scopes + check receivers

This commit is contained in:
Mikhail Glukhikh
2019-04-16 16:47:28 +03:00
parent 4b5172cda3
commit 93496f1dee
10 changed files with 267 additions and 89 deletions
@@ -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
@@ -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
View File
@@ -30,7 +30,7 @@ FILE: simple.kt
}
public final fun err(): R|kotlin/Unit| {
R|/Owner.foo|()
<Unresolved name: foo>#()
this#.<Unresolved name: foo>#()
}