Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b55ec5b

Browse files
authoredApr 24, 2024
Rollup merge of rust-lang#123794 - oli-obk:define_opaque_types2, r=lcnr
More DefineOpaqueTypes::Yes This accepts more code on stable. It is now possible to have match arms return a function item `foo::<ConcreteType>` and a function item `foo::<OpaqueTypeInDefiningScope>` in another, and that will constrain `OpaqueTypeInDefiningScope` to have the hidden type `ConcreteType`. So the following function will now compile, but on master it errors with a type mismatch on the second match arm ```rust // The function item whose generic params we want to merge. fn foo<T>(t: T) -> T { t } // Helper ensuring we can constrain `T` on `F` without explicitly specifying it fn bind<T, F: FnOnce(T) -> T>(_: T, f: F) -> F { f } fn k() -> impl Sized { let x = match true { true => { // `f` is `FnDef(foo, [infer_var])` let f = foo; // Get a value of an opaque type on stable let t = k(); // this returns `FnDef(foo, [k::return])` bind(t, f) } false => foo::<()>, }; todo!() } ``` r? `@compiler-errors` cc rust-lang#116652
2 parents 7ecbcde + 5c55d6a commit b55ec5b

File tree

4 files changed

+282
-1
lines changed

4 files changed

+282
-1
lines changed
 

‎compiler/rustc_hir_typeck/src/coercion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1139,7 +1139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11391139
// are the same function and their parameters have a LUB.
11401140
match self.commit_if_ok(|_| {
11411141
self.at(cause, self.param_env).lub(
1142-
DefineOpaqueTypes::No,
1142+
DefineOpaqueTypes::Yes,
11431143
prev_ty,
11441144
new_ty,
11451145
)

‎tests/ui/fn/fn_def_coercion.rs

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//! Test that coercing between function items of the same function,
2+
//! but with different generic args succeeds in typeck, but then fails
3+
//! in borrowck when the lifetimes can't actually be merged.
4+
5+
fn foo<T>(t: T) -> T {
6+
t
7+
}
8+
9+
fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
10+
let mut x = foo::<&'a ()>; //~ ERROR: lifetime may not live long enough
11+
x = foo::<&'b ()>; //~ ERROR: lifetime may not live long enough
12+
x = foo::<&'c ()>;
13+
x(a);
14+
x(b);
15+
x(c);
16+
}
17+
18+
fn g<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
19+
let x = foo::<&'c ()>;
20+
let _: &'c () = x(a); //~ ERROR lifetime may not live long enough
21+
}
22+
23+
fn h<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
24+
let x = foo::<&'a ()>;
25+
let _: &'a () = x(c);
26+
}
27+
28+
fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
29+
let mut x = foo::<&'c ()>;
30+
x = foo::<&'b ()>; //~ ERROR lifetime may not live long enough
31+
x = foo::<&'a ()>; //~ ERROR lifetime may not live long enough
32+
x(a);
33+
x(b);
34+
x(c);
35+
}
36+
37+
fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
38+
let x = match true {
39+
true => foo::<&'b ()>, //~ ERROR lifetime may not live long enough
40+
false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough
41+
};
42+
x(a);
43+
x(b);
44+
x(c);
45+
}
46+
47+
fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
48+
let x = match true {
49+
true => foo::<&'c ()>,
50+
false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough
51+
};
52+
53+
x(a);
54+
x(b); //~ ERROR lifetime may not live long enough
55+
x(c);
56+
}
57+
58+
fn main() {}

‎tests/ui/fn/fn_def_coercion.stderr

+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/fn_def_coercion.rs:10:17
3+
|
4+
LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
5+
| -- -- lifetime `'b` defined here
6+
| |
7+
| lifetime `'a` defined here
8+
LL | let mut x = foo::<&'a ()>;
9+
| ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b`
10+
|
11+
= help: consider adding the following bound: `'a: 'b`
12+
= note: requirement occurs because of a function pointer to `foo`
13+
= note: the function `foo` is invariant over the parameter `T`
14+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
15+
16+
error: lifetime may not live long enough
17+
--> $DIR/fn_def_coercion.rs:11:5
18+
|
19+
LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
20+
| -- -- lifetime `'b` defined here
21+
| |
22+
| lifetime `'a` defined here
23+
LL | let mut x = foo::<&'a ()>;
24+
LL | x = foo::<&'b ()>;
25+
| ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a`
26+
|
27+
= help: consider adding the following bound: `'b: 'a`
28+
= note: requirement occurs because of a function pointer to `foo`
29+
= note: the function `foo` is invariant over the parameter `T`
30+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
31+
32+
help: `'a` and `'b` must be the same: replace one with the other
33+
34+
error: lifetime may not live long enough
35+
--> $DIR/fn_def_coercion.rs:20:12
36+
|
37+
LL | fn g<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
38+
| -- -- lifetime `'c` defined here
39+
| |
40+
| lifetime `'a` defined here
41+
LL | let x = foo::<&'c ()>;
42+
LL | let _: &'c () = x(a);
43+
| ^^^^^^ type annotation requires that `'a` must outlive `'c`
44+
|
45+
= help: consider adding the following bound: `'a: 'c`
46+
47+
error: lifetime may not live long enough
48+
--> $DIR/fn_def_coercion.rs:30:5
49+
|
50+
LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
51+
| -- -- lifetime `'b` defined here
52+
| |
53+
| lifetime `'a` defined here
54+
LL | let mut x = foo::<&'c ()>;
55+
LL | x = foo::<&'b ()>;
56+
| ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a`
57+
|
58+
= help: consider adding the following bound: `'b: 'a`
59+
= note: requirement occurs because of a function pointer to `foo`
60+
= note: the function `foo` is invariant over the parameter `T`
61+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
62+
63+
error: lifetime may not live long enough
64+
--> $DIR/fn_def_coercion.rs:31:5
65+
|
66+
LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
67+
| -- -- lifetime `'b` defined here
68+
| |
69+
| lifetime `'a` defined here
70+
...
71+
LL | x = foo::<&'a ()>;
72+
| ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b`
73+
|
74+
= help: consider adding the following bound: `'a: 'b`
75+
= note: requirement occurs because of a function pointer to `foo`
76+
= note: the function `foo` is invariant over the parameter `T`
77+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
78+
79+
help: `'a` and `'b` must be the same: replace one with the other
80+
|
81+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
82+
83+
error: lifetime may not live long enough
84+
--> $DIR/fn_def_coercion.rs:39:17
85+
|
86+
LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
87+
| -- -- lifetime `'b` defined here
88+
| |
89+
| lifetime `'a` defined here
90+
LL | let x = match true {
91+
LL | true => foo::<&'b ()>,
92+
| ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a`
93+
|
94+
= help: consider adding the following bound: `'b: 'a`
95+
= note: requirement occurs because of a function pointer to `foo`
96+
= note: the function `foo` is invariant over the parameter `T`
97+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
98+
99+
error: lifetime may not live long enough
100+
--> $DIR/fn_def_coercion.rs:40:18
101+
|
102+
LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
103+
| -- -- lifetime `'b` defined here
104+
| |
105+
| lifetime `'a` defined here
106+
...
107+
LL | false => foo::<&'a ()>,
108+
| ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b`
109+
|
110+
= help: consider adding the following bound: `'a: 'b`
111+
= note: requirement occurs because of a function pointer to `foo`
112+
= note: the function `foo` is invariant over the parameter `T`
113+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
114+
115+
help: `'a` and `'b` must be the same: replace one with the other
116+
|
117+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
118+
119+
error: lifetime may not live long enough
120+
--> $DIR/fn_def_coercion.rs:50:18
121+
|
122+
LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
123+
| -- -- lifetime `'c` defined here
124+
| |
125+
| lifetime `'a` defined here
126+
...
127+
LL | false => foo::<&'a ()>,
128+
| ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c`
129+
|
130+
= help: consider adding the following bound: `'a: 'c`
131+
= note: requirement occurs because of a function pointer to `foo`
132+
= note: the function `foo` is invariant over the parameter `T`
133+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
134+
135+
error: lifetime may not live long enough
136+
--> $DIR/fn_def_coercion.rs:54:5
137+
|
138+
LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
139+
| -- -- lifetime `'b` defined here
140+
| |
141+
| lifetime `'a` defined here
142+
...
143+
LL | x(b);
144+
| ^^^^ argument requires that `'b` must outlive `'a`
145+
|
146+
= help: consider adding the following bound: `'b: 'a`
147+
148+
help: the following changes may resolve your lifetime errors
149+
|
150+
= help: add bound `'a: 'c`
151+
= help: add bound `'b: 'a`
152+
153+
error: aborting due to 9 previous errors
154+

‎tests/ui/fn/fn_def_opaque_coercion.rs

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//! Test that coercing between function items of the same function,
2+
//! but with different generic args works.
3+
4+
//@check-pass
5+
6+
#![feature(type_alias_impl_trait)]
7+
8+
fn foo<T>(t: T) -> T {
9+
t
10+
}
11+
12+
type F = impl Sized;
13+
14+
fn f(a: F) {
15+
let mut x = foo::<F>;
16+
x = foo::<()>;
17+
x(a);
18+
x(());
19+
}
20+
21+
type G = impl Sized;
22+
23+
fn g(a: G) {
24+
let x = foo::<()>;
25+
let _: () = x(a);
26+
}
27+
28+
type H = impl Sized;
29+
30+
fn h(a: H) {
31+
let x = foo::<H>;
32+
let _: H = x(());
33+
}
34+
35+
type I = impl Sized;
36+
37+
fn i(a: I) {
38+
let mut x = foo::<()>;
39+
x = foo::<I>;
40+
x(a);
41+
x(());
42+
}
43+
44+
type J = impl Sized;
45+
46+
fn j(a: J) {
47+
let x = match true {
48+
true => foo::<J>,
49+
false => foo::<()>,
50+
};
51+
x(a);
52+
x(());
53+
}
54+
55+
fn k() -> impl Sized {
56+
fn bind<T, F: FnOnce(T) -> T>(_: T, f: F) -> F {
57+
f
58+
}
59+
let x = match true {
60+
true => {
61+
let f = foo;
62+
bind(k(), f)
63+
}
64+
false => foo::<()>,
65+
};
66+
todo!()
67+
}
68+
69+
fn main() {}

0 commit comments

Comments
 (0)
Failed to load comments.