Make trait/impl where clause mismatch on region error a bit more actionable
This commit is contained in:
parent
83a28ef095
commit
01d784131f
8 changed files with 127 additions and 42 deletions
|
@ -2,11 +2,14 @@ use crate::errors::RegionOriginNote;
|
||||||
use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
|
use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
|
||||||
use crate::infer::{self, SubregionOrigin};
|
use crate::infer::{self, SubregionOrigin};
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder,
|
||||||
|
ErrorGuaranteed,
|
||||||
};
|
};
|
||||||
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_middle::traits::ObligationCauseCode;
|
use rustc_middle::traits::ObligationCauseCode;
|
||||||
use rustc_middle::ty::error::TypeError;
|
use rustc_middle::ty::error::TypeError;
|
||||||
use rustc_middle::ty::{self, Region};
|
use rustc_middle::ty::{self, IsSuggestable, Region};
|
||||||
|
use rustc_span::symbol::kw;
|
||||||
|
|
||||||
use super::ObligationCauseAsDiagArg;
|
use super::ObligationCauseAsDiagArg;
|
||||||
|
|
||||||
|
@ -313,55 +316,43 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
);
|
);
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
|
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
|
||||||
.report_extra_impl_obligation(
|
let mut err = self.report_extra_impl_obligation(
|
||||||
span,
|
span,
|
||||||
impl_item_def_id,
|
impl_item_def_id,
|
||||||
trait_item_def_id,
|
trait_item_def_id,
|
||||||
&format!("`{}: {}`", sup, sub),
|
&format!("`{}: {}`", sup, sub),
|
||||||
),
|
);
|
||||||
|
// We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
|
||||||
|
if self
|
||||||
|
.tcx
|
||||||
|
.hir()
|
||||||
|
.get_generics(impl_item_def_id)
|
||||||
|
.unwrap()
|
||||||
|
.where_clause_span
|
||||||
|
.contains(span)
|
||||||
|
{
|
||||||
|
self.suggest_copy_trait_method_bounds(
|
||||||
|
trait_item_def_id,
|
||||||
|
impl_item_def_id,
|
||||||
|
&mut err,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
err
|
||||||
|
}
|
||||||
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
|
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
|
||||||
let mut err = self.report_concrete_failure(*parent, sub, sup);
|
let mut err = self.report_concrete_failure(*parent, sub, sup);
|
||||||
|
|
||||||
let trait_item_span = self.tcx.def_span(trait_item_def_id);
|
let trait_item_span = self.tcx.def_span(trait_item_def_id);
|
||||||
let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
|
let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
|
||||||
err.span_label(
|
err.span_label(
|
||||||
trait_item_span,
|
trait_item_span,
|
||||||
format!("definition of `{}` from trait", item_name),
|
format!("definition of `{}` from trait", item_name),
|
||||||
);
|
);
|
||||||
|
self.suggest_copy_trait_method_bounds(
|
||||||
let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
|
trait_item_def_id,
|
||||||
let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
|
impl_item_def_id,
|
||||||
|
&mut err,
|
||||||
let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
|
);
|
||||||
impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
|
|
||||||
let clauses: Vec<_> = trait_predicates
|
|
||||||
.predicates
|
|
||||||
.into_iter()
|
|
||||||
.filter(|&(pred, _)| !impl_predicates.contains(pred))
|
|
||||||
.map(|(pred, _)| format!("{}", pred))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if !clauses.is_empty() {
|
|
||||||
let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
|
|
||||||
let where_clause_span = generics.tail_span_for_predicate_suggestion();
|
|
||||||
|
|
||||||
let suggestion = format!(
|
|
||||||
"{} {}",
|
|
||||||
generics.add_where_or_trailing_comma(),
|
|
||||||
clauses.join(", "),
|
|
||||||
);
|
|
||||||
err.span_suggestion(
|
|
||||||
where_clause_span,
|
|
||||||
&format!(
|
|
||||||
"try copying {} from the trait",
|
|
||||||
if clauses.len() > 1 { "these clauses" } else { "this clause" }
|
|
||||||
),
|
|
||||||
suggestion,
|
|
||||||
rustc_errors::Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
infer::AscribeUserTypeProvePredicate(span) => {
|
infer::AscribeUserTypeProvePredicate(span) => {
|
||||||
|
@ -388,6 +379,66 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn suggest_copy_trait_method_bounds(
|
||||||
|
&self,
|
||||||
|
trait_item_def_id: DefId,
|
||||||
|
impl_item_def_id: LocalDefId,
|
||||||
|
err: &mut Diagnostic,
|
||||||
|
) {
|
||||||
|
// FIXME(compiler-errors): Right now this is only being used for region
|
||||||
|
// predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
|
||||||
|
// but right now it's not really very smart when it comes to implicit `Sized`
|
||||||
|
// predicates and bounds on the trait itself.
|
||||||
|
|
||||||
|
let impl_def_id =
|
||||||
|
self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx).unwrap();
|
||||||
|
let trait_substs = self
|
||||||
|
.tcx
|
||||||
|
.impl_trait_ref(impl_def_id)
|
||||||
|
.unwrap()
|
||||||
|
// Replace the explicit self type with `Self` for better suggestion rendering
|
||||||
|
.with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
|
||||||
|
.substs;
|
||||||
|
let trait_item_substs =
|
||||||
|
ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id())
|
||||||
|
.rebase_onto(self.tcx, impl_def_id, trait_substs);
|
||||||
|
|
||||||
|
let mut is_suggestable = true;
|
||||||
|
let trait_predicates = self
|
||||||
|
.tcx
|
||||||
|
.bound_explicit_predicates_of(trait_item_def_id)
|
||||||
|
.map_bound(|p| p.predicates)
|
||||||
|
.subst_iter_copied(self.tcx, trait_item_substs)
|
||||||
|
.map(|(pred, _)| {
|
||||||
|
if !pred.is_suggestable(self.tcx, false) {
|
||||||
|
is_suggestable = false;
|
||||||
|
}
|
||||||
|
pred.to_string()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
|
||||||
|
|
||||||
|
if is_suggestable {
|
||||||
|
if trait_predicates.is_empty() {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
generics.where_clause_span,
|
||||||
|
"remove the `where` clause",
|
||||||
|
String::new(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let space = if generics.where_clause_span.is_empty() { " " } else { "" };
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
generics.where_clause_span,
|
||||||
|
"copy the `where` clause predicates from the trait",
|
||||||
|
format!("{space}where {}", trait_predicates.join(", ")),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn report_placeholder_failure(
|
pub(super) fn report_placeholder_failure(
|
||||||
&self,
|
&self,
|
||||||
placeholder_origin: SubregionOrigin<'tcx>,
|
placeholder_origin: SubregionOrigin<'tcx>,
|
||||||
|
|
|
@ -6,6 +6,11 @@ LL | fn renew<'b: 'a>(self) -> &'b mut [T];
|
||||||
...
|
...
|
||||||
LL | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
|
LL | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
|
||||||
| ^^ impl has extra requirement `'a: 'b`
|
| ^^ impl has extra requirement `'a: 'b`
|
||||||
|
|
|
||||||
|
help: copy the `where` clause predicates from the trait
|
||||||
|
|
|
||||||
|
LL | fn renew<'b: 'a>(self) -> &'b mut [T] where 'b: 'a {
|
||||||
|
| ~~~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,12 @@ LL | fn foo();
|
||||||
...
|
...
|
||||||
LL | fn foo() where 'a: 'b { }
|
LL | fn foo() where 'a: 'b { }
|
||||||
| ^^ impl has extra requirement `'a: 'b`
|
| ^^ impl has extra requirement `'a: 'b`
|
||||||
|
|
|
||||||
|
help: remove the `where` clause
|
||||||
|
|
|
||||||
|
LL - fn foo() where 'a: 'b { }
|
||||||
|
LL + fn foo() { }
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,11 @@ LL | type B<'a, 'b> where 'a: 'b;
|
||||||
...
|
...
|
||||||
LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
|
LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
|
||||||
| ^^ impl has extra requirement `'b: 'a`
|
| ^^ impl has extra requirement `'b: 'a`
|
||||||
|
|
|
||||||
|
help: copy the `where` clause predicates from the trait
|
||||||
|
|
|
||||||
|
LL | type B<'a, 'b> = (&'a(), &'b ()) where 'a: 'b;
|
||||||
|
| ~~~~~~~~~~~~
|
||||||
|
|
||||||
error[E0277]: the trait bound `T: Copy` is not satisfied
|
error[E0277]: the trait bound `T: Copy` is not satisfied
|
||||||
--> $DIR/impl_bounds.rs:18:33
|
--> $DIR/impl_bounds.rs:18:33
|
||||||
|
|
|
@ -5,13 +5,17 @@ LL | type Fut<'a> where Self: 'a;
|
||||||
| ------------ definition of `Fut` from trait
|
| ------------ definition of `Fut` from trait
|
||||||
...
|
...
|
||||||
LL | type Fut<'a> = impl Future<Output = ()>;
|
LL | type Fut<'a> = impl Future<Output = ()>;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: type must outlive the lifetime `'a` as defined here
|
note: type must outlive the lifetime `'a` as defined here
|
||||||
--> $DIR/issue-90014.rs:13:14
|
--> $DIR/issue-90014.rs:13:14
|
||||||
|
|
|
|
||||||
LL | type Fut<'a> = impl Future<Output = ()>;
|
LL | type Fut<'a> = impl Future<Output = ()>;
|
||||||
| ^^
|
| ^^
|
||||||
|
help: copy the `where` clause predicates from the trait
|
||||||
|
|
|
||||||
|
LL | type Fut<'a> = impl Future<Output = ()> where Self: 'a;
|
||||||
|
| ++++++++++++++
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ LL | type Cursor<'tx>: Cursor<'tx>
|
||||||
| ----------------------------- definition of `Cursor` from trait
|
| ----------------------------- definition of `Cursor` from trait
|
||||||
...
|
...
|
||||||
LL | type Cursor<'tx> = CursorImpl<'tx>;
|
LL | type Cursor<'tx> = CursorImpl<'tx>;
|
||||||
| ^^^^^^^^^^^^^^^- help: try copying these clauses from the trait: `where 'db: 'tx, Self: 'tx`
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: lifetime parameter instantiated with the lifetime `'db` as defined here
|
note: lifetime parameter instantiated with the lifetime `'db` as defined here
|
||||||
--> $DIR/issue-91883.rs:29:6
|
--> $DIR/issue-91883.rs:29:6
|
||||||
|
@ -17,6 +17,10 @@ note: but lifetime parameter must outlive the lifetime `'tx` as defined here
|
||||||
|
|
|
|
||||||
LL | type Cursor<'tx> = CursorImpl<'tx>;
|
LL | type Cursor<'tx> = CursorImpl<'tx>;
|
||||||
| ^^^
|
| ^^^
|
||||||
|
help: copy the `where` clause predicates from the trait
|
||||||
|
|
|
||||||
|
LL | type Cursor<'tx> = CursorImpl<'tx> where 'db: 'tx, Self: 'tx;
|
||||||
|
| +++++++++++++++++++++++++
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,17 @@ LL | type TextureIter<'a>: Iterator<Item = &'a Texture>
|
||||||
| -------------------------------------------------- definition of `TextureIter` from trait
|
| -------------------------------------------------- definition of `TextureIter` from trait
|
||||||
...
|
...
|
||||||
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
|
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: type must outlive the lifetime `'a` as defined here
|
note: type must outlive the lifetime `'a` as defined here
|
||||||
--> $DIR/issue-92033.rs:20:22
|
--> $DIR/issue-92033.rs:20:22
|
||||||
|
|
|
|
||||||
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
|
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
|
||||||
| ^^
|
| ^^
|
||||||
|
help: copy the `where` clause predicates from the trait
|
||||||
|
|
|
||||||
|
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture> where Self: 'a;
|
||||||
|
| ++++++++++++++
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,12 @@ LL | type Assoc<'a, 'b>;
|
||||||
...
|
...
|
||||||
LL | type Assoc<'a, 'b> = () where 'a: 'b;
|
LL | type Assoc<'a, 'b> = () where 'a: 'b;
|
||||||
| ^^ impl has extra requirement `'a: 'b`
|
| ^^ impl has extra requirement `'a: 'b`
|
||||||
|
|
|
||||||
|
help: remove the `where` clause
|
||||||
|
|
|
||||||
|
LL - type Assoc<'a, 'b> = () where 'a: 'b;
|
||||||
|
LL + type Assoc<'a, 'b> = () ;
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue