Rollup merge of #116865 - estebank:issue-46969, r=compiler-errors

Suggest constraining assoc types in more cases

Fix #46969.

```
error[E0308]: mismatched types
  --> $DIR/suggest-contraining-assoc-type-because-of-assoc-const.rs:12:21
   |
LL |     const N: C::M = 4u8;
   |                     ^^^ expected associated type, found `u8`
   |
   = note: expected associated type `<C as O>::M`
                         found type `u8`
help: consider constraining the associated type `<C as O>::M` to `u8`
   |
LL | impl<C: O<M = u8>> U<C> for u16 {
   |          ++++++++

```
This commit is contained in:
Ali MJ Al-Nasrawy 2023-10-18 14:24:51 +03:00 committed by GitHub
commit d69cdb2ceb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 101 additions and 43 deletions

View File

@ -341,39 +341,48 @@ impl<T> Trait<T> for X {
let tcx = self.tcx; let tcx = self.tcx;
let assoc = tcx.associated_item(proj_ty.def_id); let assoc = tcx.associated_item(proj_ty.def_id);
let (trait_ref, assoc_args) = proj_ty.trait_ref_and_own_args(tcx); let (trait_ref, assoc_args) = proj_ty.trait_ref_and_own_args(tcx);
if let Some(item) = tcx.hir().get_if_local(body_owner_def_id) { let Some(item) = tcx.hir().get_if_local(body_owner_def_id) else {
if let Some(hir_generics) = item.generics() { return false;
// Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`. };
// This will also work for `impl Trait`. let Some(hir_generics) = item.generics() else {
let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() { return false;
let generics = tcx.generics_of(body_owner_def_id); };
generics.type_param(param_ty, tcx).def_id // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
} else { // This will also work for `impl Trait`.
return false; let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() {
}; let generics = tcx.generics_of(body_owner_def_id);
let Some(def_id) = def_id.as_local() else { generics.type_param(param_ty, tcx).def_id
return false; } else {
}; return false;
};
let Some(def_id) = def_id.as_local() else {
return false;
};
// First look in the `where` clause, as this might be // First look in the `where` clause, as this might be
// `fn foo<T>(x: T) where T: Trait`. // `fn foo<T>(x: T) where T: Trait`.
for pred in hir_generics.bounds_for_param(def_id) { for pred in hir_generics.bounds_for_param(def_id) {
if self.constrain_generic_bound_associated_type_structured_suggestion( if self.constrain_generic_bound_associated_type_structured_suggestion(
diag, diag,
&trait_ref, &trait_ref,
pred.bounds, pred.bounds,
assoc, assoc,
assoc_args, assoc_args,
ty, ty,
&msg, &msg,
false, false,
) { ) {
return true; return true;
}
}
} }
} }
false // If associated item, look to constrain the params of the trait/impl.
let hir_id = match item {
hir::Node::ImplItem(item) => item.hir_id(),
hir::Node::TraitItem(item) => item.hir_id(),
_ => return false,
};
let parent = tcx.hir().get_parent_item(hir_id).def_id;
self.suggest_constraint(diag, msg, parent.into(), proj_ty, ty)
} }
/// An associated type was expected and a different type was found. /// An associated type was expected and a different type was found.
@ -426,21 +435,26 @@ impl<T> Trait<T> for X {
let impl_comparison = let impl_comparison =
matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. }); matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
let assoc = tcx.associated_item(proj_ty.def_id); let assoc = tcx.associated_item(proj_ty.def_id);
if !callable_scope || impl_comparison { if impl_comparison {
// We do not want to suggest calling functions when the reason of the // We do not want to suggest calling functions when the reason of the
// type error is a comparison of an `impl` with its `trait` or when the // type error is a comparison of an `impl` with its `trait`.
// scope is outside of a `Body`.
} else { } else {
// If we find a suitable associated function that returns the expected type, we don't let point_at_assoc_fn = if callable_scope
// want the more general suggestion later in this method about "consider constraining && self.point_at_methods_that_satisfy_associated_type(
// the associated type or calling a method that returns the associated type". diag,
let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type( assoc.container_id(tcx),
diag, current_method_ident,
assoc.container_id(tcx), proj_ty.def_id,
current_method_ident, values.expected,
proj_ty.def_id, ) {
values.expected, // If we find a suitable associated function that returns the expected type, we
); // don't want the more general suggestion later in this method about "consider
// constraining the associated type or calling a method that returns the associated
// type".
true
} else {
false
};
// Possibly suggest constraining the associated type to conform to the // Possibly suggest constraining the associated type to conform to the
// found type. // found type.
if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found) if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found)

View File

@ -0,0 +1,14 @@
// run-rustfix
trait O {
type M;
}
trait U<A: O> {
const N: A::M;
}
impl<D> O for D {
type M = u8;
}
impl<C: O<M = u8>> U<C> for u16 {
const N: C::M = 4u8; //~ ERROR mismatched types
}
fn main() {}

View File

@ -0,0 +1,14 @@
// run-rustfix
trait O {
type M;
}
trait U<A: O> {
const N: A::M;
}
impl<D> O for D {
type M = u8;
}
impl<C: O> U<C> for u16 {
const N: C::M = 4u8; //~ ERROR mismatched types
}
fn main() {}

View File

@ -0,0 +1,16 @@
error[E0308]: mismatched types
--> $DIR/suggest-contraining-assoc-type-because-of-assoc-const.rs:12:21
|
LL | const N: C::M = 4u8;
| ^^^ expected associated type, found `u8`
|
= note: expected associated type `<C as O>::M`
found type `u8`
help: consider constraining the associated type `<C as O>::M` to `u8`
|
LL | impl<C: O<M = u8>> U<C> for u16 {
| ++++++++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.