Don't lose upper non-expected type constraints to include them to intersection type during finding the result type of the fixing type variable
This commit is contained in:
+6
@@ -28737,6 +28737,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/tests/typeParameters/dontIntersectUpperBoundWithExpectedType.kt");
|
runTest("compiler/testData/diagnostics/tests/typeParameters/dontIntersectUpperBoundWithExpectedType.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("dontLoseUpperNonExpectedTypeConstraints.kt")
|
||||||
|
public void testDontLoseUpperNonExpectedTypeConstraints() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/typeParameters/dontLoseUpperNonExpectedTypeConstraints.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("extFunctionTypeAsUpperBound.kt")
|
@TestMetadata("extFunctionTypeAsUpperBound.kt")
|
||||||
public void testExtFunctionTypeAsUpperBound() throws Exception {
|
public void testExtFunctionTypeAsUpperBound() throws Exception {
|
||||||
|
|||||||
+10
@@ -125,6 +125,16 @@ class MutableVariableWithConstraints private constructor(
|
|||||||
if (old.position.from is DeclaredUpperBoundConstraintPosition<*> && new.position.from !is DeclaredUpperBoundConstraintPosition<*>)
|
if (old.position.from is DeclaredUpperBoundConstraintPosition<*> && new.position.from !is DeclaredUpperBoundConstraintPosition<*>)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We discriminate upper expected type constraints during finding a result type to fix variable (see ResultTypeResolver.kt):
|
||||||
|
* namely, we don't intersect the expected type with other upper constraints' types to prevent cases like this:
|
||||||
|
* fun <T : String> materialize(): T = null as T
|
||||||
|
* val bar: Int = materialize() // T is inferred into String & Int without discriminating upper expected type constraints
|
||||||
|
* So here we shouldn't lose upper non-expected type constraints.
|
||||||
|
*/
|
||||||
|
if (old.position.from is ExpectedTypeConstraintPosition<*> && new.position.from !is ExpectedTypeConstraintPosition<*> && old.kind.isUpper() && new.kind.isUpper())
|
||||||
|
return false
|
||||||
|
|
||||||
return when (old.kind) {
|
return when (old.kind) {
|
||||||
ConstraintKind.EQUALITY -> true
|
ConstraintKind.EQUALITY -> true
|
||||||
ConstraintKind.LOWER -> new.kind.isLower()
|
ConstraintKind.LOWER -> new.kind.isLower()
|
||||||
|
|||||||
Vendored
+2
-2
@@ -9,9 +9,9 @@ fun <T : Foo> foo(): T? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val a: Bar? = <!DEBUG_INFO_EXPRESSION_TYPE("Bar?")!><!TYPE_MISMATCH!>foo<!>()<!>
|
val a: Bar? = <!DEBUG_INFO_EXPRESSION_TYPE("Foo? & Bar?")!>foo()<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun <T : Appendable> wtf(): T = TODO()
|
fun <T : Appendable> wtf(): T = TODO()
|
||||||
val bar: Int = <!TYPE_MISMATCH!>wtf<!>() // happily compiles
|
val bar: Int = wtf() // happily compiles
|
||||||
|
|||||||
Vendored
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -CAST_NEVER_SUCCEEDS
|
||||||
|
|
||||||
|
open class Expression<K>
|
||||||
|
|
||||||
|
class ModOp<T : Number?, S : Number?>(
|
||||||
|
val expr1: Expression<T>,
|
||||||
|
val expr2: Expression<S>
|
||||||
|
)
|
||||||
|
|
||||||
|
class QueryParameter<A> : Expression<A>()
|
||||||
|
|
||||||
|
fun <T, S : T?> Expression<in S>.wrap(value: T): QueryParameter<T> = null as QueryParameter<T>
|
||||||
|
|
||||||
|
fun <T : Number?, S : T> Expression<T>.rem(t: S): ModOp<T, S> = ModOp(this, wrap(t))
|
||||||
Vendored
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun </*0*/ T : kotlin.Number?, /*1*/ S : T> Expression<T>.rem(/*0*/ t: S): ModOp<T, S>
|
||||||
|
public fun </*0*/ T, /*1*/ S : T?> Expression<in S>.wrap(/*0*/ value: T): QueryParameter<T>
|
||||||
|
|
||||||
|
public open class Expression</*0*/ K> {
|
||||||
|
public constructor Expression</*0*/ 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 final class ModOp</*0*/ T : kotlin.Number?, /*1*/ S : kotlin.Number?> {
|
||||||
|
public constructor ModOp</*0*/ T : kotlin.Number?, /*1*/ S : kotlin.Number?>(/*0*/ expr1: Expression<T>, /*1*/ expr2: Expression<S>)
|
||||||
|
public final val expr1: Expression<T>
|
||||||
|
public final val expr2: Expression<S>
|
||||||
|
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 QueryParameter</*0*/ A> : Expression<A> {
|
||||||
|
public constructor QueryParameter</*0*/ 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
|
||||||
|
}
|
||||||
@@ -6,6 +6,6 @@ sealed class Subtype<A1, B1> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <A, B> unsafeCast(value: A): B {
|
fun <A, B> unsafeCast(value: A): B {
|
||||||
val proof: Subtype<A, B> = Subtype.Trivial()
|
val proof: Subtype<A, B> = <!UPPER_BOUND_VIOLATED!>Subtype.Trivial()<!>
|
||||||
return proof.cast(value)
|
return proof.cast(value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ 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 <F> wrapAAndBToOut(x: F): Out<F> where F : A, F : B = Out()
|
||||||
|
|
||||||
fun main(a: A) {
|
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 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 y: Inv<A> = materializeInvOfAAndB() // OI and NI: required B, found A
|
||||||
val z: Out<A> = wrapAAndBToOut(<!TYPE_MISMATCH!>a<!>) // OI and NI: required B, found A
|
val z: Out<A> = <!INAPPLICABLE_CANDIDATE!>wrapAAndBToOut<!>(a) // OI and NI: required B, found A
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,6 @@ fun interface ReadOnlyProperty<in T, out V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Problem {
|
class Problem {
|
||||||
val variable: Int by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!><!TYPE_MISMATCH!>delegate<!>()<!> // delegate returns `ReadOnlyProperty<Problem, {CharSequence & Int}>`
|
val variable: Int by delegate() // delegate returns `ReadOnlyProperty<Problem, {CharSequence & Int}>`
|
||||||
fun <T : CharSequence> delegate() = null <!CAST_NEVER_SUCCEEDS!>as<!> ReadOnlyProperty<Problem, T>
|
fun <T : CharSequence> delegate() = null as ReadOnlyProperty<Problem, T>
|
||||||
}
|
}
|
||||||
Generated
+6
@@ -28833,6 +28833,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/typeParameters/dontIntersectUpperBoundWithExpectedType.kt");
|
runTest("compiler/testData/diagnostics/tests/typeParameters/dontIntersectUpperBoundWithExpectedType.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("dontLoseUpperNonExpectedTypeConstraints.kt")
|
||||||
|
public void testDontLoseUpperNonExpectedTypeConstraints() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/typeParameters/dontLoseUpperNonExpectedTypeConstraints.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("extFunctionTypeAsUpperBound.kt")
|
@TestMetadata("extFunctionTypeAsUpperBound.kt")
|
||||||
public void testExtFunctionTypeAsUpperBound() throws Exception {
|
public void testExtFunctionTypeAsUpperBound() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user