From 204c5162939760c7b16af7d42ec5ae8590dd8ae7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 19 Apr 2023 17:20:28 +0000 Subject: [PATCH 1/3] Substitute missing item suggestion correctly --- .../rustc_hir_analysis/src/check/check.rs | 2 +- compiler/rustc_hir_analysis/src/check/mod.rs | 31 ++++++++++++++----- tests/ui/async-await/issue-74047.stderr | 2 +- tests/ui/issues/issue-3344.stderr | 2 +- tests/ui/suggestions/missing-assoc-fn.stderr | 2 +- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 0c54fd70c9b..51ec5dd7a28 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -863,7 +863,7 @@ fn check_impl_items_against_trait<'tcx>( if !missing_items.is_empty() { let full_impl_span = tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(impl_id)); - missing_items_err(tcx, tcx.def_span(impl_id), &missing_items, full_impl_span); + missing_items_err(tcx, impl_id, &missing_items, full_impl_span); } if let Some(missing_items) = must_implement_one_of { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 8fe4c44fca4..f147b4657cc 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -198,7 +198,7 @@ fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_imp fn missing_items_err( tcx: TyCtxt<'_>, - impl_span: Span, + impl_def_id: LocalDefId, missing_items: &[ty::AssocItem], full_impl_span: Span, ) { @@ -211,6 +211,7 @@ fn missing_items_err( .collect::>() .join("`, `"); + let impl_span = tcx.def_span(impl_def_id); let mut err = struct_span_err!( tcx.sess, impl_span, @@ -229,7 +230,11 @@ fn missing_items_err( tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); for &trait_item in missing_items { - let snippet = suggestion_signature(trait_item, tcx); + let snippet = suggestion_signature( + tcx, + trait_item, + tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity(), + ); let code = format!("{}{}\n{}", padding, snippet, padding); let msg = format!("implement the missing item: `{snippet}`"); let appl = Applicability::HasPlaceholders; @@ -301,11 +306,11 @@ fn default_body_is_unstable( /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, - predicates: ty::GenericPredicates<'tcx>, + predicates: impl IntoIterator, Span)>, ) -> (String, String) { let mut types: FxHashMap, Vec> = FxHashMap::default(); let mut projections = vec![]; - for (predicate, _) in predicates.predicates { + for (predicate, _) in predicates { debug!("predicate {:?}", predicate); let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { @@ -367,7 +372,7 @@ fn fn_sig_suggestion<'tcx>( tcx: TyCtxt<'tcx>, sig: ty::FnSig<'tcx>, ident: Ident, - predicates: ty::GenericPredicates<'tcx>, + predicates: impl IntoIterator, Span)>, assoc: ty::AssocItem, ) -> String { let args = sig @@ -436,7 +441,17 @@ pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { /// Return placeholder code for the given associated item. /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a /// structured suggestion. -fn suggestion_signature(assoc: ty::AssocItem, tcx: TyCtxt<'_>) -> String { +fn suggestion_signature<'tcx>( + tcx: TyCtxt<'tcx>, + assoc: ty::AssocItem, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> String { + let substs = ty::InternalSubsts::identity_for_item(tcx, assoc.def_id).rebase_onto( + tcx, + assoc.container_id(tcx), + impl_trait_ref.with_self_ty(tcx, tcx.types.self_param).substs, + ); + match assoc.kind { ty::AssocKind::Fn => { // We skip the binder here because the binder would deanonymize all @@ -445,9 +460,9 @@ fn suggestion_signature(assoc: ty::AssocItem, tcx: TyCtxt<'_>) -> String { // regions just fine, showing `fn(&MyType)`. fn_sig_suggestion( tcx, - tcx.fn_sig(assoc.def_id).subst_identity().skip_binder(), + tcx.fn_sig(assoc.def_id).subst(tcx, substs).skip_binder(), assoc.ident(tcx), - tcx.predicates_of(assoc.def_id), + tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs), assoc, ) } diff --git a/tests/ui/async-await/issue-74047.stderr b/tests/ui/async-await/issue-74047.stderr index 28174825d8b..9ba73f76923 100644 --- a/tests/ui/async-await/issue-74047.stderr +++ b/tests/ui/async-await/issue-74047.stderr @@ -5,7 +5,7 @@ LL | impl TryFrom for MyStream {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Error`, `try_from` in implementation | = help: implement the missing item: `type Error = Type;` - = help: implement the missing item: `fn try_from(_: T) -> Result>::Error> { todo!() }` + = help: implement the missing item: `fn try_from(_: OtherStream) -> Result>::Error> { todo!() }` error: aborting due to previous error diff --git a/tests/ui/issues/issue-3344.stderr b/tests/ui/issues/issue-3344.stderr index 11d5999672e..e849f5d0490 100644 --- a/tests/ui/issues/issue-3344.stderr +++ b/tests/ui/issues/issue-3344.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `partial_cmp` LL | impl PartialOrd for Thing { | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `partial_cmp` in implementation | - = help: implement the missing item: `fn partial_cmp(&self, _: &Rhs) -> Option { todo!() }` + = help: implement the missing item: `fn partial_cmp(&self, _: &Thing) -> Option { todo!() }` error: aborting due to previous error diff --git a/tests/ui/suggestions/missing-assoc-fn.stderr b/tests/ui/suggestions/missing-assoc-fn.stderr index 136ec2152e0..77fa9562878 100644 --- a/tests/ui/suggestions/missing-assoc-fn.stderr +++ b/tests/ui/suggestions/missing-assoc-fn.stderr @@ -28,7 +28,7 @@ error[E0046]: not all trait items implemented, missing: `from_iter` LL | impl FromIterator<()> for X { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `from_iter` in implementation | - = help: implement the missing item: `fn from_iter(_: T) -> Self where T: IntoIterator, std::iter::IntoIterator::Item = A { todo!() }` + = help: implement the missing item: `fn from_iter(_: T) -> Self where T: IntoIterator, std::iter::IntoIterator::Item = () { todo!() }` error: aborting due to 3 previous errors From 73038d3a640f563e47554d781e958f6e4ed08bc2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 19 Apr 2023 17:22:16 +0000 Subject: [PATCH 2/3] Make missing impl item suggestions more obvious that they're missing --- compiler/rustc_hir_analysis/src/check/mod.rs | 4 ++-- tests/ui/async-await/issue-74047.stderr | 2 +- tests/ui/missing/missing-items/m2.stderr | 2 +- tests/ui/span/issue-23729.stderr | 2 +- tests/ui/span/issue-23827.stderr | 2 +- tests/ui/span/issue-24356.stderr | 2 +- ...missing-assoc-fn-applicable-suggestions.rs | 16 ++++++++++++++ ...sing-assoc-fn-applicable-suggestions.fixed | 21 ------------------- ...missing-assoc-fn-applicable-suggestions.rs | 21 ++++++++----------- ...ing-assoc-fn-applicable-suggestions.stderr | 20 ++++++++---------- 10 files changed, 41 insertions(+), 51 deletions(-) create mode 100644 tests/ui/suggestions/auxiliary/missing-assoc-fn-applicable-suggestions.rs delete mode 100644 tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index f147b4657cc..9fba538f12e 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -466,10 +466,10 @@ fn suggestion_signature<'tcx>( assoc, ) } - ty::AssocKind::Type => format!("type {} = Type;", assoc.name), + ty::AssocKind::Type => format!("type {} = /* Type */;", assoc.name), ty::AssocKind::Const => { let ty = tcx.type_of(assoc.def_id).subst_identity(); - let val = ty_kind_suggestion(ty).unwrap_or("value"); + let val = ty_kind_suggestion(ty).unwrap_or("todo!()"); format!("const {}: {} = {};", assoc.name, ty, val) } } diff --git a/tests/ui/async-await/issue-74047.stderr b/tests/ui/async-await/issue-74047.stderr index 9ba73f76923..6bdb9ded482 100644 --- a/tests/ui/async-await/issue-74047.stderr +++ b/tests/ui/async-await/issue-74047.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `Error`, `try_from` LL | impl TryFrom for MyStream {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Error`, `try_from` in implementation | - = help: implement the missing item: `type Error = Type;` + = help: implement the missing item: `type Error = /* Type */;` = help: implement the missing item: `fn try_from(_: OtherStream) -> Result>::Error> { todo!() }` error: aborting due to previous error diff --git a/tests/ui/missing/missing-items/m2.stderr b/tests/ui/missing/missing-items/m2.stderr index d18fb443aa4..835c9b2aa48 100644 --- a/tests/ui/missing/missing-items/m2.stderr +++ b/tests/ui/missing/missing-items/m2.stderr @@ -5,7 +5,7 @@ LL | impl m1::X for X { | ^^^^^^^^^^^^^^^^ missing `CONSTANT`, `Type`, `method`, `method2`, `method3`, `method4`, `method5` in implementation | = help: implement the missing item: `const CONSTANT: u32 = 42;` - = help: implement the missing item: `type Type = Type;` + = help: implement the missing item: `type Type = /* Type */;` = help: implement the missing item: `fn method(&self, _: String) -> ::Type { todo!() }` = help: implement the missing item: `fn method2(self: Box, _: String) -> ::Type { todo!() }` = help: implement the missing item: `fn method3(_: &Self, _: String) -> ::Type { todo!() }` diff --git a/tests/ui/span/issue-23729.stderr b/tests/ui/span/issue-23729.stderr index f88ce6c88db..cd854e61f2f 100644 --- a/tests/ui/span/issue-23729.stderr +++ b/tests/ui/span/issue-23729.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `Item` LL | impl Iterator for Recurrence { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Item` in implementation | - = help: implement the missing item: `type Item = Type;` + = help: implement the missing item: `type Item = /* Type */;` error: aborting due to previous error diff --git a/tests/ui/span/issue-23827.stderr b/tests/ui/span/issue-23827.stderr index 46a820f1b76..83a9e8c9b98 100644 --- a/tests/ui/span/issue-23827.stderr +++ b/tests/ui/span/issue-23827.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `Output` LL | impl FnOnce<(C,)> for Prototype { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Output` in implementation | - = help: implement the missing item: `type Output = Type;` + = help: implement the missing item: `type Output = /* Type */;` error: aborting due to previous error diff --git a/tests/ui/span/issue-24356.stderr b/tests/ui/span/issue-24356.stderr index a1f9b255020..cf666e8b4a7 100644 --- a/tests/ui/span/issue-24356.stderr +++ b/tests/ui/span/issue-24356.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `Target` LL | impl Deref for Thing { | ^^^^^^^^^^^^^^^^^^^^ missing `Target` in implementation | - = help: implement the missing item: `type Target = Type;` + = help: implement the missing item: `type Target = /* Type */;` error: aborting due to previous error diff --git a/tests/ui/suggestions/auxiliary/missing-assoc-fn-applicable-suggestions.rs b/tests/ui/suggestions/auxiliary/missing-assoc-fn-applicable-suggestions.rs new file mode 100644 index 00000000000..b026035a6a1 --- /dev/null +++ b/tests/ui/suggestions/auxiliary/missing-assoc-fn-applicable-suggestions.rs @@ -0,0 +1,16 @@ +pub trait TraitB { + type Item; +} + +pub trait TraitA { + type Type; + + fn bar(_: T) -> Self; + + fn baz(_: T) -> Self + where + T: TraitB, + ::Item: Copy; + + const A: usize; +} diff --git a/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed b/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed deleted file mode 100644 index a0cb39a3f8a..00000000000 --- a/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed +++ /dev/null @@ -1,21 +0,0 @@ -// run-rustfix -trait TraitB { - type Item; -} - -trait TraitA { - type Type; - fn bar(_: T) -> Self; - fn baz(_: T) -> Self where T: TraitB, ::Item: Copy; -} - -struct S; -struct Type; - -impl TraitA<()> for S { //~ ERROR not all trait items implemented -fn baz(_: T) -> Self where T: TraitB, ::Item: Copy { todo!() } -fn bar(_: T) -> Self { todo!() } -type Type = Type; -} - -fn main() {} diff --git a/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.rs b/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.rs index c80ede1b2be..11e0c9a3a72 100644 --- a/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.rs +++ b/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.rs @@ -1,18 +1,15 @@ -// run-rustfix -trait TraitB { - type Item; -} +// aux-build:missing-assoc-fn-applicable-suggestions.rs -trait TraitA { - type Type; - fn bar(_: T) -> Self; - fn baz(_: T) -> Self where T: TraitB, ::Item: Copy; -} +extern crate missing_assoc_fn_applicable_suggestions; +use missing_assoc_fn_applicable_suggestions::TraitA; struct S; -struct Type; - -impl TraitA<()> for S { //~ ERROR not all trait items implemented +impl TraitA<()> for S { + //~^ ERROR not all trait items implemented } +//~^ HELP implement the missing item: `type Type = /* Type */;` +//~| HELP implement the missing item: `fn bar(_: T) -> Self { todo!() }` +//~| HELP implement the missing item: `fn baz(_: T) -> Self where T: TraitB, ::Item: Copy { todo!() }` +//~| HELP implement the missing item: `const A: usize = 42;` fn main() {} diff --git a/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr b/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr index 4c75fbe4c78..657a5c546d3 100644 --- a/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr +++ b/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr @@ -1,15 +1,13 @@ -error[E0046]: not all trait items implemented, missing: `Type`, `bar`, `baz` - --> $DIR/missing-assoc-fn-applicable-suggestions.rs:15:1 +error[E0046]: not all trait items implemented, missing: `Type`, `bar`, `baz`, `A` + --> $DIR/missing-assoc-fn-applicable-suggestions.rs:7:1 | -LL | type Type; - | --------- `Type` from trait -LL | fn bar(_: T) -> Self; - | ------------------------ `bar` from trait -LL | fn baz(_: T) -> Self where T: TraitB, ::Item: Copy; - | ------------------------------------------------------------------- `baz` from trait -... -LL | impl TraitA<()> for S { - | ^^^^^^^^^^^^^^^^^^^^^ missing `Type`, `bar`, `baz` in implementation +LL | impl TraitA<()> for S { + | ^^^^^^^^^^^^^^^^^^^^^ missing `Type`, `bar`, `baz`, `A` in implementation + | + = help: implement the missing item: `type Type = /* Type */;` + = help: implement the missing item: `fn bar(_: T) -> Self { todo!() }` + = help: implement the missing item: `fn baz(_: T) -> Self where T: TraitB, ::Item: Copy { todo!() }` + = help: implement the missing item: `const A: usize = 42;` error: aborting due to previous error From f362f6e9e6cb5d55bbac6a94353209c3e3a2ebb5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 19 Apr 2023 17:47:33 +0000 Subject: [PATCH 3/3] Format missing GATs correctly --- compiler/rustc_hir_analysis/src/check/mod.rs | 8 +++++++- .../auxiliary/missing-item-sugg.rs | 5 +++++ .../ui/generic-associated-types/missing-item-sugg.rs | 11 +++++++++++ .../generic-associated-types/missing-item-sugg.stderr | 11 +++++++++++ .../missing-assoc-fn-applicable-suggestions.stderr | 2 +- 5 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 tests/ui/generic-associated-types/auxiliary/missing-item-sugg.rs create mode 100644 tests/ui/generic-associated-types/missing-item-sugg.rs create mode 100644 tests/ui/generic-associated-types/missing-item-sugg.stderr diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 9fba538f12e..4b3f3cf169d 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -466,7 +466,13 @@ fn suggestion_signature<'tcx>( assoc, ) } - ty::AssocKind::Type => format!("type {} = /* Type */;", assoc.name), + ty::AssocKind::Type => { + let (generics, where_clauses) = bounds_from_generic_predicates( + tcx, + tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs), + ); + format!("type {}{generics} = /* Type */{where_clauses};", assoc.name) + } ty::AssocKind::Const => { let ty = tcx.type_of(assoc.def_id).subst_identity(); let val = ty_kind_suggestion(ty).unwrap_or("todo!()"); diff --git a/tests/ui/generic-associated-types/auxiliary/missing-item-sugg.rs b/tests/ui/generic-associated-types/auxiliary/missing-item-sugg.rs new file mode 100644 index 00000000000..5b10aab4b3f --- /dev/null +++ b/tests/ui/generic-associated-types/auxiliary/missing-item-sugg.rs @@ -0,0 +1,5 @@ +pub trait Foo { + type Gat + where + T: std::fmt::Display; +} diff --git a/tests/ui/generic-associated-types/missing-item-sugg.rs b/tests/ui/generic-associated-types/missing-item-sugg.rs new file mode 100644 index 00000000000..35d573d8188 --- /dev/null +++ b/tests/ui/generic-associated-types/missing-item-sugg.rs @@ -0,0 +1,11 @@ +// aux-build:missing-item-sugg.rs + +extern crate missing_item_sugg; + +struct Local; +impl missing_item_sugg::Foo for Local { + //~^ ERROR not all trait items implemented, missing: `Gat` +} +//~^ HELP implement the missing item: `type Gat = /* Type */ where T: std::fmt::Display;` + +fn main() {} diff --git a/tests/ui/generic-associated-types/missing-item-sugg.stderr b/tests/ui/generic-associated-types/missing-item-sugg.stderr new file mode 100644 index 00000000000..378115f6d38 --- /dev/null +++ b/tests/ui/generic-associated-types/missing-item-sugg.stderr @@ -0,0 +1,11 @@ +error[E0046]: not all trait items implemented, missing: `Gat` + --> $DIR/missing-item-sugg.rs:6:1 + | +LL | impl missing_item_sugg::Foo for Local { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Gat` in implementation + | + = help: implement the missing item: `type Gat = /* Type */ where T: std::fmt::Display;` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr b/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr index 657a5c546d3..4c2d2776d3d 100644 --- a/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr +++ b/tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr @@ -1,7 +1,7 @@ error[E0046]: not all trait items implemented, missing: `Type`, `bar`, `baz`, `A` --> $DIR/missing-assoc-fn-applicable-suggestions.rs:7:1 | -LL | impl TraitA<()> for S { +LL | impl TraitA<()> for S { | ^^^^^^^^^^^^^^^^^^^^^ missing `Type`, `bar`, `baz`, `A` in implementation | = help: implement the missing item: `type Type = /* Type */;`