diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index 641a17bb81e..a8cace9712f 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -2885,6 +2885,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToNothing.kt"); } + @TestMetadata("smartcastToTypeParameter.kt") + public void testSmartcastToTypeParameter() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToTypeParameter.kt"); + } + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/smartcasts/booleans") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToTypeParameter.fir.txt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToTypeParameter.fir.txt new file mode 100644 index 00000000000..bd24dd43109 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToTypeParameter.fir.txt @@ -0,0 +1,43 @@ +FILE: smartcastToTypeParameter.kt + public abstract interface FirTypeScope : R|kotlin/Any| { + } + public abstract interface AbstractFirBasedSymbol|, R|FirDeclaration|> : R|kotlin/Any| { + public abstract val fir: R|E| + public get(): R|E| + + } + public abstract interface FirCallableSymbol|> : R|AbstractFirBasedSymbol| { + } + public abstract interface FirElement : R|kotlin/Any| { + } + public abstract interface FirSymbolOwner|, R|FirDeclaration|> : R|FirElement| { + public abstract val symbol: R|AbstractFirBasedSymbol| + public get(): R|AbstractFirBasedSymbol| + + } + public abstract interface FirDeclaration : R|FirElement| { + } + public abstract interface FirCallableDeclaration|> : R|FirDeclaration|, R|FirSymbolOwner| { + } + public abstract interface FirCallableMemberDeclaration|> : R|FirCallableDeclaration| { + } + private final inline fun |> computeBaseSymbols(symbol: R|S|, basedSymbol: R|S|, directOverridden: R|FirTypeScope.(S) -> kotlin/collections/List|): R|kotlin/Unit| { + } + public final fun R|FirCallableSymbol<*>|.dispatchReceiverClassOrNull(): R|kotlin/Boolean?| { + ^dispatchReceiverClassOrNull Boolean(true) + } + private final inline fun |, reified S : R|FirCallableSymbol|> createFakeOverriddenIfNeeded(originalSymbol: R|FirCallableSymbol<*>|, basedSymbol: R|S|, computeDirectOverridden: R|FirTypeScope.(S) -> kotlin/collections/List|, someCondition: R|kotlin/Boolean|): R|kotlin/Unit| { + when () { + (R|/originalSymbol| !is R|S|) -> { + ^createFakeOverriddenIfNeeded Unit + } + } + + when () { + ==(R|/originalSymbol|.R|/dispatchReceiverClassOrNull|(), Boolean(true)) && R|/someCondition| -> { + ^createFakeOverriddenIfNeeded Unit + } + } + + R|/computeBaseSymbols|(R|/originalSymbol|, R|/basedSymbol|, R|/computeDirectOverridden|) + } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToTypeParameter.kt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToTypeParameter.kt new file mode 100644 index 00000000000..47e65b2328e --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToTypeParameter.kt @@ -0,0 +1,34 @@ +interface FirTypeScope + +interface AbstractFirBasedSymbol where E : FirSymbolOwner, E : FirDeclaration { + val fir: E +} + +interface FirCallableSymbol> : AbstractFirBasedSymbol + +interface FirElement +interface FirSymbolOwner : FirElement where E : FirSymbolOwner, E : FirDeclaration { + val symbol: AbstractFirBasedSymbol +} +interface FirDeclaration : FirElement +interface FirCallableDeclaration> : FirDeclaration, FirSymbolOwner +interface FirCallableMemberDeclaration> : FirCallableDeclaration + +private inline fun > computeBaseSymbols( + symbol: S, + basedSymbol: S, + directOverridden: FirTypeScope.(S) -> List +) {} + +fun FirCallableSymbol<*>.dispatchReceiverClassOrNull(): Boolean? = true + +private inline fun , reified S : FirCallableSymbol> createFakeOverriddenIfNeeded( + originalSymbol: FirCallableSymbol<*>, + basedSymbol: S, + computeDirectOverridden: FirTypeScope.(S) -> List, + someCondition: Boolean +) { + if (originalSymbol !is S) return + if (originalSymbol.dispatchReceiverClassOrNull() == true && someCondition) return + computeBaseSymbols(originalSymbol, basedSymbol, computeDirectOverridden) +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index c850c871cd3..c81aa91cb5d 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -3263,6 +3263,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToNothing.kt"); } + @Test + @TestMetadata("smartcastToTypeParameter.kt") + public void testSmartcastToTypeParameter() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToTypeParameter.kt"); + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/smartcasts/booleans") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index d4bb412ad93..5fd9fb6cc41 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -3300,6 +3300,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToNothing.kt"); } + @Test + @TestMetadata("smartcastToTypeParameter.kt") + public void testSmartcastToTypeParameter() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/smartcastToTypeParameter.kt"); + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/smartcasts/booleans") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index be4efe9b6a6..680ab4c470d 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -25651,6 +25651,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/smartCasts/smartcastOnSameFieldOfDifferentInstances.kt"); } + @Test + @TestMetadata("smartcastToInvisibleType_java.kt") + public void testSmartcastToInvisibleType_java() throws Exception { + runTest("compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_java.kt"); + } + + @Test + @TestMetadata("smartcastToInvisibleType_kotlin.kt") + public void testSmartcastToInvisibleType_kotlin() throws Exception { + runTest("compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_kotlin.kt"); + } + @Test @TestMetadata("smartcastToNothingAfterCheckingForNull.kt") public void testSmartcastToNothingAfterCheckingForNull() throws Exception { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt index 9be1c19f66a..4108d964a8a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt @@ -53,6 +53,10 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() { override fun updateAllReceivers(flow: PersistentFlow) = throw IllegalStateException("Update of all receivers is not possible for this logic system") + + override fun ConeKotlinType.isAcceptableForSmartcast(): Boolean { + return true + } } effects.forEach { effect -> diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 1d3841fa3bb..5abc0ae47ae 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -37668,6 +37668,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/smartCasts/kt42517.kt"); } + @Test + @TestMetadata("kt44802.kt") + public void testKt44802() throws Exception { + runTest("compiler/testData/codegen/box/smartCasts/kt44802.kt"); + } + @Test @TestMetadata("kt44804.kt") public void testKt44804() throws Exception { diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaVisibilityChecker.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaVisibilityChecker.kt index 118346cea64..30e9a392e2b 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaVisibilityChecker.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaVisibilityChecker.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.fir.NoMutableState import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.getOwnerId -import org.jetbrains.kotlin.fir.resolve.calls.Candidate +import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol @NoMutableState @@ -23,7 +23,7 @@ object FirJavaVisibilityChecker : FirVisibilityChecker() { symbol: AbstractFirBasedSymbol<*>, useSiteFile: FirFile, containingDeclarations: List, - candidate: Candidate, + dispatchReceiver: ReceiverValue?, session: FirSession ): Boolean { return when (declarationVisibility) { @@ -32,7 +32,7 @@ object FirJavaVisibilityChecker : FirVisibilityChecker() { true } else { val ownerId = symbol.getOwnerId() - ownerId != null && canSeeProtectedMemberOf(containingDeclarations, candidate.dispatchReceiverValue, ownerId, session) + ownerId != null && canSeeProtectedMemberOf(containingDeclarations, dispatchReceiver, ownerId, session) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirVisibilityChecker.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirVisibilityChecker.kt index d2531c45207..ba9583fb0aa 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirVisibilityChecker.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirVisibilityChecker.kt @@ -34,7 +34,7 @@ abstract class FirVisibilityChecker : FirSessionComponent { symbol: AbstractFirBasedSymbol<*>, useSiteFile: FirFile, containingDeclarations: List, - candidate: Candidate, + dispatchReceiver: ReceiverValue?, session: FirSession ): Boolean { return true @@ -45,8 +45,6 @@ abstract class FirVisibilityChecker : FirSessionComponent { declaration: T, candidate: Candidate ): Boolean where T : FirMemberDeclaration, T : FirSymbolOwner<*> { - val symbol = declaration.symbol - if (declaration is FirCallableDeclaration<*> && (declaration.isIntersectionOverride || declaration.isSubstitutionOverride)) { @Suppress("UNCHECKED_CAST") return isVisible(declaration.originalIfFakeOverride() as T, candidate) @@ -56,8 +54,19 @@ abstract class FirVisibilityChecker : FirSessionComponent { val useSiteFile = callInfo.containingFile val containingDeclarations = callInfo.containingDeclarations val session = callInfo.session - val provider = session.firProvider + return isVisible(declaration, session, useSiteFile, containingDeclarations, candidate.dispatchReceiverValue) + } + + fun isVisible( + declaration: T, + session: FirSession, + useSiteFile: FirFile, + containingDeclarations: List, + dispatchReceiver: ReceiverValue? + ): Boolean where T : FirMemberDeclaration, T : FirSymbolOwner<*> { + val provider = session.firProvider + val symbol = declaration.symbol return when (declaration.visibility) { Visibilities.Internal -> { declaration.session == session || session.moduleVisibilityChecker?.isInFriendModule(declaration) == true @@ -91,7 +100,7 @@ abstract class FirVisibilityChecker : FirSessionComponent { Visibilities.Protected -> { val ownerId = symbol.getOwnerId() - ownerId != null && canSeeProtectedMemberOf(containingDeclarations, candidate.dispatchReceiverValue, ownerId, session) + ownerId != null && canSeeProtectedMemberOf(containingDeclarations, dispatchReceiver, ownerId, session) } else -> platformVisibilityCheck( @@ -99,7 +108,7 @@ abstract class FirVisibilityChecker : FirSessionComponent { symbol, useSiteFile, containingDeclarations, - candidate, + dispatchReceiver, session ) } @@ -110,7 +119,7 @@ abstract class FirVisibilityChecker : FirSessionComponent { symbol: AbstractFirBasedSymbol<*>, useSiteFile: FirFile, containingDeclarations: List, - candidate: Candidate, + dispatchReceiver: ReceiverValue?, session: FirSession ): Boolean diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index 5960fc3ca1a..c7be19bf2af 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -18,8 +18,7 @@ import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference -import org.jetbrains.kotlin.fir.resolve.PersistentImplicitReceiverStack -import org.jetbrains.kotlin.fir.resolve.ResolutionMode +import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.dfa.cfg.* import org.jetbrains.kotlin.fir.resolve.dfa.contracts.buildContractFir import org.jetbrains.kotlin.fir.resolve.dfa.contracts.createArgumentsMapping @@ -31,6 +30,7 @@ import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.visibilityChecker import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -84,6 +84,9 @@ abstract class FirDataFlowAnalyzer( private val receiverStack: PersistentImplicitReceiverStack get() = components.implicitReceiverStack as PersistentImplicitReceiverStack + private val symbolProvider = components.session.symbolProvider + private val visibilityChecker = components.session.visibilityChecker + override val logicSystem: PersistentLogicSystem = object : PersistentLogicSystem(components.session.inferenceComponents.ctx) { override fun processUpdatedReceiverVariable(flow: PersistentFlow, variable: RealVariable) { @@ -109,6 +112,27 @@ abstract class FirDataFlowAnalyzer( } } } + + override fun ConeKotlinType.isAcceptableForSmartcast(): Boolean { + return when (this) { + is ConeClassLikeType -> { + val symbol = fullyExpandedType(components.session).lookupTag.toSymbol(components.session) ?: return false + val declaration = symbol.fir as? FirRegularClass ?: return true + visibilityChecker.isVisible( + declaration, + components.session, + components.context.file, + components.context.containers, + dispatchReceiver = null + ) + } + is ConeTypeParameterType -> true + is ConeFlexibleType -> lowerBound.isAcceptableForSmartcast() && upperBound.isAcceptableForSmartcast() + is ConeIntersectionType -> intersectedTypes.all { it.isAcceptableForSmartcast() } + is ConeDefinitelyNotNullType -> original.isAcceptableForSmartcast() + else -> false + } + } } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt index ed7d56fdac6..2516266317f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.dfa import org.jetbrains.kotlin.fir.types.ConeInferenceContext import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.canBeNull import org.jetbrains.kotlin.fir.types.commonSuperTypeOrNull abstract class Flow { @@ -59,6 +60,8 @@ abstract class LogicSystem(protected val context: ConeInferenceCont protected abstract fun getImplicationsWithVariable(flow: FLOW, variable: DataFlowVariable): Collection + protected abstract fun ConeKotlinType.isAcceptableForSmartcast(): Boolean + // ------------------------------- Callbacks for updating implicit receiver stack ------------------------------- abstract fun processUpdatedReceiverVariable(flow: FLOW, variable: RealVariable) @@ -150,7 +153,14 @@ abstract class LogicSystem(protected val context: ConeInferenceCont } } val result = mutableSetOf() - context.commonSuperTypeOrNull(intersectedTypes)?.let { result.add(it) } + context.commonSuperTypeOrNull(intersectedTypes)?.let { + if (it.isAcceptableForSmartcast()) { + result.add(it) + } else if (!it.canBeNull) { + result.add(context.anyType()) + } + Unit + } return result } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt index 7906f64405f..584bdfe76e7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt @@ -32,19 +32,19 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo val symbolProvider: FirSymbolProvider get() = session.symbolProvider - override fun nullableNothingType(): SimpleTypeMarker { + override fun nullableNothingType(): ConeClassLikeType { return session.builtinTypes.nullableNothingType.type } - override fun nullableAnyType(): SimpleTypeMarker { + override fun nullableAnyType(): ConeClassLikeType { return session.builtinTypes.nullableAnyType.type } - override fun nothingType(): SimpleTypeMarker { + override fun nothingType(): ConeClassLikeType { return session.builtinTypes.nothingType.type } - override fun anyType(): SimpleTypeMarker { + override fun anyType(): ConeClassLikeType { return session.builtinTypes.anyType.type } diff --git a/compiler/testData/codegen/box/smartCasts/kt44802.kt b/compiler/testData/codegen/box/smartCasts/kt44802.kt new file mode 100644 index 00000000000..4c77a142448 --- /dev/null +++ b/compiler/testData/codegen/box/smartCasts/kt44802.kt @@ -0,0 +1,46 @@ +// TARGET_BACKEND: JVM +// ISSUE: KT-44802 + +// FILE: foo/Base.java +package foo; + +public interface Base { + String foo(); +} + +// FILE: foo/PackagePrivateInterface.java +package foo; + +interface PackagePrivateInterface extends Base {} + +// FILE: foo/A.java +package foo; + +public class A implements PackagePrivateInterface { + public String foo() { return "OK"; } +} + +// FILE: foo/B.java +package foo; + +public class B implements PackagePrivateInterface { + public String foo() { return "B"; } +} + +// FILE: foo/C.java +package foo; + +// FILE: main.kt +package bar + +import foo.Base +import foo.A +import foo.B + +fun testSmartcast(x: Base): String { + if (x !is A && x !is B) return "fail" + return x.foo() +} + +fun box() = testSmartcast(A()) + diff --git a/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_java.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_java.fir.kt new file mode 100644 index 00000000000..a0ce2f40ebb --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_java.fir.kt @@ -0,0 +1,53 @@ +// ISSUE: KT-44802 +// INFERENCE_HELPERS + +// FILE: foo/PackagePrivateInterface.java +package foo; + +interface PackagePrivateInterface { + default void foo() {} +} + +// FILE: foo/A.java +package foo; + +public class A implements PackagePrivateInterface {} + +// FILE: foo/B.java +package foo; + +public class B implements PackagePrivateInterface {} + +// FILE: differentPackage.kt +package bar + +import foo.A +import foo.B +import select + +fun testSmartcast(x: Any) { + if (x is A || x is B) { + x.foo() + } +} + +fun testInference(a: A, b: B) { + val x = select(a, b) + x.foo() +} + +// FILE: samePackage.kt +package foo + +import select + +fun testSmartcast(x: Any) { + if (x is A || x is B) { + x.foo() + } +} + +fun testInference(a: A, b: B) { + val x = select(a, b) + x.foo() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_java.kt b/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_java.kt new file mode 100644 index 00000000000..9182e7ec8d1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_java.kt @@ -0,0 +1,53 @@ +// ISSUE: KT-44802 +// INFERENCE_HELPERS + +// FILE: foo/PackagePrivateInterface.java +package foo; + +interface PackagePrivateInterface { + default void foo() {} +} + +// FILE: foo/A.java +package foo; + +public class A implements PackagePrivateInterface {} + +// FILE: foo/B.java +package foo; + +public class B implements PackagePrivateInterface {} + +// FILE: differentPackage.kt +package bar + +import foo.A +import foo.B +import select + +fun testSmartcast(x: Any) { + if (x is A || x is B) { + x.foo() + } +} + +fun testInference(a: A, b: B) { + val x = select(a, b) + x.foo() +} + +// FILE: samePackage.kt +package foo + +import select + +fun testSmartcast(x: Any) { + if (x is A || x is B) { + x.foo() + } +} + +fun testInference(a: A, b: B) { + val x = select(a, b) + x.foo() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_java.txt b/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_java.txt new file mode 100644 index 00000000000..46bcdf49998 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_java.txt @@ -0,0 +1,39 @@ +package + +public fun id(/*0*/ x: K): K +public fun materialize(): K +public fun select(/*0*/ vararg values: K /*kotlin.Array*/): K + +package bar { + public fun testInference(/*0*/ a: foo.A, /*1*/ b: foo.B): kotlin.Unit + public fun testSmartcast(/*0*/ x: kotlin.Any): kotlin.Unit +} + +package foo { + public fun testInference(/*0*/ a: foo.A, /*1*/ b: foo.B): kotlin.Unit + public fun testSmartcast(/*0*/ x: kotlin.Any): kotlin.Unit + + public open class A : foo.PackagePrivateInterface { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public 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 + } + + public open class B : foo.PackagePrivateInterface { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public 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 + } + + public/*package*/ interface PackagePrivateInterface { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public 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 + } +} + diff --git a/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_kotlin.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_kotlin.fir.kt new file mode 100644 index 00000000000..f22cf8a5afa --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_kotlin.fir.kt @@ -0,0 +1,43 @@ +// INFERENCE_HELPERS +// ISSUE: KT-44802 +// FILE: a.kt + +package foo +import select + +private interface PrivateInterface { + fun foo() {} +} + +class A : PrivateInterface +class B : PrivateInterface + +fun testSmartcast(x: Any) { + if (x is A || x is B) { + x.foo() + } +} + +fun testInference(a: A, b: B) { + val x = select(a, b) + x.foo() +} + +// FILE: main.kt + +package bar + +import foo.A +import foo.B +import select + +fun testSmartcast(x: Any) { + if (x is A || x is B) { + x.foo() + } +} + +fun testInference(a: A, b: B) { + val x = select(a, b) + x.foo() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_kotlin.kt b/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_kotlin.kt new file mode 100644 index 00000000000..76a61137e66 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_kotlin.kt @@ -0,0 +1,43 @@ +// INFERENCE_HELPERS +// ISSUE: KT-44802 +// FILE: a.kt + +package foo +import select + +private interface PrivateInterface { + fun foo() {} +} + +class A : PrivateInterface +class B : PrivateInterface + +fun testSmartcast(x: Any) { + if (x is A || x is B) { + x.foo() + } +} + +fun testInference(a: A, b: B) { + val x = select(a, b) + x.foo() +} + +// FILE: main.kt + +package bar + +import foo.A +import foo.B +import select + +fun testSmartcast(x: Any) { + if (x is A || x is B) { + x.foo() + } +} + +fun testInference(a: A, b: B) { + val x = select(a, b) + x.foo() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_kotlin.txt b/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_kotlin.txt new file mode 100644 index 00000000000..8769813f4d7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_kotlin.txt @@ -0,0 +1,39 @@ +package + +public fun id(/*0*/ x: K): K +public fun materialize(): K +public fun select(/*0*/ vararg values: K /*kotlin.Array*/): K + +package bar { + public fun testInference(/*0*/ a: foo.A, /*1*/ b: foo.B): kotlin.Unit + public fun testSmartcast(/*0*/ x: kotlin.Any): kotlin.Unit +} + +package foo { + public fun testInference(/*0*/ a: foo.A, /*1*/ b: foo.B): kotlin.Unit + public fun testSmartcast(/*0*/ x: kotlin.Any): kotlin.Unit + + public final class A : foo.PrivateInterface { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public 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 + } + + public final class B : foo.PrivateInterface { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public 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 + } + + private interface PrivateInterface { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public 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 + } +} + diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 99d2bb2e949..5dd7cce0ee2 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -25741,6 +25741,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/smartCasts/smartcastOnSameFieldOfDifferentInstances.kt"); } + @Test + @TestMetadata("smartcastToInvisibleType_java.kt") + public void testSmartcastToInvisibleType_java() throws Exception { + runTest("compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_java.kt"); + } + + @Test + @TestMetadata("smartcastToInvisibleType_kotlin.kt") + public void testSmartcastToInvisibleType_kotlin() throws Exception { + runTest("compiler/testData/diagnostics/tests/smartCasts/smartcastToInvisibleType_kotlin.kt"); + } + @Test @TestMetadata("smartcastToNothingAfterCheckingForNull.kt") public void testSmartcastToNothingAfterCheckingForNull() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 04cd5241f1a..f6cf267f639 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -37668,6 +37668,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/smartCasts/kt42517.kt"); } + @Test + @TestMetadata("kt44802.kt") + public void testKt44802() throws Exception { + runTest("compiler/testData/codegen/box/smartCasts/kt44802.kt"); + } + @Test @TestMetadata("kt44804.kt") public void testKt44804() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 3ee926efb95..45d24688c10 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -37668,6 +37668,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/smartCasts/kt42517.kt"); } + @Test + @TestMetadata("kt44802.kt") + public void testKt44802() throws Exception { + runTest("compiler/testData/codegen/box/smartCasts/kt44802.kt"); + } + @Test @TestMetadata("kt44804.kt") public void testKt44804() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index e155f40e682..1b704cb4793 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -30120,6 +30120,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/smartCasts/kt42517.kt"); } + @TestMetadata("kt44802.kt") + public void testKt44802() throws Exception { + runTest("compiler/testData/codegen/box/smartCasts/kt44802.kt"); + } + @TestMetadata("kt44804.kt") public void testKt44804() throws Exception { runTest("compiler/testData/codegen/box/smartCasts/kt44804.kt");