about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs44
-rw-r--r--tests/ui/suggestions/apitit-unimplemented-method.rs5
-rw-r--r--tests/ui/suggestions/apitit-unimplemented-method.stderr10
-rw-r--r--tests/ui/suggestions/auxiliary/dep.rs14
4 files changed, 56 insertions, 17 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 63d0f400aef..e70d5505aae 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<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);
@@ -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(&region)
+                    && !v.is_empty()
+                {
+                    format!(
+                        "{region}: {}",
+                        v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + ")
+                    )
+                } else {
+                    region.to_string()
+                }
             }
         })
         .collect::<Vec<_>>();
@@ -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 b182e1939b3..c0cd709e230 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<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() {}
diff --git a/tests/ui/suggestions/apitit-unimplemented-method.stderr b/tests/ui/suggestions/apitit-unimplemented-method.stderr
index b309a64e958..1f2e0ea2cad 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<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
 
diff --git a/tests/ui/suggestions/auxiliary/dep.rs b/tests/ui/suggestions/auxiliary/dep.rs
index ac0de418313..c28c8b8a52f 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<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>();
 }