Skip to content

Commit 8e09acd

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

File tree

4 files changed

+54
-17
lines changed

4 files changed

+54
-17
lines changed

compiler/rustc_hir_analysis/src/check/mod.rs

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub mod intrinsic;
7070
mod region;
7171
pub mod wfcheck;
7272

73+
use std::borrow::Cow;
7374
use std::num::NonZero;
7475

7576
pub use check::{check_abi, check_custom_abi};
@@ -86,7 +87,7 @@ use rustc_middle::query::Providers;
8687
use rustc_middle::ty::error::{ExpectedFound, TypeError};
8788
use rustc_middle::ty::print::with_types_for_signature;
8889
use rustc_middle::ty::{
89-
self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypingMode,
90+
self, GenericArgs, GenericArgsRef, OutlivesPredicate, Region, Ty, TyCtxt, 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,20 +353,23 @@ 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+
.filter(|p| !p.kind.is_synthetic())
369+
.map(|p| match tcx.mk_param_from_def(p).kind() {
370+
ty::GenericArgKind::Type(ty) => {
371+
let bounds =
372+
types.get(&ty).map(Cow::Borrowed).unwrap_or_else(|| Cow::Owned(Vec::new()));
368373
let mut bounds_str = vec![];
369374
for bound in bounds.iter().copied() {
370375
let mut projections_str = vec![];
@@ -377,7 +382,11 @@ fn bounds_from_generic_predicates<'tcx>(
377382
projections_str.push(format!("{} = {}", name, p.term));
378383
}
379384
}
380-
let bound_def_path = tcx.def_path_str(bound);
385+
let bound_def_path = if tcx.is_lang_item(bound, LangItem::MetaSized) {
386+
String::from("?Sized")
387+
} else {
388+
tcx.def_path_str(bound)
389+
};
381390
if projections_str.is_empty() {
382391
where_clauses.push(format!("{}: {}", ty, bound_def_path));
383392
} else {
@@ -393,23 +402,44 @@ fn bounds_from_generic_predicates<'tcx>(
393402
} else {
394403
format!("{}: {}", ty, bounds_str.join(" + "))
395404
}
396-
} else {
397-
ty.to_string()
405+
}
406+
ty::GenericArgKind::Const(ct) => {
407+
format!("const {ct}: {}", tcx.type_of(p.def_id).skip_binder())
408+
}
409+
ty::GenericArgKind::Lifetime(region) => {
410+
if let Some(v) = regions.get(&region)
411+
&& !v.is_empty()
412+
{
413+
format!(
414+
"{region}: {}",
415+
v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + ")
416+
)
417+
} else {
418+
region.to_string()
419+
}
398420
}
399421
})
400422
.collect::<Vec<_>>();
401423
for (ty, bounds) in types.into_iter() {
402424
if !matches!(ty.kind(), ty::Param(_)) {
403425
// Avoid suggesting the following:
404426
// 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-
);
427+
where_clauses.extend(bounds.into_iter().map(|bound| {
428+
format!(
429+
"{}: {}",
430+
ty,
431+
if tcx.is_lang_item(bound, LangItem::MetaSized) {
432+
String::from("?Sized")
433+
} else {
434+
tcx.def_path_str(bound)
435+
}
436+
)
437+
}));
408438
}
409439
}
410440

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

414444
let where_clauses = if where_clauses.is_empty() {
415445
"".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)