diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index e7a6b534f28..1c2a5ff94a1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -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() ?: 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) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallResolver.kt index d81aee7d413..c6743ce9137 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallResolver.kt @@ -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, - val typeArguments: List, + val typeArguments: List, 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 processElementsByName( token: Token, name: Name, - extensionReceiver: ReceiverValueWithPossibleTypes?, + explicitReceiver: ExpressionReceiverValue?, processor: TowerScopeLevelProcessor ): ProcessorAction interface TowerScopeLevelProcessor { - fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction + fun consumeCandidate(symbol: T, dispatchReceiverValue: ClassDispatchReceiverValue?): ProcessorAction } object Empty : TowerScopeLevel { override fun processElementsByName( token: Token, name: Name, - extensionReceiver: ReceiverValueWithPossibleTypes?, + explicitReceiver: ExpressionReceiverValue?, processor: TowerScopeLevelProcessor ): 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 processMembers( output: TowerScopeLevel.TowerScopeLevelProcessor, + 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 processElementsByName( token: TowerScopeLevel.Token, name: Name, - extensionReceiver: ReceiverValueWithPossibleTypes?, + explicitReceiver: ExpressionReceiverValue?, processor: TowerScopeLevel.TowerScopeLevelProcessor ): 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 processElementsByName( token: TowerScopeLevel.Token, name: Name, - extensionReceiver: ReceiverValueWithPossibleTypes?, + explicitReceiver: ExpressionReceiverValue?, processor: TowerScopeLevel.TowerScopeLevelProcessor ): 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( val session: FirSession, val name: Name, val token: TowerScopeLevel.Token, - 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( MemberScopeTowerLevel(session, explicitReceiver).processElementsByName( token, name, - extensionReceiver = null, + explicitReceiver = null, processor = object : TowerScopeLevel.TowerScopeLevelProcessor { - 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( towerScopeLevel.processElementsByName( token, name, - extensionReceiver = explicitReceiver, + explicitReceiver = explicitReceiver, processor = object : TowerScopeLevel.TowerScopeLevelProcessor { - 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( override fun consume( kind: TowerDataKind, - implicitReceiverType: ConeKotlinType?, towerScopeLevel: TowerScopeLevel, resultCollector: CandidateCollector, group: Int @@ -402,12 +430,16 @@ class NoExplicitReceiverTowerDataConsumer( towerScopeLevel.processElementsByName( token, name, - null, - object : TowerScopeLevel.TowerScopeLevelProcessor { - override fun consumeCandidate(symbol: T, boundDispatchReceiver: ReceiverValueWithPossibleTypes?): ProcessorAction { + explicitReceiver = null, + processor = object : TowerScopeLevel.TowerScopeLevelProcessor { + 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? = 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): 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().getClassLikeSymbolByFqName(id) as? FirClassSymbol ?: return null - return symbol.fir.defaultType() -} \ No newline at end of file + 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) +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt index 3a40f7f2b7d..45dfb4d6695 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt @@ -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) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt new file mode 100644 index 00000000000..b371990b8e1 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt @@ -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 diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt index 90101bfb5d5..e4ae6e16fd2 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolverParts.kt @@ -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 + ) + } + } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt index 1cc9d0ef6fa..a88a6307017 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt @@ -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 diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt index 5548a7c33af..d3e70831c4f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt @@ -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 withLabel(labelName: Name, type: ConeKotlinType, block: () -> T): T { + private inline fun 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() - val localScopes = mutableListOf() + private val localScopes = mutableListOf() - val labels = LinkedHashMultimap.create() + private val labels = LinkedHashMultimap.create() + private val implicitReceiverStack = mutableListOf() - val jump = ReturnTypeCalculatorWithJump(session) + private val jump = ReturnTypeCalculatorWithJump(session) private fun 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? { //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() } diff --git a/compiler/fir/resolve/testData/resolve/expresssions/access.txt b/compiler/fir/resolve/testData/resolve/expresssions/access.txt index 599d8868a52..e9b1098b266 100644 --- a/compiler/fir/resolve/testData/resolve/expresssions/access.txt +++ b/compiler/fir/resolve/testData/resolve/expresssions/access.txt @@ -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(): { + ^check R|/Foo.abc|().#(R|/bar|()) } } diff --git a/compiler/fir/resolve/testData/resolve/expresssions/receiverConsistency.txt b/compiler/fir/resolve/testData/resolve/expresssions/receiverConsistency.txt index 10391b82a6e..59c45cc154d 100644 --- a/compiler/fir/resolve/testData/resolve/expresssions/receiverConsistency.txt +++ b/compiler/fir/resolve/testData/resolve/expresssions/receiverConsistency.txt @@ -18,7 +18,7 @@ FILE: receiverConsistency.kt } public final fun test(): R|kotlin/Unit| { - R|/C.err|() + #() } } diff --git a/compiler/fir/resolve/testData/resolve/nested/simple.txt b/compiler/fir/resolve/testData/resolve/nested/simple.txt index b7f65680a77..742efc34ecf 100644 --- a/compiler/fir/resolve/testData/resolve/nested/simple.txt +++ b/compiler/fir/resolve/testData/resolve/nested/simple.txt @@ -30,7 +30,7 @@ FILE: simple.kt } public final fun err(): R|kotlin/Unit| { - R|/Owner.foo|() + #() this#.#() }