FIR: more accurate handling of dispatch receiver values

This commit fixes resolve priorities (see changed test data),
e.g. top-levels now have less priority than implicit receiver members
This commit is contained in:
Mikhail Glukhikh
2019-08-20 18:19:47 +03:00
parent fcb0b1b5eb
commit 5d6a526eec
11 changed files with 179 additions and 81 deletions
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.resultType
import org.jetbrains.kotlin.fir.resolve.typeForQualifier
import org.jetbrains.kotlin.fir.resolve.typeFromCallee
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
@@ -36,8 +37,8 @@ import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
class FirCallResolver(
private val transformer: FirBodyResolveTransformer,
private val scopes: List<FirScope>,
private val localScopes: List<FirScope>,
private val topLevelScopes: List<FirScope>,
private val localScopes: List<FirLocalScope>,
private val implicitReceiverStack: List<ImplicitReceiverValue>,
private val qualifiedResolver: FirQualifiedNameResolver
) : BodyResolveComponents by transformer {
@@ -64,9 +65,11 @@ class FirCallResolver(
file,
transformer.container
) { it.resultType }
val resolver = CallResolver(returnTypeCalculator, inferenceComponents, resolutionStageRunner)
resolver.callInfo = info
resolver.scopes = (scopes + localScopes).asReversed()
val resolver = CallResolver(
returnTypeCalculator, inferenceComponents, resolutionStageRunner,
topLevelScopes = topLevelScopes.asReversed(),
localScopes = localScopes.asReversed()
)
val consumer = createFunctionConsumer(session, name, info, inferenceComponents, resolver.collector, resolver)
val result = resolver.runTowerResolver(consumer, implicitReceiverStack.asReversed())
@@ -154,9 +157,11 @@ class FirCallResolver(
file,
transformer.container
) { it.resultType }
val resolver = CallResolver(returnTypeCalculator, inferenceComponents, resolutionStageRunner)
resolver.callInfo = info
resolver.scopes = (scopes + localScopes).asReversed()
val resolver = CallResolver(
returnTypeCalculator, inferenceComponents, resolutionStageRunner,
topLevelScopes = topLevelScopes.asReversed(),
localScopes = localScopes.asReversed()
)
val consumer = createVariableAndObjectConsumer(
session,
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
enum class TowerDataKind {
EMPTY,
@@ -17,10 +18,10 @@ enum class TowerDataKind {
class CallResolver(
val typeCalculator: ReturnTypeCalculator,
val components: InferenceComponents,
val resolutionStageRunner: ResolutionStageRunner
val resolutionStageRunner: ResolutionStageRunner,
val topLevelScopes: List<FirScope>,
val localScopes: List<FirLocalScope>
) {
var callInfo: CallInfo? = null
var scopes: List<FirScope>? = null
val session: FirSession get() = components.session
@@ -44,10 +45,39 @@ class CallResolver(
group++
)
for (scope in scopes!!) {
for (scope in localScopes) {
towerDataConsumer.consume(
TowerDataKind.TOWER_LEVEL,
ScopeTowerLevel(session, scope, implicitReceiverValue),
ScopeTowerLevel(session, scope, implicitExtensionReceiver = implicitReceiverValue),
group++
)
}
for (implicitDispatchReceiverValue in implicitReceiverValues) {
val implicitScope = implicitDispatchReceiverValue.implicitScope
if (implicitScope != null) {
towerDataConsumer.consume(
TowerDataKind.TOWER_LEVEL,
ScopeTowerLevel(session, implicitScope, implicitExtensionReceiver = implicitReceiverValue),
group++
)
}
if (implicitDispatchReceiverValue is ImplicitDispatchReceiverValue) {
val implicitCompanionScope = implicitDispatchReceiverValue.implicitCompanionScope
if (implicitCompanionScope != null) {
towerDataConsumer.consume(
TowerDataKind.TOWER_LEVEL,
ScopeTowerLevel(session, implicitCompanionScope, implicitExtensionReceiver = implicitReceiverValue),
group++
)
}
}
}
for (scope in topLevelScopes) {
towerDataConsumer.consume(
TowerDataKind.TOWER_LEVEL,
ScopeTowerLevel(session, scope, implicitExtensionReceiver = implicitReceiverValue),
group++
)
}
@@ -64,15 +94,27 @@ class CallResolver(
towerDataConsumer = consumer
var group = 0
// Member of explicit receiver' type
towerDataConsumer.consume(TowerDataKind.EMPTY, TowerScopeLevel.Empty, group++)
for (scope in scopes!!) {
// Member of local scope
for (scope in localScopes) {
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, scope), group++)
}
var blockDispatchReceivers = false
// Member of implicit receiver' type
for (implicitReceiverValue in implicitReceiverValues) {
val implicitScope = implicitReceiverValue.implicitScope
if (implicitScope != null) {
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, implicitScope), group++)
}
if (implicitReceiverValue is ImplicitDispatchReceiverValue) {
val implicitCompanionScope = implicitReceiverValue.implicitCompanionScope
if (implicitCompanionScope != null) {
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, implicitCompanionScope), group++)
}
if (blockDispatchReceivers) {
continue
}
@@ -83,6 +125,11 @@ class CallResolver(
group = processImplicitReceiver(towerDataConsumer, implicitReceiverValue, collector, group)
}
// Member of top-level scope
for (scope in topLevelScopes) {
towerDataConsumer.consume(TowerDataKind.TOWER_LEVEL, ScopeTowerLevel(session, scope), group++)
}
return collector
}
}
@@ -5,8 +5,14 @@
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.classId
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.scope
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
@@ -32,14 +38,28 @@ class ExpressionReceiverValue(
?: ConeKotlinErrorType("No type calculated for: ${explicitReceiverExpression.renderWithType()}") // TODO: assert here
}
interface ImplicitReceiverValue : ReceiverValue {
abstract class ImplicitReceiverValue(
final override val type: ConeKotlinType,
useSiteSession: FirSession,
scopeSession: ScopeSession
) : ReceiverValue {
val implicitScope: FirScope? = type.scope(useSiteSession, scopeSession)
}
class ImplicitDispatchReceiverValue(
val boundSymbol: FirClassSymbol,
override val type: ConeKotlinType
) : ImplicitReceiverValue
type: ConeKotlinType,
symbolProvider: FirSymbolProvider,
useSiteSession: FirSession,
scopeSession: ScopeSession
) : ImplicitReceiverValue(type, useSiteSession, scopeSession) {
val implicitCompanionScope: FirScope? = boundSymbol.fir.companionObject?.let { companionObject ->
symbolProvider.getClassUseSiteMemberScope(companionObject.classId, useSiteSession, scopeSession)
}
}
class ImplicitExtensionReceiverValue(
override val type: ConeKotlinType
) : ImplicitReceiverValue
type: ConeKotlinType,
useSiteSession: FirSession,
scopeSession: ScopeSession
) : ImplicitReceiverValue(type, useSiteSession, scopeSession)
@@ -69,6 +69,7 @@ abstract class SessionBasedTowerLevel(val session: FirSession) : TowerScopeLevel
protected fun AbstractFirBasedSymbol<*>.dispatchReceiverValue(): ClassDispatchReceiverValue? {
return when (this) {
is FirNamedFunctionSymbol -> fir.dispatchReceiverValue(session)
is FirPropertySymbol -> fir.dispatchReceiverValue(session)
is FirClassSymbol -> ClassDispatchReceiverValue(fir.symbol)
else -> null
}
@@ -53,7 +53,6 @@ open class FirBodyResolveTransformer(
private val booleanType = FirImplicitBooleanTypeRef(null)
final override val symbolProvider = session.service<FirSymbolProvider>()
val scopes = mutableListOf<FirScope>()
private var packageFqName = FqName.ROOT
final override lateinit var file: FirFile
@@ -67,6 +66,7 @@ open class FirBodyResolveTransformer(
}
private val localScopes = mutableListOf<FirLocalScope>()
private val topLevelScopes = mutableListOf<FirScope>()
private val implicitReceiverStack = mutableListOf<ImplicitReceiverValue>()
final override val inferenceComponents = inferenceComponents(session, returnTypeCalculator, scopeSession)
@@ -77,7 +77,7 @@ open class FirBodyResolveTransformer(
final override val resolutionStageRunner: ResolutionStageRunner = ResolutionStageRunner(inferenceComponents)
private val callResolver: FirCallResolver = FirCallResolver(
this,
scopes,
topLevelScopes,
localScopes,
implicitReceiverStack,
qualifiedResolver
@@ -94,9 +94,9 @@ open class FirBodyResolveTransformer(
override fun transformFile(file: FirFile, data: Any?): CompositeTransformResult<FirFile> {
packageFqName = file.packageFqName
this.file = file
return withScopeCleanup(scopes) {
scopes.addImportingScopes(file, session)
scopes += FirTopLevelDeclaredMemberScope(file, session)
return withScopeCleanup(topLevelScopes) {
topLevelScopes.addImportingScopes(file, session)
topLevelScopes += FirTopLevelDeclaredMemberScope(file, session)
super.transformFile(file, data)
}
}
@@ -139,27 +139,20 @@ open class FirBodyResolveTransformer(
}
override fun transformRegularClass(regularClass: FirRegularClass, data: Any?): CompositeTransformResult<FirDeclaration> {
return withScopeCleanup(scopes) {
val oldConstructorScope = primaryConstructorParametersScope
primaryConstructorParametersScope = null
val type = regularClass.defaultType()
scopes.addIfNotNull(type.scope(session, scopeSession))
val companionObject = regularClass.companionObject
if (companionObject != null) {
scopes.addIfNotNull(symbolProvider.getClassUseSiteMemberScope(companionObject.classId, session, scopeSession))
}
val result = withLabelAndReceiverType(regularClass.name, regularClass, type) {
val constructor = regularClass.declarations.firstOrNull() as? FirConstructor
if (constructor?.isPrimary == true) {
primaryConstructorParametersScope = FirLocalScope().apply {
constructor.valueParameters.forEach { this.storeDeclaration(it) }
}
val oldConstructorScope = primaryConstructorParametersScope
primaryConstructorParametersScope = null
val type = regularClass.defaultType()
val result = withLabelAndReceiverType(regularClass.name, regularClass, type) {
val constructor = regularClass.declarations.firstOrNull() as? FirConstructor
if (constructor?.isPrimary == true) {
primaryConstructorParametersScope = FirLocalScope().apply {
constructor.valueParameters.forEach { this.storeDeclaration(it) }
}
super.transformRegularClass(regularClass, data)
}
primaryConstructorParametersScope = oldConstructorScope
result
super.transformRegularClass(regularClass, data)
}
primaryConstructorParametersScope = oldConstructorScope
return result
}
override fun transformUncheckedNotNullCast(
@@ -359,17 +352,15 @@ open class FirBodyResolveTransformer(
): FirAnonymousFunction {
val receiverTypeRef = anonymousFunction.receiverTypeRef
fun transform(): FirAnonymousFunction {
return withScopeCleanup(scopes) {
scopes.addIfNotNull(receiverTypeRef?.coneTypeSafe<ConeKotlinType>()?.scope(session, scopeSession))
val expectedReturnType = lambdaResolution.expectedReturnTypeRef ?: anonymousFunction.returnTypeRef.takeUnless { it is FirImplicitTypeRef }
val expectedReturnType =
lambdaResolution.expectedReturnTypeRef ?: anonymousFunction.returnTypeRef.takeUnless { it is FirImplicitTypeRef }
val result = super.transformAnonymousFunction(anonymousFunction, expectedReturnType).single as FirAnonymousFunction
val body = result.body
if (result.returnTypeRef is FirImplicitTypeRef && body != null) {
result.transformReturnTypeRef(this, body.resultType)
result
} else {
result
}
val body = result.body
return if (result.returnTypeRef is FirImplicitTypeRef && body != null) {
result.transformReturnTypeRef(this, body.resultType)
result
} else {
result
}
}
@@ -563,18 +554,14 @@ open class FirBodyResolveTransformer(
if (function is FirNamedFunction) {
localScopes.lastOrNull()?.storeDeclaration(function)
}
return withScopeCleanup(scopes) {
scopes.addIfNotNull(receiverTypeRef?.coneTypeSafe<ConeKotlinType>()?.scope(session, scopeSession))
val result = transformFunction(function, returnTypeRef).single as FirFunction<*>
val body = result.body
if (result is FirTypedDeclaration && result.returnTypeRef is FirImplicitTypeRef && body != null) {
result.transformReturnTypeRef(this, body.resultType)
result
} else {
result
}.compose()
}
val result = transformFunction(function, returnTypeRef).single as FirFunction<*>
val body = result.body
return if (result is FirTypedDeclaration && result.returnTypeRef is FirImplicitTypeRef && body != null) {
result.transformReturnTypeRef(this, body.resultType)
result
} else {
result
}.compose()
}
override fun transformNamedFunction(namedFunction: FirNamedFunction, data: Any?): CompositeTransformResult<FirDeclaration> {
@@ -783,10 +770,16 @@ open class FirBodyResolveTransformer(
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}")
implicitReceiverStack += when (owner) {
is FirRegularClass -> {
ImplicitDispatchReceiverValue(owner.symbol, type, symbolProvider, session, scopeSession)
}
is FirFunction<*> -> {
ImplicitExtensionReceiverValue(type, session, scopeSession)
}
else -> {
throw IllegalArgumentException("Incorrect label & receiver owner: ${owner.javaClass}")
}
}
val result = block()
implicitReceiverStack.removeAt(implicitReceiverStack.size - 1)
@@ -37,11 +37,11 @@ FILE: access.kt
}
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|())
^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.bar|())
}
public final fun R|Foo|.check2(): R|kotlin/String| {
^check2 String().R|kotlin/String.plus|(R|/bar|())
^check2 String().R|kotlin/String.plus|(R|/Bar.bar|())
}
}
@@ -10,4 +10,16 @@ class Foo {
operator fun invoke(): Foo { return this }
fun bar() = x() // Should resolve to invoke
}
class Bar {
fun x() {}
val x: Bar = Bar()
operator fun invoke(): Bar { return this }
fun baz() {
x() // Should resolve to fun x()
}
}
@@ -18,3 +18,23 @@ FILE: explicitReceiver.kt
}
}
public final class Bar : R|kotlin/Any| {
public constructor(): R|Bar| {
super<R|kotlin/Any|>()
}
public final fun x(): R|kotlin/Unit| {
}
public final val x: R|Bar| = R|/Bar.Bar|()
public get(): R|Bar|
public final operator fun invoke(): R|Bar| {
^invoke this#
}
public final fun baz(): R|kotlin/Unit| {
R|/Bar.x|()
}
}
@@ -13,8 +13,8 @@ FILE: extension.kt
public final val x: R|kotlin/Int| = Int(0)
public get(): R|kotlin/Int|
public final fun foo(): R|kotlin/Unit| {
^foo R|/x|()
public final fun foo(): R|Foo| {
^foo R|/Foo.x|.R|/Foo.invoke|()
}
}
@@ -4,7 +4,7 @@ FILE: recursiveBug.kt
super<R|kotlin/Any|>()
}
public final val result: R|kotlin/String| = R|kotlin/run|<R|kotlin/String|>(<L> = run@fun <anonymous>(): R|kotlin/String| {
public final val result: R|kotlin/String| = R|kotlin/run|<R|Foo|, R|kotlin/String|>(<L> = run@fun R|Foo|.<anonymous>(it: R|Foo|): R|kotlin/String| {
R|<local>/name|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/String|>|()
}
)
@@ -1,9 +1,9 @@
FILE fqName:<root> fileName:/implicitCastToNonNull.kt
FUN name:test1 visibility:public modality:FINAL <> (x:kotlin.String?) returnType:kotlin.Int
FUN name:test1 visibility:public modality:FINAL <> (x:kotlin.String?) returnType:IrErrorType
VALUE_PARAMETER name:x index:0 type:kotlin.String?
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test1 (x: kotlin.String?): kotlin.Int declared in <root>'
WHEN type=kotlin.Int origin=IF
RETURN type=kotlin.Nothing from='public final fun test1 (x: kotlin.String?): IrErrorType declared in <root>'
WHEN type=IrErrorType origin=IF
BRANCH
if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: GET_VAR 'x: kotlin.String? declared in <root>.test1' type=kotlin.String? origin=null
@@ -11,13 +11,13 @@ FILE fqName:<root> fileName:/implicitCastToNonNull.kt
then: CONST Int type=kotlin.Int value=0
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: ERROR_CALL 'No getter found for R|kotlin/String.length|' type=kotlin.Int
FUN name:test2 visibility:public modality:FINAL <T> (x:T of <root>.test2) returnType:kotlin.Int
then: ERROR_CALL 'Unresolved reference: <Inapplicable(WRONG_RECEIVER): [kotlin/String.length]>#' type=IrErrorType
FUN name:test2 visibility:public modality:FINAL <T> (x:T of <root>.test2) returnType:IrErrorType
TYPE_PARAMETER name:T index:0 variance: superTypes:[]
VALUE_PARAMETER name:x index:0 type:T of <root>.test2
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test2 <T> (x: T of <root>.test2): kotlin.Int declared in <root>'
WHEN type=kotlin.Int origin=IF
RETURN type=kotlin.Nothing from='public final fun test2 <T> (x: T of <root>.test2): IrErrorType declared in <root>'
WHEN type=IrErrorType origin=IF
BRANCH
if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ
arg0: GET_VAR 'x: T of <root>.test2 declared in <root>.test2' type=T of <root>.test2 origin=null
@@ -25,7 +25,7 @@ FILE fqName:<root> fileName:/implicitCastToNonNull.kt
then: CONST Int type=kotlin.Int value=0
BRANCH
if: CONST Boolean type=kotlin.Boolean value=true
then: ERROR_CALL 'No getter found for R|kotlin/CharSequence.length|' type=kotlin.Int
then: ERROR_CALL 'Unresolved reference: <Inapplicable(WRONG_RECEIVER): [kotlin/CharSequence.length]>#' type=IrErrorType
FUN name:test3 visibility:public modality:FINAL <T> (x:kotlin.Any) returnType:IrErrorType [inline]
TYPE_PARAMETER name:T index:0 variance: superTypes:[]
VALUE_PARAMETER name:x index:0 type:kotlin.Any