[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:
Mikhail Zarechenskiy
2018-06-07 11:48:16 +03:00
parent 1ee37b1772
commit 9891f562cc
15 changed files with 94 additions and 20 deletions
@@ -154,6 +154,11 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
var targetType = type
if (targetType.isError) {
c.addError(ConstrainingTypeIsError(typeVariable, targetType, position))
return
}
if (type.contains(this::isCapturedTypeFromSubtyping)) {
// TypeVariable <: type -> if TypeVariable <: subType => TypeVariable <: type
if (kind == UPPER) {
@@ -92,4 +92,10 @@ class CapturedTypeFromSubtyping(
val position: ConstraintPosition
) : 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
public fun test(/*0*/ tr: Tr): [ERROR : G]
public fun test(/*0*/ tr: Tr): Tr
public interface G</*0*/ T> {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -1,4 +1,3 @@
// !WITH_NEW_INFERENCE
// See KT-6665: unresolved reference (v.bar) should not produce "unreachable code" after it
fun foo(): Int {
@@ -29,14 +28,14 @@ fun foo3(): Int {
fun bar(): Int {
val v = 1
val c = v.<!UNRESOLVED_REFERENCE!>bar<!> ?: 42
return <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>c<!>
return c
}
fun bar2(): Int {
val v = 1
val c = if (true) v.<!UNRESOLVED_REFERENCE!>bar<!> else 3
val b = <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>c<!>
return <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>b<!>
val b = c
return b
}
fun bar3(): Int {
@@ -45,6 +44,6 @@ fun bar3(): Int {
true -> v.<!UNRESOLVED_REFERENCE!>bar<!>
else -> 3
}
val b = <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>c<!>
return <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>b<!>
val b = c
return b
}
@@ -1,10 +1,9 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// !WITH_NEW_INFERENCE
// NI_EXPECTED_FILE
import kotlin.reflect.KProperty
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()
@@ -1,18 +1,18 @@
// !WITH_NEW_INFERENCE
fun test() {
run {<!RETURN_NOT_ALLOWED!>return<!>}
run {}
<!NI;UNREACHABLE_CODE!>run {}<!>
}
fun test2() {
run {<!RETURN_NOT_ALLOWED!>return@test2<!>}
run {}
<!NI;UNREACHABLE_CODE!>run {}<!>
}
fun test3() {
fun test4() {
run {<!RETURN_NOT_ALLOWED!>return@test3<!>}
run {}
<!NI;UNREACHABLE_CODE!>run {}<!>
}
}
@@ -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<!>)
}
}
@@ -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!>!
}
}
@@ -57,7 +57,7 @@ fun test3(z: Z) {
//'in' operation
fun test4(collection: Collection<A<*>>) {
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
@@ -3,7 +3,7 @@ fun foo() {
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 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
@@ -1,5 +1,4 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -SENSELESS_COMPARISON, -UNUSED_PARAMETER
// !WITH_NEW_INFERENCE
// FILE: J.java
@@ -62,7 +61,7 @@ fun test() {
takeNotNull(J.getNAny() ?: J())
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) {}
@@ -10,7 +10,7 @@ class A {
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 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 u get() = <!UNRESOLVED_REFERENCE!>field<!>
@@ -10,8 +10,8 @@ public final class A {
public final val b: [ERROR : Error function type]
public final val u: [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 z2: kotlin.collections.List<[ERROR : Error type for ParseError-argument VALUE_ARGUMENT]>
public final val z1: kotlin.Nothing
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 hashCode(): kotlin.Int
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");
}
@TestMetadata("errorUpperBoundConstraint.kt")
public void testErrorUpperBoundConstraint() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/constraints/errorUpperBoundConstraint.kt");
}
@TestMetadata("ignoreConstraintFromImplicitInNothing.kt")
public void testIgnoreConstraintFromImplicitInNothing() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/constraints/ignoreConstraintFromImplicitInNothing.kt");
@@ -9565,6 +9565,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
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")
public void testIgnoreConstraintFromImplicitInNothing() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/constraints/ignoreConstraintFromImplicitInNothing.kt");