Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Substitute missing trait items suggestion correctly #110555

Merged
merged 3 commits into from
Apr 21, 2023
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
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
41 changes: 31 additions & 10 deletions compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
) {
Expand All @@ -211,6 +211,7 @@ fn missing_items_err(
.collect::<Vec<_>>()
.join("`, `");

let impl_span = tcx.def_span(impl_def_id);
let mut err = struct_span_err!(
tcx.sess,
impl_span,
Expand All @@ -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;
Expand Down Expand Up @@ -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<Item = (ty::Predicate<'tcx>, Span)>,
) -> (String, String) {
let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = 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() {
Expand Down Expand Up @@ -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<Item = (ty::Predicate<'tcx>, Span)>,
assoc: ty::AssocItem,
) -> String {
let args = sig
Expand Down Expand Up @@ -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
Expand All @@ -445,16 +460,22 @@ 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,
)
}
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("value");
let val = ty_kind_suggestion(ty).unwrap_or("todo!()");
format!("const {}: {} = {};", assoc.name, ty, val)
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/async-await/issue-74047.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ error[E0046]: not all trait items implemented, missing: `Error`, `try_from`
LL | impl TryFrom<OtherStream> 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<Self, <Self as TryFrom<T>>::Error> { todo!() }`
= help: implement the missing item: `type Error = /* Type */;`
= help: implement the missing item: `fn try_from(_: OtherStream) -> Result<Self, <Self as TryFrom<OtherStream>>::Error> { todo!() }`

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub trait Foo {
type Gat<T>
where
T: std::fmt::Display;
}
11 changes: 11 additions & 0 deletions tests/ui/generic-associated-types/missing-item-sugg.rs
Original file line number Diff line number Diff line change
@@ -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<T> = /* Type */ where T: std::fmt::Display;`

fn main() {}
11 changes: 11 additions & 0 deletions tests/ui/generic-associated-types/missing-item-sugg.stderr
Original file line number Diff line number Diff line change
@@ -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<T> = /* Type */ where T: std::fmt::Display;`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0046`.
2 changes: 1 addition & 1 deletion tests/ui/issues/issue-3344.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::cmp::Ordering> { todo!() }`
= help: implement the missing item: `fn partial_cmp(&self, _: &Thing) -> Option<std::cmp::Ordering> { todo!() }`

error: aborting due to previous error

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/missing/missing-items/m2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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) -> <Self as m1::X>::Type { todo!() }`
= help: implement the missing item: `fn method2(self: Box<Self>, _: String) -> <Self as m1::X>::Type { todo!() }`
= help: implement the missing item: `fn method3(_: &Self, _: String) -> <Self as m1::X>::Type { todo!() }`
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/span/issue-23729.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/span/issue-23827.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `Output`
LL | impl<C: Component> 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

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/span/issue-24356.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
pub trait TraitB {
type Item;
}

pub trait TraitA<A> {
type Type;

fn bar<T>(_: T) -> Self;

fn baz<T>(_: T) -> Self
where
T: TraitB,
<T as TraitB>::Item: Copy;

const A: usize;
}
21 changes: 0 additions & 21 deletions tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed

This file was deleted.

21 changes: 9 additions & 12 deletions tests/ui/suggestions/missing-assoc-fn-applicable-suggestions.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
// run-rustfix
trait TraitB {
type Item;
}
// aux-build:missing-assoc-fn-applicable-suggestions.rs

trait TraitA<A> {
type Type;
fn bar<T>(_: T) -> Self;
fn baz<T>(_: T) -> Self where T: TraitB, <T as 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>(_: T) -> Self { todo!() }`
//~| HELP implement the missing item: `fn baz<T>(_: T) -> Self where T: TraitB, <T as TraitB>::Item: Copy { todo!() }`
//~| HELP implement the missing item: `const A: usize = 42;`

fn main() {}
Original file line number Diff line number Diff line change
@@ -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>(_: T) -> Self;
| ------------------------ `bar` from trait
LL | fn baz<T>(_: T) -> Self where T: TraitB, <T as TraitB>::Item: Copy;
| ------------------------------------------------------------------- `baz` from trait
...
LL | impl TraitA<()> for S {
| ^^^^^^^^^^^^^^^^^^^^^ missing `Type`, `bar`, `baz` in implementation
| ^^^^^^^^^^^^^^^^^^^^^ missing `Type`, `bar`, `baz`, `A` in implementation
|
= help: implement the missing item: `type Type = /* Type */;`
= help: implement the missing item: `fn bar<T>(_: T) -> Self { todo!() }`
= help: implement the missing item: `fn baz<T>(_: T) -> Self where T: TraitB, <T as TraitB>::Item: Copy { todo!() }`
= help: implement the missing item: `const A: usize = 42;`

error: aborting due to previous error

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/suggestions/missing-assoc-fn.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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>(_: T) -> Self where T: IntoIterator, std::iter::IntoIterator::Item = A { todo!() }`
= help: implement the missing item: `fn from_iter<T>(_: T) -> Self where T: IntoIterator, std::iter::IntoIterator::Item = () { todo!() }`

error: aborting due to 3 previous errors

Expand Down