Skip to content

Commit f336c23

Browse files
committed
handle const generics, ?Sized, early bound lifetimes
1 parent f4665ab commit f336c23

File tree

4 files changed

+82
-37
lines changed

4 files changed

+82
-37
lines changed

compiler/rustc_hir_analysis/src/check/mod.rs

Lines changed: 72 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ use rustc_middle::query::Providers;
8686
use rustc_middle::ty::error::{ExpectedFound, TypeError};
8787
use rustc_middle::ty::print::with_types_for_signature;
8888
use rustc_middle::ty::{
89-
self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypingMode,
89+
self, GenericArgs, GenericArgsRef, GenericParamDefKind, OutlivesPredicate, Region, Ty, TyCtxt,
90+
TypingMode,
9091
};
9192
use rustc_middle::{bug, span_bug};
9293
use rustc_session::parse::feature_err;
@@ -335,6 +336,7 @@ fn bounds_from_generic_predicates<'tcx>(
335336
assoc: ty::AssocItem,
336337
) -> (String, String) {
337338
let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default();
339+
let mut regions: FxIndexMap<Region<'tcx>, Vec<Region<'tcx>>> = FxIndexMap::default();
338340
let mut projections = vec![];
339341
for (predicate, _) in predicates {
340342
debug!("predicate {:?}", predicate);
@@ -351,65 +353,101 @@ fn bounds_from_generic_predicates<'tcx>(
351353
ty::ClauseKind::Projection(projection_pred) => {
352354
projections.push(bound_predicate.rebind(projection_pred));
353355
}
356+
ty::ClauseKind::RegionOutlives(OutlivesPredicate(a, b)) => {
357+
regions.entry(a).or_default().push(b);
358+
}
354359
_ => {}
355360
}
356361
}
357362

358363
let mut where_clauses = vec![];
359364
let generics = tcx.generics_of(assoc.def_id);
360-
let types_str = generics
365+
let params = generics
361366
.own_params
362367
.iter()
363-
.filter(|p| matches!(p.kind, GenericParamDefKind::Type { synthetic: false, .. }))
364-
.map(|p| {
365-
// we just checked that it's a type, so the unwrap can't fail
366-
let ty = tcx.mk_param_from_def(p).as_type().unwrap();
367-
if let Some(bounds) = types.get(&ty) {
368-
let mut bounds_str = vec![];
369-
for bound in bounds.iter().copied() {
370-
let mut projections_str = vec![];
371-
for projection in &projections {
372-
let p = projection.skip_binder();
373-
if bound == tcx.parent(p.projection_term.def_id)
374-
&& p.projection_term.self_ty() == ty
375-
{
376-
let name = tcx.item_name(p.projection_term.def_id);
377-
projections_str.push(format!("{} = {}", name, p.term));
368+
.filter(|p| !matches!(p.kind, GenericParamDefKind::Type { synthetic: true, .. }))
369+
.map(|p| match tcx.mk_param_from_def(p) {
370+
x if let Some(ty) = x.as_type() => {
371+
if let Some(bounds) = types.get(&ty) {
372+
let mut bounds_str = vec![];
373+
for bound in bounds.iter().copied() {
374+
let mut projections_str = vec![];
375+
for projection in &projections {
376+
let p = projection.skip_binder();
377+
if bound == tcx.parent(p.projection_term.def_id)
378+
&& p.projection_term.self_ty() == ty
379+
{
380+
let name = tcx.item_name(p.projection_term.def_id);
381+
projections_str.push(format!("{} = {}", name, p.term));
382+
}
383+
}
384+
let bound_def_path = if tcx.is_lang_item(bound, LangItem::MetaSized) {
385+
String::from("?Sized")
386+
} else {
387+
tcx.def_path_str(bound)
388+
};
389+
if projections_str.is_empty() {
390+
where_clauses.push(format!("{}: {}", ty, bound_def_path));
391+
} else {
392+
bounds_str.push(format!(
393+
"{}<{}>",
394+
bound_def_path,
395+
projections_str.join(", ")
396+
));
378397
}
379398
}
380-
let bound_def_path = tcx.def_path_str(bound);
381-
if projections_str.is_empty() {
382-
where_clauses.push(format!("{}: {}", ty, bound_def_path));
399+
if bounds_str.is_empty() {
400+
ty.to_string()
383401
} else {
384-
bounds_str.push(format!(
385-
"{}<{}>",
386-
bound_def_path,
387-
projections_str.join(", ")
388-
));
402+
format!("{}: {}", ty, bounds_str.join(" + "))
389403
}
390-
}
391-
if bounds_str.is_empty() {
404+
} else {
392405
ty.to_string()
406+
}
407+
}
408+
x if let Some(ct) = x.as_const() => {
409+
format!("const {ct}: {}", tcx.type_of(p.def_id).skip_binder())
410+
}
411+
x if let Some(region) = x.as_region() => {
412+
if let Some(v) = regions.get(&region)
413+
&& !v.is_empty()
414+
{
415+
format!(
416+
"{region}: {}",
417+
v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + ")
418+
)
393419
} else {
394-
format!("{}: {}", ty, bounds_str.join(" + "))
420+
region.to_string()
395421
}
396-
} else {
397-
ty.to_string()
422+
}
423+
_ if let Some(span) = tcx.def_ident_span(assoc.def_id) => {
424+
span_bug!(span, "GenericParamDef isn't a type, const, or region");
425+
}
426+
_ => {
427+
bug!("GenericParamDef isn't a type, const, or region");
398428
}
399429
})
400430
.collect::<Vec<_>>();
401431
for (ty, bounds) in types.into_iter() {
402432
if !matches!(ty.kind(), ty::Param(_)) {
403433
// Avoid suggesting the following:
404434
// fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
405-
where_clauses.extend(
406-
bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))),
407-
);
435+
where_clauses.extend(bounds.into_iter().map(|bound| {
436+
format!(
437+
"{}: {}",
438+
ty,
439+
if tcx.is_lang_item(bound, LangItem::MetaSized) {
440+
String::from("?Sized")
441+
} else {
442+
tcx.def_path_str(bound)
443+
}
444+
)
445+
}));
408446
}
409447
}
410448

411449
let generics =
412-
if types_str.is_empty() { "".to_string() } else { format!("<{}>", types_str.join(", ")) };
450+
if params.is_empty() { "".to_string() } else { format!("<{}>", params.join(", ")) };
413451

414452
let where_clauses = if where_clauses.is_empty() {
415453
"".to_string()

tests/ui/suggestions/apitit-unimplemented-method.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ extern crate dep;
44
use dep::*;
55

66
struct Local;
7+
78
impl Trait for Local {}
89
//~^ ERROR not all trait items implemented
910
//~| HELP implement the missing item: `fn foo(_: impl Sized) { todo!() }`
1011
//~| HELP implement the missing item: `fn bar<T>(_: impl Sized) { todo!() }`
12+
//~| HELP implement the missing item: `fn baz<const N: usize>() { todo!() }`
13+
//~| HELP implement the missing item: `fn quux<'a: 'b, 'b, T>() where T: ?Sized { todo!() }`
1114

1215
fn main() {}

tests/ui/suggestions/apitit-unimplemented-method.stderr

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
error[E0046]: not all trait items implemented, missing: `foo`, `bar`
2-
--> $DIR/apitit-unimplemented-method.rs:7:1
1+
error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `baz`, `quux`
2+
--> $DIR/apitit-unimplemented-method.rs:8:1
33
|
44
LL | impl Trait for Local {}
5-
| ^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar` in implementation
5+
| ^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar`, `baz`, `quux` in implementation
66
|
77
= help: implement the missing item: `fn foo(_: impl Sized) { todo!() }`
88
= help: implement the missing item: `fn bar<T>(_: impl Sized) { todo!() }`
9+
= help: implement the missing item: `fn baz<const N: usize>() { todo!() }`
10+
= help: implement the missing item: `fn quux<'a: 'b, 'b, T>() where T: ?Sized { todo!() }`
911

1012
error: aborting due to 1 previous error
1113

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
pub trait Trait {
22
fn foo(_: impl Sized);
33
fn bar<T>(_: impl Sized);
4+
fn baz<'a, const N: usize>();
5+
fn quux<'a: 'b, 'b, T: ?Sized>();
46
}

0 commit comments

Comments
 (0)