[FIR] Prefer the non-smartcasted receiver in resolution if it's visible
Previously, we would ignore the candidate with the non-smartcasted receiver if they have the same symbol. Now we prefer them when they're visible or when the smart cast changes the nullability.
This commit is contained in:
committed by
Space Team
parent
5186ba80e2
commit
ad2689ecbf
+3
-2
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.resolve.calls.CandidateFactory
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
|
||||
internal class CandidateFactoriesAndCollectors(
|
||||
// Common calls
|
||||
@@ -85,8 +86,8 @@ private class TowerScopeLevelProcessor(
|
||||
scope: FirScope,
|
||||
objectsByName: Boolean,
|
||||
isFromOriginalTypeInPresenceOfSmartCast: Boolean,
|
||||
) {
|
||||
resultCollector.consumeCandidate(
|
||||
): CandidateApplicability {
|
||||
return resultCollector.consumeCandidate(
|
||||
group, candidateFactory.createCandidate(
|
||||
callInfo,
|
||||
symbol,
|
||||
|
||||
+45
-21
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitAnyTypeRef
|
||||
import org.jetbrains.kotlin.fir.utils.exceptions.withConeTypeEntry
|
||||
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.HidesMembers
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
|
||||
@@ -59,7 +60,7 @@ abstract class TowerScopeLevel {
|
||||
scope: FirScope,
|
||||
objectsByName: Boolean = false,
|
||||
isFromOriginalTypeInPresenceOfSmartCast: Boolean = false,
|
||||
)
|
||||
): CandidateApplicability
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,14 +87,13 @@ class MemberScopeTowerLevel(
|
||||
val scope = dispatchReceiverValue.scope(session, scopeSession) ?: return ProcessResult.SCOPE_EMPTY
|
||||
var (empty, candidates) = scope.collectCandidates(processScopeMembers)
|
||||
|
||||
val scopeWithoutSmartcast = getOriginalReceiverExpressionIfStableSmartCast()
|
||||
?.resolvedType
|
||||
?.scope(
|
||||
session,
|
||||
scopeSession,
|
||||
bodyResolveComponents.returnTypeCalculator.callableCopyTypeCalculator,
|
||||
requiredMembersPhase = FirResolvePhase.STATUS,
|
||||
)
|
||||
val receiverTypeWithoutSmartCast = getOriginalReceiverExpressionIfStableSmartCast()?.resolvedType
|
||||
val scopeWithoutSmartcast = receiverTypeWithoutSmartCast?.scope(
|
||||
session,
|
||||
scopeSession,
|
||||
bodyResolveComponents.returnTypeCalculator.callableCopyTypeCalculator,
|
||||
requiredMembersPhase = FirResolvePhase.STATUS,
|
||||
)
|
||||
|
||||
if (scopeWithoutSmartcast == null) {
|
||||
consumeCandidates(
|
||||
@@ -107,12 +107,22 @@ class MemberScopeTowerLevel(
|
||||
scopeWithoutSmartcast.collectCandidates(processScopeMembers).let { (isEmpty, originalCandidates) ->
|
||||
empty = empty && isEmpty
|
||||
for (originalCandidate in originalCandidates) {
|
||||
map[originalCandidate.member] = MemberFromSmartcastScope(originalCandidate, cameFromSmartcast = false)
|
||||
map[originalCandidate.member] = MemberFromSmartcastScope(originalCandidate, DispatchReceiverToUse.UnwrapSmartcast)
|
||||
}
|
||||
}
|
||||
|
||||
for (candidateFromSmartCast in candidates) {
|
||||
map[candidateFromSmartCast.member] = MemberFromSmartcastScope(candidateFromSmartCast, cameFromSmartcast = true)
|
||||
val existing = map[candidateFromSmartCast.member]
|
||||
|
||||
// If both scopes return the same symbol, we want to prefer the candidate from the original scope without smartcast
|
||||
// with two exceptions:
|
||||
// - When the smart-casted type is always null, we want to return it and report UNSAFE_CALL.
|
||||
// - When the original type can be null, in this case the smart-case either makes it not-null or the call is red anyway.
|
||||
if (existing == null || dispatchReceiverValue.type.isNullableNothing || receiverTypeWithoutSmartCast.canBeNull) {
|
||||
map[candidateFromSmartCast.member] = MemberFromSmartcastScope(candidateFromSmartCast, DispatchReceiverToUse.SmartcastWithoutUnwrapping)
|
||||
} else {
|
||||
existing.dispatchReceiverToUse = DispatchReceiverToUse.SmartcastIfUnwrappedInvisible
|
||||
}
|
||||
}
|
||||
|
||||
consumeCandidates(
|
||||
@@ -170,9 +180,15 @@ class MemberScopeTowerLevel(
|
||||
return if (empty) ProcessResult.SCOPE_EMPTY else ProcessResult.FOUND
|
||||
}
|
||||
|
||||
private data class MemberFromSmartcastScope<T : FirCallableSymbol<*>>(
|
||||
private enum class DispatchReceiverToUse(val unwrapSmartcast: Boolean) {
|
||||
UnwrapSmartcast(true),
|
||||
SmartcastWithoutUnwrapping(false),
|
||||
SmartcastIfUnwrappedInvisible(true),
|
||||
}
|
||||
|
||||
private class MemberFromSmartcastScope<T : FirCallableSymbol<*>>(
|
||||
val memberWithBaseScope: MemberWithBaseScope<T>,
|
||||
val cameFromSmartcast: Boolean
|
||||
var dispatchReceiverToUse: DispatchReceiverToUse,
|
||||
)
|
||||
|
||||
private fun <T : FirCallableSymbol<*>> FirTypeScope.collectCandidates(
|
||||
@@ -208,13 +224,11 @@ class MemberScopeTowerLevel(
|
||||
?: candidatesWithSmartcast?.values?.map { it.memberWithBaseScope }
|
||||
?: error("candidatesWithoutSmartcast or candidatesWithSmartcast should be not null")
|
||||
|
||||
for (candidateWithScope in candidates) {
|
||||
val (candidate, scope) = candidateWithScope
|
||||
for ((candidate, scope) in candidates) {
|
||||
if (candidate.hasConsistentExtensionReceiver(givenExtensionReceiverOptions)) {
|
||||
val isFromOriginalTypeInPresenceOfSmartCast = candidatesWithSmartcast != null &&
|
||||
!candidatesWithSmartcast.getValue(candidateWithScope.member).cameFromSmartcast
|
||||
|
||||
val dispatchReceiverToUse = when {
|
||||
val dispatchReceiverToUse = candidatesWithSmartcast?.getValue(candidate)?.dispatchReceiverToUse
|
||||
val isFromOriginalTypeInPresenceOfSmartCast = dispatchReceiverToUse?.unwrapSmartcast == true
|
||||
val dispatchReceiver = when {
|
||||
isFromOriginalTypeInPresenceOfSmartCast ->
|
||||
getOriginalReceiverExpressionIfStableSmartCast()
|
||||
// For a chain inference stub in dispatch receiver, we have to provide an explicit cast to Any
|
||||
@@ -229,13 +243,23 @@ class MemberScopeTowerLevel(
|
||||
else -> dispatchReceiverValue.receiverExpression
|
||||
}
|
||||
|
||||
output.consumeCandidate(
|
||||
val applicability = output.consumeCandidate(
|
||||
candidate,
|
||||
dispatchReceiverToUse,
|
||||
dispatchReceiver,
|
||||
givenExtensionReceiverOptions,
|
||||
scope,
|
||||
isFromOriginalTypeInPresenceOfSmartCast = isFromOriginalTypeInPresenceOfSmartCast
|
||||
)
|
||||
|
||||
if (applicability == CandidateApplicability.K2_VISIBILITY_ERROR && dispatchReceiverToUse == DispatchReceiverToUse.SmartcastIfUnwrappedInvisible) {
|
||||
output.consumeCandidate(
|
||||
candidate,
|
||||
dispatchReceiverValue.receiverExpression,
|
||||
givenExtensionReceiverOptions,
|
||||
scope,
|
||||
isFromOriginalTypeInPresenceOfSmartCast = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.InferredEmptyIntersection
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -140,6 +141,18 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
replaceCalleeReference(calleeReference.toResolvedReference())
|
||||
replaceDispatchReceiver(dispatchReceiver)
|
||||
replaceExtensionReceiver(extensionReceiver)
|
||||
|
||||
// If the explicit receiver is a smartcast expression, we can choose to use the unwrapped expression as dispatch receiver.
|
||||
// To maintain the invariant
|
||||
// explicitReceiver != null => explicitReceiver == dispatchReceiver || explicitReceiver == extensionReceiver
|
||||
// we update the explicit receiver here.
|
||||
// We only do this if the candidate is successful, otherwise, we can lose the explicit receiver node in red code like
|
||||
// fun f(s: String, action: (String.() -> Unit)?) {
|
||||
// s.action?.let { it() }
|
||||
//}
|
||||
if (subCandidate.explicitReceiverKind == ExplicitReceiverKind.DISPATCH_RECEIVER && subCandidate.applicability.isSuccess) {
|
||||
replaceExplicitReceiver(dispatchReceiver)
|
||||
}
|
||||
}
|
||||
|
||||
qualifiedAccessExpression.replaceContextReceiverArguments(subCandidate.contextReceiverArguments())
|
||||
|
||||
+4
-8
@@ -29,12 +29,10 @@ FILE fqName:<root> fileName:/propertyInitializationAfterSmartCast.kt
|
||||
TYPE_OP type=<root>.Derived_1 origin=CAST typeOperand=<root>.Derived_1
|
||||
GET_VAR '<this>: <root>.Base_1 declared in <root>.Base_1' type=<root>.Base_1 origin=null
|
||||
SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:x type:kotlin.Any? visibility:private [final]' type=kotlin.Unit origin=null
|
||||
receiver: TYPE_OP type=<root>.Derived_1 origin=IMPLICIT_CAST typeOperand=<root>.Derived_1
|
||||
GET_VAR '<this>: <root>.Base_1 declared in <root>.Base_1' type=<root>.Base_1 origin=null
|
||||
receiver: GET_VAR '<this>: <root>.Base_1 declared in <root>.Base_1' type=<root>.Base_1 origin=null
|
||||
value: CONST String type=kotlin.String value="O"
|
||||
SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:y type:kotlin.Any? visibility:private [final]' type=kotlin.Unit origin=null
|
||||
receiver: TYPE_OP type=<root>.Derived_1 origin=IMPLICIT_CAST typeOperand=<root>.Derived_1
|
||||
GET_VAR '<this>: <root>.Base_1 declared in <root>.Base_1' type=<root>.Base_1 origin=null
|
||||
receiver: GET_VAR '<this>: <root>.Base_1 declared in <root>.Base_1' type=<root>.Base_1 origin=null
|
||||
value: CONST String type=kotlin.String value="O"
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
|
||||
overridden:
|
||||
@@ -114,12 +112,10 @@ FILE fqName:<root> fileName:/propertyInitializationAfterSmartCast.kt
|
||||
TYPE_OP type=<root>.Impl_2 origin=CAST typeOperand=<root>.Impl_2
|
||||
GET_VAR '<this>: <root>.Base_2 declared in <root>.Base_2' type=<root>.Base_2 origin=null
|
||||
SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:x type:kotlin.Any? visibility:private [final]' type=kotlin.Unit origin=null
|
||||
receiver: TYPE_OP type=<root>.Impl_2 origin=IMPLICIT_CAST typeOperand=<root>.Impl_2
|
||||
GET_VAR '<this>: <root>.Base_2 declared in <root>.Base_2' type=<root>.Base_2 origin=null
|
||||
receiver: GET_VAR '<this>: <root>.Base_2 declared in <root>.Base_2' type=<root>.Base_2 origin=null
|
||||
value: CONST String type=kotlin.String value="K"
|
||||
SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:y type:kotlin.Any? visibility:private [final]' type=kotlin.Unit origin=null
|
||||
receiver: TYPE_OP type=<root>.Impl_2 origin=IMPLICIT_CAST typeOperand=<root>.Impl_2
|
||||
GET_VAR '<this>: <root>.Base_2 declared in <root>.Base_2' type=<root>.Base_2 origin=null
|
||||
receiver: GET_VAR '<this>: <root>.Base_2 declared in <root>.Base_2' type=<root>.Base_2 origin=null
|
||||
value: CONST String type=kotlin.String value="K"
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
|
||||
overridden:
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
|
||||
open class SuperFoo {
|
||||
public fun bar() {
|
||||
if (this is Foo) {
|
||||
|
||||
+17
@@ -27,4 +27,21 @@ class Derived : Base() {
|
||||
x.y = x.y + 1
|
||||
}
|
||||
}
|
||||
|
||||
protected fun baz2(x: Base?) {
|
||||
x.<!INVISIBLE_REFERENCE!>foo<!>()
|
||||
x.<!INVISIBLE_REFERENCE!>bar<!>()
|
||||
|
||||
x.<!INVISIBLE_REFERENCE!>x<!> = x.<!INVISIBLE_REFERENCE!>x<!> + 1
|
||||
x.<!INVISIBLE_SETTER!>y<!> = x<!UNSAFE_CALL!>.<!>y + 1
|
||||
|
||||
if (x is Derived) {
|
||||
x.foo()
|
||||
x.bar()
|
||||
x.baz(x)
|
||||
|
||||
x.x = x.x + 1
|
||||
x.y = x.y + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
@@ -27,4 +27,21 @@ class Derived : Base() {
|
||||
<!INVISIBLE_SETTER!>x.y<!> = x.y + 1
|
||||
}
|
||||
}
|
||||
|
||||
protected fun baz2(x: Base?) {
|
||||
x<!UNSAFE_CALL!>.<!><!INVISIBLE_MEMBER!>foo<!>()
|
||||
x<!UNSAFE_CALL!>.<!><!INVISIBLE_MEMBER!>bar<!>()
|
||||
|
||||
x<!UNSAFE_CALL!>.<!><!INVISIBLE_MEMBER!>x<!> = x<!UNSAFE_CALL!>.<!><!INVISIBLE_MEMBER!>x<!> + 1
|
||||
<!INVISIBLE_SETTER!>x<!UNSAFE_CALL!>.<!>y<!> = x<!UNSAFE_CALL!>.<!>y + 1
|
||||
|
||||
if (x is Derived) {
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.foo()
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.bar()
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.baz(<!DEBUG_INFO_SMARTCAST!>x<!>)
|
||||
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.x = <!DEBUG_INFO_SMARTCAST!>x<!>.x + 1
|
||||
<!DEBUG_INFO_SMARTCAST!>x<!>.y = <!DEBUG_INFO_SMARTCAST!>x<!>.y + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
package
|
||||
|
||||
public open class Base {
|
||||
public constructor Base()
|
||||
protected open var x: kotlin.Int
|
||||
public open var y: kotlin.Int
|
||||
protected open fun bar(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
protected open fun foo(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Derived : Base {
|
||||
public constructor Derived()
|
||||
protected open override /*1*/ /*fake_override*/ var x: kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ var y: kotlin.Int
|
||||
protected open override /*1*/ fun bar(): kotlin.Unit
|
||||
protected final fun baz(/*0*/ x: Base): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
protected open override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+4
-4
@@ -41,10 +41,10 @@ fun testWithSubject_ok(x: Boolean, y: Boolean?, any: Any, z: Boolean) {
|
||||
x !in x -> {}
|
||||
x is String -> {}
|
||||
x !is String -> {}
|
||||
x <!OVERLOAD_RESOLUTION_AMBIGUITY!><<!> x -> {}
|
||||
x <!OVERLOAD_RESOLUTION_AMBIGUITY!>><!> x -> {}
|
||||
x <!OVERLOAD_RESOLUTION_AMBIGUITY!><=<!> x -> {}
|
||||
x <!OVERLOAD_RESOLUTION_AMBIGUITY!>>=<!> x -> {}
|
||||
x < x -> {}
|
||||
x > x -> {}
|
||||
x <= x -> {}
|
||||
x >= x -> {}
|
||||
x == x -> {}
|
||||
x != x -> {}
|
||||
<!DEPRECATED_IDENTITY_EQUALS!>x === x<!> -> {}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
FILE fqName:<root> fileName:/smartCastInValInitialization.kt
|
||||
CLASS CLASS name:RootBus modality:FINAL visibility:public superTypes:[<root>.MessageBusImpl]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.RootBus
|
||||
CONSTRUCTOR visibility:public <> () returnType:<root>.RootBus [primary]
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () declared in <root>.MessageBusImpl'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:RootBus modality:FINAL visibility:public superTypes:[<root>.MessageBusImpl]'
|
||||
PROPERTY FAKE_OVERRIDE name:parentBus visibility:public modality:FINAL [fake_override,val]
|
||||
overridden:
|
||||
public final parentBus: kotlin.Any?
|
||||
FUN FAKE_OVERRIDE name:<get-parentBus> visibility:public modality:FINAL <> ($this:<root>.MessageBusImpl) returnType:kotlin.Any? [fake_override]
|
||||
correspondingProperty: PROPERTY FAKE_OVERRIDE name:parentBus visibility:public modality:FINAL [fake_override,val]
|
||||
overridden:
|
||||
public final fun <get-parentBus> (): kotlin.Any? declared in <root>.MessageBusImpl
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.MessageBusImpl
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
|
||||
overridden:
|
||||
public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in <root>.MessageBusImpl
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
|
||||
overridden:
|
||||
public open fun hashCode (): kotlin.Int declared in <root>.MessageBusImpl
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
|
||||
overridden:
|
||||
public open fun toString (): kotlin.String declared in <root>.MessageBusImpl
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
CLASS CLASS name:MessageBusImpl modality:OPEN visibility:public superTypes:[kotlin.Any]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.MessageBusImpl
|
||||
CONSTRUCTOR visibility:public <> () returnType:<root>.MessageBusImpl [primary]
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () declared in kotlin.Any'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:MessageBusImpl modality:OPEN visibility:public superTypes:[kotlin.Any]'
|
||||
PROPERTY name:parentBus visibility:public modality:FINAL [val]
|
||||
FIELD PROPERTY_BACKING_FIELD name:parentBus type:kotlin.Any? visibility:private [final]
|
||||
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-parentBus> visibility:public modality:FINAL <> ($this:<root>.MessageBusImpl) returnType:kotlin.Any?
|
||||
correspondingProperty: PROPERTY name:parentBus visibility:public modality:FINAL [val]
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.MessageBusImpl
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun <get-parentBus> (): kotlin.Any? declared in <root>.MessageBusImpl'
|
||||
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:parentBus type:kotlin.Any? visibility:private [final]' type=kotlin.Any? origin=null
|
||||
receiver: GET_VAR '<this>: <root>.MessageBusImpl declared in <root>.MessageBusImpl.<get-parentBus>' type=<root>.MessageBusImpl origin=null
|
||||
ANONYMOUS_INITIALIZER isStatic=false
|
||||
BLOCK_BODY
|
||||
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
|
||||
TYPE_OP type=<root>.RootBus origin=CAST typeOperand=<root>.RootBus
|
||||
GET_VAR '<this>: <root>.MessageBusImpl declared in <root>.MessageBusImpl' type=<root>.MessageBusImpl origin=null
|
||||
SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:parentBus type:kotlin.Any? visibility:private [final]' type=kotlin.Unit origin=null
|
||||
receiver: TYPE_OP type=<root>.RootBus origin=IMPLICIT_CAST typeOperand=<root>.RootBus
|
||||
GET_VAR '<this>: <root>.MessageBusImpl declared in <root>.MessageBusImpl' type=<root>.MessageBusImpl origin=null
|
||||
value: CONST Null type=kotlin.Nothing? value=null
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
|
||||
overridden:
|
||||
public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
|
||||
overridden:
|
||||
public open fun hashCode (): kotlin.Int declared in kotlin.Any
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
|
||||
overridden:
|
||||
public open fun toString (): kotlin.String declared in kotlin.Any
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
@@ -1,25 +0,0 @@
|
||||
class RootBus : MessageBusImpl {
|
||||
constructor() /* primary */ {
|
||||
super/*MessageBusImpl*/()
|
||||
/* <init>() */
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
open class MessageBusImpl {
|
||||
constructor() /* primary */ {
|
||||
super/*Any*/()
|
||||
/* <init>() */
|
||||
|
||||
}
|
||||
|
||||
val parentBus: Any?
|
||||
get
|
||||
|
||||
init {
|
||||
<this> as RootBus /*~> Unit */
|
||||
<this> /*as RootBus */.#parentBus = null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
class RootBus: MessageBusImpl()
|
||||
|
||||
open class MessageBusImpl {
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
FILE fqName:<root> fileName:/smartCastAside.kt
|
||||
CLASS INTERFACE name:A modality:ABSTRACT visibility:public superTypes:[kotlin.Any]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.A
|
||||
FUN name:foo visibility:public modality:ABSTRACT <> ($this:<root>.A) returnType:kotlin.Unit
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.A
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
|
||||
overridden:
|
||||
public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
|
||||
overridden:
|
||||
public open fun hashCode (): kotlin.Int declared in kotlin.Any
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
|
||||
overridden:
|
||||
public open fun toString (): kotlin.String declared in kotlin.Any
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
CLASS INTERFACE name:B modality:ABSTRACT visibility:public superTypes:[<root>.A]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.B
|
||||
FUN name:bar visibility:public modality:ABSTRACT <> ($this:<root>.B) returnType:kotlin.Unit
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.B
|
||||
FUN FAKE_OVERRIDE name:foo visibility:public modality:ABSTRACT <> ($this:<root>.A) returnType:kotlin.Unit [fake_override]
|
||||
overridden:
|
||||
public abstract fun foo (): kotlin.Unit declared in <root>.A
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.A
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
|
||||
overridden:
|
||||
public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in <root>.A
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
|
||||
overridden:
|
||||
public open fun hashCode (): kotlin.Int declared in <root>.A
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
|
||||
overridden:
|
||||
public open fun toString (): kotlin.String declared in <root>.A
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
CLASS INTERFACE name:C modality:ABSTRACT visibility:public superTypes:[<root>.A]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.C
|
||||
FUN name:baz visibility:public modality:ABSTRACT <> ($this:<root>.C) returnType:kotlin.Unit
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.C
|
||||
FUN FAKE_OVERRIDE name:foo visibility:public modality:ABSTRACT <> ($this:<root>.A) returnType:kotlin.Unit [fake_override]
|
||||
overridden:
|
||||
public abstract fun foo (): kotlin.Unit declared in <root>.A
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.A
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
|
||||
overridden:
|
||||
public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in <root>.A
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
|
||||
overridden:
|
||||
public open fun hashCode (): kotlin.Int declared in <root>.A
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
|
||||
overridden:
|
||||
public open fun toString (): kotlin.String declared in <root>.A
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
FUN name:test visibility:public modality:FINAL <> (param:<root>.B) returnType:kotlin.Unit
|
||||
VALUE_PARAMETER name:param index:0 type:<root>.B
|
||||
BLOCK_BODY
|
||||
WHEN type=kotlin.Unit origin=IF
|
||||
BRANCH
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=<root>.C
|
||||
GET_VAR 'param: <root>.B declared in <root>.test' type=<root>.B origin=null
|
||||
then: BLOCK type=kotlin.Unit origin=null
|
||||
CALL 'public abstract fun foo (): kotlin.Unit declared in <root>.A' type=kotlin.Unit origin=null
|
||||
$this: TYPE_OP type=<root>.C origin=IMPLICIT_CAST typeOperand=<root>.C
|
||||
GET_VAR 'param: <root>.B declared in <root>.test' type=<root>.B origin=null
|
||||
CALL 'public abstract fun bar (): kotlin.Unit declared in <root>.B' type=kotlin.Unit origin=null
|
||||
$this: GET_VAR 'param: <root>.B declared in <root>.test' type=<root>.B origin=null
|
||||
CALL 'public abstract fun baz (): kotlin.Unit declared in <root>.C' type=kotlin.Unit origin=null
|
||||
$this: TYPE_OP type=<root>.C origin=IMPLICIT_CAST typeOperand=<root>.C
|
||||
GET_VAR 'param: <root>.B declared in <root>.test' type=<root>.B origin=null
|
||||
@@ -1,24 +0,0 @@
|
||||
interface A {
|
||||
abstract fun foo()
|
||||
|
||||
}
|
||||
|
||||
interface B : A {
|
||||
abstract fun bar()
|
||||
|
||||
}
|
||||
|
||||
interface C : A {
|
||||
abstract fun baz()
|
||||
|
||||
}
|
||||
|
||||
fun test(param: B) {
|
||||
when {
|
||||
param is C -> { // BLOCK
|
||||
param /*as C */.foo()
|
||||
param.bar()
|
||||
param /*as C */.baz()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
interface A {
|
||||
fun foo()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user