Skip to content

Commit 01d7841

Browse files
Make trait/impl where clause mismatch on region error a bit more actionable
1 parent 83a28ef commit 01d7841

File tree

8 files changed

+127
-42
lines changed

8 files changed

+127
-42
lines changed

compiler/rustc_infer/src/infer/error_reporting/note.rs

Lines changed: 90 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ use crate::errors::RegionOriginNote;
22
use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
33
use crate::infer::{self, SubregionOrigin};
44
use rustc_errors::{
5-
fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
5+
fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder,
6+
ErrorGuaranteed,
67
};
8+
use rustc_hir::def_id::{DefId, LocalDefId};
79
use rustc_middle::traits::ObligationCauseCode;
810
use rustc_middle::ty::error::TypeError;
9-
use rustc_middle::ty::{self, Region};
11+
use rustc_middle::ty::{self, IsSuggestable, Region};
12+
use rustc_span::symbol::kw;
1013

1114
use super::ObligationCauseAsDiagArg;
1215

@@ -313,55 +316,43 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
313316
);
314317
err
315318
}
316-
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
317-
.report_extra_impl_obligation(
319+
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
320+
let mut err = self.report_extra_impl_obligation(
318321
span,
319322
impl_item_def_id,
320323
trait_item_def_id,
321324
&format!("`{}: {}`", sup, sub),
322-
),
325+
);
326+
// We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
327+
if self
328+
.tcx
329+
.hir()
330+
.get_generics(impl_item_def_id)
331+
.unwrap()
332+
.where_clause_span
333+
.contains(span)
334+
{
335+
self.suggest_copy_trait_method_bounds(
336+
trait_item_def_id,
337+
impl_item_def_id,
338+
&mut err,
339+
);
340+
}
341+
err
342+
}
323343
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
324344
let mut err = self.report_concrete_failure(*parent, sub, sup);
325-
326345
let trait_item_span = self.tcx.def_span(trait_item_def_id);
327346
let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
328347
err.span_label(
329348
trait_item_span,
330349
format!("definition of `{}` from trait", item_name),
331350
);
332-
333-
let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
334-
let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
335-
336-
let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
337-
impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
338-
let clauses: Vec<_> = trait_predicates
339-
.predicates
340-
.into_iter()
341-
.filter(|&(pred, _)| !impl_predicates.contains(pred))
342-
.map(|(pred, _)| format!("{}", pred))
343-
.collect();
344-
345-
if !clauses.is_empty() {
346-
let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
347-
let where_clause_span = generics.tail_span_for_predicate_suggestion();
348-
349-
let suggestion = format!(
350-
"{} {}",
351-
generics.add_where_or_trailing_comma(),
352-
clauses.join(", "),
353-
);
354-
err.span_suggestion(
355-
where_clause_span,
356-
&format!(
357-
"try copying {} from the trait",
358-
if clauses.len() > 1 { "these clauses" } else { "this clause" }
359-
),
360-
suggestion,
361-
rustc_errors::Applicability::MaybeIncorrect,
362-
);
363-
}
364-
351+
self.suggest_copy_trait_method_bounds(
352+
trait_item_def_id,
353+
impl_item_def_id,
354+
&mut err,
355+
);
365356
err
366357
}
367358
infer::AscribeUserTypeProvePredicate(span) => {
@@ -388,6 +379,66 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
388379
}
389380
}
390381

382+
pub fn suggest_copy_trait_method_bounds(
383+
&self,
384+
trait_item_def_id: DefId,
385+
impl_item_def_id: LocalDefId,
386+
err: &mut Diagnostic,
387+
) {
388+
// FIXME(compiler-errors): Right now this is only being used for region
389+
// predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
390+
// but right now it's not really very smart when it comes to implicit `Sized`
391+
// predicates and bounds on the trait itself.
392+
393+
let impl_def_id =
394+
self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx).unwrap();
395+
let trait_substs = self
396+
.tcx
397+
.impl_trait_ref(impl_def_id)
398+
.unwrap()
399+
// Replace the explicit self type with `Self` for better suggestion rendering
400+
.with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
401+
.substs;
402+
let trait_item_substs =
403+
ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id())
404+
.rebase_onto(self.tcx, impl_def_id, trait_substs);
405+
406+
let mut is_suggestable = true;
407+
let trait_predicates = self
408+
.tcx
409+
.bound_explicit_predicates_of(trait_item_def_id)
410+
.map_bound(|p| p.predicates)
411+
.subst_iter_copied(self.tcx, trait_item_substs)
412+
.map(|(pred, _)| {
413+
if !pred.is_suggestable(self.tcx, false) {
414+
is_suggestable = false;
415+
}
416+
pred.to_string()
417+
})
418+
.collect::<Vec<_>>();
419+
420+
let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
421+
422+
if is_suggestable {
423+
if trait_predicates.is_empty() {
424+
err.span_suggestion_verbose(
425+
generics.where_clause_span,
426+
"remove the `where` clause",
427+
String::new(),
428+
Applicability::MachineApplicable,
429+
);
430+
} else {
431+
let space = if generics.where_clause_span.is_empty() { " " } else { "" };
432+
err.span_suggestion_verbose(
433+
generics.where_clause_span,
434+
"copy the `where` clause predicates from the trait",
435+
format!("{space}where {}", trait_predicates.join(", ")),
436+
Applicability::MachineApplicable,
437+
);
438+
}
439+
}
440+
}
441+
391442
pub(super) fn report_placeholder_failure(
392443
&self,
393444
placeholder_origin: SubregionOrigin<'tcx>,

src/test/ui/compare-method/region-extra-2.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ LL | fn renew<'b: 'a>(self) -> &'b mut [T];
66
...
77
LL | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
88
| ^^ impl has extra requirement `'a: 'b`
9+
|
10+
help: copy the `where` clause predicates from the trait
11+
|
12+
LL | fn renew<'b: 'a>(self) -> &'b mut [T] where 'b: 'a {
13+
| ~~~~~~~~~~~~
914

1015
error: aborting due to previous error
1116

src/test/ui/compare-method/region-extra.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ LL | fn foo();
66
...
77
LL | fn foo() where 'a: 'b { }
88
| ^^ impl has extra requirement `'a: 'b`
9+
|
10+
help: remove the `where` clause
11+
|
12+
LL - fn foo() where 'a: 'b { }
13+
LL + fn foo() { }
14+
|
915

1016
error: aborting due to previous error
1117

src/test/ui/generic-associated-types/impl_bounds.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ LL | type B<'a, 'b> where 'a: 'b;
1515
...
1616
LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
1717
| ^^ impl has extra requirement `'b: 'a`
18+
|
19+
help: copy the `where` clause predicates from the trait
20+
|
21+
LL | type B<'a, 'b> = (&'a(), &'b ()) where 'a: 'b;
22+
| ~~~~~~~~~~~~
1823

1924
error[E0277]: the trait bound `T: Copy` is not satisfied
2025
--> $DIR/impl_bounds.rs:18:33

src/test/ui/generic-associated-types/issue-90014.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ LL | type Fut<'a> where Self: 'a;
55
| ------------ definition of `Fut` from trait
66
...
77
LL | type Fut<'a> = impl Future<Output = ()>;
8-
| ^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a`
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^
99
|
1010
note: type must outlive the lifetime `'a` as defined here
1111
--> $DIR/issue-90014.rs:13:14
1212
|
1313
LL | type Fut<'a> = impl Future<Output = ()>;
1414
| ^^
15+
help: copy the `where` clause predicates from the trait
16+
|
17+
LL | type Fut<'a> = impl Future<Output = ()> where Self: 'a;
18+
| ++++++++++++++
1519

1620
error: aborting due to previous error
1721

src/test/ui/generic-associated-types/issue-91883.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | type Cursor<'tx>: Cursor<'tx>
55
| ----------------------------- definition of `Cursor` from trait
66
...
77
LL | type Cursor<'tx> = CursorImpl<'tx>;
8-
| ^^^^^^^^^^^^^^^- help: try copying these clauses from the trait: `where 'db: 'tx, Self: 'tx`
8+
| ^^^^^^^^^^^^^^^
99
|
1010
note: lifetime parameter instantiated with the lifetime `'db` as defined here
1111
--> $DIR/issue-91883.rs:29:6
@@ -17,6 +17,10 @@ note: but lifetime parameter must outlive the lifetime `'tx` as defined here
1717
|
1818
LL | type Cursor<'tx> = CursorImpl<'tx>;
1919
| ^^^
20+
help: copy the `where` clause predicates from the trait
21+
|
22+
LL | type Cursor<'tx> = CursorImpl<'tx> where 'db: 'tx, Self: 'tx;
23+
| +++++++++++++++++++++++++
2024

2125
error: aborting due to previous error
2226

src/test/ui/generic-associated-types/issue-92033.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ LL | type TextureIter<'a>: Iterator<Item = &'a Texture>
55
| -------------------------------------------------- definition of `TextureIter` from trait
66
...
77
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
8-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a`
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
99
|
1010
note: type must outlive the lifetime `'a` as defined here
1111
--> $DIR/issue-92033.rs:20:22
1212
|
1313
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
1414
| ^^
15+
help: copy the `where` clause predicates from the trait
16+
|
17+
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture> where Self: 'a;
18+
| ++++++++++++++
1519

1620
error: aborting due to previous error
1721

src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ LL | type Assoc<'a, 'b>;
66
...
77
LL | type Assoc<'a, 'b> = () where 'a: 'b;
88
| ^^ impl has extra requirement `'a: 'b`
9+
|
10+
help: remove the `where` clause
11+
|
12+
LL - type Assoc<'a, 'b> = () where 'a: 'b;
13+
LL + type Assoc<'a, 'b> = () ;
14+
|
915

1016
error: aborting due to previous error
1117

0 commit comments

Comments
 (0)