Skip to content

Commit

Permalink
Auto merge of rust-lang#118882 - compiler-errors:normalized-sig-wf, r…
Browse files Browse the repository at this point in the history
…=<try>

Check normalized call signature for WF in mir typeck

Unfortunately we don't check that the built-in implementations for `Fn*` traits are actually well-formed in the same way that we do for user-provided impls.

Essentially, when checking a call terminator, we end up with a signature that references an unnormalized `<[closure] as FnOnce<...>>::Output` in its output. That output type, due to the built-in impl, doesn't follow the expected rule that `WF(ty)` implies `WF(normalized(ty))`. We fix this by also checking the normalized signature here.

**See** boxy's detailed and useful explanation comment which explains this in more detail: rust-lang#114936 (comment)

Fixes rust-lang#114936
Fixes rust-lang#118876

r? types
cc `@BoxyUwU` `@lcnr`
  • Loading branch information
bors committed Jan 22, 2024
2 parents a58ec8f + b981ced commit 49d2f53
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 1 deletion.
12 changes: 12 additions & 0 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1425,6 +1425,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::Boring,
);
let sig = self.normalize(sig, term_location);
// HACK(#114936): `WF(sig)` does not imply `WF(normalized(sig))`
// with built-in `Fn` implementations, since the impl may not be
// well-formed itself.
self.prove_predicates(
sig.inputs_and_output.iter().map(|ty| {
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
ty.into(),
)))
}),
term_location.to_locations(),
ConstraintCategory::Boring,
);
self.check_call_dest(body, term, &sig, *destination, *target, term_location);

// The ordinary liveness rules will ensure that all
Expand Down
27 changes: 27 additions & 0 deletions tests/ui/nll/check-normalized-sig-for-wf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// <https://github.com/rust-lang/rust/issues/114936>
fn whoops(
s: String,
f: impl for<'s> FnOnce(&'s str) -> (&'static str, [&'static &'s (); 0]),
) -> &'static str
{
f(&s).0
//~^ ERROR `s` does not live long enough
}

// <https://github.com/rust-lang/rust/issues/118876>
fn extend<T>(input: &T) -> &'static T {
struct Bounded<'a, 'b: 'static, T>(&'a T, [&'b (); 0]);
let n: Box<dyn FnOnce(&T) -> Bounded<'static, '_, T>> = Box::new(|x| Bounded(x, []));
n(input).0
//~^ ERROR borrowed data escapes outside of function
}

// <https://github.com/rust-lang/rust/issues/118876>
fn extend_mut<'a, T>(input: &'a mut T) -> &'static mut T {
struct Bounded<'a, 'b: 'static, T>(&'a mut T, [&'b (); 0]);
let mut n: Box<dyn FnMut(&mut T) -> Bounded<'static, '_, T>> = Box::new(|x| Bounded(x, []));
n(input).0
//~^ ERROR borrowed data escapes outside of function
}

fn main() {}
47 changes: 47 additions & 0 deletions tests/ui/nll/check-normalized-sig-for-wf.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
error[E0597]: `s` does not live long enough
--> $DIR/check-normalized-sig-for-wf.rs:7:7
|
LL | s: String,
| - binding `s` declared here
...
LL | f(&s).0
| --^^-
| | |
| | borrowed value does not live long enough
| argument requires that `s` is borrowed for `'static`
LL |
LL | }
| - `s` dropped here while still borrowed

error[E0521]: borrowed data escapes outside of function
--> $DIR/check-normalized-sig-for-wf.rs:15:5
|
LL | fn extend<T>(input: &T) -> &'static T {
| ----- - let's call the lifetime of this reference `'1`
| |
| `input` is a reference that is only valid in the function body
...
LL | n(input).0
| ^^^^^^^^
| |
| `input` escapes the function body here
| argument requires that `'1` must outlive `'static`

error[E0521]: borrowed data escapes outside of function
--> $DIR/check-normalized-sig-for-wf.rs:23:5
|
LL | fn extend_mut<'a, T>(input: &'a mut T) -> &'static mut T {
| -- ----- `input` is a reference that is only valid in the function body
| |
| lifetime `'a` defined here
...
LL | n(input).0
| ^^^^^^^^
| |
| `input` escapes the function body here
| argument requires that `'a` must outlive `'static`

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0521, E0597.
For more information about an error, try `rustc --explain E0521`.
2 changes: 2 additions & 0 deletions tests/ui/nll/missing-universe-cause-issue-114907.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ fn main() {
accept(callback);
//~^ ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR implementation of `FnOnce` is not general enough
//~| ERROR implementation of `FnOnce` is not general enough
//~| ERROR implementation of `FnOnce` is not general enough
//~| ERROR higher-ranked subtype error
Expand Down
36 changes: 35 additions & 1 deletion tests/ui/nll/missing-universe-cause-issue-114907.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,40 @@ help: consider specifying the type of the closure parameters
LL | let callback = |_: &_| {};
| ~~~~~~~

error: implementation of `FnOnce` is not general enough
--> $DIR/missing-universe-cause-issue-114907.rs:33:5
|
LL | accept(callback);
| ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0308]: mismatched types
--> $DIR/missing-universe-cause-issue-114907.rs:33:5
|
LL | accept(callback);
| ^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected trait `for<'a> FnOnce(&'a ())`
found trait `FnOnce(&())`
note: this closure does not fulfill the lifetime requirements
--> $DIR/missing-universe-cause-issue-114907.rs:32:20
|
LL | let callback = |_| {};
| ^^^
note: the lifetime requirement is introduced here
--> $DIR/missing-universe-cause-issue-114907.rs:20:21
|
LL | struct Handshake<R: Role> {
| ^^^^
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider specifying the type of the closure parameters
|
LL | let callback = |_: &_| {};
| ~~~~~~~

error: higher-ranked subtype error
--> $DIR/missing-universe-cause-issue-114907.rs:33:21
|
Expand All @@ -77,6 +111,6 @@ LL | accept(callback);
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 6 previous errors
error: aborting due to 8 previous errors

For more information about this error, try `rustc --explain E0308`.

0 comments on commit 49d2f53

Please sign in to comment.