K2: Avoid false-positive overload resolution ambiguity with smart casts

The idea is that when we have successful candidates both from smart cast
and original type, we should discriminate in the favor of former ones.

While this problem (see kt55722.kt) existed before this branch is merged,
initially it was recognized on FP Ultimate when we stopped assuming
captured types from the same projections as equal (see kt55722Initial.kt).

^KT-55722 Fixed
^KT-55024 Fixed
^KT-56283 Related
^KT-56310 Related
This commit is contained in:
Denis.Zharkov
2023-01-02 12:00:14 +01:00
committed by Space Team
parent 7b6c6fceb6
commit b6b132a9a3
27 changed files with 1034 additions and 35 deletions
@@ -27371,6 +27371,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt37692.kt");
}
@Test
@TestMetadata("kt55722.kt")
public void testKt55722() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt55722.kt");
}
@Test
@TestMetadata("kt55722Initial.kt")
public void testKt55722Initial() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt55722Initial.kt");
}
@Test
@TestMetadata("numberOfDefaults.kt")
public void testNumberOfDefaults() throws Exception {
@@ -34694,12 +34706,30 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/visibility/javaInterfaceFieldDirectAccess.kt");
}
@Test
@TestMetadata("kt56283.kt")
public void testKt56283() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/kt56283.kt");
}
@Test
@TestMetadata("lackOfInvisibleSetterOfJavaClassInSamePackage.kt")
public void testLackOfInvisibleSetterOfJavaClassInSamePackage() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.kt");
}
@Test
@TestMetadata("moreSpecificProtected.kt")
public void testMoreSpecificProtected() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/moreSpecificProtected.kt");
}
@Test
@TestMetadata("moreSpecificProtectedSimple.kt")
public void testMoreSpecificProtectedSimple() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/moreSpecificProtectedSimple.kt");
}
@Test
@TestMetadata("notOverridingInternal.kt")
public void testNotOverridingInternal() throws Exception {
@@ -34801,6 +34831,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
public void testProtectedVisibilityAndSmartcast_overrideSameType() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/protectedVisibilityAndSmartcast_overrideSameType.kt");
}
@Test
@TestMetadata("smartCastAndSuppressedVisibility.kt")
public void testSmartCastAndSuppressedVisibility() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/smartCastAndSuppressedVisibility.kt");
}
}
@Nested
@@ -27383,6 +27383,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt37692.kt");
}
@Test
@TestMetadata("kt55722.kt")
public void testKt55722() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt55722.kt");
}
@Test
@TestMetadata("kt55722Initial.kt")
public void testKt55722Initial() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt55722Initial.kt");
}
@Test
@TestMetadata("numberOfDefaults.kt")
public void testNumberOfDefaults() throws Exception {
@@ -34790,12 +34802,30 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/visibility/javaInterfaceFieldDirectAccess.kt");
}
@Test
@TestMetadata("kt56283.kt")
public void testKt56283() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/kt56283.kt");
}
@Test
@TestMetadata("lackOfInvisibleSetterOfJavaClassInSamePackage.kt")
public void testLackOfInvisibleSetterOfJavaClassInSamePackage() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.kt");
}
@Test
@TestMetadata("moreSpecificProtected.kt")
public void testMoreSpecificProtected() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/moreSpecificProtected.kt");
}
@Test
@TestMetadata("moreSpecificProtectedSimple.kt")
public void testMoreSpecificProtectedSimple() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/moreSpecificProtectedSimple.kt");
}
@Test
@TestMetadata("notOverridingInternal.kt")
public void testNotOverridingInternal() throws Exception {
@@ -34897,6 +34927,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
public void testProtectedVisibilityAndSmartcast_overrideSameType() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/protectedVisibilityAndSmartcast_overrideSameType.kt");
}
@Test
@TestMetadata("smartCastAndSuppressedVisibility.kt")
public void testSmartCastAndSuppressedVisibility() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/smartCastAndSuppressedVisibility.kt");
}
}
@Nested
@@ -27371,6 +27371,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt37692.kt");
}
@Test
@TestMetadata("kt55722.kt")
public void testKt55722() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt55722.kt");
}
@Test
@TestMetadata("kt55722Initial.kt")
public void testKt55722Initial() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt55722Initial.kt");
}
@Test
@TestMetadata("numberOfDefaults.kt")
public void testNumberOfDefaults() throws Exception {
@@ -34694,12 +34706,30 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/visibility/javaInterfaceFieldDirectAccess.kt");
}
@Test
@TestMetadata("kt56283.kt")
public void testKt56283() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/kt56283.kt");
}
@Test
@TestMetadata("lackOfInvisibleSetterOfJavaClassInSamePackage.kt")
public void testLackOfInvisibleSetterOfJavaClassInSamePackage() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.kt");
}
@Test
@TestMetadata("moreSpecificProtected.kt")
public void testMoreSpecificProtected() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/moreSpecificProtected.kt");
}
@Test
@TestMetadata("moreSpecificProtectedSimple.kt")
public void testMoreSpecificProtectedSimple() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/moreSpecificProtectedSimple.kt");
}
@Test
@TestMetadata("notOverridingInternal.kt")
public void testNotOverridingInternal() throws Exception {
@@ -34801,6 +34831,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
public void testProtectedVisibilityAndSmartcast_overrideSameType() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/protectedVisibilityAndSmartcast_overrideSameType.kt");
}
@Test
@TestMetadata("smartCastAndSuppressedVisibility.kt")
public void testSmartCastAndSuppressedVisibility() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/smartCastAndSuppressedVisibility.kt");
}
}
@Nested
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.fir.session
import org.jetbrains.kotlin.fir.NoMutableState
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.calls.ConeCompositeConflictResolver
import org.jetbrains.kotlin.fir.resolve.calls.ConeIntegerOperatorConflictResolver
import org.jetbrains.kotlin.fir.resolve.calls.ConeOverloadConflictResolver
import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.calls.jvm.ConeEquivalentCallConflictResolver
import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents
import org.jetbrains.kotlin.fir.types.typeContext
@@ -28,7 +25,8 @@ object JsCallConflictResolverFactory : ConeCallConflictResolverFactory() {
return ConeCompositeConflictResolver(
ConeOverloadConflictResolver(specificityComparator, components, transformerComponents),
ConeEquivalentCallConflictResolver(specificityComparator, components, transformerComponents),
ConeIntegerOperatorConflictResolver(specificityComparator, components, transformerComponents)
ConeIntegerOperatorConflictResolver(specificityComparator, components, transformerComponents),
FilteringOutOriginalInPresenceOfSmartCastConeCallConflictResolver
)
}
}
@@ -6,10 +6,7 @@
package org.jetbrains.kotlin.fir.session
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.calls.ConeCompositeConflictResolver
import org.jetbrains.kotlin.fir.resolve.calls.ConeIntegerOperatorConflictResolver
import org.jetbrains.kotlin.fir.resolve.calls.ConeOverloadConflictResolver
import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.calls.jvm.ConeEquivalentCallConflictResolver
import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
@@ -24,7 +21,8 @@ object NativeCallConflictResolverFactory : ConeCallConflictResolverFactory() {
return ConeCompositeConflictResolver(
ConeOverloadConflictResolver(specificityComparator, components, transformerComponents),
ConeEquivalentCallConflictResolver(specificityComparator, components, transformerComponents),
ConeIntegerOperatorConflictResolver(specificityComparator, components, transformerComponents)
ConeIntegerOperatorConflictResolver(specificityComparator, components, transformerComponents),
FilteringOutOriginalInPresenceOfSmartCastConeCallConflictResolver
)
}
}
@@ -7,12 +7,8 @@ package org.jetbrains.kotlin.fir.resolve.calls.jvm
import org.jetbrains.kotlin.fir.NoMutableState
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.calls.ConeCompositeConflictResolver
import org.jetbrains.kotlin.fir.resolve.calls.ConeIntegerOperatorConflictResolver
import org.jetbrains.kotlin.fir.resolve.calls.ConeOverloadConflictResolver
import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer
import org.jetbrains.kotlin.fir.types.typeContext
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
import org.jetbrains.kotlin.resolve.jvm.JvmTypeSpecificityComparator
@@ -29,7 +25,8 @@ object JvmCallConflictResolverFactory : ConeCallConflictResolverFactory() {
ConeOverloadConflictResolver(specificityComparator, components, transformerComponents),
ConeEquivalentCallConflictResolver(specificityComparator, components, transformerComponents),
JvmPlatformOverloadsConflictResolver(specificityComparator, components, transformerComponents),
ConeIntegerOperatorConflictResolver(specificityComparator, components, transformerComponents)
ConeIntegerOperatorConflictResolver(specificityComparator, components, transformerComponents),
FilteringOutOriginalInPresenceOfSmartCastConeCallConflictResolver
)
}
}
@@ -39,7 +39,9 @@ class Candidate(
private val baseSystem: ConstraintStorage,
override val callInfo: CallInfo,
val originScope: FirScope?,
val isFromCompanionObjectTypeScope: Boolean = false
val isFromCompanionObjectTypeScope: Boolean = false,
// It's only true if we're in the member scope of smart cast receiver and this particular candidate came from original type
val isFromOriginalTypeInPresenceOfSmartCast: Boolean = false,
) : AbstractCandidate() {
var systemInitialized: Boolean = false
@@ -54,7 +54,8 @@ class CandidateFactory private constructor(
scope: FirScope?,
dispatchReceiverValue: ReceiverValue? = null,
givenExtensionReceiverOptions: List<ReceiverValue> = emptyList(),
objectsByName: Boolean = false
objectsByName: Boolean = false,
isFromOriginalTypeInPresenceOfSmartCast: Boolean = false,
): Candidate {
@Suppress("NAME_SHADOWING")
val symbol = symbol.unwrapIntegerOperatorSymbolIfNeeded(callInfo)
@@ -74,7 +75,8 @@ class CandidateFactory private constructor(
ExplicitReceiverKind.DISPATCH_RECEIVER -> dispatchReceiverValue.isCandidateFromCompanionObjectTypeScope()
// The following cases are not applicable for companion objects.
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> false
}
},
isFromOriginalTypeInPresenceOfSmartCast,
)
// The counterpart in FE 1.0 checks if the given descriptor is VariableDescriptor yet not PropertyDescriptor.
@@ -0,0 +1,76 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.utils.sure
/**
* In case of MemberScopeTowerLevel with smart cast dispatch receiver, we may create candidates both from smart cast type and from
* the member scope of original expression's type (without smart cast).
*
* It might be necessary because the ones from smart cast might be invisible (e.g., because they are protected in other class).
*
* open class A {
* open protected fun foo(a: Derived) {}
* fun f(a: A, d: Derived) {
* when (a) {
* is B -> {
* a.foo(d) // should be resolved to A::foo, not the public B::foo
* }
* }
* }
* }
* class B : A() {
* override fun foo(a: Derived) {}
* public fun foo(a: Base) {}
* }
*
* If we would just resolve `a.foo(d)` if `a` had a type B, then we would choose a public B::foo, because the other one `foo` is protected in B,
* so we can't call it outside the B subclasses.
*
* But that resolution result would be less precise result that the one before smart-cast applied (A::foo has more specific parameters),
* so at MemberScopeTowerLevel we create candidates both from A's and B's scopes on the same level.
*
* But in case when there would be successful candidates from both types, we discriminate ones from original type, thus sticking to the candidates
* from smart cast type.
*
* See more details at KT-51460, KT-55722, KT-56310 and relevant tests
* - testData/diagnostics/tests/visibility/moreSpecificProtectedSimple.kt
* - testData/diagnostics/tests/smartCasts/kt51460.kt
*/
object FilteringOutOriginalInPresenceOfSmartCastConeCallConflictResolver : ConeCallConflictResolver() {
override fun chooseMaximallySpecificCandidates(
candidates: Set<Candidate>,
discriminateGenerics: Boolean,
discriminateAbstracts: Boolean
): Set<Candidate> {
val (originalIfSmartCastPresent, other) = candidates.partition { it.isFromOriginalTypeInPresenceOfSmartCast }
// If we have both successful candidates from smart cast and original, use the former one as they might have more correct return type
if (originalIfSmartCastPresent.isNotEmpty() && other.isNotEmpty()) return other.toSet().discriminateByInvokeVariablePriority()
return candidates.discriminateByInvokeVariablePriority()
}
// See the relevant test at testData/diagnostics/tests/resolve/invoke/kt9517.kt
private fun Set<Candidate>.discriminateByInvokeVariablePriority(): Set<Candidate> {
if (size <= 1) return this
// Resulting successful candidates should always belong to the same tower group.
// Thus, if one of them is not variable + invoke, it should be applied to others, too.
if (first().callInfo.candidateForCommonInvokeReceiver == null) return this
val (originalIfSmartCastPresent, other) = partition {
it.callInfo.candidateForCommonInvokeReceiver.sure {
"If one candidate within a group is variable+invoke, other should be the same, but $it found"
}.isFromOriginalTypeInPresenceOfSmartCast
}
if (originalIfSmartCastPresent.isNotEmpty() && other.isNotEmpty()) return other.toSet()
return this
}
}
@@ -76,7 +76,8 @@ private class TowerScopeLevelProcessor(
dispatchReceiverValue: ReceiverValue?,
givenExtensionReceiverOptions: List<ReceiverValue>,
scope: FirScope,
objectsByName: Boolean
objectsByName: Boolean,
isFromOriginalTypeInPresenceOfSmartCast: Boolean
) {
resultCollector.consumeCandidate(
group, candidateFactory.createCandidate(
@@ -86,7 +87,8 @@ private class TowerScopeLevelProcessor(
scope,
dispatchReceiverValue,
givenExtensionReceiverOptions,
objectsByName
objectsByName,
isFromOriginalTypeInPresenceOfSmartCast
), candidateFactory.context
)
}
@@ -9,9 +9,6 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.ContextReceiverGroup
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression
@@ -59,7 +56,8 @@ abstract class TowerScopeLevel {
dispatchReceiverValue: ReceiverValue?,
givenExtensionReceiverOptions: List<ReceiverValue>,
scope: FirScope,
objectsByName: Boolean = false
objectsByName: Boolean = false,
isFromOriginalTypeInPresenceOfSmartCast: Boolean = false,
)
}
}
@@ -87,9 +85,7 @@ class MemberScopeTowerLevel(
val scope = dispatchReceiverValue.scope(session, scopeSession) ?: return ProcessResult.SCOPE_EMPTY
var (empty, candidates) = scope.collectCandidates(processScopeMembers)
val scopeWithoutSmartcast = (dispatchReceiverValue.receiverExpression as? FirSmartCastExpression)
?.takeIf { it.isStable }
?.originalExpression?.typeRef
val scopeWithoutSmartcast = getOriginalReceiverExpressionIfStableSmartCast()?.typeRef
?.coneType
?.scope(
session,
@@ -169,12 +165,16 @@ class MemberScopeTowerLevel(
candidatesFromSmartcast.forEach { put(it, true) }
}
val candidates = mutableListOf<MemberWithBaseScope<T>>()
// The code below is assumed to be for sake of optimization only.
// It helps to avoid creating candidates both for some member in the original type and for its override in the smart cast
// when they are both visible.
// But semantically it should be OK to declare `val candidates` as `candidatesMapping.keys.toList()`
val overridableGroups = session.overrideService.createOverridableGroups(
candidatesFromOriginalType + candidatesFromSmartcast,
FirIntersectionScopeOverrideChecker(session)
)
val candidates = mutableListOf<MemberWithBaseScope<T>>()
for (group in overridableGroups) {
val visibleCandidates = group.filter {
visibilityChecker.isVisible(it.member.fir, callInfo, dispatchReceiverValue)
@@ -183,7 +183,7 @@ class MemberScopeTowerLevel(
val visibleCandidatesFromSmartcast = visibleCandidates.filter { candidatesMapping.getValue(it) }
candidates += visibleCandidatesFromSmartcast.ifEmpty { group }
}
consumeCandidates(output, candidates)
consumeCandidates(output, candidates, candidatesMapping)
}
private fun <T : FirCallableSymbol<*>> FirTypeScope.collectCandidates(
@@ -206,20 +206,39 @@ class MemberScopeTowerLevel(
private fun <T : FirCallableSymbol<*>> consumeCandidates(
output: TowerScopeLevelProcessor<T>,
candidatesWithScope: List<MemberWithBaseScope<T>>
candidatesWithScope: List<MemberWithBaseScope<T>>,
// The map is not null only if there's a smart cast type on a dispatch receiver
// and candidates are present both in smart cast and original types.
// isFromSmartCast[candidate] == true iff exactly that member is present in smart cast type
isFromSmartCast: Map<MemberWithBaseScope<T>, Boolean>? = null
) {
for ((candidate, scope) in candidatesWithScope) {
for (candidateWithScope in candidatesWithScope) {
val (candidate, scope) = candidateWithScope
if (candidate.hasConsistentExtensionReceiver(givenExtensionReceiverOptions)) {
val isFromOriginalTypeInPresenceOfSmartCast = isFromSmartCast != null && !isFromSmartCast.getValue(candidateWithScope)
val dispatchReceiverToUse = when {
isFromOriginalTypeInPresenceOfSmartCast ->
getOriginalReceiverExpressionIfStableSmartCast()?.let(::ExpressionReceiverValue)
else -> dispatchReceiverValue
}
output.consumeCandidate(
candidate,
dispatchReceiverValue,
dispatchReceiverToUse,
givenExtensionReceiverOptions,
scope
scope,
isFromOriginalTypeInPresenceOfSmartCast = isFromOriginalTypeInPresenceOfSmartCast
)
}
}
}
private fun getOriginalReceiverExpressionIfStableSmartCast() =
(dispatchReceiverValue.receiverExpression as? FirSmartCastExpression)
?.takeIf { it.isStable }
?.originalExpression
override fun processFunctionsByName(
info: CallInfo,
processor: TowerScopeLevelProcessor<FirFunctionSymbol<*>>
@@ -0,0 +1,18 @@
FILE: kt55722.kt
public abstract interface A<T> : R|kotlin/Any| {
public open fun foo(x: R|T?|): R|kotlin/Unit| {
}
}
public abstract interface B<F> : R|A<F>| {
public abstract override fun foo(x: R|F?|): R|kotlin/Unit|
}
public final fun <T> bar(x: R|A<in T>|): R|kotlin/Unit| {
when () {
(R|<local>/x| is R|B<in T>|) -> {
R|<local>/x|.R|SubstitutionOverride</B.foo: R|kotlin/Unit|>|(Null(null))
}
}
}
@@ -0,0 +1,17 @@
// FIR_IDENTICAL
// FIR_DUMP
// SKIP_TXT
interface A<T> {
fun foo(x: T?) {}
}
interface B<F> : A<F> {
override fun foo(x: F?)
}
fun <T> bar(x: A<in T>) {
if (x is B) {
x.foo(null) // Shouldn't be OVERLOAD_RESOLUTION_AMBIGUITY
}
}
@@ -0,0 +1,14 @@
FILE: kt55722Initial.kt
public abstract interface MyConsumer<T> : R|kotlin/Any| {
public open fun consume(x: R|T|): R|kotlin/Unit| {
}
}
public final fun foo(x: R|MyConsumer<in kotlin/CharSequence>?|, v: R|kotlin/CharSequence|): R|kotlin/Unit| {
when () {
!=(R|<local>/x|, Null(null)) -> {
R|<local>/x|.R|SubstitutionOverride</MyConsumer.consume: R|kotlin/Unit|>|(R|<local>/v|)
}
}
}
@@ -0,0 +1,13 @@
// FIR_IDENTICAL
// FIR_DUMP
// SKIP_TXT
interface MyConsumer<T> {
fun consume(x: T) {}
}
fun foo(x: MyConsumer<in CharSequence>?, v: CharSequence) {
if (x != null) {
x.consume(v)
}
}
@@ -0,0 +1,26 @@
// SKIP_TXT
// FIR_DUMP
open class Base
class Derived : Base()
open class A(protected open val foo: Base) {
protected open fun bar(): Base = Base()
fun f(other: A) {
other.foo // OK in K1 and K2
other.bar() // OK in K1 and K2
when (other) {
is B -> {
// OK in K2, INVISIBLE_MEMBER (B::foo) in K1
other.foo
other.bar()
}
}
}
}
class B(override val foo: Derived): A(foo) {
override fun bar(): Derived = Derived()
}
@@ -0,0 +1,51 @@
FILE: kt56283.fir.kt
public open class Base : R|kotlin/Any| {
public constructor(): R|Base| {
super<R|kotlin/Any|>()
}
}
public final class Derived : R|Base| {
public constructor(): R|Derived| {
super<R|Base|>()
}
}
public open class A : R|kotlin/Any| {
public constructor(foo: R|Base|): R|A| {
super<R|kotlin/Any|>()
}
protected open val foo: R|Base| = R|<local>/foo|
protected get(): R|Base|
protected open fun bar(): R|Base| {
^bar R|/Base.Base|()
}
public final fun f(other: R|A|): R|kotlin/Unit| {
R|<local>/other|.R|/A.foo|
R|<local>/other|.R|/A.bar|()
when (R|<local>/other|) {
($subj$ is R|B|) -> {
R|<local>/other|.R|/A.foo|
R|<local>/other|.R|/A.bar|()
}
}
}
}
public final class B : R|A| {
public constructor(foo: R|Derived|): R|B| {
super<R|A|>(R|<local>/foo|)
}
protected open override val foo: R|Derived| = R|<local>/foo|
protected get(): R|Derived|
protected open override fun bar(): R|Derived| {
^bar R|/Derived.Derived|()
}
}
@@ -0,0 +1,26 @@
// SKIP_TXT
// FIR_DUMP
open class Base
class Derived : Base()
open class A(protected open val foo: Base) {
protected open fun bar(): Base = Base()
fun f(other: A) {
other.foo // OK in K1 and K2
other.bar() // OK in K1 and K2
when (other) {
is B -> {
// OK in K2, INVISIBLE_MEMBER (B::foo) in K1
<!DEBUG_INFO_SMARTCAST!>other<!>.<!INVISIBLE_MEMBER!>foo<!>
<!DEBUG_INFO_SMARTCAST!>other<!>.<!INVISIBLE_MEMBER!>bar<!>()
}
}
}
}
class B(override val foo: Derived): A(foo) {
override fun bar(): Derived = Derived()
}
@@ -0,0 +1,106 @@
// SKIP_TXT
// FIR_DUMP
// CHECK_TYPE
open class Base
class Derived : Base()
interface M1
interface M2
interface M2Sub : M2
interface M3
interface M3Sub : M3
interface M4
interface M5
interface M5Sub : M5
interface M5SubSub : M5Sub
interface M6
open class A {
public fun foo(a1: Base, a2: Base): M1 = TODO()
protected open fun foo(a1: Base, a2: Derived): M2 = TODO()
protected open fun foo(a1: Derived, a2: Derived): M3 = TODO()
public fun baz(a1: Base, a2: Base): M4 = TODO()
protected open fun baz(a1: Derived, a2: Derived): M5 = TODO()
}
open class B : A() {
public val fromB: Any = Any()
override fun foo(a1: Base, a2: Derived): M2Sub = TODO()
override fun baz(a1: Derived, a2: Derived): M5Sub = TODO()
fun f(a: A, b: B, c: C, d: Derived) {
// Only visible is M1
a.foo(d, d) checkType { _<M1>() }
// We may call M3 and it's the most specific by its parameters
b.foo(d, d) checkType { _<M3>() }
// We can't call M3 (and M3Sub) as it's protected overriden in C, so it's invisible because
// we only allow to call protected members on dispatch receiver values that are subtypes of a dispatch receiver parameter
// So, the next visible and specific member is M2Sub
c.foo(d, d) checkType { _<M2Sub>() }
// Only visible is M4
a.baz(d, d) checkType { _<M4>() }
// M5Sub is more specific and visible for `b` receiver
b.baz(d, d) checkType { _<M5Sub>() }
// M5SubSub is invisible because it's protected in something that is not our super-class
// M6 and M1 are visible, but M6 is more specific
c.baz(d, d) checkType { _<M6>() }
when (a) {
is C -> {
// Make sure smart cast works
a.fromC
// The same logic as for `c.foo`
a.foo(d, d) checkType { _<M2Sub>() }
// The same logic as for `c.baz`
a.baz(d, d) checkType { _<M6>() }
}
is B -> {
// Make sure smart cast works
a.fromB
// The same logic as `b.foo`
a.foo(d, d) checkType { _<M3>() }
// The same logic as for `b.baz`
a.baz(d, d) checkType { _<M5Sub>() }
}
}
when (b) {
is C -> {
b.fromC
// In K1, it works just as `c.foo`
b.foo(d, d) checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><M2Sub>() }
// In K2, M3Sub is invisible, but we have candidate M3 from original receiver and we choose it
// Unlike the case of `c.foo` when we choose M2Sub because we don't have more special M3 there in the scope of C
// (in the meaning of overload comparison by the value parameter types)
b.foo(d, d) checkType { _<M3>() }
// In K1, it works just as `c.foo`
b.baz(d, d) checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><M6>() }
// In K2, M5SubSub is invisible, but we have candidate M5Sub from original receiver and we choose it
// Unlike the case of `c.baz` when we choose M6 because we don't have more special M5Sub there in the scope of C
// (in the meaning of overload comparison by the value parameter types)
b.baz(d, d) checkType { _<M5Sub>() }
}
}
}
}
class C : B() {
public val fromC: Any = Any()
override fun foo(a1: Derived, a2: Derived): M3Sub = TODO()
override fun baz(a1: Derived, a2: Derived): M5SubSub = TODO()
// public fallback
public fun baz(a1: Derived, a2: Base): M6 = TODO()
}
@@ -0,0 +1,171 @@
FILE: moreSpecificProtected.fir.kt
public open class Base : R|kotlin/Any| {
public constructor(): R|Base| {
super<R|kotlin/Any|>()
}
}
public final class Derived : R|Base| {
public constructor(): R|Derived| {
super<R|Base|>()
}
}
public abstract interface M1 : R|kotlin/Any| {
}
public abstract interface M2 : R|kotlin/Any| {
}
public abstract interface M2Sub : R|M2| {
}
public abstract interface M3 : R|kotlin/Any| {
}
public abstract interface M3Sub : R|M3| {
}
public abstract interface M4 : R|kotlin/Any| {
}
public abstract interface M5 : R|kotlin/Any| {
}
public abstract interface M5Sub : R|M5| {
}
public abstract interface M5SubSub : R|M5Sub| {
}
public abstract interface M6 : R|kotlin/Any| {
}
public open class A : R|kotlin/Any| {
public constructor(): R|A| {
super<R|kotlin/Any|>()
}
public final fun foo(a1: R|Base|, a2: R|Base|): R|M1| {
^foo R|kotlin/TODO|()
}
protected open fun foo(a1: R|Base|, a2: R|Derived|): R|M2| {
^foo R|kotlin/TODO|()
}
protected open fun foo(a1: R|Derived|, a2: R|Derived|): R|M3| {
^foo R|kotlin/TODO|()
}
public final fun baz(a1: R|Base|, a2: R|Base|): R|M4| {
^baz R|kotlin/TODO|()
}
protected open fun baz(a1: R|Derived|, a2: R|Derived|): R|M5| {
^baz R|kotlin/TODO|()
}
}
public open class B : R|A| {
public constructor(): R|B| {
super<R|A|>()
}
public final val fromB: R|kotlin/Any| = R|kotlin/Any.Any|()
public get(): R|kotlin/Any|
protected open override fun foo(a1: R|Base|, a2: R|Derived|): R|M2Sub| {
^foo R|kotlin/TODO|()
}
protected open override fun baz(a1: R|Derived|, a2: R|Derived|): R|M5Sub| {
^baz R|kotlin/TODO|()
}
public final fun f(a: R|A|, b: R|B|, c: R|C|, d: R|Derived|): R|kotlin/Unit| {
R|<local>/a|.R|/A.foo|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M1|>(checkType@fun R|CheckTypeInv<M1>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_|<R|M1|>()
}
)
R|<local>/b|.R|/A.foo|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M3|>(checkType@fun R|CheckTypeInv<M3>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_|<R|M3|>()
}
)
R|<local>/c|.R|/B.foo|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M2Sub|>(checkType@fun R|CheckTypeInv<M2Sub>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_|<R|M2Sub|>()
}
)
R|<local>/a|.R|/A.baz|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M4|>(checkType@fun R|CheckTypeInv<M4>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_|<R|M4|>()
}
)
R|<local>/b|.R|/B.baz|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M5Sub|>(checkType@fun R|CheckTypeInv<M5Sub>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_|<R|M5Sub|>()
}
)
R|<local>/c|.R|/C.baz|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M6|>(checkType@fun R|CheckTypeInv<M6>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_|<R|M6|>()
}
)
when (R|<local>/a|) {
($subj$ is R|C|) -> {
R|<local>/a|.R|/C.fromC|
R|<local>/a|.R|/B.foo|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M2Sub|>(checkType@fun R|CheckTypeInv<M2Sub>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_|<R|M2Sub|>()
}
)
R|<local>/a|.R|/C.baz|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M6|>(checkType@fun R|CheckTypeInv<M6>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_|<R|M6|>()
}
)
}
($subj$ is R|B|) -> {
R|<local>/a|.R|/B.fromB|
R|<local>/a|.R|/A.foo|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M3|>(checkType@fun R|CheckTypeInv<M3>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_|<R|M3|>()
}
)
R|<local>/a|.R|/B.baz|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M5Sub|>(checkType@fun R|CheckTypeInv<M5Sub>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_|<R|M5Sub|>()
}
)
}
}
when (R|<local>/b|) {
($subj$ is R|C|) -> {
R|<local>/b|.R|/C.fromC|
R|<local>/b|.R|/A.foo|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M3|>(checkType@fun R|CheckTypeInv<M3>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_<None of the following candidates is applicable because of receiver type mismatch: [/_]>#|<R|M2Sub|>()
}
)
R|<local>/b|.R|/A.foo|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M3|>(checkType@fun R|CheckTypeInv<M3>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_|<R|M3|>()
}
)
R|<local>/b|.R|/B.baz|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M5Sub|>(checkType@fun R|CheckTypeInv<M5Sub>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_<None of the following candidates is applicable because of receiver type mismatch: [/_]>#|<R|M6|>()
}
)
R|<local>/b|.R|/B.baz|(R|<local>/d|, R|<local>/d|).R|/checkType|<R|M5Sub|>(checkType@fun R|CheckTypeInv<M5Sub>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|/_|<R|M5Sub|>()
}
)
}
}
}
}
public final class C : R|B| {
public constructor(): R|C| {
super<R|B|>()
}
public final val fromC: R|kotlin/Any| = R|kotlin/Any.Any|()
public get(): R|kotlin/Any|
protected open override fun foo(a1: R|Derived|, a2: R|Derived|): R|M3Sub| {
^foo R|kotlin/TODO|()
}
protected open override fun baz(a1: R|Derived|, a2: R|Derived|): R|M5SubSub| {
^baz R|kotlin/TODO|()
}
public final fun baz(a1: R|Derived|, a2: R|Base|): R|M6| {
^baz R|kotlin/TODO|()
}
}
@@ -0,0 +1,106 @@
// SKIP_TXT
// FIR_DUMP
// CHECK_TYPE
open class Base
class Derived : Base()
interface M1
interface M2
interface M2Sub : M2
interface M3
interface M3Sub : M3
interface M4
interface M5
interface M5Sub : M5
interface M5SubSub : M5Sub
interface M6
open class A {
public fun foo(a1: Base, a2: Base): M1 = TODO()
protected open fun foo(a1: Base, a2: Derived): M2 = TODO()
protected open fun foo(a1: Derived, a2: Derived): M3 = TODO()
public fun baz(a1: Base, a2: Base): M4 = TODO()
protected open fun baz(a1: Derived, a2: Derived): M5 = TODO()
}
open class B : A() {
public val fromB: Any = Any()
override fun foo(a1: Base, a2: Derived): M2Sub = TODO()
override fun baz(a1: Derived, a2: Derived): M5Sub = TODO()
fun f(a: A, b: B, c: C, d: Derived) {
// Only visible is M1
a.foo(d, d) checkType { _<M1>() }
// We may call M3 and it's the most specific by its parameters
b.foo(d, d) checkType { _<M3>() }
// We can't call M3 (and M3Sub) as it's protected overriden in C, so it's invisible because
// we only allow to call protected members on dispatch receiver values that are subtypes of a dispatch receiver parameter
// So, the next visible and specific member is M2Sub
c.foo(d, d) checkType { _<M2Sub>() }
// Only visible is M4
a.baz(d, d) checkType { _<M4>() }
// M5Sub is more specific and visible for `b` receiver
b.baz(d, d) checkType { _<M5Sub>() }
// M5SubSub is invisible because it's protected in something that is not our super-class
// M6 and M1 are visible, but M6 is more specific
c.baz(d, d) checkType { _<M6>() }
when (a) {
is C -> {
// Make sure smart cast works
<!DEBUG_INFO_SMARTCAST!>a<!>.fromC
// The same logic as for `c.foo`
<!DEBUG_INFO_SMARTCAST!>a<!>.foo(d, d) checkType { _<M2Sub>() }
// The same logic as for `c.baz`
<!DEBUG_INFO_SMARTCAST!>a<!>.baz(d, d) checkType { _<M6>() }
}
is B -> {
// Make sure smart cast works
<!DEBUG_INFO_SMARTCAST!>a<!>.fromB
// The same logic as `b.foo`
<!DEBUG_INFO_SMARTCAST!>a<!>.foo(d, d) checkType { _<M3>() }
// The same logic as for `b.baz`
<!DEBUG_INFO_SMARTCAST!>a<!>.baz(d, d) checkType { _<M5Sub>() }
}
}
when (b) {
is C -> {
<!DEBUG_INFO_SMARTCAST!>b<!>.fromC
// In K1, it works just as `c.foo`
b.foo(d, d) checkType { _<M2Sub>() }
// In K2, M3Sub is invisible, but we have candidate M3 from original receiver and we choose it
// Unlike the case of `c.foo` when we choose M2Sub because we don't have more special M3 there in the scope of C
// (in the meaning of overload comparison by the value parameter types)
b.foo(d, d) checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><M3>() }
// In K1, it works just as `c.foo`
<!DEBUG_INFO_SMARTCAST!>b<!>.baz(d, d) checkType { _<M6>() }
// In K2, M5SubSub is invisible, but we have candidate M5Sub from original receiver and we choose it
// Unlike the case of `c.baz` when we choose M6 because we don't have more special M5Sub there in the scope of C
// (in the meaning of overload comparison by the value parameter types)
<!DEBUG_INFO_SMARTCAST!>b<!>.baz(d, d) checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><M5Sub>() }
}
}
}
}
class C : B() {
public val fromC: Any = Any()
override fun foo(a1: Derived, a2: Derived): M3Sub = TODO()
override fun baz(a1: Derived, a2: Derived): M5SubSub = TODO()
// public fallback
public fun baz(a1: Derived, a2: Base): M6 = TODO()
}
@@ -0,0 +1,55 @@
// SKIP_TXT
// FIR_DUMP
// ISSUE: KT-56310
interface Base
interface Derived : Base
interface M1 {
val success: Boolean
}
interface M1Sub : M1
open class A {
open protected fun baz(a: Derived): M1 = TODO()
open protected fun foo(a: Derived): M1 = TODO()
fun f(a: A, b: B, d: Derived) {
a.baz(d).success // OK in K1 and K2
a.foo(d).success // OK in K1 and K2
// Both K1 and K2 resolves calls to B's members with String return type because other's members in B type are invisible
b.baz(d).length
b.foo(d).length
when (a) {
is B -> {
// OK in K1 because `a.baz(d)` resolved to String returning methid (just as `b.baz(d)`)
a.baz(d).<!UNRESOLVED_REFERENCE!>length<!>
// OK in K2, because we have two visible candidates:
// - A::baz from original (after unwrapping smart cast) receiver
// - B::baz that returns String
// But the first one is more specific via its parameter types
a.baz(d).success // Unresolved reference in K1, going to be OK in K2
// Works in K2 for the same reasons as `a.baz(d)`
// In K1, works by coincidence because we bind override groups for members from original and smart cast receiver,
// and as return type from B is the same (not more specific), we choose the member from A as a group representative.
// Thus, we have successful candidates
// - A::foo
// - B::foo returning String
// But A::foo is more specific, so we choose it
a.foo(d).success
}
}
}
}
class B : A() {
override fun baz(a: Derived): M1Sub = TODO()
public fun baz(a: Base): String = TODO()
// The only difference between `baz` and `foo` is that the former has more specific covariant return type (M1Sub)
override fun foo(a: Derived): M1 = TODO()
public fun foo(a: Base): String = TODO()
}
@@ -0,0 +1,63 @@
FILE: moreSpecificProtectedSimple.fir.kt
public abstract interface Base : R|kotlin/Any| {
}
public abstract interface Derived : R|Base| {
}
public abstract interface M1 : R|kotlin/Any| {
public abstract val success: R|kotlin/Boolean|
public get(): R|kotlin/Boolean|
}
public abstract interface M1Sub : R|M1| {
}
public open class A : R|kotlin/Any| {
public constructor(): R|A| {
super<R|kotlin/Any|>()
}
protected open fun baz(a: R|Derived|): R|M1| {
^baz R|kotlin/TODO|()
}
protected open fun foo(a: R|Derived|): R|M1| {
^foo R|kotlin/TODO|()
}
public final fun f(a: R|A|, b: R|B|, d: R|Derived|): R|kotlin/Unit| {
R|<local>/a|.R|/A.baz|(R|<local>/d|).R|/M1.success|
R|<local>/a|.R|/A.foo|(R|<local>/d|).R|/M1.success|
R|<local>/b|.R|/B.baz|(R|<local>/d|).R|kotlin/String.length|
R|<local>/b|.R|/B.foo|(R|<local>/d|).R|kotlin/String.length|
when (R|<local>/a|) {
($subj$ is R|B|) -> {
R|<local>/a|.R|/A.baz|(R|<local>/d|).<Unresolved name: length>#
R|<local>/a|.R|/A.baz|(R|<local>/d|).R|/M1.success|
R|<local>/a|.R|/A.foo|(R|<local>/d|).R|/M1.success|
}
}
}
}
public final class B : R|A| {
public constructor(): R|B| {
super<R|A|>()
}
protected open override fun baz(a: R|Derived|): R|M1Sub| {
^baz R|kotlin/TODO|()
}
public final fun baz(a: R|Base|): R|kotlin/String| {
^baz R|kotlin/TODO|()
}
protected open override fun foo(a: R|Derived|): R|M1| {
^foo R|kotlin/TODO|()
}
public final fun foo(a: R|Base|): R|kotlin/String| {
^foo R|kotlin/TODO|()
}
}
@@ -0,0 +1,55 @@
// SKIP_TXT
// FIR_DUMP
// ISSUE: KT-56310
interface Base
interface Derived : Base
interface M1 {
val success: Boolean
}
interface M1Sub : M1
open class A {
open protected fun baz(a: Derived): M1 = TODO()
open protected fun foo(a: Derived): M1 = TODO()
fun f(a: A, b: B, d: Derived) {
a.baz(d).success // OK in K1 and K2
a.foo(d).success // OK in K1 and K2
// Both K1 and K2 resolves calls to B's members with String return type because other's members in B type are invisible
b.baz(d).length
b.foo(d).length
when (a) {
is B -> {
// OK in K1 because `a.baz(d)` resolved to String returning methid (just as `b.baz(d)`)
<!DEBUG_INFO_SMARTCAST!>a<!>.baz(d).length
// OK in K2, because we have two visible candidates:
// - A::baz from original (after unwrapping smart cast) receiver
// - B::baz that returns String
// But the first one is more specific via its parameter types
<!DEBUG_INFO_SMARTCAST!>a<!>.baz(d).<!UNRESOLVED_REFERENCE!>success<!> // Unresolved reference in K1, going to be OK in K2
// Works in K2 for the same reasons as `a.baz(d)`
// In K1, works by coincidence because we bind override groups for members from original and smart cast receiver,
// and as return type from B is the same (not more specific), we choose the member from A as a group representative.
// Thus, we have successful candidates
// - A::foo
// - B::foo returning String
// But A::foo is more specific, so we choose it
a.foo(d).success
}
}
}
}
class B : A() {
override fun baz(a: Derived): M1Sub = TODO()
public fun baz(a: Base): String = TODO()
// The only difference between `baz` and `foo` is that the former has more specific covariant return type (M1Sub)
override fun foo(a: Derived): M1 = TODO()
public fun foo(a: Base): String = TODO()
}
@@ -0,0 +1,20 @@
// SKIP_TXT
// ISSUE: KT-55024
// MODULE: a
interface A {
fun foo()
}
internal sealed class B(val x: A) : A {
override fun foo() {}
fun bar() {}
}
// MODULE: b(a)
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
private fun test_1(x: A) {
if (x is B) {
x.foo()
x.bar()
}
}
@@ -0,0 +1,20 @@
// SKIP_TXT
// ISSUE: KT-55024
// MODULE: a
interface A {
fun foo()
}
internal sealed class B(val x: A) : A {
override fun foo() {}
fun bar() {}
}
// MODULE: b(a)
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
private fun test_1(x: A) {
if (x is B) {
x.foo()
<!DEBUG_INFO_SMARTCAST!>x<!>.bar()
}
}
@@ -27383,6 +27383,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt37692.kt");
}
@Test
@TestMetadata("kt55722.kt")
public void testKt55722() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt55722.kt");
}
@Test
@TestMetadata("kt55722Initial.kt")
public void testKt55722Initial() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt55722Initial.kt");
}
@Test
@TestMetadata("numberOfDefaults.kt")
public void testNumberOfDefaults() throws Exception {
@@ -34790,12 +34802,30 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/visibility/javaInterfaceFieldDirectAccess.kt");
}
@Test
@TestMetadata("kt56283.kt")
public void testKt56283() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/kt56283.kt");
}
@Test
@TestMetadata("lackOfInvisibleSetterOfJavaClassInSamePackage.kt")
public void testLackOfInvisibleSetterOfJavaClassInSamePackage() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/lackOfInvisibleSetterOfJavaClassInSamePackage.kt");
}
@Test
@TestMetadata("moreSpecificProtected.kt")
public void testMoreSpecificProtected() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/moreSpecificProtected.kt");
}
@Test
@TestMetadata("moreSpecificProtectedSimple.kt")
public void testMoreSpecificProtectedSimple() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/moreSpecificProtectedSimple.kt");
}
@Test
@TestMetadata("notOverridingInternal.kt")
public void testNotOverridingInternal() throws Exception {
@@ -34897,6 +34927,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
public void testProtectedVisibilityAndSmartcast_overrideSameType() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/protectedVisibilityAndSmartcast_overrideSameType.kt");
}
@Test
@TestMetadata("smartCastAndSuppressedVisibility.kt")
public void testSmartCastAndSuppressedVisibility() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/smartCastAndSuppressedVisibility.kt");
}
}
@Nested