summaryrefslogtreecommitdiffstats
path: root/tests/ui/higher-ranked/subtype
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/higher-ranked/subtype')
-rw-r--r--tests/ui/higher-ranked/subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr17
-rw-r--r--tests/ui/higher-ranked/subtype/hr-subtype.bound_a_vs_free_x.stderr17
-rw-r--r--tests/ui/higher-ranked/subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr31
-rw-r--r--tests/ui/higher-ranked/subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr42
-rw-r--r--tests/ui/higher-ranked/subtype/hr-subtype.free_x_vs_free_y.stderr19
-rw-r--r--tests/ui/higher-ranked/subtype/hr-subtype.rs111
-rw-r--r--tests/ui/higher-ranked/subtype/placeholder-pattern-fail.rs25
-rw-r--r--tests/ui/higher-ranked/subtype/placeholder-pattern-fail.stderr12
-rw-r--r--tests/ui/higher-ranked/subtype/placeholder-pattern.rs18
-rw-r--r--tests/ui/higher-ranked/subtype/return-static.rs13
10 files changed, 305 insertions, 0 deletions
diff --git a/tests/ui/higher-ranked/subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr
new file mode 100644
index 000000000..b7264c7e9
--- /dev/null
+++ b/tests/ui/higher-ranked/subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+ --> $DIR/hr-subtype.rs:54:13
+ |
+LL | gimme::<$t1>(None::<$t2>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+...
+LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
+LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) }
+ | |_____________________________________________- in this macro invocation
+ |
+ = note: expected enum `Option<for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32>`
+ found enum `Option<for<'a> fn(&'a u32, &'a u32) -> &'a u32>`
+ = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-ranked/subtype/hr-subtype.bound_a_vs_free_x.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.bound_a_vs_free_x.stderr
new file mode 100644
index 000000000..2355979b0
--- /dev/null
+++ b/tests/ui/higher-ranked/subtype/hr-subtype.bound_a_vs_free_x.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+ --> $DIR/hr-subtype.rs:54:13
+ |
+LL | gimme::<$t1>(None::<$t2>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+...
+LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
+LL | | fn(&'x u32)) }
+ | |______________- in this macro invocation
+ |
+ = note: expected enum `Option<for<'a> fn(&'a u32)>`
+ found enum `Option<fn(&u32)>`
+ = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-ranked/subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr
new file mode 100644
index 000000000..a73c03feb
--- /dev/null
+++ b/tests/ui/higher-ranked/subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr
@@ -0,0 +1,31 @@
+error[E0308]: mismatched types
+ --> $DIR/hr-subtype.rs:54:13
+ |
+LL | gimme::<$t1>(None::<$t2>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+...
+LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
+LL | | for<'a> fn(Inv<'a>, Inv<'a>)) }
+ | |__________________________________- in this macro invocation
+ |
+ = note: expected enum `Option<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>`
+ found enum `Option<for<'a> fn(Inv<'a>, Inv<'a>)>`
+ = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+ --> $DIR/hr-subtype.rs:54:13
+ |
+LL | gimme::<$t1>(None::<$t2>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+...
+LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
+LL | | for<'a> fn(Inv<'a>, Inv<'a>)) }
+ | |__________________________________- in this macro invocation
+ |
+ = note: expected enum `Option<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>`
+ found enum `Option<for<'a> fn(Inv<'a>, Inv<'a>)>`
+ = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-ranked/subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
new file mode 100644
index 000000000..31d36d716
--- /dev/null
+++ b/tests/ui/higher-ranked/subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
@@ -0,0 +1,42 @@
+error: lifetime may not live long enough
+ --> $DIR/hr-subtype.rs:48:13
+ |
+LL | fn subtype<'x, 'y: 'x, 'z: 'y>() {
+ | -- -- lifetime `'y` defined here
+ | |
+ | lifetime `'x` defined here
+LL | gimme::<$t2>(None::<$t1>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
+...
+LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
+LL | | fn(Inv<'y>)) }
+ | |______________- in this macro invocation
+ |
+ = help: consider adding the following bound: `'x: 'y`
+ = note: requirement occurs because of the type `Inv<'_>`, which makes the generic argument `'_` invariant
+ = note: the struct `Inv<'a>` is invariant over the parameter `'a`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+ = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: lifetime may not live long enough
+ --> $DIR/hr-subtype.rs:54:13
+ |
+LL | fn supertype<'x, 'y: 'x, 'z: 'y>() {
+ | -- -- lifetime `'y` defined here
+ | |
+ | lifetime `'x` defined here
+LL | gimme::<$t1>(None::<$t2>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
+...
+LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
+LL | | fn(Inv<'y>)) }
+ | |______________- in this macro invocation
+ |
+ = help: consider adding the following bound: `'x: 'y`
+ = note: requirement occurs because of the type `Inv<'_>`, which makes the generic argument `'_` invariant
+ = note: the struct `Inv<'a>` is invariant over the parameter `'a`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+ = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/higher-ranked/subtype/hr-subtype.free_x_vs_free_y.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.free_x_vs_free_y.stderr
new file mode 100644
index 000000000..269cde54c
--- /dev/null
+++ b/tests/ui/higher-ranked/subtype/hr-subtype.free_x_vs_free_y.stderr
@@ -0,0 +1,19 @@
+error: lifetime may not live long enough
+ --> $DIR/hr-subtype.rs:54:13
+ |
+LL | fn supertype<'x, 'y: 'x, 'z: 'y>() {
+ | -- -- lifetime `'y` defined here
+ | |
+ | lifetime `'x` defined here
+LL | gimme::<$t1>(None::<$t2>);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
+...
+LL | / check! { free_x_vs_free_y: (fn(&'x u32),
+LL | | fn(&'y u32)) }
+ | |______________- in this macro invocation
+ |
+ = help: consider adding the following bound: `'x: 'y`
+ = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/higher-ranked/subtype/hr-subtype.rs b/tests/ui/higher-ranked/subtype/hr-subtype.rs
new file mode 100644
index 000000000..c770e0de8
--- /dev/null
+++ b/tests/ui/higher-ranked/subtype/hr-subtype.rs
@@ -0,0 +1,111 @@
+// Targeted tests for the higher-ranked subtyping code.
+
+#![allow(dead_code)]
+
+// revisions: bound_a_vs_bound_a
+// revisions: bound_a_vs_bound_b
+// revisions: bound_inv_a_vs_bound_inv_b
+// revisions: bound_co_a_vs_bound_co_b
+// revisions: bound_a_vs_free_x
+// revisions: free_x_vs_free_x
+// revisions: free_x_vs_free_y
+// revisions: free_inv_x_vs_free_inv_y
+// revisions: bound_a_b_vs_bound_a
+// revisions: bound_co_a_b_vs_bound_co_a
+// revisions: bound_contra_a_contra_b_ret_co_a
+// revisions: bound_co_a_co_b_ret_contra_a
+// revisions: bound_inv_a_b_vs_bound_inv_a
+// revisions: bound_a_b_ret_a_vs_bound_a_ret_a
+
+//[bound_a_vs_bound_a] check-pass
+//[bound_a_vs_bound_b] check-pass
+//[bound_inv_a_vs_bound_inv_b] check-pass
+//[bound_co_a_vs_bound_co_b] check-pass
+//[free_x_vs_free_x] check-pass
+//[bound_co_a_b_vs_bound_co_a] check-pass
+//[bound_co_a_co_b_ret_contra_a] check-pass
+//[bound_a_b_vs_bound_a] check-pass
+//[bound_contra_a_contra_b_ret_co_a] check-pass
+
+fn gimme<T>(_: Option<T>) {}
+
+struct Inv<'a> {
+ x: *mut &'a u32,
+}
+
+struct Co<'a> {
+ x: fn(&'a u32),
+}
+
+struct Contra<'a> {
+ x: &'a u32,
+}
+
+macro_rules! check {
+ ($rev:ident: ($t1:ty, $t2:ty)) => {
+ #[cfg($rev)]
+ fn subtype<'x, 'y: 'x, 'z: 'y>() {
+ gimme::<$t2>(None::<$t1>);
+ //[free_inv_x_vs_free_inv_y]~^ ERROR
+ }
+
+ #[cfg($rev)]
+ fn supertype<'x, 'y: 'x, 'z: 'y>() {
+ gimme::<$t1>(None::<$t2>);
+ //[bound_a_vs_free_x]~^ ERROR
+ //[free_x_vs_free_y]~^^ ERROR
+ //[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR
+ //[bound_inv_a_b_vs_bound_inv_a]~| ERROR
+ //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^^ ERROR
+ //[free_inv_x_vs_free_inv_y]~^^^^^^ ERROR
+ }
+ };
+}
+
+// If both have bound regions, they are equivalent, regardless of
+// variant.
+check! { bound_a_vs_bound_a: (for<'a> fn(&'a u32),
+for<'a> fn(&'a u32)) }
+check! { bound_a_vs_bound_b: (for<'a> fn(&'a u32),
+for<'b> fn(&'b u32)) }
+check! { bound_inv_a_vs_bound_inv_b: (for<'a> fn(Inv<'a>),
+for<'b> fn(Inv<'b>)) }
+check! { bound_co_a_vs_bound_co_b: (for<'a> fn(Co<'a>),
+for<'b> fn(Co<'b>)) }
+
+// Bound is a subtype of free.
+check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
+fn(&'x u32)) }
+
+// Two free regions are relatable if subtyping holds.
+check! { free_x_vs_free_x: (fn(&'x u32),
+fn(&'x u32)) }
+check! { free_x_vs_free_y: (fn(&'x u32),
+fn(&'y u32)) }
+check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
+fn(Inv<'y>)) }
+
+// Somewhat surprisingly, a fn taking two distinct bound lifetimes and
+// a fn taking one bound lifetime can be interchangeable, but only if
+// we are co- or contra-variant with respect to both lifetimes.
+//
+// The reason is:
+// - if we are covariant, then 'a and 'b can be set to the call-site
+// intersection;
+// - if we are contravariant, then 'a can be inferred to 'static.
+check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
+for<'a> fn(&'a u32, &'a u32)) }
+check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
+for<'a> fn(Co<'a>, Co<'a>)) }
+check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
+for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
+check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
+for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) }
+
+// If we make those lifetimes invariant, then the two types are not interchangeable.
+check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
+for<'a> fn(Inv<'a>, Inv<'a>)) }
+check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
+for<'a> fn(&'a u32, &'a u32) -> &'a u32) }
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/subtype/placeholder-pattern-fail.rs b/tests/ui/higher-ranked/subtype/placeholder-pattern-fail.rs
new file mode 100644
index 000000000..bd4533e04
--- /dev/null
+++ b/tests/ui/higher-ranked/subtype/placeholder-pattern-fail.rs
@@ -0,0 +1,25 @@
+// Check that incorrect higher ranked subtyping
+// causes an error.
+struct Inv<'a>(fn(&'a ()) -> &'a ());
+fn hr_subtype<'c>(f: for<'a, 'b> fn(Inv<'a>, Inv<'a>)) {
+ // ok
+ let _: for<'a> fn(Inv<'a>, Inv<'a>) = f;
+ let sub: for<'a> fn(Inv<'a>, Inv<'a>) = f;
+ // no
+ let _: for<'a, 'b> fn(Inv<'a>, Inv<'b>) = sub;
+ //~^ ERROR mismatched types
+}
+
+fn simple1<'c>(x: (&'c i32,)) {
+ let _x: (&'static i32,) = x;
+}
+
+fn simple2<'c>(x: (&'c i32,)) {
+ let _: (&'static i32,) = x;
+}
+
+fn main() {
+ hr_subtype(|_, _| {});
+ simple1((&3,));
+ simple2((&3,));
+}
diff --git a/tests/ui/higher-ranked/subtype/placeholder-pattern-fail.stderr b/tests/ui/higher-ranked/subtype/placeholder-pattern-fail.stderr
new file mode 100644
index 000000000..73b0a3173
--- /dev/null
+++ b/tests/ui/higher-ranked/subtype/placeholder-pattern-fail.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+ --> $DIR/placeholder-pattern-fail.rs:9:47
+ |
+LL | let _: for<'a, 'b> fn(Inv<'a>, Inv<'b>) = sub;
+ | ^^^ one type is more general than the other
+ |
+ = note: expected fn pointer `for<'a, 'b> fn(Inv<'a>, Inv<'b>)`
+ found fn pointer `for<'a> fn(Inv<'a>, Inv<'a>)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-ranked/subtype/placeholder-pattern.rs b/tests/ui/higher-ranked/subtype/placeholder-pattern.rs
new file mode 100644
index 000000000..061e66e54
--- /dev/null
+++ b/tests/ui/higher-ranked/subtype/placeholder-pattern.rs
@@ -0,0 +1,18 @@
+// check-pass
+// Check that higher ranked subtyping correctly works when using
+// placeholder patterns.
+fn hr_subtype<'c>(f: for<'a, 'b> fn(&'a (), &'b ())) {
+ let _: for<'a> fn(&'a (), &'a ()) = f;
+ let _: for<'a, 'b> fn(&'a (), &'b ()) = f;
+ let _: for<'a> fn(&'a (), &'c ()) = f;
+ let _: fn(&'c (), &'c ()) = f;
+}
+
+fn simple<'c>(x: (&'static i32,)) {
+ let _: (&'c i32,) = x;
+}
+
+fn main() {
+ hr_subtype(|_, _| {});
+ simple((&3,));
+}
diff --git a/tests/ui/higher-ranked/subtype/return-static.rs b/tests/ui/higher-ranked/subtype/return-static.rs
new file mode 100644
index 000000000..6455854f3
--- /dev/null
+++ b/tests/ui/higher-ranked/subtype/return-static.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+fn make<T>() -> T {
+ panic!()
+}
+
+fn take<T>(x: T) {}
+
+fn main() {
+ let x: for<'a> fn(&'a u32) -> _ = make();
+ let y: &'static u32 = x(&22);
+ take::<for<'b> fn(&'b u32) -> &'b u32>(x);
+}