From e40ba73950d3bd83ae0baa02eeb8781d161a4f80 Mon Sep 17 00:00:00 2001 From: Pavel Kirpichenkov Date: Tue, 4 Feb 2020 17:26:28 +0300 Subject: [PATCH] [NI] Add resolution applicability for resolved candidates with error New resolution applicability is needed in cases when error is found, but candidate still should be selected. Currently there are two cases, when this behaviour is required: - unstable smartcast (choose candidate with non-nullable parameter) - unknown lambda parameter type (against non-functional expected type) KT-36264 --- ...irOldFrontendDiagnosticsTestGenerated.java | 5 ++ .../tower/KotlinToResolvedCallTransformer.kt | 4 +- .../calls/model/KotlinCallDiagnostics.kt | 4 +- .../resolve/calls/tower/ImplicitScopeTower.kt | 3 +- .../resolve/calls/tower/TowerResolver.kt | 9 +- .../kotlin/resolve/calls/tower/TowerUtils.kt | 2 +- .../diagnostics/tests/resolve/kt36264.fir.kt | 19 ++++ .../diagnostics/tests/resolve/kt36264.kt | 19 ++++ .../diagnostics/tests/resolve/kt36264.txt | 26 ++++++ .../varnotnull/unnecessaryWithMap.fir.kt | 1 - .../varnotnull/unnecessaryWithMap.kt | 3 +- .../diagnostics/notLinked/dfa/neg/46.kt | 88 +++++++++++++++++++ .../diagnostics/notLinked/dfa/pos/53.kt | 76 ---------------- .../DiagnosticsTestSpecGenerated.java | 5 ++ .../checkers/DiagnosticsTestGenerated.java | 5 ++ .../DiagnosticsUsingJavacTestGenerated.java | 5 ++ 16 files changed, 188 insertions(+), 86 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/resolve/kt36264.fir.kt create mode 100644 compiler/testData/diagnostics/tests/resolve/kt36264.kt create mode 100644 compiler/testData/diagnostics/tests/resolve/kt36264.txt create mode 100644 compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/46.kt diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index bd590ca4ce0..6c654b9d268 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -18362,6 +18362,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/resolve/inferenceInLinkedLambdasDependentOnExpectedType.kt"); } + @TestMetadata("kt36264.kt") + public void testKt36264() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/kt36264.kt"); + } + @TestMetadata("localObject.kt") public void testLocalObject() throws Exception { runTest("compiler/testData/diagnostics/tests/resolve/localObject.kt"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt index 2bd536fc4d3..255e712916c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt @@ -875,7 +875,9 @@ class NewResolvedCallImpl( } fun ResolutionCandidateApplicability.toResolutionStatus(): ResolutionStatus = when (this) { - ResolutionCandidateApplicability.RESOLVED, ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY -> ResolutionStatus.SUCCESS + ResolutionCandidateApplicability.RESOLVED, + ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY, + ResolutionCandidateApplicability.RESOLVED_WITH_ERROR -> ResolutionStatus.SUCCESS ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER -> ResolutionStatus.RECEIVER_TYPE_ERROR else -> ResolutionStatus.OTHER_ERROR } 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 ee3927b86bc..7d912582c87 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 @@ -141,7 +141,7 @@ class SmartCastDiagnostic( class UnstableSmartCast( val argument: ExpressionKotlinCallArgument, val targetType: UnwrappedType -) : KotlinCallDiagnostic(MAY_THROW_RUNTIME_ERROR) { +) : KotlinCallDiagnostic(RESOLVED_WITH_ERROR) { override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this) } @@ -213,7 +213,7 @@ class ResolvedToSamWithVarargDiagnostic(val argument: KotlinCallArgument) : Kotl class NotEnoughInformationForLambdaParameter( val lambdaArgument: LambdaKotlinCallArgument, val parameterIndex: Int -) : KotlinCallDiagnostic(RESOLVED) { +) : KotlinCallDiagnostic(RESOLVED_WITH_ERROR) { override fun report(reporter: DiagnosticReporter) { reporter.onCallArgument(lambdaArgument, 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 41ffee506a2..029ea406cdb 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 @@ -74,6 +74,7 @@ fun getResultApplicability(diagnostics: Collection) = enum class ResolutionCandidateApplicability { RESOLVED, // call success or has uncompleted inference or in other words possible successful candidate + RESOLVED_WITH_ERROR, // call has error, but it is still successful from resolution perspective RESOLVED_LOW_PRIORITY, CONVENTION_ERROR, // missing infix, operator etc MAY_THROW_RUNTIME_ERROR, // unsafe call or unstable smart cast @@ -108,7 +109,7 @@ class UsedSmartCastForDispatchReceiver(val smartCastType: KotlinType) : Resoluti object ErrorDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED) // todo discuss and change to INAPPLICABLE object LowPriorityDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED_LOW_PRIORITY) object DynamicDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED_LOW_PRIORITY) -object UnstableSmartCastDiagnostic : ResolutionDiagnostic(MAY_THROW_RUNTIME_ERROR) +object UnstableSmartCastDiagnostic : ResolutionDiagnostic(RESOLVED_WITH_ERROR) object HiddenExtensionRelatedToDynamicTypes : ResolutionDiagnostic(HIDDEN) object HiddenDescriptor : ResolutionDiagnostic(HIDDEN) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt index c584ce8316e..45ba0c0d19d 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt @@ -311,10 +311,15 @@ class TowerResolver { override fun getSuccessfulCandidates(): Collection? { if (!isSuccessful) return null val firstGroupWithResolved = candidateGroups.firstOrNull { - it.any { it.resultingApplicability == ResolutionCandidateApplicability.RESOLVED } + it.any(::isSuccessfulCandidate) } ?: return null - return firstGroupWithResolved.filter { it.resultingApplicability == ResolutionCandidateApplicability.RESOLVED } + return firstGroupWithResolved.filter(::isSuccessfulCandidate) + } + + private fun isSuccessfulCandidate(candidate: C): Boolean { + return candidate.resultingApplicability == ResolutionCandidateApplicability.RESOLVED + || candidate.resultingApplicability == ResolutionCandidateApplicability.RESOLVED_WITH_ERROR } override fun pushCandidates(candidates: Collection) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt index 4b9bf9d0a14..173282abadc 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt @@ -27,7 +27,7 @@ private val INAPPLICABLE_STATUSES = setOf( ) val ResolutionCandidateApplicability.isSuccess: Boolean - get() = this <= ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY + get() = this <= ResolutionCandidateApplicability.RESOLVED_WITH_ERROR val CallableDescriptor.isSynthesized: Boolean get() = (this is CallableMemberDescriptor && kind == CallableMemberDescriptor.Kind.SYNTHESIZED) diff --git a/compiler/testData/diagnostics/tests/resolve/kt36264.fir.kt b/compiler/testData/diagnostics/tests/resolve/kt36264.fir.kt new file mode 100644 index 00000000000..351bb9506df --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/kt36264.fir.kt @@ -0,0 +1,19 @@ +// !WITH_NEW_INFERENCE +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface A +class B : A + +val String.ext: A + get() = TODO() + +class Cls { + fun take(arg: B) {} + + fun test(s: String) { + if (s.ext is B) + take(s.ext) + } +} + +fun take(arg: Any) {} diff --git a/compiler/testData/diagnostics/tests/resolve/kt36264.kt b/compiler/testData/diagnostics/tests/resolve/kt36264.kt new file mode 100644 index 00000000000..8b3b9f3af38 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/kt36264.kt @@ -0,0 +1,19 @@ +// !WITH_NEW_INFERENCE +// !DIAGNOSTICS: -UNUSED_PARAMETER + +interface A +class B : A + +val String.ext: A + get() = TODO() + +class Cls { + fun take(arg: B) {} + + fun test(s: String) { + if (s.ext is B) + take(s.ext) + } +} + +fun take(arg: Any) {} diff --git a/compiler/testData/diagnostics/tests/resolve/kt36264.txt b/compiler/testData/diagnostics/tests/resolve/kt36264.txt new file mode 100644 index 00000000000..bd0398ffb08 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/kt36264.txt @@ -0,0 +1,26 @@ +package + +public val kotlin.String.ext: A +public fun take(/*0*/ arg: kotlin.Any): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class B : A { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Cls { + public constructor Cls() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun take(/*0*/ arg: B): kotlin.Unit + public final fun test(/*0*/ s: kotlin.String): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/unnecessaryWithMap.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/unnecessaryWithMap.fir.kt index e318583a437..2e77dcc451a 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/unnecessaryWithMap.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/unnecessaryWithMap.fir.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE fun create(): Map = null!! operator fun Map.iterator(): Iterator> = null!! diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/unnecessaryWithMap.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/unnecessaryWithMap.kt index 76dcbf2a3fe..e58eeca864d 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/unnecessaryWithMap.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/unnecessaryWithMap.kt @@ -1,4 +1,3 @@ -// !WITH_NEW_INFERENCE fun create(): Map = null!! operator fun Map.iterator(): Iterator> = null!! @@ -14,7 +13,7 @@ class MyClass { m = create() // See KT-7428 for ((k, v) in m) - res += (k.length + v.length) + res += (k.length + v.length) return res } } \ No newline at end of file diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/46.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/46.kt new file mode 100644 index 00000000000..10f8361a2ac --- /dev/null +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/46.kt @@ -0,0 +1,88 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_VALUE -VARIABLE_WITH_REDUNDANT_INITIALIZER +// SKIP_TXT + +/* + * KOTLIN DIAGNOSTICS NOT LINKED SPEC TEST (NEGATIVE) + * + * SECTIONS: dfa + * NUMBER: 46 + * DESCRIPTION: Raw data flow analysis test + * HELPERS: classes, objects, typealiases, functions, enumClasses, interfaces, sealedClasses + */ + +// TESTCASE NUMBER: 1 +fun case_1(x: Int) = "" +fun case_1(x: Int?) = 10 +fun case_1() { + var x: Int? = 10 + var y = { x = null } + if (x != null) { + val z = case_1(x) + z + } +} + +// TESTCASE NUMBER: 2 +val case_2_prop: Int? + get() = 10 +fun case_2(x: Int) = "" +fun case_2(x: Int?) = 10 +fun case_2() { + if (case_2_prop != null) { + val z = case_2(case_2_prop) + z + } +} + +// TESTCASE NUMBER: 3 +class Case4 { + var x: Int? = 10 +} +fun case_3(x: Int) = "" +fun case_3(x: Int?) = 10 +fun case_3(y: Case4) { + if (y.x != null) { + val z = case_3(y.x) + z + } +} + +// TESTCASE NUMBER: 4 +open class Case5 { + open val x: Int? = 10 +} +fun case_4(x: Int) = "" +fun case_4(x: Int?) = 10 +fun case_4(y: Case4) { + if (y.x != null) { + val z = case_4(y.x) + z + } +} + +// TESTCASE NUMBER: 5 +class Case6 { + val x: Int? by lazy { 10 } +} +fun case_5(x: Int) = "" +fun case_5(x: Int?) = 10 +fun case_5(y: Case4) { + if (y.x != null) { + val z = case_5(y.x) + z + } +} + +// TESTCASE NUMBER: 6 +var case_6_prop: Int? + get() = 10 + set(value) {} +fun case_6(x: Int) = "" +fun case_6(x: Int?) = 10 +fun case_6() { + if (case_6_prop != null) { + val z = case_6(case_6_prop) + z + } +} diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/53.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/53.kt index fa865c4232b..56601aeb3c1 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/53.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/53.kt @@ -21,79 +21,3 @@ fun case_1() { z } } - -// TESTCASE NUMBER: 2 -fun case_2(x: Int) = "" -fun case_2(x: Int?) = 10 -fun case_2() { - var x: Int? = 10 - var y = { x = null } - if (x != null) { - val z = case_2(x) - z - } -} - -// TESTCASE NUMBER: 3 -val case_3_prop: Int? - get() = 10 -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) - z - } -} - -// TESTCASE NUMBER: 4 -class Case4 { - var x: Int? = 10 -} -fun case_4(x: Int) = "" -fun case_4(x: Int?) = 10 -fun case_4(y: Case4) { - if (y.x != null) { - val z = case_4(y.x) - z - } -} - -// TESTCASE NUMBER: 5 -open class Case5 { - open val x: Int? = 10 -} -fun case_5(x: Int) = "" -fun case_5(x: Int?) = 10 -fun case_5(y: Case4) { - if (y.x != null) { - val z = case_5(y.x) - z - } -} - -// TESTCASE NUMBER: 6 -class Case6 { - val x: Int? by lazy { 10 } -} -fun case_6(x: Int) = "" -fun case_6(x: Int?) = 10 -fun case_6(y: Case4) { - if (y.x != null) { - val z = case_6(y.x) - z - } -} - -// TESTCASE NUMBER: 7 -var case_7_prop: Int? - get() = 10 - set(value) {} -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) - z - } -} diff --git a/compiler/tests-spec/tests/org/jetbrains/kotlin/spec/checkers/DiagnosticsTestSpecGenerated.java b/compiler/tests-spec/tests/org/jetbrains/kotlin/spec/checkers/DiagnosticsTestSpecGenerated.java index 822dd5227b0..42534c28f5e 100644 --- a/compiler/tests-spec/tests/org/jetbrains/kotlin/spec/checkers/DiagnosticsTestSpecGenerated.java +++ b/compiler/tests-spec/tests/org/jetbrains/kotlin/spec/checkers/DiagnosticsTestSpecGenerated.java @@ -4842,6 +4842,11 @@ public class DiagnosticsTestSpecGenerated extends AbstractDiagnosticsTestSpec { runTest("compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/45.kt"); } + @TestMetadata("46.kt") + public void test46() throws Exception { + runTest("compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/46.kt"); + } + @TestMetadata("5.kt") public void test5() throws Exception { runTest("compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/5.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index f4e9f61dddf..eac8c930a51 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -18374,6 +18374,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/resolve/inferenceInLinkedLambdasDependentOnExpectedType.kt"); } + @TestMetadata("kt36264.kt") + public void testKt36264() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/kt36264.kt"); + } + @TestMetadata("localObject.kt") public void testLocalObject() throws Exception { runTest("compiler/testData/diagnostics/tests/resolve/localObject.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 9edec4e8c6f..49cf27c5a86 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -18364,6 +18364,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/resolve/inferenceInLinkedLambdasDependentOnExpectedType.kt"); } + @TestMetadata("kt36264.kt") + public void testKt36264() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/kt36264.kt"); + } + @TestMetadata("localObject.kt") public void testLocalObject() throws Exception { runTest("compiler/testData/diagnostics/tests/resolve/localObject.kt");