Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 33 additions & 11 deletions compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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;
Expand Down Expand Up @@ -335,6 +336,7 @@ fn bounds_from_generic_predicates<'tcx>(
assoc: ty::AssocItem,
) -> (String, String) {
let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default();
let mut regions: FxIndexMap<Region<'tcx>, Vec<Region<'tcx>>> = FxIndexMap::default();
let mut projections = vec![];
for (predicate, _) in predicates {
debug!("predicate {:?}", predicate);
Expand All @@ -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![];
Expand All @@ -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 {
Expand All @@ -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(&region)
&& !v.is_empty()
{
format!(
"{region}: {}",
v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + ")
)
} else {
region.to_string()
}
}
})
.collect::<Vec<_>>();
Expand All @@ -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()
Expand Down
5 changes: 4 additions & 1 deletion tests/ui/suggestions/apitit-unimplemented-method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(_: impl Sized) { todo!() }`
//~| HELP implement the missing item: `fn bar<T>(_: impl Sized) where Foo<T>: MetaSized { todo!() }`
//~| HELP implement the missing item: `fn baz<const N: usize>() { todo!() }`
//~| HELP implement the missing item: `fn quux<'a: 'b, 'b, T>() where T: ?Sized { todo!() }`

fn main() {}
10 changes: 6 additions & 4 deletions tests/ui/suggestions/apitit-unimplemented-method.stderr
Original file line number Diff line number Diff line change
@@ -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<T>(_: impl Sized) { todo!() }`
= help: implement the missing item: `fn bar<T>(_: impl Sized) where Foo<T>: MetaSized { todo!() }`
= help: implement the missing item: `fn baz<const N: usize>() { todo!() }`
= help: implement the missing item: `fn quux<'a: 'b, 'b, T>() where T: ?Sized { todo!() }`

error: aborting due to 1 previous error

Expand Down
14 changes: 13 additions & 1 deletion tests/ui/suggestions/auxiliary/dep.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
#![feature(sized_hierarchy)]

use std::marker::MetaSized;

pub struct Foo<T> {
inner: T,
}

pub trait Trait {
fn foo(_: impl Sized);
fn bar<T>(_: impl Sized);
fn bar<T>(_: impl Sized)
where
Foo<T>: MetaSized;
fn baz<'a, const N: usize>();
fn quux<'a: 'b, 'b, T: ?Sized>();
}
Loading