mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-10 08:31:29 +00:00
Don't fix a type variable into the intersection type if there is an explicit expected type
^KT-43303 Fixed ^KT-42396 Fixed ^KT-42472 Fixed
This commit is contained in:
@@ -28731,6 +28731,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/deprecatedSyntax.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("dontIntersectUpperBoundWithExpectedType.kt")
|
||||
public void testDontIntersectUpperBoundWithExpectedType() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/dontIntersectUpperBoundWithExpectedType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extFunctionTypeAsUpperBound.kt")
|
||||
public void testExtFunctionTypeAsUpperBound() throws Exception {
|
||||
@@ -28767,6 +28773,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/implicitNothingOnDelegates.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt42396.kt")
|
||||
public void testKt42396() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42396.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt42472.kt")
|
||||
public void testKt42472() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42472.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("misplacedConstraints.kt")
|
||||
public void testMisplacedConstraints() throws Exception {
|
||||
|
||||
@@ -215,7 +215,20 @@ class ResultTypeResolver(
|
||||
val upperConstraints =
|
||||
variableWithConstraints.constraints.filter { it.kind == ConstraintKind.UPPER && this@findSuperType.isProperTypeForFixation(it.type) }
|
||||
if (upperConstraints.isNotEmpty()) {
|
||||
val upperType = intersectTypes(upperConstraints.map { it.type })
|
||||
val intersectionUpperType = intersectTypes(upperConstraints.map { it.type })
|
||||
val isThereExpectedTypeConstraint = upperConstraints.any { it.isExpectedTypePosition() }
|
||||
val nonExpectedTypeConstraints = upperConstraints.filterNot { it.isExpectedTypePosition() }
|
||||
val resultIsActuallyIntersection = intersectionUpperType.typeConstructor().isIntersection()
|
||||
val upperType = if (isThereExpectedTypeConstraint && nonExpectedTypeConstraints.isNotEmpty() && resultIsActuallyIntersection) {
|
||||
/*
|
||||
* We shouldn't infer a type variable into the intersection type if there is an explicit expected type,
|
||||
* otherwise it can lead to something like this:
|
||||
*
|
||||
* fun <T : String> materialize(): T = null as T
|
||||
* val bar: Int = materialize() // no errors, T is inferred into String & Int
|
||||
*/
|
||||
intersectTypes(nonExpectedTypeConstraints.map { it.type })
|
||||
} else intersectionUpperType
|
||||
|
||||
return typeApproximator.approximateToSubType(
|
||||
upperType,
|
||||
|
||||
@@ -106,3 +106,6 @@ class ConstrainingTypeIsError(
|
||||
class OnlyInputTypesDiagnostic(val typeVariable: TypeVariableMarker) : ConstraintSystemError(INAPPLICABLE)
|
||||
|
||||
object LowerPriorityToPreserveCompatibility : ConstraintSystemError(RESOLVED_NEED_PRESERVE_COMPATIBILITY)
|
||||
|
||||
fun Constraint.isExpectedTypePosition() =
|
||||
position.from is ExpectedTypeConstraintPosition<*> || position.from is DelegatedPropertyConstraintPosition<*>
|
||||
|
||||
@@ -2,6 +2,6 @@ fun <T> f(): T? = "OK" as? T
|
||||
|
||||
fun g(): Nothing = throw RuntimeException("fail")
|
||||
|
||||
fun <T : Any> h(): T = run { f() } ?: run { g() }
|
||||
fun <T : Any> h(): T = run<T?> { f() } ?: run { g() }
|
||||
|
||||
fun box(): String = h<String>()
|
||||
|
||||
@@ -12,7 +12,7 @@ fun test(x: X<Number>) {
|
||||
fun <S, D: S> g() {
|
||||
fun <T : S> foo(): T = TODO()
|
||||
|
||||
val <!UNUSED_VARIABLE!>y<!> = <!TYPE_INFERENCE_UPPER_BOUND_VIOLATED{OI}!>foo<!>() as Int
|
||||
val <!UNUSED_VARIABLE!>y<!> = <!TYPE_INFERENCE_UPPER_BOUND_VIOLATED{OI}, TYPE_MISMATCH!>foo<!>() as Int
|
||||
|
||||
val <!UNUSED_VARIABLE!>y2<!> = foo() as D
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ fun <T: A> emptyNullableListOfA(): List<T>? = null
|
||||
|
||||
fun testExclExcl() {
|
||||
doList(<!TYPE_INFERENCE_UPPER_BOUND_VIOLATED{OI}!>emptyNullableListOfA<!>()!!) //should be an error here
|
||||
val <!UNUSED_VARIABLE!>l<!>: List<Int> = id(<!TYPE_INFERENCE_UPPER_BOUND_VIOLATED{OI}!>emptyNullableListOfA<!>()!!)
|
||||
val <!UNUSED_VARIABLE!>l<!>: List<Int> = <!TYPE_MISMATCH!><!TYPE_MISMATCH!>id<!>(<!TYPE_INFERENCE_UPPER_BOUND_VIOLATED{OI}, TYPE_MISMATCH!>emptyNullableListOfA<!>()<!TYPE_MISMATCH!>!!<!>)<!>
|
||||
|
||||
doList(strangeNullableList { doInt(it) }!!) //lambda should be analyzed (at completion phase)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
open class Foo
|
||||
|
||||
class Bar
|
||||
|
||||
fun <T : Foo> foo(): T? {
|
||||
return null
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val a: Bar? = <!DEBUG_INFO_EXPRESSION_TYPE("Bar?")!><!TYPE_MISMATCH!>foo<!>()<!>
|
||||
}
|
||||
|
||||
|
||||
fun <T : Appendable> wtf(): T = TODO()
|
||||
val bar: Int = <!TYPE_MISMATCH!>wtf<!>() // happily compiles
|
||||
17
compiler/testData/diagnostics/tests/typeParameters/dontIntersectUpperBoundWithExpectedType.kt
vendored
Normal file
17
compiler/testData/diagnostics/tests/typeParameters/dontIntersectUpperBoundWithExpectedType.kt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
open class Foo
|
||||
|
||||
class Bar
|
||||
|
||||
fun <T : Foo> foo(): T? {
|
||||
return null
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val a: Bar? = <!DEBUG_INFO_EXPRESSION_TYPE("Foo?"), TYPE_MISMATCH!><!TYPE_MISMATCH!>foo<!>()<!>
|
||||
}
|
||||
|
||||
|
||||
fun <T : Appendable> wtf(): T = TODO()
|
||||
val bar: Int = <!TYPE_MISMATCH!><!TYPE_MISMATCH!>wtf<!>()<!> // happily compiles
|
||||
20
compiler/testData/diagnostics/tests/typeParameters/dontIntersectUpperBoundWithExpectedType.txt
vendored
Normal file
20
compiler/testData/diagnostics/tests/typeParameters/dontIntersectUpperBoundWithExpectedType.txt
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package
|
||||
|
||||
public val bar: kotlin.Int
|
||||
public fun </*0*/ T : Foo> foo(): T?
|
||||
public fun main(): kotlin.Unit
|
||||
public fun </*0*/ T : kotlin.text.Appendable /* = java.lang.Appendable */> wtf(): T
|
||||
|
||||
public final class Bar {
|
||||
public constructor Bar()
|
||||
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 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
|
||||
}
|
||||
@@ -18,6 +18,6 @@ private object Scope {
|
||||
fun <T> materialize(): T = Any() as T
|
||||
|
||||
fun test(i: Inv<out Number>) {
|
||||
val <!UNUSED_VARIABLE!>p<!>: Int by <!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>Scope.Delegate(i)<!>
|
||||
val <!UNUSED_VARIABLE!>p<!>: Int by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE{OI}, IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>Scope.<!TYPE_MISMATCH{OI}!>Delegate<!>(<!TYPE_MISMATCH{OI}!>i<!>)<!>
|
||||
}
|
||||
}
|
||||
|
||||
17
compiler/testData/diagnostics/tests/typeParameters/kt42396.fir.kt
vendored
Normal file
17
compiler/testData/diagnostics/tests/typeParameters/kt42396.fir.kt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||
|
||||
interface A
|
||||
interface B
|
||||
|
||||
class Out<out F>
|
||||
class Inv<F>
|
||||
|
||||
fun <F> materializeOutOfAAndB(): Out<F> where F : A, F : B = Out()
|
||||
fun <F> materializeInvOfAAndB(): Inv<F> where F : A, F : B = Inv()
|
||||
fun <F> wrapAAndBToOut(x: F): Out<F> where F : A, F : B = Out()
|
||||
|
||||
fun main(a: A) {
|
||||
val x: Out<A> = <!TYPE_MISMATCH!>materializeOutOfAAndB<!>() // OI: inferred type A is not a subtype of B; `F` is instantiated as `A`, so upper bounds was violated
|
||||
val y: Inv<A> = <!TYPE_MISMATCH!>materializeInvOfAAndB()<!> // OI and NI: required B, found A
|
||||
val z: Out<A> = wrapAAndBToOut(<!TYPE_MISMATCH!>a<!>) // OI and NI: required B, found A
|
||||
}
|
||||
17
compiler/testData/diagnostics/tests/typeParameters/kt42396.kt
vendored
Normal file
17
compiler/testData/diagnostics/tests/typeParameters/kt42396.kt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||
|
||||
interface A
|
||||
interface B
|
||||
|
||||
class Out<out F>
|
||||
class Inv<F>
|
||||
|
||||
fun <F> materializeOutOfAAndB(): Out<F> where F : A, F : B = Out()
|
||||
fun <F> materializeInvOfAAndB(): Inv<F> where F : A, F : B = Inv()
|
||||
fun <F> wrapAAndBToOut(x: F): Out<F> where F : A, F : B = Out()
|
||||
|
||||
fun main(a: A) {
|
||||
val x: Out<A> = materializeOutOfAAndB() // OI: inferred type A is not a subtype of B; `F` is instantiated as `A`, so upper bounds was violated
|
||||
val y: Inv<A> = <!TYPE_MISMATCH!>materializeInvOfAAndB()<!> // OI and NI: required B, found A
|
||||
val z: Out<A> = wrapAAndBToOut(<!TYPE_MISMATCH!>a<!>) // OI and NI: required B, found A
|
||||
}
|
||||
32
compiler/testData/diagnostics/tests/typeParameters/kt42396.txt
vendored
Normal file
32
compiler/testData/diagnostics/tests/typeParameters/kt42396.txt
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package
|
||||
|
||||
public fun main(/*0*/ a: A): kotlin.Unit
|
||||
public fun </*0*/ F : A> materializeInvOfAAndB(): Inv<F> where F : B
|
||||
public fun </*0*/ F : A> materializeOutOfAAndB(): Out<F> where F : B
|
||||
public fun </*0*/ F : A> wrapAAndBToOut(/*0*/ x: F): Out<F> where F : B
|
||||
|
||||
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 interface 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 Inv</*0*/ F> {
|
||||
public constructor Inv</*0*/ F>()
|
||||
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 Out</*0*/ out F> {
|
||||
public constructor Out</*0*/ out F>()
|
||||
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
|
||||
}
|
||||
12
compiler/testData/diagnostics/tests/typeParameters/kt42472.fir.kt
vendored
Normal file
12
compiler/testData/diagnostics/tests/typeParameters/kt42472.fir.kt
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
fun interface ReadOnlyProperty<in T, out V> {
|
||||
operator fun getValue(thisRef: T, property: KProperty<*>): V
|
||||
}
|
||||
|
||||
class Problem {
|
||||
val variable: Int by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!><!TYPE_MISMATCH!>delegate<!>()<!> // delegate returns `ReadOnlyProperty<Problem, {CharSequence & Int}>`
|
||||
fun <T : CharSequence> delegate() = null <!CAST_NEVER_SUCCEEDS!>as<!> ReadOnlyProperty<Problem, T>
|
||||
}
|
||||
12
compiler/testData/diagnostics/tests/typeParameters/kt42472.kt
vendored
Normal file
12
compiler/testData/diagnostics/tests/typeParameters/kt42472.kt
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
fun interface ReadOnlyProperty<in T, out V> {
|
||||
operator fun getValue(thisRef: T, property: KProperty<*>): V
|
||||
}
|
||||
|
||||
class Problem {
|
||||
val variable: Int by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!><!TYPE_MISMATCH!>delegate<!>()<!> // delegate returns `ReadOnlyProperty<Problem, {CharSequence & Int}>`
|
||||
fun <T : CharSequence> delegate() = null <!CAST_NEVER_SUCCEEDS!>as<!> ReadOnlyProperty<Problem, T>
|
||||
}
|
||||
18
compiler/testData/diagnostics/tests/typeParameters/kt42472.txt
vendored
Normal file
18
compiler/testData/diagnostics/tests/typeParameters/kt42472.txt
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package
|
||||
|
||||
public final class Problem {
|
||||
public constructor Problem()
|
||||
public final val variable: kotlin.Int
|
||||
public final fun </*0*/ T : kotlin.CharSequence> delegate(): ReadOnlyProperty<Problem, T>
|
||||
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 fun interface ReadOnlyProperty</*0*/ in T, /*1*/ out V> {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract operator fun getValue(/*0*/ thisRef: T, /*1*/ property: kotlin.reflect.KProperty<*>): V
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@@ -8,5 +8,5 @@ fun test1(l: List<Number>) {
|
||||
|
||||
val i: Int = l.firstTyped()
|
||||
|
||||
val s: String = l.<!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH{OI}!>firstTyped()<!>
|
||||
val s: String = <!TYPE_MISMATCH!>l.<!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH{OI}!><!TYPE_MISMATCH!>firstTyped<!>()<!><!>
|
||||
}
|
||||
|
||||
@@ -28827,6 +28827,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/deprecatedSyntax.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("dontIntersectUpperBoundWithExpectedType.kt")
|
||||
public void testDontIntersectUpperBoundWithExpectedType() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/dontIntersectUpperBoundWithExpectedType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extFunctionTypeAsUpperBound.kt")
|
||||
public void testExtFunctionTypeAsUpperBound() throws Exception {
|
||||
@@ -28863,6 +28869,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/implicitNothingOnDelegates.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt42396.kt")
|
||||
public void testKt42396() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42396.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt42472.kt")
|
||||
public void testKt42472() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42472.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("misplacedConstraints.kt")
|
||||
public void testMisplacedConstraints() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user