[NI] Make subtyping algorithm more robust to error types
During subtyping/incorporation we transform types (e.g. changing nullability, form of the type) and, basically, we're doing this to some FIXPOINT. It's important that we use `KotlinType.hashCode()` to compare types, but for error types hashCode is a hashCode of its supertype and, for example, `makeNullableAsSpecified` method recreate type every time. So, we continue to generate new constraints and we'll never stop incorporation algorithm
This commit is contained in:
+5
@@ -154,6 +154,11 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
|||||||
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
|
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
|
||||||
|
|
||||||
var targetType = type
|
var targetType = type
|
||||||
|
if (targetType.isError) {
|
||||||
|
c.addError(ConstrainingTypeIsError(typeVariable, targetType, position))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (type.contains(this::isCapturedTypeFromSubtyping)) {
|
if (type.contains(this::isCapturedTypeFromSubtyping)) {
|
||||||
// TypeVariable <: type -> if TypeVariable <: subType => TypeVariable <: type
|
// TypeVariable <: type -> if TypeVariable <: subType => TypeVariable <: type
|
||||||
if (kind == UPPER) {
|
if (kind == UPPER) {
|
||||||
|
|||||||
+6
@@ -93,3 +93,9 @@ class CapturedTypeFromSubtyping(
|
|||||||
) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
|
) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
|
||||||
|
|
||||||
class NotEnoughInformationForTypeParameter(val typeVariable: NewTypeVariable) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
|
class NotEnoughInformationForTypeParameter(val typeVariable: NewTypeVariable) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
|
||||||
|
|
||||||
|
class ConstrainingTypeIsError(
|
||||||
|
val typeVariable: NewTypeVariable,
|
||||||
|
val constraintType: UnwrappedType,
|
||||||
|
val position: IncorporationConstraintPosition
|
||||||
|
) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
public fun test(/*0*/ tr: Tr): [ERROR : G]
|
public fun test(/*0*/ tr: Tr): Tr
|
||||||
|
|
||||||
public interface G</*0*/ T> {
|
public interface G</*0*/ T> {
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
|||||||
+5
-6
@@ -1,4 +1,3 @@
|
|||||||
// !WITH_NEW_INFERENCE
|
|
||||||
// See KT-6665: unresolved reference (v.bar) should not produce "unreachable code" after it
|
// See KT-6665: unresolved reference (v.bar) should not produce "unreachable code" after it
|
||||||
|
|
||||||
fun foo(): Int {
|
fun foo(): Int {
|
||||||
@@ -29,14 +28,14 @@ fun foo3(): Int {
|
|||||||
fun bar(): Int {
|
fun bar(): Int {
|
||||||
val v = 1
|
val v = 1
|
||||||
val c = v.<!UNRESOLVED_REFERENCE!>bar<!> ?: 42
|
val c = v.<!UNRESOLVED_REFERENCE!>bar<!> ?: 42
|
||||||
return <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>c<!>
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bar2(): Int {
|
fun bar2(): Int {
|
||||||
val v = 1
|
val v = 1
|
||||||
val c = if (true) v.<!UNRESOLVED_REFERENCE!>bar<!> else 3
|
val c = if (true) v.<!UNRESOLVED_REFERENCE!>bar<!> else 3
|
||||||
val b = <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>c<!>
|
val b = c
|
||||||
return <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>b<!>
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bar3(): Int {
|
fun bar3(): Int {
|
||||||
@@ -45,6 +44,6 @@ fun bar3(): Int {
|
|||||||
true -> v.<!UNRESOLVED_REFERENCE!>bar<!>
|
true -> v.<!UNRESOLVED_REFERENCE!>bar<!>
|
||||||
else -> 3
|
else -> 3
|
||||||
}
|
}
|
||||||
val b = <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>c<!>
|
val b = c
|
||||||
return <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>b<!>
|
return b
|
||||||
}
|
}
|
||||||
+1
-2
@@ -1,10 +1,9 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
// !WITH_NEW_INFERENCE
|
|
||||||
// NI_EXPECTED_FILE
|
// NI_EXPECTED_FILE
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
var a: Int by A()
|
var a: Int by A()
|
||||||
var a1 by <!OI;DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!>A()<!>
|
var a1 by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!>A()<!>
|
||||||
|
|
||||||
var b: Int by B()
|
var b: Int by B()
|
||||||
|
|
||||||
|
|||||||
Vendored
+3
-3
@@ -1,18 +1,18 @@
|
|||||||
// !WITH_NEW_INFERENCE
|
// !WITH_NEW_INFERENCE
|
||||||
fun test() {
|
fun test() {
|
||||||
run {<!RETURN_NOT_ALLOWED!>return<!>}
|
run {<!RETURN_NOT_ALLOWED!>return<!>}
|
||||||
run {}
|
<!NI;UNREACHABLE_CODE!>run {}<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test2() {
|
fun test2() {
|
||||||
run {<!RETURN_NOT_ALLOWED!>return@test2<!>}
|
run {<!RETURN_NOT_ALLOWED!>return@test2<!>}
|
||||||
run {}
|
<!NI;UNREACHABLE_CODE!>run {}<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test3() {
|
fun test3() {
|
||||||
fun test4() {
|
fun test4() {
|
||||||
run {<!RETURN_NOT_ALLOWED!>return@test3<!>}
|
run {<!RETURN_NOT_ALLOWED!>return@test3<!>}
|
||||||
run {}
|
<!NI;UNREACHABLE_CODE!>run {}<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
// !LANGUAGE: +NewInference
|
||||||
|
|
||||||
|
// FILE: Sam.java
|
||||||
|
|
||||||
|
public interface Sam<K> {
|
||||||
|
Sam.Result<K> compute();
|
||||||
|
|
||||||
|
public static class Result<V> {
|
||||||
|
public static <V> Sam.Result<V> create(V value) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: Foo.java
|
||||||
|
|
||||||
|
public class Foo {
|
||||||
|
public static <T> void foo(Sam<T> var1) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.kt
|
||||||
|
|
||||||
|
fun test(e: <!UNRESOLVED_REFERENCE!>ErrorType<!>) {
|
||||||
|
Foo.foo {
|
||||||
|
Sam.Result.create(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>e<!>)
|
||||||
|
}
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun test(/*0*/ e: [ERROR : ErrorType]): kotlin.Unit
|
||||||
|
|
||||||
|
public open class Foo {
|
||||||
|
public constructor Foo()
|
||||||
|
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
|
||||||
|
|
||||||
|
// Static members
|
||||||
|
public open fun </*0*/ T : kotlin.Any!> foo(/*0*/ var1: Sam<T!>!): kotlin.Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Sam</*0*/ K : kotlin.Any!> {
|
||||||
|
public abstract fun compute(): Sam.Result<K!>!
|
||||||
|
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 open class Result</*0*/ V : kotlin.Any!> {
|
||||||
|
public constructor Result</*0*/ V : kotlin.Any!>()
|
||||||
|
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
|
||||||
|
|
||||||
|
// Static members
|
||||||
|
public open fun </*0*/ V : kotlin.Any!> create(/*0*/ value: V!): Sam.Result<V!>!
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -57,7 +57,7 @@ fun test3(z: Z) {
|
|||||||
//'in' operation
|
//'in' operation
|
||||||
fun test4(collection: Collection<A<*>>) {
|
fun test4(collection: Collection<A<*>>) {
|
||||||
id(<!OI;TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>newA<!>() in collection)
|
id(<!OI;TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>newA<!>() in collection)
|
||||||
id(newA<Int>() in collection)
|
<!NI;UNREACHABLE_CODE!>id(newA<Int>() in collection)<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
//boolean operations
|
//boolean operations
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ fun foo() {
|
|||||||
fun bar1() = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!><!NI;DEBUG_INFO_MISSING_UNRESOLVED!>bar1<!>()<!>
|
fun bar1() = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!><!NI;DEBUG_INFO_MISSING_UNRESOLVED!>bar1<!>()<!>
|
||||||
|
|
||||||
fun bar2() = 1 <!NI;OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!><!NI;DEBUG_INFO_MISSING_UNRESOLVED!>bar2<!>()<!>
|
fun bar2() = 1 <!NI;OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!><!NI;DEBUG_INFO_MISSING_UNRESOLVED!>bar2<!>()<!>
|
||||||
fun bar3() = id(<!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!><!NI;DEBUG_INFO_MISSING_UNRESOLVED!>bar3<!>()<!>)
|
fun <!NI;IMPLICIT_NOTHING_RETURN_TYPE!>bar3<!>() = id(<!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!><!NI;DEBUG_INFO_MISSING_UNRESOLVED!>bar3<!>()<!>)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> id(x: T) = x
|
fun <T> id(x: T) = x
|
||||||
|
|||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -SENSELESS_COMPARISON, -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_VARIABLE -SENSELESS_COMPARISON, -UNUSED_PARAMETER
|
||||||
// !WITH_NEW_INFERENCE
|
|
||||||
|
|
||||||
// FILE: J.java
|
// FILE: J.java
|
||||||
|
|
||||||
@@ -62,7 +61,7 @@ fun test() {
|
|||||||
takeNotNull(J.getNAny() ?: J())
|
takeNotNull(J.getNAny() ?: J())
|
||||||
|
|
||||||
val x = <!UNRESOLVED_REFERENCE!>unresolved<!> ?: null
|
val x = <!UNRESOLVED_REFERENCE!>unresolved<!> ?: null
|
||||||
<!OI;UNREACHABLE_CODE!>val y =<!> <!UNRESOLVED_REFERENCE!>unresolved<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>foo<!> ?: return
|
<!UNREACHABLE_CODE!>val y =<!> <!UNRESOLVED_REFERENCE!>unresolved<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>foo<!> ?: return
|
||||||
}
|
}
|
||||||
|
|
||||||
fun takeNotNull(s: J) {}
|
fun takeNotNull(s: J) {}
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ class A {
|
|||||||
val a get() = <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>b<!>
|
val a get() = <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>b<!>
|
||||||
val b get() = <!NI;DEBUG_INFO_MISSING_UNRESOLVED, TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>a<!>
|
val b get() = <!NI;DEBUG_INFO_MISSING_UNRESOLVED, TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>a<!>
|
||||||
|
|
||||||
val z1 get() = id(<!NI;DEBUG_INFO_MISSING_UNRESOLVED, OI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE, TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>z1<!>)
|
val <!NI;IMPLICIT_NOTHING_PROPERTY_TYPE!>z1<!> get() = id(<!NI;DEBUG_INFO_MISSING_UNRESOLVED, OI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE, TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>z1<!>)
|
||||||
val z2 get() = l(<!NI;DEBUG_INFO_MISSING_UNRESOLVED, OI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE, TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>z2<!>)
|
val z2 get() = l(<!NI;DEBUG_INFO_MISSING_UNRESOLVED, OI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE, TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>z2<!>)
|
||||||
|
|
||||||
val u get() = <!UNRESOLVED_REFERENCE!>field<!>
|
val u get() = <!UNRESOLVED_REFERENCE!>field<!>
|
||||||
|
|||||||
+2
-2
@@ -10,8 +10,8 @@ public final class A {
|
|||||||
public final val b: [ERROR : Error function type]
|
public final val b: [ERROR : Error function type]
|
||||||
public final val u: [ERROR : Error function type]
|
public final val u: [ERROR : Error function type]
|
||||||
public final val y: [ERROR : Error function type]
|
public final val y: [ERROR : Error function type]
|
||||||
public final val z1: [ERROR : Error type for ParseError-argument VALUE_ARGUMENT]
|
public final val z1: kotlin.Nothing
|
||||||
public final val z2: kotlin.collections.List<[ERROR : Error type for ParseError-argument VALUE_ARGUMENT]>
|
public final val z2: kotlin.collections.List<kotlin.Nothing>
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
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 hashCode(): kotlin.Int
|
||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|||||||
@@ -9565,6 +9565,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/inference/constraints/equalityConstraintOnNullableType.kt");
|
runTest("compiler/testData/diagnostics/tests/inference/constraints/equalityConstraintOnNullableType.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("errorUpperBoundConstraint.kt")
|
||||||
|
public void testErrorUpperBoundConstraint() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/inference/constraints/errorUpperBoundConstraint.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ignoreConstraintFromImplicitInNothing.kt")
|
@TestMetadata("ignoreConstraintFromImplicitInNothing.kt")
|
||||||
public void testIgnoreConstraintFromImplicitInNothing() throws Exception {
|
public void testIgnoreConstraintFromImplicitInNothing() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/inference/constraints/ignoreConstraintFromImplicitInNothing.kt");
|
runTest("compiler/testData/diagnostics/tests/inference/constraints/ignoreConstraintFromImplicitInNothing.kt");
|
||||||
|
|||||||
Generated
+5
@@ -9565,6 +9565,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
runTest("compiler/testData/diagnostics/tests/inference/constraints/equalityConstraintOnNullableType.kt");
|
runTest("compiler/testData/diagnostics/tests/inference/constraints/equalityConstraintOnNullableType.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("errorUpperBoundConstraint.kt")
|
||||||
|
public void testErrorUpperBoundConstraint() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/inference/constraints/errorUpperBoundConstraint.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ignoreConstraintFromImplicitInNothing.kt")
|
@TestMetadata("ignoreConstraintFromImplicitInNothing.kt")
|
||||||
public void testIgnoreConstraintFromImplicitInNothing() throws Exception {
|
public void testIgnoreConstraintFromImplicitInNothing() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/inference/constraints/ignoreConstraintFromImplicitInNothing.kt");
|
runTest("compiler/testData/diagnostics/tests/inference/constraints/ignoreConstraintFromImplicitInNothing.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user