[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
This commit is contained in:
Pavel Kirpichenkov
2020-02-04 17:26:28 +03:00
parent 4fa87d2caa
commit e40ba73950
16 changed files with 188 additions and 86 deletions
@@ -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");
@@ -875,7 +875,9 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
}
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
}
@@ -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)
}
@@ -74,6 +74,7 @@ fun getResultApplicability(diagnostics: Collection<KotlinCallDiagnostic>) =
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)
@@ -311,10 +311,15 @@ class TowerResolver {
override fun getSuccessfulCandidates(): Collection<C>? {
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<C>) {
@@ -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)
@@ -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) {}
+19
View File
@@ -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(<!NI;SMARTCAST_IMPOSSIBLE, SMARTCAST_IMPOSSIBLE!>s.ext<!>)
}
}
fun take(arg: Any) {}
+26
View File
@@ -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
}
@@ -1,4 +1,3 @@
// !WITH_NEW_INFERENCE
fun create(): Map<String, String> = null!!
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = null!!
@@ -1,4 +1,3 @@
// !WITH_NEW_INFERENCE
fun create(): Map<String, String> = null!!
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = null!!
@@ -14,7 +13,7 @@ class MyClass {
m = create()
// See KT-7428
for ((k, v) in <!SMARTCAST_IMPOSSIBLE!>m<!>)
res <!NI;OVERLOAD_RESOLUTION_AMBIGUITY!>+=<!> (<!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>k<!>.<!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>length<!> <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>+<!> <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>v<!>.<!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>length<!>)
res += (k.length + v.length)
return res
}
}
@@ -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(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?"), SMARTCAST_IMPOSSIBLE, SMARTCAST_IMPOSSIBLE!>x<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>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(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?"), SMARTCAST_IMPOSSIBLE, SMARTCAST_IMPOSSIBLE!>case_2_prop<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>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(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?"), SMARTCAST_IMPOSSIBLE, SMARTCAST_IMPOSSIBLE!>y.x<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>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(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?"), SMARTCAST_IMPOSSIBLE, SMARTCAST_IMPOSSIBLE!>y.x<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>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(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?"), SMARTCAST_IMPOSSIBLE, SMARTCAST_IMPOSSIBLE!>y.x<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>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(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?"), SMARTCAST_IMPOSSIBLE, SMARTCAST_IMPOSSIBLE!>case_6_prop<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>z<!>
}
}
@@ -21,79 +21,3 @@ fun case_1() {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>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(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!>x<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>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(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!>case_3_prop<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>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(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!>y.x<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>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(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!>y.x<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>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(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!>y.x<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>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(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!>case_7_prop<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>z<!>
}
}
@@ -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");
@@ -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");
@@ -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");