Rollup merge of #110555 - compiler-errors:subst-missing-trait-items, r=cjgillot

Substitute missing trait items suggestion correctly

Properly substitute missing item suggestions, so that when they reference generics from their parent trait they actually have the right time for the impl.

Also, some other minor tweaks like using `/* Type */` to signify a GAT's type is actually missing, and fixing generic arg suggestions for GATs in general.
This commit is contained in:
Matthias Krüger 2023-04-21 06:44:29 +02:00 committed by GitHub
commit 7d046551a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 100 additions and 62 deletions

View File

@ -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 {

View File

@ -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::<Vec<_>>()
.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<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() {
@ -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
@ -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,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)
}
}

View File

@ -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

View File

@ -0,0 +1,5 @@
pub trait Foo {
type Gat<T>
where
T: std::fmt::Display;
}

View File

@ -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() {}

View File

@ -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`.

View File

@ -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

View File

@ -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!() }`

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -1,21 +0,0 @@
// run-rustfix
trait TraitB {
type Item;
}
trait TraitA<A> {
type Type;
fn bar<T>(_: T) -> Self;
fn baz<T>(_: T) -> Self where T: TraitB, <T as TraitB>::Item: Copy;
}
struct S;
struct Type;
impl TraitA<()> for S { //~ ERROR not all trait items implemented
fn baz<T>(_: T) -> Self where T: TraitB, <T as TraitB>::Item: Copy { todo!() }
fn bar<T>(_: T) -> Self { todo!() }
type Type = Type;
}
fn main() {}

View File

@ -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() {}

View File

@ -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

View File

@ -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