Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f9fab1f

Browse files
authoredDec 29, 2022
Rollup merge of rust-lang#106208 - compiler-errors:compare-item-region-err, r=estebank
Make trait/impl `where` clause mismatch on region error a bit more actionable Improve `where` clause suggestions for GATs/methods that have incompatible region predicates in their `where` clauses. Also addresses this diagnostic that went away rust-lang#106129 (comment)
2 parents 0f86c76 + 6e794dc commit f9fab1f

10 files changed

+150
-42
lines changed
 

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

+84-39
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,38 @@ 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 let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
328+
&& generics.where_clause_span.contains(span)
329+
{
330+
self.suggest_copy_trait_method_bounds(
331+
trait_item_def_id,
332+
impl_item_def_id,
333+
&mut err,
334+
);
335+
}
336+
err
337+
}
323338
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
324339
let mut err = self.report_concrete_failure(*parent, sub, sup);
325-
326340
let trait_item_span = self.tcx.def_span(trait_item_def_id);
327341
let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
328342
err.span_label(
329343
trait_item_span,
330344
format!("definition of `{}` from trait", item_name),
331345
);
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-
346+
self.suggest_copy_trait_method_bounds(
347+
trait_item_def_id,
348+
impl_item_def_id,
349+
&mut err,
350+
);
365351
err
366352
}
367353
infer::AscribeUserTypeProvePredicate(span) => {
@@ -388,6 +374,65 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
388374
}
389375
}
390376

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

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

+5
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

+6
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

+5
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

+5-1
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

+5-1
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

+5-1
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

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
trait Foo {
2+
type T<'a1, 'b1>
3+
where
4+
'a1: 'b1;
5+
}
6+
7+
impl Foo for () {
8+
type T<'a2, 'b2> = () where 'b2: 'a2;
9+
//~^ ERROR impl has stricter requirements than trait
10+
}
11+
12+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0276]: impl has stricter requirements than trait
2+
--> $DIR/mismatched-where-clause-regions.rs:8:38
3+
|
4+
LL | type T<'a1, 'b1>
5+
| ---------------- definition of `T` from trait
6+
...
7+
LL | type T<'a2, 'b2> = () where 'b2: 'a2;
8+
| ^^^ impl has extra requirement `'b2: 'a2`
9+
|
10+
help: copy the `where` clause predicates from the trait
11+
|
12+
LL | type T<'a2, 'b2> = () where 'a2: 'b2;
13+
| ~~~~~~~~~~~~~~
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0276`.

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

+6
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)
Please sign in to comment.