Check that closures satisfy their where bounds
This commit is contained in:
parent
f001f9301c
commit
253408b409
16 changed files with 343 additions and 22 deletions
|
@ -575,7 +575,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||||
// generators don't take arguments.
|
// generators don't take arguments.
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Closure(_, substs) => {
|
ty::Closure(did, substs) => {
|
||||||
// Only check the upvar types for WF, not the rest
|
// Only check the upvar types for WF, not the rest
|
||||||
// of the types within. This is needed because we
|
// of the types within. This is needed because we
|
||||||
// capture the signature and it may not be WF
|
// 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
|
// probably always be WF, because it should be
|
||||||
// shorthand for something like `where(T: 'a) {
|
// shorthand for something like `where(T: 'a) {
|
||||||
// fn(&'a T) }`, as discussed in #25860.
|
// fn(&'a T) }`, as discussed in #25860.
|
||||||
//
|
walker.skip_current_subtree(); // subtree handled below
|
||||||
// Note that we are also skipping the generic
|
// FIXME(eddyb) add the type to `walker` instead of recursing.
|
||||||
// types. This is consistent with the `outlives`
|
self.compute(substs.as_closure().tupled_upvars_ty().into());
|
||||||
// code, but anyway doesn't matter: within the fn
|
// Note that we cannot skip the generic types
|
||||||
|
// types. Normally, within the fn
|
||||||
// body where they are created, the generics will
|
// body where they are created, the generics will
|
||||||
// always be WF, and outside of that fn body we
|
// always be WF, and outside of that fn body we
|
||||||
// are not directly inspecting closure types
|
// are not directly inspecting closure types
|
||||||
// anyway, except via auto trait matching (which
|
// anyway, except via auto trait matching (which
|
||||||
// only inspects the upvar types).
|
// only inspects the upvar types).
|
||||||
walker.skip_current_subtree(); // subtree handled below
|
// But when a closure is part of a type-alias-impl-trait
|
||||||
// FIXME(eddyb) add the type to `walker` instead of recursing.
|
// then the function that created the defining site may
|
||||||
self.compute(substs.as_closure().tupled_upvars_ty().into());
|
// 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(_) => {
|
ty::FnPtr(_) => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![feature(generic_const_exprs)]
|
#![feature(generic_const_exprs)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
|
fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
|
||||||
//~^ ERROR overly complex generic constant
|
//~^ ERROR cycle detected when building an abstract representation
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -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
|
--> $DIR/closures.rs:3:35
|
||||||
|
|
|
|
||||||
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
|
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: ...which requires building THIR for `test::{constant#0}`...
|
||||||
= note: this operation may be supported in the future
|
--> $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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0391`.
|
||||||
|
|
18
src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr
Normal file
18
src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr
Normal 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
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub fn crash<V>(v: &V)
|
||||||
where
|
where
|
||||||
for<'a> &'a V: T + 'static,
|
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() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
error: higher-ranked lifetime error
|
error[E0477]: the type `&'a V` does not fulfill the required lifetime
|
||||||
--> $DIR/issue-59311.rs:17:9
|
--> $DIR/issue-59311.rs:17:5
|
||||||
|
|
|
|
||||||
LL | v.t(|| {});
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0477`.
|
||||||
|
|
14
src/test/ui/type-alias-impl-trait/issue-53092.rs
Normal file
14
src/test/ui/type-alias-impl-trait/issue-53092.rs
Normal 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);
|
||||||
|
}
|
19
src/test/ui/type-alias-impl-trait/issue-53092.stderr
Normal file
19
src/test/ui/type-alias-impl-trait/issue-53092.stderr
Normal 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`.
|
24
src/test/ui/type-alias-impl-trait/issue-60564-working.rs
Normal file
24
src/test/ui/type-alias-impl-trait/issue-60564-working.rs
Normal 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() {}
|
|
@ -20,6 +20,13 @@ where
|
||||||
(0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
|
(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 non-defining opaque type use in defining scope
|
||||||
//~| ERROR type mismatch resolving
|
//~| 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,122 @@ LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from
|
||||||
found type parameter `I`
|
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]>`
|
= 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
|
error: non-defining opaque type use in defining scope
|
||||||
--> $DIR/issue-60564.rs:20:9
|
--> $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>;
|
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`.
|
||||||
|
|
18
src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs
Normal file
18
src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs
Normal 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);
|
||||||
|
}
|
19
src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr
Normal file
19
src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr
Normal 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`.
|
23
src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs
Normal file
23
src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs
Normal 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);
|
||||||
|
}
|
17
src/test/ui/type-alias-impl-trait/wf_check_closures.rs
Normal file
17
src/test/ui/type-alias-impl-trait/wf_check_closures.rs
Normal 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();
|
||||||
|
}
|
19
src/test/ui/type-alias-impl-trait/wf_check_closures.stderr
Normal file
19
src/test/ui/type-alias-impl-trait/wf_check_closures.stderr
Normal 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`.
|
Loading…
Add table
Add a link
Reference in a new issue