Rollup merge of #67406 - ohadravid:suggest-assoc-type, r=estebank
Suggest associated type when the specified one cannot be found Fixes #67386, so code like this: ``` use std::ops::Deref; fn homura<T: Deref<Trget = i32>>(_: T) {} fn main() {} ``` results in: ``` error[E0220]: associated type `Trget` not found for `std::ops::Deref` --> type-binding.rs:6:20 | 6 | fn homura<T: Deref<Trget = i32>>(_: T) {} | ^^^^^^^^^^^ help: there is an associated type with a similar name: `Target` error: aborting due to previous error ``` (The `help` is new) I used an `all_candidates: impl Fn() -> Iterator<...>` instead of `collect`ing to avoid the cost of allocating the Vec when no errors are found, at the expense of a little added complexity. r? @estebank
This commit is contained in:
commit
06985c6859
|
@ -1145,11 +1145,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, we have to walk through the supertraits to find
|
// Otherwise, we have to walk through the supertraits to find
|
||||||
// those that do.
|
// those that do.
|
||||||
let candidates = traits::supertraits(tcx, trait_ref).filter(|r| {
|
|
||||||
self.trait_defines_associated_type_named(r.def_id(), binding.item_name)
|
|
||||||
});
|
|
||||||
self.one_bound_for_assoc_type(
|
self.one_bound_for_assoc_type(
|
||||||
candidates,
|
|| traits::supertraits(tcx, trait_ref),
|
||||||
&trait_ref.print_only_trait_path().to_string(),
|
&trait_ref.print_only_trait_path().to_string(),
|
||||||
binding.item_name,
|
binding.item_name,
|
||||||
binding.span
|
binding.span
|
||||||
|
@ -1531,50 +1528,48 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
|
|
||||||
debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
|
debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
|
||||||
|
|
||||||
let bounds = predicates.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref());
|
|
||||||
|
|
||||||
// Check that there is exactly one way to find an associated type with the
|
|
||||||
// correct name.
|
|
||||||
let suitable_bounds = traits::transitive_bounds(tcx, bounds)
|
|
||||||
.filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name));
|
|
||||||
|
|
||||||
let param_hir_id = tcx.hir().as_local_hir_id(ty_param_def_id).unwrap();
|
let param_hir_id = tcx.hir().as_local_hir_id(ty_param_def_id).unwrap();
|
||||||
let param_name = tcx.hir().ty_param_name(param_hir_id);
|
let param_name = tcx.hir().ty_param_name(param_hir_id);
|
||||||
self.one_bound_for_assoc_type(suitable_bounds,
|
self.one_bound_for_assoc_type(
|
||||||
¶m_name.as_str(),
|
|| traits::transitive_bounds(tcx, predicates
|
||||||
assoc_name,
|
.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref())),
|
||||||
span)
|
¶m_name.as_str(),
|
||||||
|
assoc_name,
|
||||||
|
span,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks that `bounds` contains exactly one element and reports appropriate
|
|
||||||
// errors otherwise.
|
|
||||||
fn one_bound_for_assoc_type<I>(&self,
|
fn one_bound_for_assoc_type<I>(&self,
|
||||||
mut bounds: I,
|
all_candidates: impl Fn() -> I,
|
||||||
ty_param_name: &str,
|
ty_param_name: &str,
|
||||||
assoc_name: ast::Ident,
|
assoc_name: ast::Ident,
|
||||||
span: Span)
|
span: Span)
|
||||||
-> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
|
-> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
|
||||||
where I: Iterator<Item = ty::PolyTraitRef<'tcx>>
|
where I: Iterator<Item = ty::PolyTraitRef<'tcx>>
|
||||||
{
|
{
|
||||||
let bound = match bounds.next() {
|
let mut matching_candidates = all_candidates().filter(|r| {
|
||||||
|
self.trait_defines_associated_type_named(r.def_id(), assoc_name)
|
||||||
|
});
|
||||||
|
|
||||||
|
let bound = match matching_candidates.next() {
|
||||||
Some(bound) => bound,
|
Some(bound) => bound,
|
||||||
None => {
|
None => {
|
||||||
struct_span_err!(self.tcx().sess, span, E0220,
|
self.complain_about_assoc_type_not_found(
|
||||||
"associated type `{}` not found for `{}`",
|
all_candidates,
|
||||||
assoc_name,
|
ty_param_name,
|
||||||
ty_param_name)
|
assoc_name,
|
||||||
.span_label(span, format!("associated type `{}` not found", assoc_name))
|
span
|
||||||
.emit();
|
);
|
||||||
return Err(ErrorReported);
|
return Err(ErrorReported);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("one_bound_for_assoc_type: bound = {:?}", bound);
|
debug!("one_bound_for_assoc_type: bound = {:?}", bound);
|
||||||
|
|
||||||
if let Some(bound2) = bounds.next() {
|
if let Some(bound2) = matching_candidates.next() {
|
||||||
debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
|
debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
|
||||||
|
|
||||||
let bounds = iter::once(bound).chain(iter::once(bound2)).chain(bounds);
|
let bounds = iter::once(bound).chain(iter::once(bound2)).chain(matching_candidates);
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self.tcx().sess, span, E0221,
|
self.tcx().sess, span, E0221,
|
||||||
"ambiguous associated type `{}` in bounds of `{}`",
|
"ambiguous associated type `{}` in bounds of `{}`",
|
||||||
|
@ -1606,6 +1601,50 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
return Ok(bound);
|
return Ok(bound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn complain_about_assoc_type_not_found<I>(&self,
|
||||||
|
all_candidates: impl Fn() -> I,
|
||||||
|
ty_param_name: &str,
|
||||||
|
assoc_name: ast::Ident,
|
||||||
|
span: Span)
|
||||||
|
where I: Iterator<Item = ty::PolyTraitRef<'tcx>> {
|
||||||
|
let mut err = struct_span_err!(self.tcx().sess, span, E0220,
|
||||||
|
"associated type `{}` not found for `{}`",
|
||||||
|
assoc_name,
|
||||||
|
ty_param_name);
|
||||||
|
|
||||||
|
let all_candidate_names: Vec<_> = all_candidates()
|
||||||
|
.map(|r| self.tcx().associated_items(r.def_id()))
|
||||||
|
.flatten()
|
||||||
|
.filter_map(|item|
|
||||||
|
if item.kind == ty::AssocKind::Type {
|
||||||
|
Some(item.ident.name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if let Some(suggested_name) = find_best_match_for_name(
|
||||||
|
all_candidate_names.iter(),
|
||||||
|
&assoc_name.as_str(),
|
||||||
|
None,
|
||||||
|
) {
|
||||||
|
err.span_suggestion(
|
||||||
|
span,
|
||||||
|
"there is an associated type with a similar name",
|
||||||
|
suggested_name.to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
err.span_label(
|
||||||
|
span,
|
||||||
|
format!("associated type `{}` not found", assoc_name)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
|
||||||
// Create a type from a path to an associated type.
|
// Create a type from a path to an associated type.
|
||||||
// For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
|
// For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
|
||||||
// and item_segment is the path segment for `D`. We return a type and a def for
|
// and item_segment is the path segment for `D`. We return a type and a def for
|
||||||
|
@ -1660,10 +1699,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let candidates = traits::supertraits(tcx, ty::Binder::bind(trait_ref))
|
self.one_bound_for_assoc_type(
|
||||||
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_ident));
|
|| traits::supertraits(tcx, ty::Binder::bind(trait_ref)),
|
||||||
|
"Self",
|
||||||
self.one_bound_for_assoc_type(candidates, "Self", assoc_ident, span)?
|
assoc_ident,
|
||||||
|
span
|
||||||
|
)?
|
||||||
}
|
}
|
||||||
(&ty::Param(_), Res::SelfTy(Some(param_did), None)) |
|
(&ty::Param(_), Res::SelfTy(Some(param_did), None)) |
|
||||||
(&ty::Param(_), Res::Def(DefKind::TyParam, param_did)) => {
|
(&ty::Param(_), Res::Def(DefKind::TyParam, param_did)) => {
|
||||||
|
|
|
@ -2,7 +2,7 @@ error[E0220]: associated type `Trget` not found for `std::ops::Deref`
|
||||||
--> $DIR/type-binding.rs:6:20
|
--> $DIR/type-binding.rs:6:20
|
||||||
|
|
|
|
||||||
LL | fn homura<T: Deref<Trget = i32>>(_: T) {}
|
LL | fn homura<T: Deref<Trget = i32>>(_: T) {}
|
||||||
| ^^^^^^^^^^^ associated type `Trget` not found
|
| ^^^^^^^^^^^ help: there is an associated type with a similar name: `Target`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue