Rollup merge of #119389 - estebank:issue-116925, r=TaKO8Ki
Provide more context on recursive `impl` evaluation overflow When an associated type `Self::Assoc` is part of a `where` clause, we end up unable to evaluate the requirement and emit a E0275. We now point at the associated type if specified in the `impl`. If so, we also suggest using that type instead of `Self::Assoc`. Otherwise, we explain that these are not allowed. ``` error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` --> $DIR/impl-wf-cycle-1.rs:15:1 | LL | / impl<T: Grault> Grault for (T,) LL | | LL | | where LL | | Self::A: Baz, LL | | Self::B: Fiz, | |_________________^ LL | { LL | type A = (); | ------ associated type `<(T,) as Grault>::A` is specified here | note: required for `(T,)` to implement `Grault` --> $DIR/impl-wf-cycle-1.rs:15:17 | LL | impl<T: Grault> Grault for (T,) | ^^^^^^ ^^^^ ... LL | Self::A: Baz, | --- unsatisfied trait bound introduced here = note: 1 redundant requirement hidden = note: required for `(T,)` to implement `Grault` help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound | LL - Self::A: Baz, | ``` ``` error[E0275]: overflow evaluating the requirement `<T as B>::Type == <T as B>::Type` --> $DIR/impl-wf-cycle-3.rs:7:1 | LL | / impl<T> B for T LL | | where LL | | T: A<Self::Type>, | |_____________________^ LL | { LL | type Type = bool; | --------- associated type `<T as B>::Type` is specified here | note: required for `T` to implement `B` --> $DIR/impl-wf-cycle-3.rs:7:9 | LL | impl<T> B for T | ^ ^ LL | where LL | T: A<Self::Type>, | ------------- unsatisfied trait bound introduced here help: replace the associated type with the type specified in this `impl` | LL | T: A<bool>, | ~~~~ ``` ``` error[E0275]: overflow evaluating the requirement `<T as Filter>::ToMatch == <T as Filter>::ToMatch` --> $DIR/impl-wf-cycle-4.rs:5:1 | LL | / impl<T> Filter for T LL | | where LL | | T: Fn(Self::ToMatch), | |_________________________^ | note: required for `T` to implement `Filter` --> $DIR/impl-wf-cycle-4.rs:5:9 | LL | impl<T> Filter for T | ^^^^^^ ^ LL | where LL | T: Fn(Self::ToMatch), | ----------------- unsatisfied trait bound introduced here note: associated types for the current `impl` cannot be restricted in `where` clauses --> $DIR/impl-wf-cycle-4.rs:7:11 | LL | T: Fn(Self::ToMatch), | ^^^^^^^^^^^^^ ``` Fix #116925
This commit is contained in:
commit
fd92d88c28
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
use crate::traits::{NormalizeExt, ObligationCtxt};
|
use crate::traits::{ImplDerivedObligationCause, NormalizeExt, ObligationCtxt};
|
||||||
|
|
||||||
use hir::def::CtorOf;
|
use hir::def::CtorOf;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
@ -2973,7 +2973,7 @@ fn note_obligation_cause_code<T>(
|
|||||||
| ObligationCauseCode::ObjectTypeBound(..) => {}
|
| ObligationCauseCode::ObjectTypeBound(..) => {}
|
||||||
ObligationCauseCode::RustCall => {
|
ObligationCauseCode::RustCall => {
|
||||||
if let Some(pred) = predicate.to_opt_poly_trait_pred()
|
if let Some(pred) = predicate.to_opt_poly_trait_pred()
|
||||||
&& Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
|
&& Some(pred.def_id()) == tcx.lang_items().sized_trait()
|
||||||
{
|
{
|
||||||
err.note("argument required to be sized due to `extern \"rust-call\"` ABI");
|
err.note("argument required to be sized due to `extern \"rust-call\"` ABI");
|
||||||
}
|
}
|
||||||
@ -3022,15 +3022,15 @@ fn note_obligation_cause_code<T>(
|
|||||||
let def_id = trait_pred.def_id();
|
let def_id = trait_pred.def_id();
|
||||||
let visible_item = if let Some(local) = def_id.as_local() {
|
let visible_item = if let Some(local) = def_id.as_local() {
|
||||||
// Check for local traits being reachable.
|
// Check for local traits being reachable.
|
||||||
let vis = &self.tcx.resolutions(()).effective_visibilities;
|
let vis = &tcx.resolutions(()).effective_visibilities;
|
||||||
// Account for non-`pub` traits in the root of the local crate.
|
// Account for non-`pub` traits in the root of the local crate.
|
||||||
let is_locally_reachable = self.tcx.parent(def_id).is_crate_root();
|
let is_locally_reachable = tcx.parent(def_id).is_crate_root();
|
||||||
vis.is_reachable(local) || is_locally_reachable
|
vis.is_reachable(local) || is_locally_reachable
|
||||||
} else {
|
} else {
|
||||||
// Check for foreign traits being reachable.
|
// Check for foreign traits being reachable.
|
||||||
self.tcx.visible_parent_map(()).get(&def_id).is_some()
|
tcx.visible_parent_map(()).get(&def_id).is_some()
|
||||||
};
|
};
|
||||||
if Some(def_id) == self.tcx.lang_items().sized_trait()
|
if Some(def_id) == tcx.lang_items().sized_trait()
|
||||||
&& let Some(hir::Node::TraitItem(hir::TraitItem {
|
&& let Some(hir::Node::TraitItem(hir::TraitItem {
|
||||||
ident,
|
ident,
|
||||||
kind: hir::TraitItemKind::Type(bounds, None),
|
kind: hir::TraitItemKind::Type(bounds, None),
|
||||||
@ -3039,7 +3039,7 @@ fn note_obligation_cause_code<T>(
|
|||||||
// Do not suggest relaxing if there is an explicit `Sized` obligation.
|
// Do not suggest relaxing if there is an explicit `Sized` obligation.
|
||||||
&& !bounds.iter()
|
&& !bounds.iter()
|
||||||
.filter_map(|bound| bound.trait_ref())
|
.filter_map(|bound| bound.trait_ref())
|
||||||
.any(|tr| tr.trait_def_id() == self.tcx.lang_items().sized_trait())
|
.any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait())
|
||||||
{
|
{
|
||||||
let (span, separator) = if let [.., last] = bounds {
|
let (span, separator) = if let [.., last] = bounds {
|
||||||
(last.span().shrink_to_hi(), " +")
|
(last.span().shrink_to_hi(), " +")
|
||||||
@ -3102,10 +3102,8 @@ fn note_obligation_cause_code<T>(
|
|||||||
}
|
}
|
||||||
ObligationCauseCode::Coercion { source, target } => {
|
ObligationCauseCode::Coercion { source, target } => {
|
||||||
let mut file = None;
|
let mut file = None;
|
||||||
let source =
|
let source = tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file);
|
||||||
self.tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file);
|
let target = tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file);
|
||||||
let target =
|
|
||||||
self.tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file);
|
|
||||||
err.note(with_forced_trimmed_paths!(format!(
|
err.note(with_forced_trimmed_paths!(format!(
|
||||||
"required for the cast from `{source}` to `{target}`",
|
"required for the cast from `{source}` to `{target}`",
|
||||||
)));
|
)));
|
||||||
@ -3158,7 +3156,7 @@ fn note_obligation_cause_code<T>(
|
|||||||
err.help("see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information");
|
err.help("see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information");
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.tcx.sess.is_nightly_build()
|
if tcx.sess.is_nightly_build()
|
||||||
&& matches!(is_constable, IsConstable::Fn | IsConstable::Ctor)
|
&& matches!(is_constable, IsConstable::Fn | IsConstable::Ctor)
|
||||||
{
|
{
|
||||||
err.help(
|
err.help(
|
||||||
@ -3168,8 +3166,8 @@ fn note_obligation_cause_code<T>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObligationCauseCode::VariableType(hir_id) => {
|
ObligationCauseCode::VariableType(hir_id) => {
|
||||||
let parent_node = self.tcx.hir().parent_id(hir_id);
|
let parent_node = tcx.hir().parent_id(hir_id);
|
||||||
match self.tcx.opt_hir_node(parent_node) {
|
match tcx.opt_hir_node(parent_node) {
|
||||||
Some(Node::Local(hir::Local { ty: Some(ty), .. })) => {
|
Some(Node::Local(hir::Local { ty: Some(ty), .. })) => {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
ty.span.shrink_to_lo(),
|
ty.span.shrink_to_lo(),
|
||||||
@ -3207,7 +3205,7 @@ fn note_obligation_cause_code<T>(
|
|||||||
err.note("all local variables must have a statically known size");
|
err.note("all local variables must have a statically known size");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !self.tcx.features().unsized_locals {
|
if !tcx.features().unsized_locals {
|
||||||
err.help("unsized locals are gated as an unstable feature");
|
err.help("unsized locals are gated as an unstable feature");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3289,7 +3287,7 @@ fn note_obligation_cause_code<T>(
|
|||||||
err.note("all function arguments must have a statically known size");
|
err.note("all function arguments must have a statically known size");
|
||||||
}
|
}
|
||||||
if tcx.sess.opts.unstable_features.is_nightly_build()
|
if tcx.sess.opts.unstable_features.is_nightly_build()
|
||||||
&& !self.tcx.features().unsized_fn_params
|
&& !tcx.features().unsized_fn_params
|
||||||
{
|
{
|
||||||
err.help("unsized fn params are gated as an unstable feature");
|
err.help("unsized fn params are gated as an unstable feature");
|
||||||
}
|
}
|
||||||
@ -3358,7 +3356,7 @@ fn note_obligation_cause_code<T>(
|
|||||||
"all values captured by value by a closure must have a statically known size",
|
"all values captured by value by a closure must have a statically known size",
|
||||||
);
|
);
|
||||||
let hir::ExprKind::Closure(closure) =
|
let hir::ExprKind::Closure(closure) =
|
||||||
self.tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind
|
tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind
|
||||||
else {
|
else {
|
||||||
bug!("expected closure in SizedClosureCapture obligation");
|
bug!("expected closure in SizedClosureCapture obligation");
|
||||||
};
|
};
|
||||||
@ -3369,7 +3367,7 @@ fn note_obligation_cause_code<T>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => {
|
ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => {
|
||||||
let what = match self.tcx.coroutine_kind(coroutine_def_id) {
|
let what = match tcx.coroutine_kind(coroutine_def_id) {
|
||||||
None
|
None
|
||||||
| Some(hir::CoroutineKind::Coroutine(_))
|
| Some(hir::CoroutineKind::Coroutine(_))
|
||||||
| Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => {
|
| Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => {
|
||||||
@ -3420,10 +3418,10 @@ fn note_obligation_cause_code<T>(
|
|||||||
'print: {
|
'print: {
|
||||||
if !is_upvar_tys_infer_tuple {
|
if !is_upvar_tys_infer_tuple {
|
||||||
let mut file = None;
|
let mut file = None;
|
||||||
let ty_str = self.tcx.short_ty_string(ty, &mut file);
|
let ty_str = tcx.short_ty_string(ty, &mut file);
|
||||||
let msg = format!("required because it appears within the type `{ty_str}`");
|
let msg = format!("required because it appears within the type `{ty_str}`");
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) {
|
ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) {
|
||||||
Some(ident) => err.span_note(ident.span, msg),
|
Some(ident) => err.span_note(ident.span, msg),
|
||||||
None => err.note(msg),
|
None => err.note(msg),
|
||||||
},
|
},
|
||||||
@ -3446,7 +3444,7 @@ fn note_obligation_cause_code<T>(
|
|||||||
{
|
{
|
||||||
break 'print;
|
break 'print;
|
||||||
}
|
}
|
||||||
err.span_note(self.tcx.def_span(def_id), msg)
|
err.span_note(tcx.def_span(def_id), msg)
|
||||||
}
|
}
|
||||||
ty::CoroutineWitness(def_id, args) => {
|
ty::CoroutineWitness(def_id, args) => {
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
@ -3463,7 +3461,7 @@ fn note_obligation_cause_code<T>(
|
|||||||
err.note(msg.trim_end_matches(", ").to_string())
|
err.note(msg.trim_end_matches(", ").to_string())
|
||||||
}
|
}
|
||||||
ty::Coroutine(def_id, _) => {
|
ty::Coroutine(def_id, _) => {
|
||||||
let sp = self.tcx.def_span(def_id);
|
let sp = tcx.def_span(def_id);
|
||||||
|
|
||||||
// Special-case this to say "async block" instead of `[static coroutine]`.
|
// Special-case this to say "async block" instead of `[static coroutine]`.
|
||||||
let kind = tcx.coroutine_kind(def_id).unwrap();
|
let kind = tcx.coroutine_kind(def_id).unwrap();
|
||||||
@ -3475,7 +3473,7 @@ fn note_obligation_cause_code<T>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
ty::Closure(def_id, _) => err.span_note(
|
ty::Closure(def_id, _) => err.span_note(
|
||||||
self.tcx.def_span(def_id),
|
tcx.def_span(def_id),
|
||||||
"required because it's used within this closure",
|
"required because it's used within this closure",
|
||||||
),
|
),
|
||||||
ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"),
|
ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"),
|
||||||
@ -3519,14 +3517,12 @@ fn note_obligation_cause_code<T>(
|
|||||||
self.resolve_vars_if_possible(data.derived.parent_trait_pred);
|
self.resolve_vars_if_possible(data.derived.parent_trait_pred);
|
||||||
let parent_def_id = parent_trait_pred.def_id();
|
let parent_def_id = parent_trait_pred.def_id();
|
||||||
let mut file = None;
|
let mut file = None;
|
||||||
let self_ty =
|
let self_ty_str =
|
||||||
self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
|
tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
|
||||||
let msg = format!(
|
let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string();
|
||||||
"required for `{self_ty}` to implement `{}`",
|
let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
|
||||||
parent_trait_pred.print_modifiers_and_trait_path()
|
|
||||||
);
|
|
||||||
let mut is_auto_trait = false;
|
let mut is_auto_trait = false;
|
||||||
match self.tcx.hir().get_if_local(data.impl_or_alias_def_id) {
|
match tcx.hir().get_if_local(data.impl_or_alias_def_id) {
|
||||||
Some(Node::Item(hir::Item {
|
Some(Node::Item(hir::Item {
|
||||||
kind: hir::ItemKind::Trait(is_auto, ..),
|
kind: hir::ItemKind::Trait(is_auto, ..),
|
||||||
ident,
|
ident,
|
||||||
@ -3538,7 +3534,7 @@ fn note_obligation_cause_code<T>(
|
|||||||
err.span_note(ident.span, msg);
|
err.span_note(ident.span, msg);
|
||||||
}
|
}
|
||||||
Some(Node::Item(hir::Item {
|
Some(Node::Item(hir::Item {
|
||||||
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
|
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
|
||||||
..
|
..
|
||||||
})) => {
|
})) => {
|
||||||
let mut spans = Vec::with_capacity(2);
|
let mut spans = Vec::with_capacity(2);
|
||||||
@ -3565,6 +3561,15 @@ fn note_obligation_cause_code<T>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
err.span_note(spans, msg);
|
err.span_note(spans, msg);
|
||||||
|
point_at_assoc_type_restriction(
|
||||||
|
tcx,
|
||||||
|
err,
|
||||||
|
&self_ty_str,
|
||||||
|
&trait_name,
|
||||||
|
predicate,
|
||||||
|
&generics,
|
||||||
|
&data,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
err.note(msg);
|
err.note(msg);
|
||||||
@ -3618,9 +3623,8 @@ fn note_obligation_cause_code<T>(
|
|||||||
pluralize!(count)
|
pluralize!(count)
|
||||||
));
|
));
|
||||||
let mut file = None;
|
let mut file = None;
|
||||||
let self_ty = self
|
let self_ty =
|
||||||
.tcx
|
tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
|
||||||
.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
|
|
||||||
err.note(format!(
|
err.note(format!(
|
||||||
"required for `{self_ty}` to implement `{}`",
|
"required for `{self_ty}` to implement `{}`",
|
||||||
parent_trait_pred.print_modifiers_and_trait_path()
|
parent_trait_pred.print_modifiers_and_trait_path()
|
||||||
@ -3678,10 +3682,7 @@ fn note_obligation_cause_code<T>(
|
|||||||
multispan.push_span_label(span, "required by this bound");
|
multispan.push_span_label(span, "required by this bound");
|
||||||
err.span_note(
|
err.span_note(
|
||||||
multispan,
|
multispan,
|
||||||
format!(
|
format!("required by a bound on the type alias `{}`", tcx.item_name(def_id)),
|
||||||
"required by a bound on the type alias `{}`",
|
|
||||||
self.infcx.tcx.item_name(def_id)
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ObligationCauseCode::FunctionArgumentObligation {
|
ObligationCauseCode::FunctionArgumentObligation {
|
||||||
@ -3712,25 +3713,23 @@ fn note_obligation_cause_code<T>(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => {
|
ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => {
|
||||||
let item_name = self.tcx.item_name(trait_item_def_id);
|
let item_name = tcx.item_name(trait_item_def_id);
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"the requirement `{predicate}` appears on the `impl`'s {kind} \
|
"the requirement `{predicate}` appears on the `impl`'s {kind} \
|
||||||
`{item_name}` but not on the corresponding trait's {kind}",
|
`{item_name}` but not on the corresponding trait's {kind}",
|
||||||
);
|
);
|
||||||
let sp = self
|
let sp = tcx
|
||||||
.tcx
|
|
||||||
.opt_item_ident(trait_item_def_id)
|
.opt_item_ident(trait_item_def_id)
|
||||||
.map(|i| i.span)
|
.map(|i| i.span)
|
||||||
.unwrap_or_else(|| self.tcx.def_span(trait_item_def_id));
|
.unwrap_or_else(|| tcx.def_span(trait_item_def_id));
|
||||||
let mut assoc_span: MultiSpan = sp.into();
|
let mut assoc_span: MultiSpan = sp.into();
|
||||||
assoc_span.push_span_label(
|
assoc_span.push_span_label(
|
||||||
sp,
|
sp,
|
||||||
format!("this trait's {kind} doesn't have the requirement `{predicate}`"),
|
format!("this trait's {kind} doesn't have the requirement `{predicate}`"),
|
||||||
);
|
);
|
||||||
if let Some(ident) = self
|
if let Some(ident) = tcx
|
||||||
.tcx
|
|
||||||
.opt_associated_item(trait_item_def_id)
|
.opt_associated_item(trait_item_def_id)
|
||||||
.and_then(|i| self.tcx.opt_item_ident(i.container_id(self.tcx)))
|
.and_then(|i| tcx.opt_item_ident(i.container_id(tcx)))
|
||||||
{
|
{
|
||||||
assoc_span.push_span_label(ident.span, "in this trait");
|
assoc_span.push_span_label(ident.span, "in this trait");
|
||||||
}
|
}
|
||||||
@ -4820,6 +4819,29 @@ fn hint_missing_borrow<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collect all the paths that reference `Self`.
|
||||||
|
/// Used to suggest replacing associated types with an explicit type in `where` clauses.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SelfVisitor<'v> {
|
||||||
|
pub paths: Vec<&'v hir::Ty<'v>>,
|
||||||
|
pub name: Option<Symbol>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'v> Visitor<'v> for SelfVisitor<'v> {
|
||||||
|
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
|
||||||
|
if let hir::TyKind::Path(path) = ty.kind
|
||||||
|
&& let hir::QPath::TypeRelative(inner_ty, segment) = path
|
||||||
|
&& (Some(segment.ident.name) == self.name || self.name.is_none())
|
||||||
|
&& let hir::TyKind::Path(inner_path) = inner_ty.kind
|
||||||
|
&& let hir::QPath::Resolved(None, inner_path) = inner_path
|
||||||
|
&& let Res::SelfTyAlias { .. } = inner_path.res
|
||||||
|
{
|
||||||
|
self.paths.push(ty);
|
||||||
|
}
|
||||||
|
hir::intravisit::walk_ty(self, ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Collect all the returned expressions within the input expression.
|
/// Collect all the returned expressions within the input expression.
|
||||||
/// Used to point at the return spans when we want to suggest some change to them.
|
/// Used to point at the return spans when we want to suggest some change to them.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -5064,6 +5086,134 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
|
|||||||
Some(sugg)
|
Some(sugg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// On `impl` evaluation cycles, look for `Self::AssocTy` restrictions in `where` clauses, explain
|
||||||
|
/// they are not allowed and if possible suggest alternatives.
|
||||||
|
fn point_at_assoc_type_restriction(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
err: &mut Diagnostic,
|
||||||
|
self_ty_str: &str,
|
||||||
|
trait_name: &str,
|
||||||
|
predicate: ty::Predicate<'_>,
|
||||||
|
generics: &hir::Generics<'_>,
|
||||||
|
data: &ImplDerivedObligationCause<'_>,
|
||||||
|
) {
|
||||||
|
let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let ty::ClauseKind::Projection(proj) = clause else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let name = tcx.item_name(proj.projection_ty.def_id);
|
||||||
|
let mut predicates = generics.predicates.iter().peekable();
|
||||||
|
let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None;
|
||||||
|
while let Some(pred) = predicates.next() {
|
||||||
|
let hir::WherePredicate::BoundPredicate(pred) = pred else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let mut bounds = pred.bounds.iter().peekable();
|
||||||
|
while let Some(bound) = bounds.next() {
|
||||||
|
let Some(trait_ref) = bound.trait_ref() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if bound.span() != data.span {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let hir::TyKind::Path(path) = pred.bounded_ty.kind
|
||||||
|
&& let hir::QPath::TypeRelative(ty, segment) = path
|
||||||
|
&& segment.ident.name == name
|
||||||
|
&& let hir::TyKind::Path(inner_path) = ty.kind
|
||||||
|
&& let hir::QPath::Resolved(None, inner_path) = inner_path
|
||||||
|
&& let Res::SelfTyAlias { .. } = inner_path.res
|
||||||
|
{
|
||||||
|
// The following block is to determine the right span to delete for this bound
|
||||||
|
// that will leave valid code after the suggestion is applied.
|
||||||
|
let span = if pred.origin == hir::PredicateOrigin::WhereClause
|
||||||
|
&& generics
|
||||||
|
.predicates
|
||||||
|
.iter()
|
||||||
|
.filter(|p| {
|
||||||
|
matches!(
|
||||||
|
p,
|
||||||
|
hir::WherePredicate::BoundPredicate(p)
|
||||||
|
if hir::PredicateOrigin::WhereClause == p.origin
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.count()
|
||||||
|
== 1
|
||||||
|
{
|
||||||
|
// There's only one `where` bound, that needs to be removed. Remove the whole
|
||||||
|
// `where` clause.
|
||||||
|
generics.where_clause_span
|
||||||
|
} else if let Some(hir::WherePredicate::BoundPredicate(next)) = predicates.peek()
|
||||||
|
&& pred.origin == next.origin
|
||||||
|
{
|
||||||
|
// There's another bound, include the comma for the current one.
|
||||||
|
pred.span.until(next.span)
|
||||||
|
} else if let Some(prev) = prev
|
||||||
|
&& pred.origin == prev.origin
|
||||||
|
{
|
||||||
|
// Last bound, try to remove the previous comma.
|
||||||
|
prev.span.shrink_to_hi().to(pred.span)
|
||||||
|
} else if pred.origin == hir::PredicateOrigin::WhereClause {
|
||||||
|
pred.span.with_hi(generics.where_clause_span.hi())
|
||||||
|
} else {
|
||||||
|
pred.span
|
||||||
|
};
|
||||||
|
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
span,
|
||||||
|
"associated type for the current `impl` cannot be restricted in `where` \
|
||||||
|
clauses, remove this bound",
|
||||||
|
"",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if let Some(new) =
|
||||||
|
tcx.associated_items(data.impl_or_alias_def_id).find_by_name_and_kind(
|
||||||
|
tcx,
|
||||||
|
Ident::with_dummy_span(name),
|
||||||
|
ty::AssocKind::Type,
|
||||||
|
data.impl_or_alias_def_id,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// The associated type is specified in the `impl` we're
|
||||||
|
// looking at. Point at it.
|
||||||
|
let span = tcx.def_span(new.def_id);
|
||||||
|
err.span_label(
|
||||||
|
span,
|
||||||
|
format!(
|
||||||
|
"associated type `<{self_ty_str} as {trait_name}>::{name}` is specified \
|
||||||
|
here",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// Search for the associated type `Self::{name}`, get
|
||||||
|
// its type and suggest replacing the bound with it.
|
||||||
|
let mut visitor = SelfVisitor { paths: vec![], name: Some(name) };
|
||||||
|
visitor.visit_trait_ref(trait_ref);
|
||||||
|
for path in visitor.paths {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
path.span,
|
||||||
|
"replace the associated type with the type specified in this `impl`",
|
||||||
|
tcx.type_of(new.def_id).skip_binder().to_string(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut visitor = SelfVisitor { paths: vec![], name: None };
|
||||||
|
visitor.visit_trait_ref(trait_ref);
|
||||||
|
let span: MultiSpan =
|
||||||
|
visitor.paths.iter().map(|p| p.span).collect::<Vec<Span>>().into();
|
||||||
|
err.span_note(
|
||||||
|
span,
|
||||||
|
"associated types for the current `impl` cannot be restricted in `where` \
|
||||||
|
clauses",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = Some(pred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
|
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
|
||||||
let mut refs = vec![];
|
let mut refs = vec![];
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@ LL | | where
|
|||||||
LL | | Self::A: Baz,
|
LL | | Self::A: Baz,
|
||||||
LL | | Self::B: Fiz,
|
LL | | Self::B: Fiz,
|
||||||
| |_________________^
|
| |_________________^
|
||||||
|
LL | {
|
||||||
|
LL | type A = ();
|
||||||
|
| ------ associated type `<(T,) as Grault>::A` is specified here
|
||||||
|
|
|
|
||||||
note: required for `(T,)` to implement `Grault`
|
note: required for `(T,)` to implement `Grault`
|
||||||
--> $DIR/impl-wf-cycle-1.rs:15:17
|
--> $DIR/impl-wf-cycle-1.rs:15:17
|
||||||
@ -18,6 +21,10 @@ LL | Self::A: Baz,
|
|||||||
| --- unsatisfied trait bound introduced here
|
| --- unsatisfied trait bound introduced here
|
||||||
= note: 1 redundant requirement hidden
|
= note: 1 redundant requirement hidden
|
||||||
= note: required for `(T,)` to implement `Grault`
|
= note: required for `(T,)` to implement `Grault`
|
||||||
|
help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound
|
||||||
|
|
|
||||||
|
LL - Self::A: Baz,
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@ LL | |
|
|||||||
LL | | where
|
LL | | where
|
||||||
LL | | Self::A: Copy,
|
LL | | Self::A: Copy,
|
||||||
| |__________________^
|
| |__________________^
|
||||||
|
LL | {
|
||||||
|
LL | type A = ();
|
||||||
|
| ------ associated type `<(T,) as Grault>::A` is specified here
|
||||||
|
|
|
|
||||||
note: required for `(T,)` to implement `Grault`
|
note: required for `(T,)` to implement `Grault`
|
||||||
--> $DIR/impl-wf-cycle-2.rs:7:17
|
--> $DIR/impl-wf-cycle-2.rs:7:17
|
||||||
@ -15,6 +18,11 @@ LL | impl<T: Grault> Grault for (T,)
|
|||||||
...
|
...
|
||||||
LL | Self::A: Copy,
|
LL | Self::A: Copy,
|
||||||
| ---- unsatisfied trait bound introduced here
|
| ---- unsatisfied trait bound introduced here
|
||||||
|
help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound
|
||||||
|
|
|
||||||
|
LL - where
|
||||||
|
LL - Self::A: Copy,
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
13
tests/ui/associated-types/impl-wf-cycle-3.rs
Normal file
13
tests/ui/associated-types/impl-wf-cycle-3.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
trait A<T> {}
|
||||||
|
|
||||||
|
trait B {
|
||||||
|
type Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> B for T //~ ERROR overflow evaluating the requirement
|
||||||
|
where
|
||||||
|
T: A<Self::Type>,
|
||||||
|
{
|
||||||
|
type Type = bool;
|
||||||
|
}
|
||||||
|
fn main() {}
|
27
tests/ui/associated-types/impl-wf-cycle-3.stderr
Normal file
27
tests/ui/associated-types/impl-wf-cycle-3.stderr
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
error[E0275]: overflow evaluating the requirement `<T as B>::Type == <T as B>::Type`
|
||||||
|
--> $DIR/impl-wf-cycle-3.rs:7:1
|
||||||
|
|
|
||||||
|
LL | / impl<T> B for T
|
||||||
|
LL | | where
|
||||||
|
LL | | T: A<Self::Type>,
|
||||||
|
| |_____________________^
|
||||||
|
LL | {
|
||||||
|
LL | type Type = bool;
|
||||||
|
| --------- associated type `<T as B>::Type` is specified here
|
||||||
|
|
|
||||||
|
note: required for `T` to implement `B`
|
||||||
|
--> $DIR/impl-wf-cycle-3.rs:7:9
|
||||||
|
|
|
||||||
|
LL | impl<T> B for T
|
||||||
|
| ^ ^
|
||||||
|
LL | where
|
||||||
|
LL | T: A<Self::Type>,
|
||||||
|
| ------------- unsatisfied trait bound introduced here
|
||||||
|
help: replace the associated type with the type specified in this `impl`
|
||||||
|
|
|
||||||
|
LL | T: A<bool>,
|
||||||
|
| ~~~~
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0275`.
|
15
tests/ui/associated-types/impl-wf-cycle-4.rs
Normal file
15
tests/ui/associated-types/impl-wf-cycle-4.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
trait Filter {
|
||||||
|
type ToMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Filter for T //~ ERROR overflow evaluating the requirement
|
||||||
|
where
|
||||||
|
T: Fn(Self::ToMatch),
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
struct JustFilter<F: Filter> {
|
||||||
|
filter: F,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
25
tests/ui/associated-types/impl-wf-cycle-4.stderr
Normal file
25
tests/ui/associated-types/impl-wf-cycle-4.stderr
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
error[E0275]: overflow evaluating the requirement `<T as Filter>::ToMatch == <T as Filter>::ToMatch`
|
||||||
|
--> $DIR/impl-wf-cycle-4.rs:5:1
|
||||||
|
|
|
||||||
|
LL | / impl<T> Filter for T
|
||||||
|
LL | | where
|
||||||
|
LL | | T: Fn(Self::ToMatch),
|
||||||
|
| |_________________________^
|
||||||
|
|
|
||||||
|
note: required for `T` to implement `Filter`
|
||||||
|
--> $DIR/impl-wf-cycle-4.rs:5:9
|
||||||
|
|
|
||||||
|
LL | impl<T> Filter for T
|
||||||
|
| ^^^^^^ ^
|
||||||
|
LL | where
|
||||||
|
LL | T: Fn(Self::ToMatch),
|
||||||
|
| ----------------- unsatisfied trait bound introduced here
|
||||||
|
note: associated types for the current `impl` cannot be restricted in `where` clauses
|
||||||
|
--> $DIR/impl-wf-cycle-4.rs:7:11
|
||||||
|
|
|
||||||
|
LL | T: Fn(Self::ToMatch),
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0275`.
|
31
tests/ui/associated-types/impl-wf-cycle-5.fixed
Normal file
31
tests/ui/associated-types/impl-wf-cycle-5.fixed
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
trait Baz {}
|
||||||
|
impl Baz for () {}
|
||||||
|
impl<T> Baz for (T,) {}
|
||||||
|
|
||||||
|
trait Fiz {}
|
||||||
|
impl Fiz for bool {}
|
||||||
|
|
||||||
|
trait Grault {
|
||||||
|
type A;
|
||||||
|
type B;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grault for () {
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Grault for (T,)
|
||||||
|
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
where
|
||||||
|
T: Grault,
|
||||||
|
{
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: <((),) as Grault>::A = ();
|
||||||
|
}
|
32
tests/ui/associated-types/impl-wf-cycle-5.rs
Normal file
32
tests/ui/associated-types/impl-wf-cycle-5.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
trait Baz {}
|
||||||
|
impl Baz for () {}
|
||||||
|
impl<T> Baz for (T,) {}
|
||||||
|
|
||||||
|
trait Fiz {}
|
||||||
|
impl Fiz for bool {}
|
||||||
|
|
||||||
|
trait Grault {
|
||||||
|
type A;
|
||||||
|
type B;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grault for () {
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Grault for (T,)
|
||||||
|
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
where
|
||||||
|
T: Grault,
|
||||||
|
Self::A: Baz,
|
||||||
|
{
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: <((),) as Grault>::A = ();
|
||||||
|
}
|
31
tests/ui/associated-types/impl-wf-cycle-5.stderr
Normal file
31
tests/ui/associated-types/impl-wf-cycle-5.stderr
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
--> $DIR/impl-wf-cycle-5.rs:20:1
|
||||||
|
|
|
||||||
|
LL | / impl<T> Grault for (T,)
|
||||||
|
LL | |
|
||||||
|
LL | | where
|
||||||
|
LL | | T: Grault,
|
||||||
|
LL | | Self::A: Baz,
|
||||||
|
| |_________________^
|
||||||
|
LL | {
|
||||||
|
LL | type A = ();
|
||||||
|
| ------ associated type `<(T,) as Grault>::A` is specified here
|
||||||
|
|
|
||||||
|
note: required for `(T,)` to implement `Grault`
|
||||||
|
--> $DIR/impl-wf-cycle-5.rs:20:9
|
||||||
|
|
|
||||||
|
LL | impl<T> Grault for (T,)
|
||||||
|
| ^^^^^^ ^^^^
|
||||||
|
...
|
||||||
|
LL | Self::A: Baz,
|
||||||
|
| --- unsatisfied trait bound introduced here
|
||||||
|
help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound
|
||||||
|
|
|
||||||
|
LL - T: Grault,
|
||||||
|
LL - Self::A: Baz,
|
||||||
|
LL + T: Grault,
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0275`.
|
30
tests/ui/associated-types/impl-wf-cycle-6.fixed
Normal file
30
tests/ui/associated-types/impl-wf-cycle-6.fixed
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
trait Baz {}
|
||||||
|
impl Baz for () {}
|
||||||
|
impl<T> Baz for (T,) {}
|
||||||
|
|
||||||
|
trait Fiz {}
|
||||||
|
impl Fiz for bool {}
|
||||||
|
|
||||||
|
trait Grault {
|
||||||
|
type A;
|
||||||
|
type B;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grault for () {
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Grault> Grault for (T,)
|
||||||
|
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
|
||||||
|
{
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: <((),) as Grault>::A = ();
|
||||||
|
}
|
31
tests/ui/associated-types/impl-wf-cycle-6.rs
Normal file
31
tests/ui/associated-types/impl-wf-cycle-6.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
trait Baz {}
|
||||||
|
impl Baz for () {}
|
||||||
|
impl<T> Baz for (T,) {}
|
||||||
|
|
||||||
|
trait Fiz {}
|
||||||
|
impl Fiz for bool {}
|
||||||
|
|
||||||
|
trait Grault {
|
||||||
|
type A;
|
||||||
|
type B;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Grault for () {
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Grault> Grault for (T,)
|
||||||
|
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
where
|
||||||
|
Self::A: Baz,
|
||||||
|
{
|
||||||
|
type A = ();
|
||||||
|
type B = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: <((),) as Grault>::A = ();
|
||||||
|
}
|
29
tests/ui/associated-types/impl-wf-cycle-6.stderr
Normal file
29
tests/ui/associated-types/impl-wf-cycle-6.stderr
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
--> $DIR/impl-wf-cycle-6.rs:20:1
|
||||||
|
|
|
||||||
|
LL | / impl<T: Grault> Grault for (T,)
|
||||||
|
LL | |
|
||||||
|
LL | | where
|
||||||
|
LL | | Self::A: Baz,
|
||||||
|
| |_________________^
|
||||||
|
LL | {
|
||||||
|
LL | type A = ();
|
||||||
|
| ------ associated type `<(T,) as Grault>::A` is specified here
|
||||||
|
|
|
||||||
|
note: required for `(T,)` to implement `Grault`
|
||||||
|
--> $DIR/impl-wf-cycle-6.rs:20:17
|
||||||
|
|
|
||||||
|
LL | impl<T: Grault> Grault for (T,)
|
||||||
|
| ^^^^^^ ^^^^
|
||||||
|
...
|
||||||
|
LL | Self::A: Baz,
|
||||||
|
| --- unsatisfied trait bound introduced here
|
||||||
|
help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound
|
||||||
|
|
|
||||||
|
LL - where
|
||||||
|
LL - Self::A: Baz,
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0275`.
|
Loading…
Reference in New Issue
Block a user