diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 63d0f400aefc4..e70d5505aae36 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -70,6 +70,7 @@ pub mod intrinsic; mod region; pub mod wfcheck; +use std::borrow::Cow; use std::num::NonZero; pub use check::{check_abi, check_custom_abi}; @@ -86,7 +87,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::print::with_types_for_signature; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypingMode, + self, GenericArgs, GenericArgsRef, OutlivesPredicate, Region, Ty, TyCtxt, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; @@ -335,6 +336,7 @@ fn bounds_from_generic_predicates<'tcx>( assoc: ty::AssocItem, ) -> (String, String) { let mut types: FxIndexMap, Vec> = FxIndexMap::default(); + let mut regions: FxIndexMap, Vec>> = FxIndexMap::default(); let mut projections = vec![]; for (predicate, _) in predicates { debug!("predicate {:?}", predicate); @@ -351,20 +353,23 @@ fn bounds_from_generic_predicates<'tcx>( ty::ClauseKind::Projection(projection_pred) => { projections.push(bound_predicate.rebind(projection_pred)); } + ty::ClauseKind::RegionOutlives(OutlivesPredicate(a, b)) => { + regions.entry(a).or_default().push(b); + } _ => {} } } let mut where_clauses = vec![]; let generics = tcx.generics_of(assoc.def_id); - let types_str = generics + let params = generics .own_params .iter() - .filter(|p| matches!(p.kind, GenericParamDefKind::Type { synthetic: false, .. })) - .map(|p| { - // we just checked that it's a type, so the unwrap can't fail - let ty = tcx.mk_param_from_def(p).as_type().unwrap(); - if let Some(bounds) = types.get(&ty) { + .filter(|p| !p.kind.is_synthetic()) + .map(|p| match tcx.mk_param_from_def(p).kind() { + ty::GenericArgKind::Type(ty) => { + let bounds = + types.get(&ty).map(Cow::Borrowed).unwrap_or_else(|| Cow::Owned(Vec::new())); let mut bounds_str = vec![]; for bound in bounds.iter().copied() { let mut projections_str = vec![]; @@ -377,7 +382,11 @@ fn bounds_from_generic_predicates<'tcx>( projections_str.push(format!("{} = {}", name, p.term)); } } - let bound_def_path = tcx.def_path_str(bound); + let bound_def_path = if tcx.is_lang_item(bound, LangItem::MetaSized) { + String::from("?Sized") + } else { + tcx.def_path_str(bound) + }; if projections_str.is_empty() { where_clauses.push(format!("{}: {}", ty, bound_def_path)); } else { @@ -393,8 +402,21 @@ fn bounds_from_generic_predicates<'tcx>( } else { format!("{}: {}", ty, bounds_str.join(" + ")) } - } else { - ty.to_string() + } + ty::GenericArgKind::Const(ct) => { + format!("const {ct}: {}", tcx.type_of(p.def_id).skip_binder()) + } + ty::GenericArgKind::Lifetime(region) => { + if let Some(v) = regions.get(®ion) + && !v.is_empty() + { + format!( + "{region}: {}", + v.into_iter().map(Region::to_string).collect::>().join(" + ") + ) + } else { + region.to_string() + } } }) .collect::>(); @@ -409,7 +431,7 @@ fn bounds_from_generic_predicates<'tcx>( } let generics = - if types_str.is_empty() { "".to_string() } else { format!("<{}>", types_str.join(", ")) }; + if params.is_empty() { "".to_string() } else { format!("<{}>", params.join(", ")) }; let where_clauses = if where_clauses.is_empty() { "".to_string() diff --git a/tests/ui/suggestions/apitit-unimplemented-method.rs b/tests/ui/suggestions/apitit-unimplemented-method.rs index b182e1939b3e3..c0cd709e2300a 100644 --- a/tests/ui/suggestions/apitit-unimplemented-method.rs +++ b/tests/ui/suggestions/apitit-unimplemented-method.rs @@ -4,9 +4,12 @@ extern crate dep; use dep::*; struct Local; + impl Trait for Local {} //~^ ERROR not all trait items implemented //~| HELP implement the missing item: `fn foo(_: impl Sized) { todo!() }` -//~| HELP implement the missing item: `fn bar(_: impl Sized) { todo!() }` +//~| HELP implement the missing item: `fn bar(_: impl Sized) where Foo: MetaSized { todo!() }` +//~| HELP implement the missing item: `fn baz() { todo!() }` +//~| HELP implement the missing item: `fn quux<'a: 'b, 'b, T>() where T: ?Sized { todo!() }` fn main() {} diff --git a/tests/ui/suggestions/apitit-unimplemented-method.stderr b/tests/ui/suggestions/apitit-unimplemented-method.stderr index b309a64e95829..1f2e0ea2cad94 100644 --- a/tests/ui/suggestions/apitit-unimplemented-method.stderr +++ b/tests/ui/suggestions/apitit-unimplemented-method.stderr @@ -1,11 +1,13 @@ -error[E0046]: not all trait items implemented, missing: `foo`, `bar` - --> $DIR/apitit-unimplemented-method.rs:7:1 +error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `baz`, `quux` + --> $DIR/apitit-unimplemented-method.rs:8:1 | LL | impl Trait for Local {} - | ^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar` in implementation + | ^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar`, `baz`, `quux` in implementation | = help: implement the missing item: `fn foo(_: impl Sized) { todo!() }` - = help: implement the missing item: `fn bar(_: impl Sized) { todo!() }` + = help: implement the missing item: `fn bar(_: impl Sized) where Foo: MetaSized { todo!() }` + = help: implement the missing item: `fn baz() { todo!() }` + = help: implement the missing item: `fn quux<'a: 'b, 'b, T>() where T: ?Sized { todo!() }` error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/auxiliary/dep.rs b/tests/ui/suggestions/auxiliary/dep.rs index ac0de418313c0..c28c8b8a52f51 100644 --- a/tests/ui/suggestions/auxiliary/dep.rs +++ b/tests/ui/suggestions/auxiliary/dep.rs @@ -1,4 +1,16 @@ +#![feature(sized_hierarchy)] + +use std::marker::MetaSized; + +pub struct Foo { + inner: T, +} + pub trait Trait { fn foo(_: impl Sized); - fn bar(_: impl Sized); + fn bar(_: impl Sized) + where + Foo: MetaSized; + fn baz<'a, const N: usize>(); + fn quux<'a: 'b, 'b, T: ?Sized>(); }