From 796f8e6bce8e9b91d9e938906335f5eda296c9c2 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 3 Jun 2021 09:48:50 +0300 Subject: [PATCH] Revert "FIR checkers: report SMARTCAST_IMPOSSIBLE" This reverts commit 84334b08 --- .../resolve/smartcasts/nullability.dot | 24 ++-- .../resolve/smartcasts/nullability.fir.txt | 16 +-- .../resolve/smartcasts/nullability.kt | 16 +-- .../diagnostics/FirDiagnosticsList.kt | 6 - .../fir/analysis/diagnostics/FirErrors.kt | 1 - .../FirFunctionReturnTypeMismatchChecker.kt | 24 +--- .../diagnostics/FirDefaultErrorMessages.kt | 8 -- .../coneDiagnosticToFirDiagnostic.kt | 29 +---- .../fir/backend/Fir2IrImplicitCastInserter.kt | 1 - .../kotlin/fir/resolve/ScopeUtils.kt | 21 ---- .../kotlin/fir/resolve/calls/Arguments.kt | 31 +++-- .../kotlin/fir/resolve/calls/FirReceivers.kt | 8 +- .../fir/resolve/calls/ResolutionDiagnostic.kt | 17 ++- .../fir/resolve/calls/ResolutionStages.kt | 15 --- .../scopes/FirUnstableSmartcastTypeScope.kt | 106 ------------------ .../calls/tower/CandidateApplicability.kt | 2 +- .../calls/model/KotlinCallDiagnostics.kt | 4 +- .../resolve/calls/tower/ImplicitScopeTower.kt | 2 +- ...rtcastWhenOpenGetterWithOverloading.fir.kt | 15 +++ ...eSmartcastWhenOpenGetterWithOverloading.kt | 1 - ...leSmartcastWithOverloadedExtensions.fir.kt | 14 +++ ...stableSmartcastWithOverloadedExtensions.kt | 1 - .../tests/smartCasts/inference/kt39010.fir.kt | 11 ++ .../tests/smartCasts/inference/kt39010.kt | 1 - .../smartCasts/inference/kt39010_2.fir.kt | 16 +++ .../tests/smartCasts/inference/kt39010_2.kt | 1 - .../unstableSmartCast.fir.kt | 37 ++++++ .../intersectionScope/unstableSmartCast.kt | 1 - .../localDelegatedPropertyAfter.fir.kt | 4 +- .../localDelegatedPropertyBefore.fir.kt | 4 +- .../tests/smartCasts/openInSealed.fir.kt | 2 +- .../tests/smartCasts/propertyToNotNull.fir.kt | 2 +- .../smartCasts/publicVals/customGetter.fir.kt | 13 +++ .../smartCasts/publicVals/customGetter.kt | 1 - .../tests/smartCasts/publicVals/open.fir.kt | 11 ++ .../tests/smartCasts/publicVals/open.kt | 1 - .../smartCasts/publicVals/otherModule.fir.kt | 35 ++++++ .../smartCasts/publicVals/otherModule.kt | 1 - .../tests/smartCasts/publicVals/var.fir.kt | 15 +++ .../tests/smartCasts/publicVals/var.kt | 1 - .../tests/smartCasts/unstableToStable.fir.kt | 18 +++ .../tests/smartCasts/unstableToStable.kt | 1 - .../smartCasts/unstableToStableTypes.fir.kt | 22 ++++ .../tests/smartCasts/unstableToStableTypes.kt | 1 - .../contracts/smartcasts/receiver.fir.kt | 2 +- .../fir/handlers/FirDiagnosticsHandler.kt | 4 +- .../diagnostics/notLinked/dfa/pos/53.fir.kt | 4 +- .../diagnostics/KtFirDataClassConverters.kt | 9 -- .../api/fir/diagnostics/KtFirDiagnostics.kt | 7 -- .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 10 -- idea/testData/checker/infos/SmartCasts.fir.kt | 8 +- 51 files changed, 297 insertions(+), 308 deletions(-) delete mode 100644 compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirUnstableSmartcastTypeScope.kt create mode 100644 compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWhenOpenGetterWithOverloading.fir.kt create mode 100644 compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWithOverloadedExtensions.fir.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/inference/kt39010.fir.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/inference/kt39010_2.fir.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.fir.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/publicVals/customGetter.fir.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/publicVals/open.fir.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.fir.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/publicVals/var.fir.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/unstableToStable.fir.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/unstableToStableTypes.fir.kt diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.dot b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.dot index 9636ca4f760..6fbd681984e 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.dot +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.dot @@ -492,11 +492,11 @@ digraph nullability_kt { 176 [label="Access variable R|/Q.data|"]; 177 [label="Access variable R|/q|"]; 178 [label="Access variable R|/Q.data|"]; - 179 [label="Access variable #"]; + 179 [label="Access variable #"]; 180 [label="Access variable R|/q|"]; 181 [label="Access variable R|/Q.data|"]; - 182 [label="Access variable #"]; - 183 [label="Function call: R|/q|.R|/Q.data|.#.R|kotlin/Int.inc|()"]; + 182 [label="Access variable #"]; + 183 [label="Function call: R|/q|.R|/Q.data|.#.R|kotlin/Int.inc|()"]; 184 [label="Exit block"]; } 185 [label="Exit when branch result"]; @@ -566,11 +566,11 @@ digraph nullability_kt { 208 [label="Access variable R|/Q.data|"]; 209 [label="Access variable R|/q|"]; 210 [label="Access variable R|/Q.data|"]; - 211 [label="Access variable #"]; + 211 [label="Access variable #"]; 212 [label="Access variable R|/q|"]; 213 [label="Access variable R|/Q.data|"]; - 214 [label="Access variable #"]; - 215 [label="Function call: R|/q|.R|/Q.data|.#.R|kotlin/Int.inc|()"]; + 214 [label="Access variable #"]; + 215 [label="Function call: R|/q|.R|/Q.data|.#.R|kotlin/Int.inc|()"]; 216 [label="Exit block"]; } 217 [label="Exit function test_6" style="filled" fillcolor=red]; @@ -1280,11 +1280,11 @@ digraph nullability_kt { 490 [label="Access variable R|/QImplWithCustomGetter.data|"]; 491 [label="Access variable R|/q|"]; 492 [label="Access variable R|/QImplWithCustomGetter.data|"]; - 493 [label="Access variable #"]; + 493 [label="Access variable #"]; 494 [label="Access variable R|/q|"]; 495 [label="Access variable R|/QImplWithCustomGetter.data|"]; - 496 [label="Access variable #"]; - 497 [label="Function call: R|/q|.R|/QImplWithCustomGetter.data|.#.R|kotlin/Int.inc|()"]; + 496 [label="Access variable #"]; + 497 [label="Function call: R|/q|.R|/QImplWithCustomGetter.data|.#.R|kotlin/Int.inc|()"]; 498 [label="Exit block"]; } 499 [label="Exit when branch result"]; @@ -1363,11 +1363,11 @@ digraph nullability_kt { 524 [label="Access variable R|/QImplMutable.data|"]; 525 [label="Access variable R|/q|"]; 526 [label="Access variable R|/QImplMutable.data|"]; - 527 [label="Access variable #"]; + 527 [label="Access variable #"]; 528 [label="Access variable R|/q|"]; 529 [label="Access variable R|/QImplMutable.data|"]; - 530 [label="Access variable #"]; - 531 [label="Function call: R|/q|.R|/QImplMutable.data|.#.R|kotlin/Int.inc|()"]; + 530 [label="Access variable #"]; + 531 [label="Function call: R|/q|.R|/QImplMutable.data|.#.R|kotlin/Int.inc|()"]; 532 [label="Exit block"]; } 533 [label="Exit when branch result"]; diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.fir.txt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.fir.txt index c9de93e9311..cfb6f6d0941 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.fir.txt @@ -102,8 +102,8 @@ FILE: nullability.kt when () { !=(R|/q|?.{ $subj$.R|/Q.data| }?.{ $subj$.R|/MyData.s| }?.{ $subj$.R|kotlin/Int.inc|() }, Null(null)) -> { R|/q|.R|/Q.data| - R|/q|.R|/Q.data|.# - R|/q|.R|/Q.data|.#.R|kotlin/Int.inc|() + R|/q|.R|/Q.data|.# + R|/q|.R|/Q.data|.#.R|kotlin/Int.inc|() } } @@ -111,8 +111,8 @@ FILE: nullability.kt public final fun test_6(q: R|Q?|): R|kotlin/Unit| { R|/q|?.{ $subj$.R|/Q.data| }?.{ $subj$.R|/MyData.s| }?.{ $subj$.R|kotlin/Int.inc|() } ?: ^test_6 Unit R|/q|.R|/Q.data| - R|/q|.R|/Q.data|.# - R|/q|.R|/Q.data|.#.R|kotlin/Int.inc|() + R|/q|.R|/Q.data|.# + R|/q|.R|/Q.data|.#.R|kotlin/Int.inc|() } public final fun test_7(q: R|Q?|): R|kotlin/Unit| { when () { @@ -216,8 +216,8 @@ FILE: nullability.kt when () { !=(R|/q|?.{ $subj$.R|/QImplWithCustomGetter.data| }?.{ $subj$.R|/MyData.s| }?.{ $subj$.R|kotlin/Int.inc|() }, Null(null)) -> { R|/q|.R|/QImplWithCustomGetter.data| - R|/q|.R|/QImplWithCustomGetter.data|.# - R|/q|.R|/QImplWithCustomGetter.data|.#.R|kotlin/Int.inc|() + R|/q|.R|/QImplWithCustomGetter.data|.# + R|/q|.R|/QImplWithCustomGetter.data|.#.R|kotlin/Int.inc|() } } @@ -226,8 +226,8 @@ FILE: nullability.kt when () { !=(R|/q|?.{ $subj$.R|/QImplMutable.data| }?.{ $subj$.R|/MyData.s| }?.{ $subj$.R|kotlin/Int.inc|() }, Null(null)) -> { R|/q|.R|/QImplMutable.data| - R|/q|.R|/QImplMutable.data|.# - R|/q|.R|/QImplMutable.data|.#.R|kotlin/Int.inc|() + R|/q|.R|/QImplMutable.data|.# + R|/q|.R|/QImplMutable.data|.#.R|kotlin/Int.inc|() } } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.kt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.kt index 7347a02d70f..3f5877d797c 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.kt +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.kt @@ -67,8 +67,8 @@ fun test_5(q: Q?) { // `q.data` is a property that has an open getter, so we can NOT smartcast it to non-nullable MyData. if (q?.data?.s?.inc() != null) { q.data // good - q.data.s // should be bad - q.data.s.inc() // should be bad + q.data.s // should be bad + q.data.s.inc() // should be bad } } @@ -76,8 +76,8 @@ fun test_6(q: Q?) { // `q.data` is a property that has an open getter, so we can NOT smartcast it to non-nullable MyData. q?.data?.s?.inc() ?: return q.data // good - q.data.s // should be bad - q.data.s.inc() // should be bad + q.data.s // should be bad + q.data.s.inc() // should be bad } fun test_7(q: Q?) { @@ -162,8 +162,8 @@ fun test_12(q: QImplWithCustomGetter?) { // `q.data` is a property that has an open getter, so we can NOT smartcast it to non-nullable MyData. if (q?.data?.s?.inc() != null) { q.data // good - q.data.s // should be bad - q.data.s.inc() // should be bad + q.data.s // should be bad + q.data.s.inc() // should be bad } } @@ -171,7 +171,7 @@ fun test_13(q: QImplMutable?) { // `q.data` is a property that is mutable, so we can NOT smartcast it to non-nullable MyData. if (q?.data?.s?.inc() != null) { q.data // good - q.data.s // should be bad - q.data.s.inc() // should be bad + q.data.s // should be bad + q.data.s.inc() // should be bad } } diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 92d0a254536..2c97bb44d62 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -465,12 +465,6 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter("variance") parameter("containingType") } - - val SMARTCAST_IMPOSSIBLE by error { - parameter("desiredType") - parameter("subject") - parameter("description") - } } val REFLECTION by object : DiagnosticGroup("Reflection") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index aa4527c7633..664138a9b07 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -303,7 +303,6 @@ object FirErrors { val INCOMPATIBLE_TYPES_WARNING by warning2() val TYPE_VARIANCE_CONFLICT by error4(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT) val TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE by error4(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT) - val SMARTCAST_IMPOSSIBLE by error3() // Reflection val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirFunctionReturnTypeMismatchChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirFunctionReturnTypeMismatchChecker.kt index 735a4d02f65..503eeee20d5 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirFunctionReturnTypeMismatchChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirFunctionReturnTypeMismatchChecker.kt @@ -10,16 +10,13 @@ import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeForTypeMismatch import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULL_FOR_NONNULL_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SMARTCAST_IMPOSSIBLE import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction -import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast import org.jetbrains.kotlin.fir.expressions.FirReturnExpression import org.jetbrains.kotlin.fir.expressions.FirWhenExpression import org.jetbrains.kotlin.fir.expressions.isExhaustive import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.types.SmartcastStability object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() { override fun check(expression: FirReturnExpression, context: CheckerContext, reporter: DiagnosticReporter) { @@ -39,23 +36,10 @@ object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() { if (resultExpression.isNullLiteral && functionReturnType.nullability == ConeNullability.NOT_NULL) { reporter.reportOn(resultExpression.source, NULL_FOR_NONNULL_TYPE, context) } else { - if (resultExpression is FirExpressionWithSmartcast && resultExpression.smartcastStability != SmartcastStability.STABLE_VALUE && - isSubtypeForTypeMismatch(typeContext, subtype = resultExpression.smartcastType.coneType, supertype = functionReturnType) - ) { - reporter.reportOn( - returnExpressionSource, - SMARTCAST_IMPOSSIBLE, - functionReturnType, - resultExpression, - resultExpression.smartcastStability.description, - context - ) - } else { - reporter.report( - RETURN_TYPE_MISMATCH.on(returnExpressionSource, functionReturnType, returnExpressionType, targetElement), - context - ) - } + reporter.report( + RETURN_TYPE_MISMATCH.on(returnExpressionSource, functionReturnType, returnExpressionType, targetElement), + context + ) } } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 929d70221f1..07c3d7ffbf3 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -273,7 +273,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_SUPERTYPE_ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SINGLETON_IN_SUPERTYPE -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SMARTCAST_IMPOSSIBLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPES_FOR_ANNOTATION_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPERTYPE_APPEARS_TWICE @@ -635,13 +634,6 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE, "Extension function type can not be used as an upper bound") map.put(INCOMPATIBLE_TYPES, "Incompatible types: {0} and {1}", RENDER_TYPE, RENDER_TYPE) map.put(INCOMPATIBLE_TYPES_WARNING, "Potentially incompatible types: {0} and {1}", RENDER_TYPE, RENDER_TYPE) - map.put( - SMARTCAST_IMPOSSIBLE, - "Smart cast to ''{0}'' is impossible, because ''{1}'' is a {2}", - RENDER_TYPE, - FIR, - TO_STRING - ) map.put( TYPE_VARIANCE_CONFLICT, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index 04441913800..93c6faa5af0 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -46,15 +46,6 @@ private fun ConeDiagnostic.toFirDiagnostic( val candidate = candidates.first { it.currentApplicability == CandidateApplicability.UNSAFE_CALL } val unsafeCall = candidate.diagnostics.firstIsInstance() mapUnsafeCallError(candidate, unsafeCall, source, qualifiedAccessSource) - } else if (this.applicability == CandidateApplicability.UNSTABLE_SMARTCAST) { - val unstableSmartcast = - this.candidates.first { it.currentApplicability == CandidateApplicability.UNSTABLE_SMARTCAST }.diagnostics.firstIsInstance() - FirErrors.SMARTCAST_IMPOSSIBLE.on( - unstableSmartcast.argument.source, - unstableSmartcast.targetType, - unstableSmartcast.argument, - unstableSmartcast.argument.smartcastStability.description - ) } else { FirErrors.NONE_APPLICABLE.on(source, this.candidates.map { it.symbol }) } @@ -143,8 +134,8 @@ private fun mapInapplicableCandidateError( source: FirSourceElement, qualifiedAccessSource: FirSourceElement?, ): List> { - val genericDiagnostic = FirErrors.INAPPLICABLE_CANDIDATE.on(source, diagnostic.candidate.symbol) - val diagnostics = diagnostic.candidate.diagnostics.filter { it.applicability == diagnostic.applicability }.mapNotNull { rootCause -> + // TODO: Need to distinguish SMARTCAST_IMPOSSIBLE + return diagnostic.candidate.diagnostics.filter { it.applicability == diagnostic.applicability }.mapNotNull { rootCause -> when (rootCause) { is VarargArgumentOutsideParentheses -> FirErrors.VARARG_OUTSIDE_PARENTHESES.on( rootCause.argument.source ?: qualifiedAccessSource @@ -175,21 +166,9 @@ private fun mapInapplicableCandidateError( is InfixCallOfNonInfixFunction -> FirErrors.INFIX_MODIFIER_REQUIRED.on(source, rootCause.function) is OperatorCallOfNonOperatorFunction -> FirErrors.OPERATOR_MODIFIER_REQUIRED.on(source, rootCause.function, rootCause.function.fir.name.asString()) - is UnstableSmartCast -> FirErrors.SMARTCAST_IMPOSSIBLE.on( - rootCause.argument.source, - rootCause.targetType, - rootCause.argument, - rootCause.argument.smartcastStability.description - ) - else -> genericDiagnostic + else -> null } - }.distinct() - return if (diagnostics.size > 1) { - // If there are more specific diagnostics, filter out the generic diagnostic. - diagnostics.filter { it != genericDiagnostic } - } else { - diagnostics - } + }.ifEmpty { listOf(FirErrors.INAPPLICABLE_CANDIDATE.on(source, diagnostic.candidate.symbol)) } } @OptIn(ExperimentalStdlibApi::class) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt index abaea391d69..dc07ee5d493 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt @@ -31,7 +31,6 @@ import org.jetbrains.kotlin.ir.util.classId import org.jetbrains.kotlin.ir.util.coerceToUnitIfNeeded import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.types.AbstractTypeChecker -import org.jetbrains.kotlin.types.SmartcastStability class Fir2IrImplicitCastInserter( private val components: Fir2IrComponents, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt index 3476998ac1e..560d369abb6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt @@ -10,11 +10,9 @@ import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirResolvePhase -import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolved import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator -import org.jetbrains.kotlin.fir.scopes.FirUnstableSmartcastTypeScope import org.jetbrains.kotlin.fir.scopes.FirTypeScope import org.jetbrains.kotlin.fir.scopes.impl.FirScopeWithFakeOverrideTypeCalculator import org.jetbrains.kotlin.fir.scopes.impl.FirStandardOverrideChecker @@ -27,25 +25,6 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.types.SmartcastStability - -fun FirExpressionWithSmartcast.smartcastScope( - useSiteSession: FirSession, - scopeSession: ScopeSession -): FirTypeScope? { - val smartcastType = smartcastType.coneType - val smartcastScope = smartcastType.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing) - if (smartcastStability == SmartcastStability.STABLE_VALUE) { - return smartcastScope - } - val originalScope = originalType.coneType.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing) - ?: return smartcastScope - - if (smartcastScope == null) { - return originalScope - } - return FirUnstableSmartcastTypeScope(smartcastType, smartcastScope, originalScope) -} fun ConeKotlinType.scope( useSiteSession: FirSession, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index 2bab2ce415b..55a636e0315 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -30,9 +30,9 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible +import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition import org.jetbrains.kotlin.types.AbstractTypeChecker -import org.jetbrains.kotlin.types.SmartcastStability import org.jetbrains.kotlin.types.model.CaptureStatus import org.jetbrains.kotlin.types.model.TypeSystemCommonSuperTypesContext import org.jetbrains.kotlin.utils.addToStdlib.runIf @@ -358,7 +358,17 @@ private fun checkApplicabilityForArgumentType( ) { if (expectedType == null) return - fun subtypeError(actualExpectedType: ConeKotlinType): ResolutionDiagnostic { + fun unstableSmartCastOrSubtypeError( + unstableType: ConeKotlinType?, + actualExpectedType: ConeKotlinType, + position: ConstraintPosition + ): ResolutionDiagnostic { + if (unstableType != null) { + if (csBuilder.addSubtypeConstraintIfCompatible(unstableType, actualExpectedType, position)) { + return UnstableSmartCast.ResolutionError(argument, unstableType) + } + } + if (argument.isNullLiteral && actualExpectedType.nullability == ConeNullability.NOT_NULL) { return NullForNotNullType(argument) } @@ -396,17 +406,14 @@ private fun checkApplicabilityForArgumentType( } if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) { - val smartcastExpression = argument as? FirExpressionWithSmartcast - if (smartcastExpression != null && smartcastExpression.smartcastStability != SmartcastStability.STABLE_VALUE) { - val unstableType = smartcastExpression.smartcastType.coneType - if (csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) { - sink.reportDiagnostic(UnstableSmartCast(smartcastExpression, expectedType)) - return - } - } - if (!isReceiver) { - sink.reportDiagnosticIfNotNull(subtypeError(expectedType)) + sink.reportDiagnosticIfNotNull( + unstableSmartCastOrSubtypeError( + unstableType = null, // TODO: handle unstable smartcasts + expectedType, + position + ) + ) return } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt index ac21f72d6ec..295a7d69eeb 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.fir.resolve.calls import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic import org.jetbrains.kotlin.fir.expressions.FirExpression -import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionWithSmartcast import org.jetbrains.kotlin.fir.expressions.builder.buildThisReceiverExpression @@ -17,7 +16,6 @@ import org.jetbrains.kotlin.fir.renderWithType import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.constructType import org.jetbrains.kotlin.fir.resolve.scope -import org.jetbrains.kotlin.fir.resolve.smartcastScope import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator import org.jetbrains.kotlin.fir.scopes.FirTypeScope @@ -59,11 +57,7 @@ abstract class AbstractExplicitReceiverValue : AbstractExplic class ExpressionReceiverValue( override val explicitReceiver: FirExpression -) : AbstractExplicitReceiverValue(), ReceiverValue { - override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirTypeScope? = - (receiverExpression as? FirExpressionWithSmartcast)?.smartcastScope(useSiteSession, scopeSession) - ?: type.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing) -} +) : AbstractExplicitReceiverValue(), ReceiverValue sealed class ImplicitReceiverValue>( val boundSymbol: S, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt index 3a7f9658e10..301e342c9d8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.fir.resolve.calls import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.expressions.FirExpression -import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType @@ -75,7 +74,21 @@ object LowerPriorityToPreserveCompatibilityDiagnostic : ResolutionDiagnostic(RES object CandidateChosenUsingOverloadResolutionByLambdaAnnotation : ResolutionDiagnostic(RESOLVED) -class UnstableSmartCast(val argument: FirExpressionWithSmartcast, val targetType: ConeKotlinType) : ResolutionDiagnostic(UNSTABLE_SMARTCAST) +sealed class UnstableSmartCast( + val argument: FirExpression, + val targetType: ConeKotlinType, + applicability: CandidateApplicability +) : ResolutionDiagnostic(applicability) { + class ResolutionError( + argument: FirExpression, + targetType: ConeKotlinType, + ) : UnstableSmartCast(argument, targetType, MAY_THROW_RUNTIME_ERROR) + + class DiagnosticError( + argument: FirExpression, + targetType: ConeKotlinType, + ) : UnstableSmartCast(argument, targetType, RESOLVED_WITH_ERROR) +} class ArgumentTypeMismatch( val expectedType: ConeKotlinType, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index ca015cddf83..a462399fe23 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -26,8 +26,6 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.* import org.jetbrains.kotlin.types.AbstractNullabilityChecker -import org.jetbrains.kotlin.types.AbstractTypeChecker -import org.jetbrains.kotlin.types.SmartcastStability abstract class ResolutionStage { abstract suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) @@ -107,19 +105,6 @@ object CheckDispatchReceiver : ResolutionStage() { } } - if (explicitReceiverExpression is FirExpressionWithSmartcast && explicitReceiverExpression.smartcastStability != SmartcastStability.STABLE_VALUE) { - val expectedDispatchReceiverType = (candidate.symbol.fir as? FirCallableMemberDeclaration)?.dispatchReceiverType - if (expectedDispatchReceiverType != null && - !AbstractTypeChecker.isSubtypeOf( - context.session.typeContext, - explicitReceiverExpression.originalType.coneType, - expectedDispatchReceiverType - ) - ) { - sink.yieldDiagnostic(UnstableSmartCast(explicitReceiverExpression, expectedDispatchReceiverType)) - } - } - val dispatchReceiverValueType = candidate.dispatchReceiverValue?.type ?: return if (!AbstractNullabilityChecker.isSubtypeOfAny(context.session.typeContext, dispatchReceiverValueType)) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirUnstableSmartcastTypeScope.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirUnstableSmartcastTypeScope.kt deleted file mode 100644 index 2cefa9de96a..00000000000 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirUnstableSmartcastTypeScope.kt +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2010-2021 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.scopes - -import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration -import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor -import org.jetbrains.kotlin.fir.symbols.impl.* -import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.name.Name - -/** - * Special type scope for unstable smartcast. The purpose of this scope is only to report "SMARTCAST_IMPOSSIBLE" diagnostics. - * - * This scope will serve all candidates available in the original scope. In addition, it also serve all additional members that are - * available from the smartcast type. This way, these additional members can be resolved. Later in - * [org.jetbrains.kotlin.fir.resolve.calls.CheckDispatchReceiver], these additional members are rejected with "UnstableSmartcast" - * diagnostic, which surfaces as "SMARTCAST_IMPOSSIBLE" diagnostic. - */ -class FirUnstableSmartcastTypeScope( - private val smartcastType: ConeKotlinType, - private val smartcastScope: FirTypeScope, - private val originalScope: FirTypeScope -) : FirTypeScope(), FirContainingNamesAwareScope { - private val scopes = listOf(smartcastScope, originalScope) - override fun processClassifiersByNameWithSubstitution( - name: Name, - processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit - ) { - for (scope in scopes) { - scope.processClassifiersByNameWithSubstitution(name, processor) - } - } - - private inline fun processComposite( - process: FirTypeScope.(Name, (T) -> Unit) -> Unit, - name: Name, - noinline processor: (T) -> Unit - ) { - val unique = mutableSetOf() - for (scope in scopes) { - scope.process(name) { - if (unique.add(it)) { - processor(it) - } - } - } - } - - override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { - return processComposite(FirScope::processFunctionsByName, name, processor) - } - - override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { - return processComposite(FirScope::processPropertiesByName, name, processor) - } - - private inline fun > processTypedComposite( - process: FirTypeScope.(N, (T, FirTypeScope) -> ProcessorAction) -> ProcessorAction, - name: N, - noinline processor: (T, FirTypeScope) -> ProcessorAction - ): ProcessorAction { - originalScope.process(name) { symbol, firTypeScope -> - processor(symbol, firTypeScope) - }.let { if (it == ProcessorAction.STOP) return ProcessorAction.STOP } - - smartcastScope.process(name) { symbol, firTypeScope -> - // Only process the symbol if the dispatcher type is exactly the smartcast type. This way, we don't add any additional - // symbols that already exists in the original scope. - if ((symbol.fir as? FirCallableMemberDeclaration)?.dispatchReceiverType == smartcastType) { - processor(symbol, firTypeScope) - } else { - ProcessorAction.NEXT - } - }.let { if (it == ProcessorAction.STOP) return ProcessorAction.STOP } - return ProcessorAction.NEXT - } - - override fun processDirectOverriddenFunctionsWithBaseScope( - functionSymbol: FirNamedFunctionSymbol, - processor: (FirNamedFunctionSymbol, FirTypeScope) -> ProcessorAction - ): ProcessorAction { - return processTypedComposite(FirTypeScope::processDirectOverriddenFunctionsWithBaseScope, functionSymbol, processor) - } - - override fun processDirectOverriddenPropertiesWithBaseScope( - propertySymbol: FirPropertySymbol, - processor: (FirPropertySymbol, FirTypeScope) -> ProcessorAction - ): ProcessorAction { - return processTypedComposite(FirTypeScope::processDirectOverriddenPropertiesWithBaseScope, propertySymbol, processor) - } - - override fun getCallableNames(): Set { - return scopes.flatMapTo(hashSetOf()) { it.getContainingCallableNamesIfPresent() } - } - - override fun getClassifierNames(): Set { - return scopes.flatMapTo(hashSetOf()) { it.getContainingClassifierNamesIfPresent() } - } - - override val scopeOwnerLookupNames: List by lazy(LazyThreadSafetyMode.PUBLICATION) { - scopes.flatMap { it.scopeOwnerLookupNames } - } -} diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt index 7943b5fb18a..d6c6dc02548 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt @@ -15,7 +15,7 @@ enum class CandidateApplicability { IMPOSSIBLE_TO_GENERATE, // access to outer class from nested RUNTIME_ERROR, // problems with visibility UNSAFE_CALL, // receiver nullability doesn't match - UNSTABLE_SMARTCAST, // unstable smart cast + MAY_THROW_RUNTIME_ERROR, // unstable smart cast CONVENTION_ERROR, // missing infix, operator etc RESOLVED_LOW_PRIORITY, RESOLVED_NEED_PRESERVE_COMPATIBILITY, // call resolved successfully, but using new features that changes resolve diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt index 1aee781a4f3..11a592577f3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt @@ -161,7 +161,7 @@ sealed class UnstableSmartCast( class UnstableSmartCastResolutionError( argument: ExpressionKotlinCallArgument, targetType: UnwrappedType, -) : UnstableSmartCast(argument, targetType, UNSTABLE_SMARTCAST) +) : UnstableSmartCast(argument, targetType, MAY_THROW_RUNTIME_ERROR) class UnstableSmartCastDiagnosticError( argument: ExpressionKotlinCallArgument, @@ -218,7 +218,7 @@ class ArgumentTypeMismatchDiagnostic( val expectedType: UnwrappedType, val actualType: UnwrappedType, val expressionArgument: ExpressionKotlinCallArgument -) : KotlinCallDiagnostic(UNSTABLE_SMARTCAST) { +) : KotlinCallDiagnostic(MAY_THROW_RUNTIME_ERROR) { override fun report(reporter: DiagnosticReporter) { reporter.onCallArgument(expressionArgument, this) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt index 2f70131750e..418d191202a 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt @@ -120,7 +120,7 @@ object ErrorDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED) // todo discus object LowPriorityDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED_LOW_PRIORITY) object DynamicDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED_LOW_PRIORITY) object ResolvedUsingNewFeatures : ResolutionDiagnostic(RESOLVED_NEED_PRESERVE_COMPATIBILITY) -object UnstableSmartCastDiagnostic : ResolutionDiagnostic(UNSTABLE_SMARTCAST) +object UnstableSmartCastDiagnostic : ResolutionDiagnostic(MAY_THROW_RUNTIME_ERROR) object HiddenExtensionRelatedToDynamicTypes : ResolutionDiagnostic(HIDDEN) object HiddenDescriptor : ResolutionDiagnostic(HIDDEN) diff --git a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWhenOpenGetterWithOverloading.fir.kt b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWhenOpenGetterWithOverloading.fir.kt new file mode 100644 index 00000000000..eef4481310c --- /dev/null +++ b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWhenOpenGetterWithOverloading.fir.kt @@ -0,0 +1,15 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface Ctx +class CtxImpl : Ctx { + fun doJob(a: Int) {} + fun doJob(s: String) {} +} + +open class Test(open val ctx: Ctx) { + fun test() { + when (ctx) { + is CtxImpl -> ctx.doJob(2) + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWhenOpenGetterWithOverloading.kt b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWhenOpenGetterWithOverloading.kt index 838a09497f6..9470f9633c6 100644 --- a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWhenOpenGetterWithOverloading.kt +++ b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWhenOpenGetterWithOverloading.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER interface Ctx diff --git a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWithOverloadedExtensions.fir.kt b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWithOverloadedExtensions.fir.kt new file mode 100644 index 00000000000..8aa89b44288 --- /dev/null +++ b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWithOverloadedExtensions.fir.kt @@ -0,0 +1,14 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +class A +class B + +fun A.foo(a: A) {} +fun A.foo(b: B) {} +var a: A? = null + +fun smartCastInterference(b: B) { + if (a != null) { + a.foo(b) + } +} diff --git a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWithOverloadedExtensions.kt b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWithOverloadedExtensions.kt index dd7243cff22..8a05ee7fba5 100644 --- a/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWithOverloadedExtensions.kt +++ b/compiler/testData/diagnostics/tests/nullabilityAndSmartCasts/unstableSmartcastWithOverloadedExtensions.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER class A diff --git a/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010.fir.kt new file mode 100644 index 00000000000..1c01fc7674d --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010.fir.kt @@ -0,0 +1,11 @@ +class A { + fun foo(): E = TODO() +} + +class B(var a: A<*>?) { + fun bar() { + if (a != null) { + a.foo() + } + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010.kt b/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010.kt index b9398fa2c9f..79b4b03581d 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL class A { fun foo(): E = TODO() } diff --git a/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010_2.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010_2.fir.kt new file mode 100644 index 00000000000..29b5304ca7b --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010_2.fir.kt @@ -0,0 +1,16 @@ +open class A { +} + +class B : A() { + fun foo() {} +} + +interface KI { + val a: A<*> +} + +fun KI.bar() { + if (a is B) { + a.foo() + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010_2.kt b/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010_2.kt index ecdf447cc75..92ad9e96636 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010_2.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/inference/kt39010_2.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL open class A { } diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.fir.kt new file mode 100644 index 00000000000..e6af93cd7ea --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.fir.kt @@ -0,0 +1,37 @@ +// !CHECK_TYPE + +interface A { + fun foo(): CharSequence? + fun baz(x: Any) {} +} + +interface B { + fun foo(): String + fun baz(x: Int): String ="" + fun baz(x: Int, y: Int) {} + + fun foobar(): CharSequence? +} + +interface C { + fun foo(): String + fun baz(x: Int): String ="" + fun baz(x: Int, y: Int) {} + + fun foobar(): String +} + +var x: A = null!! + +fun test() { + x.foo().checkType { _() } + + if (x is B && x is C) { + x.foo().checkType { _() } + x.baz("") + x.baz(1).checkType { _() } + x.baz(1, 2) + + x.foobar().checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.kt b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.kt index bc5813c837f..e8db585a64d 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/intersectionScope/unstableSmartCast.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !CHECK_TYPE interface A { diff --git a/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyAfter.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyAfter.fir.kt index 934a279a0bb..13f0a640d8d 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyAfter.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyAfter.fir.kt @@ -10,6 +10,6 @@ fun failsWithClassCastException() { val sometimesNotInt: Any? by AlternatingDelegate() if (sometimesNotInt is Int) { - sometimesNotInt.inc() + sometimesNotInt.inc() } -} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyBefore.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyBefore.fir.kt index 13b63862b6b..8777e5aea0a 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyBefore.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/localDelegatedPropertyBefore.fir.kt @@ -10,6 +10,6 @@ fun failsWithClassCastException() { val sometimesNotInt: Any? by AlternatingDelegate() if (sometimesNotInt is Int) { - sometimesNotInt.inc() + sometimesNotInt.inc() } -} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/openInSealed.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/openInSealed.fir.kt index 70a19484fba..e8928c7d8f1 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/openInSealed.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/openInSealed.fir.kt @@ -2,7 +2,7 @@ sealed class My(open val x: Int?) { init { if (x != null) { // Should be error: property is open - x.hashCode() + x.hashCode() } } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/propertyToNotNull.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/propertyToNotNull.fir.kt index cd502255331..f14a192a0df 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/propertyToNotNull.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/propertyToNotNull.fir.kt @@ -7,7 +7,7 @@ class Immutable(val x: String?) { class Mutable(var y: String?) { fun foo(): String { - if (y != null) return y + if (y != null) return y return "" } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/publicVals/customGetter.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/publicVals/customGetter.fir.kt new file mode 100644 index 00000000000..6cbdc76ca22 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/publicVals/customGetter.fir.kt @@ -0,0 +1,13 @@ +public class X { + private val x : String? = null + public val y: CharSequence? + get() = x?.subSequence(0, 1) + public fun fn(): Int { + if (y != null) + // With non-default getter smartcast is not possible + return y.length + else + return 0 + } +} + diff --git a/compiler/testData/diagnostics/tests/smartCasts/publicVals/customGetter.kt b/compiler/testData/diagnostics/tests/smartCasts/publicVals/customGetter.kt index 61f6ed0bc73..645344871e1 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/publicVals/customGetter.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/publicVals/customGetter.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL public class X { private val x : String? = null public val y: CharSequence? diff --git a/compiler/testData/diagnostics/tests/smartCasts/publicVals/open.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/publicVals/open.fir.kt new file mode 100644 index 00000000000..4c34ecac3aa --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/publicVals/open.fir.kt @@ -0,0 +1,11 @@ +public open class A() { + public open val foo: Int? = 1 +} + +infix fun Int.bar(i: Int) = i + +fun test() { + val p = A() + // For open value properties, smart casts should not work + if (p.foo is Int) p.foo bar 11 +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/publicVals/open.kt b/compiler/testData/diagnostics/tests/smartCasts/publicVals/open.kt index 3bfb8482af7..770e1fcca6a 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/publicVals/open.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/publicVals/open.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL public open class A() { public open val foo: Int? = 1 } diff --git a/compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.fir.kt new file mode 100644 index 00000000000..10449588bdd --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.fir.kt @@ -0,0 +1,35 @@ +// MODULE: m1 +// FILE: a.kt + +package a + +public class X { + public val x : String? = null +} + +// MODULE: m2(m1) +// FILE: b.kt + +package b + +import a.X + +public fun X.gav(): Int { + if (x != null) + // Smart cast is not possible if definition is in another module + return x.length + else + return 0 +} + +// FILE: c.kt + +package a + +public fun X.gav(): Int { + if (x != null) + // Even if it's in the same package + return x.length + else + return 0 +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.kt b/compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.kt index ab085b21210..c5496f9ab03 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // MODULE: m1 // FILE: a.kt diff --git a/compiler/testData/diagnostics/tests/smartCasts/publicVals/var.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/publicVals/var.fir.kt new file mode 100644 index 00000000000..8b8e840c20a --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/publicVals/var.fir.kt @@ -0,0 +1,15 @@ +public class X { + public var x : String? = null + private var y: String? = "abc" + public fun fn(): Int { + if (x != null) + // Smartcast is not possible for variable properties + return x.length + else if (y != null) + // Even if they are private + return y.length + else + return 0 + } +} + diff --git a/compiler/testData/diagnostics/tests/smartCasts/publicVals/var.kt b/compiler/testData/diagnostics/tests/smartCasts/publicVals/var.kt index 94cb475bdd9..c8ca4850b83 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/publicVals/var.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/publicVals/var.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL public class X { public var x : String? = null private var y: String? = "abc" diff --git a/compiler/testData/diagnostics/tests/smartCasts/unstableToStable.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/unstableToStable.fir.kt new file mode 100644 index 00000000000..472d38cca3b --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/unstableToStable.fir.kt @@ -0,0 +1,18 @@ +class Foo(var x: Int?) { + init { + if (x != null) { + val y = x + // Error: x is not stable, Type(y) = Int? + x.hashCode() + y.hashCode() + if (y == x) { + // Still error + y.hashCode() + } + if (x == null && y != x) { + // Still error + y.hashCode() + } + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/unstableToStable.kt b/compiler/testData/diagnostics/tests/smartCasts/unstableToStable.kt index 5216bc63586..53baa677a91 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/unstableToStable.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/unstableToStable.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL class Foo(var x: Int?) { init { if (x != null) { diff --git a/compiler/testData/diagnostics/tests/smartCasts/unstableToStableTypes.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/unstableToStableTypes.fir.kt new file mode 100644 index 00000000000..4702c095847 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/unstableToStableTypes.fir.kt @@ -0,0 +1,22 @@ +class Bar { + fun bar() {} +} + +class Foo(var x: Any) { + init { + if (x is Bar) { + val y = x + // Error: x is not stable, Type(y) = Any + x.bar() + y.bar() + if (y == x) { + // Still error + y.bar() + } + if (x !is Bar && y != x) { + // Still error + y.bar() + } + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/unstableToStableTypes.kt b/compiler/testData/diagnostics/tests/smartCasts/unstableToStableTypes.kt index 1a872d2f169..5119d5d11b1 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/unstableToStableTypes.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/unstableToStableTypes.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL class Bar { fun bar() {} } diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/receiver.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/receiver.fir.kt index 6fb91017f33..bf485ab0d1e 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/receiver.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/receiver.fir.kt @@ -28,7 +28,7 @@ class UnstableReceiver { x.inc() } else { - x.dec() + x.dec() } } } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt index 6fe6e2bacc6..e49ce937d6f 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt @@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFactory1 import org.jetbrains.kotlin.checkers.utils.TypeOfCall +import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.rendering.Renderers import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.analysis.diagnostics.* @@ -42,7 +43,6 @@ import org.jetbrains.kotlin.test.model.TestFile import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.services.* import org.jetbrains.kotlin.test.utils.AbstractTwoAttributesMetaInfoProcessor -import org.jetbrains.kotlin.types.SmartcastStability import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addIfNotNull @@ -176,7 +176,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes diagnosedRangesToDiagnosticNames: Map> ): FirDiagnosticWithParameters1? = DebugInfoDiagnosticFactory1.EXPRESSION_TYPE.createDebugInfoDiagnostic(element, diagnosedRangesToDiagnosticNames) { - element.typeRef.renderAsString((element as? FirExpressionWithSmartcast)?.takeIf { it.smartcastStability == SmartcastStability.STABLE_VALUE }?.originalType) + element.typeRef.renderAsString((element as? FirExpressionWithSmartcast)?.originalType) } private fun FirTypeRef.renderAsString(originalTypeRef: FirTypeRef?): String { diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/53.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/53.fir.kt index 501fe32d597..84ee533bd4c 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/53.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/53.fir.kt @@ -33,7 +33,7 @@ fun case_3(x: Int) = "" fun case_3(x: Int?) = 10 fun case_3() { if (case_3_prop != null) { - val z = case_3(case_3_prop) + val z = case_3(case_3_prop) z } } @@ -89,7 +89,7 @@ fun case_7(x: Int) = "" fun case_7(x: Int?) = 10 fun case_7() { if (case_7_prop != null) { - val z = case_7(case_7_prop) + val z = case_7(case_7_prop) z } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index c0d366f98a9..c684d733e7c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -1382,15 +1382,6 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } - add(FirErrors.SMARTCAST_IMPOSSIBLE) { firDiagnostic -> - SmartcastImpossibleImpl( - firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), - firDiagnostic.b.source!!.psi as KtExpression, - firDiagnostic.c, - firDiagnostic as FirPsiDiagnostic<*>, - token, - ) - } add(FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED) { firDiagnostic -> ExtensionInClassReferenceNotAllowedImpl( firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a as FirCallableDeclaration), diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index cb48e8a13a5..99d600c0497 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -978,13 +978,6 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val containingType: KtType } - abstract class SmartcastImpossible : KtFirDiagnostic() { - override val diagnosticClass get() = SmartcastImpossible::class - abstract val desiredType: KtType - abstract val subject: KtExpression - abstract val description: String - } - abstract class ExtensionInClassReferenceNotAllowed : KtFirDiagnostic() { override val diagnosticClass get() = ExtensionInClassReferenceNotAllowed::class abstract val referencedDeclaration: KtCallableSymbol diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index e6458906b79..151597931e3 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -1579,16 +1579,6 @@ internal class TypeVarianceConflictInExpandedTypeImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } -internal class SmartcastImpossibleImpl( - override val desiredType: KtType, - override val subject: KtExpression, - override val description: String, - firDiagnostic: FirPsiDiagnostic<*>, - override val token: ValidityToken, -) : KtFirDiagnostic.SmartcastImpossible(), KtAbstractFirDiagnostic { - override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) -} - internal class ExtensionInClassReferenceNotAllowedImpl( override val referencedDeclaration: KtCallableSymbol, firDiagnostic: FirPsiDiagnostic<*>, diff --git a/idea/testData/checker/infos/SmartCasts.fir.kt b/idea/testData/checker/infos/SmartCasts.fir.kt index e927bee71fa..503884ed227 100644 --- a/idea/testData/checker/infos/SmartCasts.fir.kt +++ b/idea/testData/checker/infos/SmartCasts.fir.kt @@ -234,13 +234,13 @@ class Mutable(var x: String?) { fun foo(): String { if (x is String) { - return x + return x } if (x != null) { - return x + return x } if (xx is String) { - return xx + return xx } return "" } @@ -248,7 +248,7 @@ class Mutable(var x: String?) { fun bar(other: Mutable): String { var y = other if (y.x is String) { - return y.x + return y.x } return "" }