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.
|
||||
}
|
||||
|
||||
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(_) => {
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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`.
|
||||
|
|
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
|
||||
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() {}
|
||||
|
|
|
@ -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`.
|
||||
|
|
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())
|
||||
//~^ 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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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`.
|
||||
|
|
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