From 253408b4090bc15b88bb5faecaf1e9765be80587 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 10 May 2022 14:19:19 +0000 Subject: [PATCH 1/2] Check that closures satisfy their where bounds --- .../rustc_trait_selection/src/traits/wf.rs | 24 ++-- .../generic_const_exprs/closures.rs | 2 +- .../generic_const_exprs/closures.stderr | 25 +++- .../issue-59311.nll.stderr | 18 +++ .../higher-rank-trait-bounds/issue-59311.rs | 2 +- .../issue-59311.stderr | 13 +- .../ui/type-alias-impl-trait/issue-53092.rs | 14 ++ .../type-alias-impl-trait/issue-53092.stderr | 19 +++ .../issue-60564-working.rs | 24 ++++ .../ui/type-alias-impl-trait/issue-60564.rs | 7 + .../type-alias-impl-trait/issue-60564.stderr | 121 +++++++++++++++++- .../type-alias-impl-trait/wf-check-fn-def.rs | 18 +++ .../wf-check-fn-def.stderr | 19 +++ .../type-alias-impl-trait/wf-check-fn-ptrs.rs | 23 ++++ .../wf_check_closures.rs | 17 +++ .../wf_check_closures.stderr | 19 +++ 16 files changed, 343 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr create mode 100644 src/test/ui/type-alias-impl-trait/issue-53092.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-53092.stderr create mode 100644 src/test/ui/type-alias-impl-trait/issue-60564-working.rs create mode 100644 src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs create mode 100644 src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr create mode 100644 src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs create mode 100644 src/test/ui/type-alias-impl-trait/wf_check_closures.rs create mode 100644 src/test/ui/type-alias-impl-trait/wf_check_closures.stderr diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index de0ade64247df..ca40c3452e25b 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -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(_) => { diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.rs b/src/test/ui/const-generics/generic_const_exprs/closures.rs index 847843fe1a63e..1ea310d063b82 100644 --- a/src/test/ui/const-generics/generic_const_exprs/closures.rs +++ b/src/test/ui/const-generics/generic_const_exprs/closures.rs @@ -1,6 +1,6 @@ #![feature(generic_const_exprs)] #![allow(incomplete_features)] fn test() -> [u8; N + (|| 42)()] {} -//~^ ERROR overly complex generic constant +//~^ ERROR cycle detected when building an abstract representation fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.stderr b/src/test/ui/const-generics/generic_const_exprs/closures.stderr index 18010413b9394..a15dd2016e9e4 100644 --- a/src/test/ui/const-generics/generic_const_exprs/closures.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/closures.stderr @@ -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() -> [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() -> [u8; N + (|| 42)()] {} + | ^^^^^^^^^^^^^ +note: ...which requires type-checking `test::{constant#0}`... + --> $DIR/closures.rs:3:35 + | +LL | fn test() -> [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() -> [u8; N + (|| 42)()] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr new file mode 100644 index 0000000000000..15e83ab5a347d --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr @@ -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 + diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.rs b/src/test/ui/higher-rank-trait-bounds/issue-59311.rs index d617571753c1d..6970857728560 100644 --- a/src/test/ui/higher-rank-trait-bounds/issue-59311.rs +++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.rs @@ -14,7 +14,7 @@ pub fn crash(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() {} diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr index c16c820615324..3dd05bba5c0a1 100644 --- a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr +++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr @@ -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`. diff --git a/src/test/ui/type-alias-impl-trait/issue-53092.rs b/src/test/ui/type-alias-impl-trait/issue-53092.rs new file mode 100644 index 0000000000000..45792ba97a7a0 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-53092.rs @@ -0,0 +1,14 @@ +#![feature(type_alias_impl_trait)] +#![allow(dead_code)] + +type Bug = impl Fn(T) -> U + Copy; + +const CONST_BUG: Bug = unsafe { std::mem::transmute(|_: u8| ()) }; + +fn make_bug>() -> Bug { + |x| x.into() //~ ERROR the trait bound `U: From` is not satisfied +} + +fn main() { + CONST_BUG(0); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-53092.stderr b/src/test/ui/type-alias-impl-trait/issue-53092.stderr new file mode 100644 index 0000000000000..2d423a0c0dff5 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-53092.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `U: From` is not satisfied + --> $DIR/issue-53092.rs:9:5 + | +LL | |x| x.into() + | ^^^^^^^^^^^^ the trait `From` is not implemented for `U` + | +note: required by a bound in `make_bug` + --> $DIR/issue-53092.rs:8:19 + | +LL | fn make_bug>() -> Bug { + | ^^^^^^^ required by this bound in `make_bug` +help: consider restricting type parameter `U` + | +LL | type Bug> = impl Fn(T) -> U + Copy; + | +++++++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-60564-working.rs b/src/test/ui/type-alias-impl-trait/issue-60564-working.rs new file mode 100644 index 0000000000000..38accc8241cb5 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-60564-working.rs @@ -0,0 +1,24 @@ +#![feature(type_alias_impl_trait)] + +// check-pass + +trait IterBits { + type BitsIter: Iterator; + fn iter_bits(self, n: u8) -> Self::BitsIter; +} + +impl IterBits for T +where + T: std::ops::Shr + + std::ops::BitAnd + + std::convert::From + + std::convert::TryInto, + E: std::fmt::Debug, +{ + type BitsIter = impl std::iter::Iterator; + 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() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.rs b/src/test/ui/type-alias-impl-trait/issue-60564.rs index 0aeebae639e91..48d8dff2b9392 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60564.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60564.rs @@ -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 `>::Error == E` + //~| ERROR no implementation for `T >> T` + //~| ERROR no implementation for `T & T` + //~| ERROR the trait bound `T: From` + //~| ERROR the trait bound `T: Copy` is not satisfied + //~| ERROR `E` doesn't implement `Debug` + //~| ERROR the trait bound `u8: From` is not satisfied } } diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.stderr b/src/test/ui/type-alias-impl-trait/issue-60564.stderr index 9cb07cbbb4408..4ef53973a7c74 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60564.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60564.stderr @@ -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>, [closure@$DIR/issue-60564.rs:20:28: 20:100]>` +error[E0271]: type mismatch resolving `>::Error == E` + --> $DIR/issue-60564.rs:20:9 + | +LL | type IterBitsIter = impl std::iter::Iterator; + | - 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 `` + --> $DIR/issue-60564.rs:15:37 + | +LL | + std::convert::TryInto, + | ^^^^^^^^^ required by this bound in `` + +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 `` + --> $DIR/issue-60564.rs:12:8 + | +LL | T: std::ops::Shr + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `` +help: consider restricting type parameter `T` + | +LL | type IterBitsIter = impl std::iter::Iterator; + | +++++++++++++++ + +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 `` + --> $DIR/issue-60564.rs:13:11 + | +LL | + std::ops::BitAnd + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `` +help: consider restricting type parameter `T` + | +LL | type IterBitsIter = impl std::iter::Iterator; + | ++++++++++++++++++ + +error[E0277]: the trait bound `T: From` 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` is not implemented for `T` + | +note: required by a bound in `` + --> $DIR/issue-60564.rs:14:11 + | +LL | + std::convert::From + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `` +help: consider restricting type parameter `T` + | +LL | type IterBitsIter, E, I> = impl std::iter::Iterator; + | ++++++++++++++++++++++++ + +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 `` + --> $DIR/issue-60564.rs:10:9 + | +LL | impl IterBits for T + | ^^^^ required by this bound in `` +help: consider restricting type parameter `T` + | +LL | type IterBitsIter = impl std::iter::Iterator; + | +++++++++++++++++++ + +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 `` + --> $DIR/issue-60564.rs:16:8 + | +LL | E: std::fmt::Debug, + | ^^^^^^^^^^^^^^^ required by this bound in `` +help: consider restricting type parameter `E` + | +LL | type IterBitsIter = impl std::iter::Iterator; + | +++++++++++++++++ + +error[E0277]: the trait bound `u8: From` 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` is not implemented for `u8` + | + = note: required because of the requirements on the impl of `Into` for `T` + = note: required because of the requirements on the impl of `TryFrom` for `u8` + = note: required because of the requirements on the impl of `TryInto` for `T` +note: required by a bound in `` + --> $DIR/issue-60564.rs:15:11 + | +LL | + std::convert::TryInto, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `` +help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement + | +LL | type IterBitsIter = impl std::iter::Iterator where u8: From; + | +++++++++++++++++ + 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 = impl std::iter::Iterator; | ^ -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`. diff --git a/src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs new file mode 100644 index 0000000000000..449e9fbd0d847 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs @@ -0,0 +1,18 @@ +#![feature(type_alias_impl_trait)] + +trait Bar { + fn bar(&self); +} + +type FooFn = impl FnOnce(B); + +fn foo() -> FooFn { + fn mop(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 = unsafe { core::mem::zeroed() }; + boom(42); +} diff --git a/src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr new file mode 100644 index 0000000000000..e0005489d1e7c --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr @@ -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(bar: B) { bar.bar() } + | ^^^ required by this bound in `mop` +help: consider restricting type parameter `B` + | +LL | type FooFn = impl FnOnce(B); + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs b/src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs new file mode 100644 index 0000000000000..3b8470e4ae628 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs @@ -0,0 +1,23 @@ +#![feature(type_alias_impl_trait)] + +// build-pass + +trait Bar { + fn bar(&self); +} + +type FooFn = impl FnOnce(B); + +fn foo() -> FooFn { + fn mop(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 = unsafe { core::mem::zeroed() }; + boom(42); +} diff --git a/src/test/ui/type-alias-impl-trait/wf_check_closures.rs b/src/test/ui/type-alias-impl-trait/wf_check_closures.rs new file mode 100644 index 0000000000000..2c70696ffcf48 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/wf_check_closures.rs @@ -0,0 +1,17 @@ +#![feature(type_alias_impl_trait)] + +trait Bar { + fn bar(&self); +} + +type FooFn = impl FnOnce(); + +fn foo(bar: B) -> FooFn { + move || { bar.bar() } + //~^ ERROR the trait bound `B: Bar` is not satisfied +} + +fn main() { + let boom: FooFn = unsafe { core::mem::zeroed() }; + boom(); +} diff --git a/src/test/ui/type-alias-impl-trait/wf_check_closures.stderr b/src/test/ui/type-alias-impl-trait/wf_check_closures.stderr new file mode 100644 index 0000000000000..58ae8617b9bd9 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/wf_check_closures.stderr @@ -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(bar: B) -> FooFn { + | ^^^ required by this bound in `foo` +help: consider restricting type parameter `B` + | +LL | type FooFn = impl FnOnce(); + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 7a4ac84a902084e613f1668b9e08297f4901320a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 10 May 2022 14:32:12 +0000 Subject: [PATCH 2/2] For non-defining opaque type usage errors, don't try to also prove all trait bounds --- .../src/region_infer/opaque_types.rs | 107 +------------- .../rustc_trait_selection/src/opaque_types.rs | 101 +++++++++++++ .../generic_duplicate_param_use.rs | 1 - .../generic_duplicate_param_use.stderr | 18 +-- .../ui/type-alias-impl-trait/issue-60564.rs | 8 -- .../type-alias-impl-trait/issue-60564.stderr | 133 +----------------- .../issue-68368-non-defining-use.rs | 1 - .../issue-68368-non-defining-use.stderr | 14 +- ...ssue-69136-inner-lifetime-resolve-error.rs | 1 - ...-69136-inner-lifetime-resolve-error.stderr | 14 +- 10 files changed, 108 insertions(+), 290 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index f3d37a6be7b48..810737587912b 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,11 +1,8 @@ -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; use rustc_hir::def_id::DefId; use rustc_hir::OpaqueTyOrigin; use rustc_infer::infer::InferCtxt; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, TyCtxt, TypeFoldable}; -use rustc_span::Span; use rustc_trait_selection::opaque_types::InferCtxtExt; use super::RegionInferenceContext; @@ -107,21 +104,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { let opaque_type_key = OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs }; - let remapped_type = infcx.infer_opaque_definition_from_instantiation( + let ty = infcx.infer_opaque_definition_from_instantiation( opaque_type_key, universal_concrete_type, origin, ); - let ty = if check_opaque_type_parameter_valid( - infcx.tcx, - opaque_type_key, - origin, - concrete_type.span, - ) { - remapped_type - } else { - infcx.tcx.ty_error() - }; // Sometimes two opaque types are the same only after we remap the generic parameters // back to the opaque type definition. E.g. we may have `OpaqueType` mapped to `(X, Y)` // and `OpaqueType` mapped to `(Y, X)`, and those are the same, but we only know that @@ -184,95 +171,3 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } } - -fn check_opaque_type_parameter_valid( - tcx: TyCtxt<'_>, - opaque_type_key: OpaqueTypeKey<'_>, - origin: OpaqueTyOrigin, - span: Span, -) -> bool { - match origin { - // No need to check return position impl trait (RPIT) - // because for type and const parameters they are correct - // by construction: we convert - // - // fn foo() -> impl Trait - // - // into - // - // type Foo - // fn foo() -> Foo. - // - // For lifetime parameters we convert - // - // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> - // - // into - // - // type foo::<'p0..'pn>::Foo<'q0..'qm> - // fn foo() -> foo::<'static..'static>::Foo<'l0..'lm>. - // - // which would error here on all of the `'static` args. - OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true, - // Check these - OpaqueTyOrigin::TyAlias => {} - } - let opaque_generics = tcx.generics_of(opaque_type_key.def_id); - let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); - for (i, arg) in opaque_type_key.substs.iter().enumerate() { - let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - GenericArgKind::Lifetime(lt) if lt.is_static() => { - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_label( - tcx.def_span(opaque_generics.param_at(i, tcx).def_id), - "cannot use static lifetime; use a bound lifetime \ - instead or remove the lifetime parameter from the \ - opaque type", - ) - .emit(); - return false; - } - GenericArgKind::Lifetime(lt) => { - matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_)) - } - GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)), - }; - - if arg_is_param { - seen_params.entry(arg).or_default().push(i); - } else { - // Prevent `fn foo() -> Foo` from being defining. - let opaque_param = opaque_generics.param_at(i, tcx); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note( - tcx.def_span(opaque_param.def_id), - &format!( - "used non-generic {} `{}` for generic parameter", - opaque_param.kind.descr(), - arg, - ), - ) - .emit(); - return false; - } - } - - for (_, indices) in seen_params { - if indices.len() > 1 { - let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); - let spans: Vec<_> = indices - .into_iter() - .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) - .collect(); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note(spans, &format!("{} used multiple times", descr)) - .emit(); - return false; - } - } - true -} diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 74f5185d67236..238c6d9999075 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -82,6 +82,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { )); debug!(?definition_ty); + if !check_opaque_type_parameter_valid( + self.tcx, + opaque_type_key, + origin, + instantiated_ty.span, + ) { + return self.tcx.ty_error(); + } + // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs` // on stable and we'd break that. if let OpaqueTyOrigin::TyAlias = origin { @@ -148,6 +157,98 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } +fn check_opaque_type_parameter_valid( + tcx: TyCtxt<'_>, + opaque_type_key: OpaqueTypeKey<'_>, + origin: OpaqueTyOrigin, + span: Span, +) -> bool { + match origin { + // No need to check return position impl trait (RPIT) + // because for type and const parameters they are correct + // by construction: we convert + // + // fn foo() -> impl Trait + // + // into + // + // type Foo + // fn foo() -> Foo. + // + // For lifetime parameters we convert + // + // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> + // + // into + // + // type foo::<'p0..'pn>::Foo<'q0..'qm> + // fn foo() -> foo::<'static..'static>::Foo<'l0..'lm>. + // + // which would error here on all of the `'static` args. + OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true, + // Check these + OpaqueTyOrigin::TyAlias => {} + } + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); + for (i, arg) in opaque_type_key.substs.iter().enumerate() { + let arg_is_param = match arg.unpack() { + GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), + GenericArgKind::Lifetime(lt) if lt.is_static() => { + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_label( + tcx.def_span(opaque_generics.param_at(i, tcx).def_id), + "cannot use static lifetime; use a bound lifetime \ + instead or remove the lifetime parameter from the \ + opaque type", + ) + .emit(); + return false; + } + GenericArgKind::Lifetime(lt) => { + matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_)) + } + GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)), + }; + + if arg_is_param { + seen_params.entry(arg).or_default().push(i); + } else { + // Prevent `fn foo() -> Foo` from being defining. + let opaque_param = opaque_generics.param_at(i, tcx); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note( + tcx.def_span(opaque_param.def_id), + &format!( + "used non-generic {} `{}` for generic parameter", + opaque_param.kind.descr(), + arg, + ), + ) + .emit(); + return false; + } + } + + for (_, indices) in seen_params { + if indices.len() > 1 { + let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); + let spans: Vec<_> = indices + .into_iter() + .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) + .collect(); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note(spans, &format!("{} used multiple times", descr)) + .emit(); + return false; + } + } + true +} + struct ReverseMapper<'tcx> { tcx: TyCtxt<'tcx>, diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs index cf46add124cb3..093c1c231861f 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs @@ -15,7 +15,6 @@ type TwoConsts = impl Debug; fn one_ty(t: T) -> TwoTys { t //~^ ERROR non-defining opaque type use in defining scope - //~| ERROR `U` doesn't implement `Debug` } fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> { diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr index d661196e1bf19..b2edcc5526a4a 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr @@ -1,14 +1,3 @@ -error[E0277]: `U` doesn't implement `Debug` - --> $DIR/generic_duplicate_param_use.rs:16:5 - | -LL | t - | ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` - | -help: consider restricting type parameter `U` - | -LL | type TwoTys = impl Debug; - | +++++++++++++++++ - error: non-defining opaque type use in defining scope --> $DIR/generic_duplicate_param_use.rs:16:5 | @@ -22,7 +11,7 @@ LL | type TwoTys = impl Debug; | ^ ^ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:22:5 + --> $DIR/generic_duplicate_param_use.rs:21:5 | LL | t | ^ @@ -34,7 +23,7 @@ LL | type TwoLifetimes<'a, 'b> = impl Debug; | ^^ ^^ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:27:5 + --> $DIR/generic_duplicate_param_use.rs:26:5 | LL | t | ^ @@ -45,6 +34,5 @@ note: constant used multiple times LL | type TwoConsts = impl Debug; | ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.rs b/src/test/ui/type-alias-impl-trait/issue-60564.rs index 48d8dff2b9392..4fc7679311a2e 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60564.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60564.rs @@ -19,14 +19,6 @@ where fn iter_bits(self, n: u8) -> Self::BitsIter { (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 `>::Error == E` - //~| ERROR no implementation for `T >> T` - //~| ERROR no implementation for `T & T` - //~| ERROR the trait bound `T: From` - //~| ERROR the trait bound `T: Copy` is not satisfied - //~| ERROR `E` doesn't implement `Debug` - //~| ERROR the trait bound `u8: From` is not satisfied } } diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.stderr b/src/test/ui/type-alias-impl-trait/issue-60564.stderr index 4ef53973a7c74..bbc93657be32f 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60564.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60564.stderr @@ -1,132 +1,3 @@ -error[E0271]: type mismatch resolving `<[closure@$DIR/issue-60564.rs:20:28: 20:100] as FnOnce<(u8,)>>::Output == I` - --> $DIR/issue-60564.rs:20:9 - | -LL | type IterBitsIter = impl std::iter::Iterator; - | - this type parameter -... -LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found type parameter `I` - | - = note: expected type `u8` - found type parameter `I` - = note: required because of the requirements on the impl of `Iterator` for `Map>, [closure@$DIR/issue-60564.rs:20:28: 20:100]>` - -error[E0271]: type mismatch resolving `>::Error == E` - --> $DIR/issue-60564.rs:20:9 - | -LL | type IterBitsIter = impl std::iter::Iterator; - | - 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 `` - --> $DIR/issue-60564.rs:15:37 - | -LL | + std::convert::TryInto, - | ^^^^^^^^^ required by this bound in `` - -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 `` - --> $DIR/issue-60564.rs:12:8 - | -LL | T: std::ops::Shr - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `` -help: consider restricting type parameter `T` - | -LL | type IterBitsIter = impl std::iter::Iterator; - | +++++++++++++++ - -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 `` - --> $DIR/issue-60564.rs:13:11 - | -LL | + std::ops::BitAnd - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `` -help: consider restricting type parameter `T` - | -LL | type IterBitsIter = impl std::iter::Iterator; - | ++++++++++++++++++ - -error[E0277]: the trait bound `T: From` 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` is not implemented for `T` - | -note: required by a bound in `` - --> $DIR/issue-60564.rs:14:11 - | -LL | + std::convert::From - | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `` -help: consider restricting type parameter `T` - | -LL | type IterBitsIter, E, I> = impl std::iter::Iterator; - | ++++++++++++++++++++++++ - -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 `` - --> $DIR/issue-60564.rs:10:9 - | -LL | impl IterBits for T - | ^^^^ required by this bound in `` -help: consider restricting type parameter `T` - | -LL | type IterBitsIter = impl std::iter::Iterator; - | +++++++++++++++++++ - -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 `` - --> $DIR/issue-60564.rs:16:8 - | -LL | E: std::fmt::Debug, - | ^^^^^^^^^^^^^^^ required by this bound in `` -help: consider restricting type parameter `E` - | -LL | type IterBitsIter = impl std::iter::Iterator; - | +++++++++++++++++ - -error[E0277]: the trait bound `u8: From` 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` is not implemented for `u8` - | - = note: required because of the requirements on the impl of `Into` for `T` - = note: required because of the requirements on the impl of `TryFrom` for `u8` - = note: required because of the requirements on the impl of `TryInto` for `T` -note: required by a bound in `` - --> $DIR/issue-60564.rs:15:11 - | -LL | + std::convert::TryInto, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `` -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement - | -LL | type IterBitsIter = impl std::iter::Iterator where u8: From; - | +++++++++++++++++ - error: non-defining opaque type use in defining scope --> $DIR/issue-60564.rs:20:9 | @@ -139,7 +10,5 @@ note: used non-generic type `u8` for generic parameter LL | type IterBitsIter = impl std::iter::Iterator; | ^ -error: aborting due to 9 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs index bffff8787e4a2..b50462bf237bb 100644 --- a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs +++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs @@ -8,7 +8,6 @@ type Alias<'a, U> = impl Trait; fn f<'a>() -> Alias<'a, ()> {} //~^ ERROR non-defining opaque type use in defining scope -//~| ERROR the trait bound `(): Trait` is not satisfied fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr index b79d638ad9951..8059621b61a09 100644 --- a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr @@ -1,14 +1,3 @@ -error[E0277]: the trait bound `(): Trait` is not satisfied - --> $DIR/issue-68368-non-defining-use.rs:9:29 - | -LL | fn f<'a>() -> Alias<'a, ()> {} - | ^^ the trait `Trait` is not implemented for `()` - | -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement - | -LL | type Alias<'a, U> = impl Trait where (): Trait; - | ++++++++++++++++++ - error: non-defining opaque type use in defining scope --> $DIR/issue-68368-non-defining-use.rs:9:29 | @@ -21,6 +10,5 @@ note: used non-generic type `()` for generic parameter LL | type Alias<'a, U> = impl Trait; | ^ -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs index b0de8bf6aa4f2..428454bc04844 100644 --- a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs +++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs @@ -19,6 +19,5 @@ type Return = impl WithAssoc; fn my_fun() -> Return<()> {} //~^ ERROR non-defining opaque type use in defining scope -//~| ERROR non-defining opaque type use in defining scope fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr index d038fbbe1b40a..7b50c8af26e5f 100644 --- a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr @@ -26,18 +26,6 @@ note: used non-generic type `()` for generic parameter LL | type Return = impl WithAssoc; | ^ -error: non-defining opaque type use in defining scope - --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27 - | -LL | fn my_fun() -> Return<()> {} - | ^^ - | -note: used non-generic type `()` for generic parameter - --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13 - | -LL | type Return = impl WithAssoc; - | ^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0261`.