1
Fork 0

Check that closures satisfy their where bounds

This commit is contained in:
Oli Scherer 2022-05-10 14:19:19 +00:00
parent f001f9301c
commit 253408b409
16 changed files with 343 additions and 22 deletions

View file

@ -575,7 +575,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
// generators don't take arguments.
}
ty::Closure(_, substs) => {
ty::Closure(did, substs) => {
// Only check the upvar types for WF, not the rest
// of the types within. This is needed because we
// capture the signature and it may not be WF
@ -596,18 +596,26 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
// probably always be WF, because it should be
// shorthand for something like `where(T: 'a) {
// fn(&'a T) }`, as discussed in #25860.
//
// Note that we are also skipping the generic
// types. This is consistent with the `outlives`
// code, but anyway doesn't matter: within the fn
walker.skip_current_subtree(); // subtree handled below
// FIXME(eddyb) add the type to `walker` instead of recursing.
self.compute(substs.as_closure().tupled_upvars_ty().into());
// Note that we cannot skip the generic types
// types. Normally, within the fn
// body where they are created, the generics will
// always be WF, and outside of that fn body we
// are not directly inspecting closure types
// anyway, except via auto trait matching (which
// only inspects the upvar types).
walker.skip_current_subtree(); // subtree handled below
// FIXME(eddyb) add the type to `walker` instead of recursing.
self.compute(substs.as_closure().tupled_upvars_ty().into());
// But when a closure is part of a type-alias-impl-trait
// then the function that created the defining site may
// have had more bounds available than the type alias
// specifies. This may cause us to have a closure in the
// hidden type that is not actually well formed and
// can cause compiler crashes when the user abuses unsafe
// code to procure such a closure.
// See src/test/ui/type-alias-impl-trait/wf_check_closures.rs
let obligations = self.nominal_obligations(did, substs);
self.out.extend(obligations);
}
ty::FnPtr(_) => {

View file

@ -1,6 +1,6 @@
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
//~^ ERROR overly complex generic constant
//~^ ERROR cycle detected when building an abstract representation
fn main() {}

View file

@ -1,13 +1,26 @@
error: overly complex generic constant
error[E0391]: cycle detected when building an abstract representation for test::{constant#0}
--> $DIR/closures.rs:3:35
|
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
| ^^^^-------^^
| |
| borrowing is not supported in generic constants
| ^^^^^^^^^^^^^
|
= help: consider moving this anonymous constant into a `const` function
= note: this operation may be supported in the future
note: ...which requires building THIR for `test::{constant#0}`...
--> $DIR/closures.rs:3:35
|
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
| ^^^^^^^^^^^^^
note: ...which requires type-checking `test::{constant#0}`...
--> $DIR/closures.rs:3:35
|
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
| ^^^^^^^^^^^^^
= note: ...which again requires building an abstract representation for test::{constant#0}, completing the cycle
note: cycle used when checking that `test` is well-formed
--> $DIR/closures.rs:3:1
|
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0391`.

View file

@ -0,0 +1,18 @@
error: higher-ranked lifetime error
--> $DIR/issue-59311.rs:17:5
|
LL | v.t(|| {});
| ^^^^^^^^^^
|
= note: could not prove [closure@$DIR/issue-59311.rs:17:9: 17:14] well-formed
error: higher-ranked lifetime error
--> $DIR/issue-59311.rs:17:9
|
LL | v.t(|| {});
| ^^^^^
|
= note: could not prove for<'a> &'a V: 'static
error: aborting due to 2 previous errors

View file

@ -14,7 +14,7 @@ pub fn crash<V>(v: &V)
where
for<'a> &'a V: T + 'static,
{
v.t(|| {}); //~ ERROR: higher-ranked lifetime error
v.t(|| {}); //~ ERROR: `&'a V` does not fulfill the required lifetime
}
fn main() {}

View file

@ -1,10 +1,15 @@
error: higher-ranked lifetime error
--> $DIR/issue-59311.rs:17:9
error[E0477]: the type `&'a V` does not fulfill the required lifetime
--> $DIR/issue-59311.rs:17:5
|
LL | v.t(|| {});
| ^^^^^
| ^^^^^^^^^^
|
= note: could not prove for<'a> &'a V: 'static
note: type must satisfy the static lifetime as required by this binding
--> $DIR/issue-59311.rs:15:24
|
LL | for<'a> &'a V: T + 'static,
| ^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0477`.

View file

@ -0,0 +1,14 @@
#![feature(type_alias_impl_trait)]
#![allow(dead_code)]
type Bug<T, U> = impl Fn(T) -> U + Copy;
const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
fn make_bug<T, U: From<T>>() -> Bug<T, U> {
|x| x.into() //~ ERROR the trait bound `U: From<T>` is not satisfied
}
fn main() {
CONST_BUG(0);
}

View file

@ -0,0 +1,19 @@
error[E0277]: the trait bound `U: From<T>` is not satisfied
--> $DIR/issue-53092.rs:9:5
|
LL | |x| x.into()
| ^^^^^^^^^^^^ the trait `From<T>` is not implemented for `U`
|
note: required by a bound in `make_bug`
--> $DIR/issue-53092.rs:8:19
|
LL | fn make_bug<T, U: From<T>>() -> Bug<T, U> {
| ^^^^^^^ required by this bound in `make_bug`
help: consider restricting type parameter `U`
|
LL | type Bug<T, U: std::convert::From<T>> = impl Fn(T) -> U + Copy;
| +++++++++++++++++++++++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,24 @@
#![feature(type_alias_impl_trait)]
// check-pass
trait IterBits {
type BitsIter: Iterator<Item = u8>;
fn iter_bits(self, n: u8) -> Self::BitsIter;
}
impl<T: Copy, E> IterBits for T
where
T: std::ops::Shr<Output = T>
+ std::ops::BitAnd<T, Output = T>
+ std::convert::From<u8>
+ std::convert::TryInto<u8, Error = E>,
E: std::fmt::Debug,
{
type BitsIter = impl std::iter::Iterator<Item = u8>;
fn iter_bits(self, n: u8) -> Self::BitsIter {
(0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
}
}
fn main() {}

View file

@ -20,6 +20,13 @@ where
(0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
//~^ ERROR non-defining opaque type use in defining scope
//~| ERROR type mismatch resolving
//~| ERROR type mismatch resolving `<T as TryInto<u8>>::Error == E`
//~| ERROR no implementation for `T >> T`
//~| ERROR no implementation for `T & T`
//~| ERROR the trait bound `T: From<u8>`
//~| ERROR the trait bound `T: Copy` is not satisfied
//~| ERROR `E` doesn't implement `Debug`
//~| ERROR the trait bound `u8: From<T>` is not satisfied
}
}

View file

@ -11,6 +11,122 @@ LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from
found type parameter `I`
= note: required because of the requirements on the impl of `Iterator` for `Map<Rev<std::ops::Range<u8>>, [closure@$DIR/issue-60564.rs:20:28: 20:100]>`
error[E0271]: type mismatch resolving `<T as TryInto<u8>>::Error == E`
--> $DIR/issue-60564.rs:20:9
|
LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
| - this type parameter
...
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `E`, found enum `Infallible`
|
= note: expected type parameter `E`
found enum `Infallible`
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:15:37
|
LL | + std::convert::TryInto<u8, Error = E>,
| ^^^^^^^^^ required by this bound in `<T as IterBits>`
error[E0277]: no implementation for `T >> T`
--> $DIR/issue-60564.rs:20:9
|
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T >> T`
|
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:12:8
|
LL | T: std::ops::Shr<Output = T>
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
help: consider restricting type parameter `T`
|
LL | type IterBitsIter<T: std::ops::Shr, E, I> = impl std::iter::Iterator<Item = I>;
| +++++++++++++++
error[E0277]: no implementation for `T & T`
--> $DIR/issue-60564.rs:20:9
|
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T & T`
|
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:13:11
|
LL | + std::ops::BitAnd<T, Output = T>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
help: consider restricting type parameter `T`
|
LL | type IterBitsIter<T: std::ops::BitAnd, E, I> = impl std::iter::Iterator<Item = I>;
| ++++++++++++++++++
error[E0277]: the trait bound `T: From<u8>` is not satisfied
--> $DIR/issue-60564.rs:20:9
|
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<u8>` is not implemented for `T`
|
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:14:11
|
LL | + std::convert::From<u8>
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
help: consider restricting type parameter `T`
|
LL | type IterBitsIter<T: std::convert::From<u8>, E, I> = impl std::iter::Iterator<Item = I>;
| ++++++++++++++++++++++++
error[E0277]: the trait bound `T: Copy` is not satisfied
--> $DIR/issue-60564.rs:20:9
|
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
|
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:10:9
|
LL | impl<T: Copy, E> IterBits for T
| ^^^^ required by this bound in `<T as IterBits>`
help: consider restricting type parameter `T`
|
LL | type IterBitsIter<T: std::marker::Copy, E, I> = impl std::iter::Iterator<Item = I>;
| +++++++++++++++++++
error[E0277]: `E` doesn't implement `Debug`
--> $DIR/issue-60564.rs:20:9
|
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `E` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:16:8
|
LL | E: std::fmt::Debug,
| ^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
help: consider restricting type parameter `E`
|
LL | type IterBitsIter<T, E: std::fmt::Debug, I> = impl std::iter::Iterator<Item = I>;
| +++++++++++++++++
error[E0277]: the trait bound `u8: From<T>` is not satisfied
--> $DIR/issue-60564.rs:20:9
|
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<T>` is not implemented for `u8`
|
= note: required because of the requirements on the impl of `Into<u8>` for `T`
= note: required because of the requirements on the impl of `TryFrom<T>` for `u8`
= note: required because of the requirements on the impl of `TryInto<u8>` for `T`
note: required by a bound in `<T as IterBits>`
--> $DIR/issue-60564.rs:15:11
|
LL | + std::convert::TryInto<u8, Error = E>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I> where u8: From<T>;
| +++++++++++++++++
error: non-defining opaque type use in defining scope
--> $DIR/issue-60564.rs:20:9
|
@ -23,6 +139,7 @@ note: used non-generic type `u8` for generic parameter
LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
| ^
error: aborting due to 2 previous errors
error: aborting due to 9 previous errors
For more information about this error, try `rustc --explain E0271`.
Some errors have detailed explanations: E0271, E0277.
For more information about an error, try `rustc --explain E0271`.

View file

@ -0,0 +1,18 @@
#![feature(type_alias_impl_trait)]
trait Bar {
fn bar(&self);
}
type FooFn<B> = impl FnOnce(B);
fn foo<B: Bar>() -> FooFn<B> {
fn mop<B: Bar>(bar: B) { bar.bar() }
mop // NOTE: no function pointer, but function zst item
//~^ ERROR the trait bound `B: Bar` is not satisfied
}
fn main() {
let boom: FooFn<u32> = unsafe { core::mem::zeroed() };
boom(42);
}

View file

@ -0,0 +1,19 @@
error[E0277]: the trait bound `B: Bar` is not satisfied
--> $DIR/wf-check-fn-def.rs:11:5
|
LL | mop // NOTE: no function pointer, but function zst item
| ^^^ the trait `Bar` is not implemented for `B`
|
note: required by a bound in `mop`
--> $DIR/wf-check-fn-def.rs:10:15
|
LL | fn mop<B: Bar>(bar: B) { bar.bar() }
| ^^^ required by this bound in `mop`
help: consider restricting type parameter `B`
|
LL | type FooFn<B: Bar> = impl FnOnce(B);
| +++++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,23 @@
#![feature(type_alias_impl_trait)]
// build-pass
trait Bar {
fn bar(&self);
}
type FooFn<B> = impl FnOnce(B);
fn foo<B: Bar>() -> FooFn<B> {
fn mop<B: Bar>(bar: B) { bar.bar() }
mop as fn(B)
// function pointers don't have any obligations on them,
// thus the above compiles. It's obviously unsound to just
// procure a `FooFn` from the ether without making sure that
// the pointer is actually legal for all `B`
}
fn main() {
let boom: FooFn<u32> = unsafe { core::mem::zeroed() };
boom(42);
}

View file

@ -0,0 +1,17 @@
#![feature(type_alias_impl_trait)]
trait Bar {
fn bar(&self);
}
type FooFn<B> = impl FnOnce();
fn foo<B: Bar>(bar: B) -> FooFn<B> {
move || { bar.bar() }
//~^ ERROR the trait bound `B: Bar` is not satisfied
}
fn main() {
let boom: FooFn<u32> = unsafe { core::mem::zeroed() };
boom();
}

View file

@ -0,0 +1,19 @@
error[E0277]: the trait bound `B: Bar` is not satisfied
--> $DIR/wf_check_closures.rs:10:5
|
LL | move || { bar.bar() }
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `B`
|
note: required by a bound in `foo`
--> $DIR/wf_check_closures.rs:9:11
|
LL | fn foo<B: Bar>(bar: B) -> FooFn<B> {
| ^^^ required by this bound in `foo`
help: consider restricting type parameter `B`
|
LL | type FooFn<B: Bar> = impl FnOnce();
| +++++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.