Skip to content

Commit a65c9b3

Browse files
authored
Rollup merge of rust-lang#92683 - jackh726:issue-92033, r=estebank
Suggest copying trait associated type bounds on lifetime error Closes rust-lang#92033 Kind of the most simple suggestion to make - we don't try to be fancy. Turns out, it's still pretty useful (the couple existing tests that trigger this error end up fixed - for this error - upon applying the fix). r? `@estebank` cc `@nikomatsakis`
2 parents 30b3f35 + 3d19c8d commit a65c9b3

File tree

12 files changed

+163
-28
lines changed

12 files changed

+163
-28
lines changed

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
6464
.or_else(|| self.try_report_mismatched_static_lifetime())
6565
}
6666

67-
pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
67+
pub(super) fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
6868
match (&self.error, self.regions) {
6969
(Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), *sub, *sup)),
7070
(Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {

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

+52
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
102102
"...so that the definition in impl matches the definition from the trait",
103103
);
104104
}
105+
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
106+
self.note_region_origin(err, &parent);
107+
}
105108
}
106109
}
107110

@@ -345,6 +348,55 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
345348
trait_item_def_id,
346349
&format!("`{}: {}`", sup, sub),
347350
),
351+
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
352+
let mut err = self.report_concrete_failure(*parent, sub, sup);
353+
354+
let trait_item_span = self.tcx.def_span(trait_item_def_id);
355+
let item_name = self.tcx.item_name(impl_item_def_id);
356+
err.span_label(
357+
trait_item_span,
358+
format!("definition of `{}` from trait", item_name),
359+
);
360+
361+
let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
362+
let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
363+
364+
let impl_predicates: rustc_data_structures::stable_set::FxHashSet<_> =
365+
impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
366+
let clauses: Vec<_> = trait_predicates
367+
.predicates
368+
.into_iter()
369+
.filter(|&(pred, _)| !impl_predicates.contains(pred))
370+
.map(|(pred, _)| format!("{}", pred))
371+
.collect();
372+
373+
if !clauses.is_empty() {
374+
let where_clause_span = self
375+
.tcx
376+
.hir()
377+
.get_generics(impl_item_def_id.expect_local())
378+
.unwrap()
379+
.where_clause
380+
.tail_span_for_suggestion();
381+
382+
let suggestion = format!(
383+
"{} {}",
384+
if !impl_predicates.is_empty() { "," } else { " where" },
385+
clauses.join(", "),
386+
);
387+
err.span_suggestion(
388+
where_clause_span,
389+
&format!(
390+
"try copying {} from the trait",
391+
if clauses.len() > 1 { "these clauses" } else { "this clause" }
392+
),
393+
suggestion,
394+
rustc_errors::Applicability::MaybeIncorrect,
395+
);
396+
}
397+
398+
err
399+
}
348400
}
349401
}
350402

compiler/rustc_infer/src/infer/mod.rs

+17
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,13 @@ pub enum SubregionOrigin<'tcx> {
438438
/// Comparing the signature and requirements of an impl associated type
439439
/// against the containing trait
440440
CompareImplTypeObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId },
441+
442+
/// Checking that the bounds of a trait's associated type hold for a given impl
443+
CheckAssociatedTypeBounds {
444+
parent: Box<SubregionOrigin<'tcx>>,
445+
impl_item_def_id: DefId,
446+
trait_item_def_id: DefId,
447+
},
441448
}
442449

443450
// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -1832,6 +1839,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
18321839
ReferenceOutlivesReferent(_, a) => a,
18331840
CompareImplMethodObligation { span, .. } => span,
18341841
CompareImplTypeObligation { span, .. } => span,
1842+
CheckAssociatedTypeBounds { ref parent, .. } => parent.span(),
18351843
}
18361844
}
18371845

@@ -1862,6 +1870,15 @@ impl<'tcx> SubregionOrigin<'tcx> {
18621870
trait_item_def_id,
18631871
},
18641872

1873+
traits::ObligationCauseCode::CheckAssociatedTypeBounds {
1874+
impl_item_def_id,
1875+
trait_item_def_id,
1876+
} => SubregionOrigin::CheckAssociatedTypeBounds {
1877+
impl_item_def_id,
1878+
trait_item_def_id,
1879+
parent: Box::new(default()),
1880+
},
1881+
18651882
_ => default(),
18661883
}
18671884
}

compiler/rustc_middle/src/traits/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,12 @@ pub enum ObligationCauseCode<'tcx> {
285285
trait_item_def_id: DefId,
286286
},
287287

288+
/// Checking that the bounds of a trait's associated type hold for a given impl
289+
CheckAssociatedTypeBounds {
290+
impl_item_def_id: DefId,
291+
trait_item_def_id: DefId,
292+
},
293+
288294
/// Checking that this expression can be assigned where it needs to be
289295
// FIXME(eddyb) #11161 is the original Expr required?
290296
ExprAssignable,

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1932,7 +1932,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
19321932
| ObligationCauseCode::AwaitableExpr(_)
19331933
| ObligationCauseCode::ForLoopIterator
19341934
| ObligationCauseCode::QuestionMark
1935-
| ObligationCauseCode::LetElse => {}
1935+
| ObligationCauseCode::LetElse
1936+
| ObligationCauseCode::CheckAssociatedTypeBounds { .. } => {}
19361937
ObligationCauseCode::SliceOrArrayElem => {
19371938
err.note("slice and array elements must have `Sized` type");
19381939
}

compiler/rustc_typeck/src/check/compare_method.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1378,7 +1378,14 @@ pub fn check_type_bounds<'tcx>(
13781378
let mut selcx = traits::SelectionContext::new(&infcx);
13791379

13801380
let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
1381-
let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
1381+
let normalize_cause = ObligationCause::new(
1382+
impl_ty_span,
1383+
impl_ty_hir_id,
1384+
ObligationCauseCode::CheckAssociatedTypeBounds {
1385+
impl_item_def_id: impl_ty.def_id,
1386+
trait_item_def_id: trait_ty.def_id,
1387+
},
1388+
);
13821389
let mk_cause = |span: Span| {
13831390
let code = if span.is_dummy() {
13841391
traits::MiscObligation

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@ LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
1919
error[E0478]: lifetime bound not satisfied
2020
--> $DIR/impl_bounds.rs:17:35
2121
|
22+
LL | type B<'a, 'b> where 'a: 'b;
23+
| ---------------------------- definition of `B` from trait
24+
...
2225
LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
23-
| ^^^^^^^^^^^^^^^
26+
| - ^^^^^^^^^^^^^^^
27+
| |
28+
| help: try copying this clause from the trait: `, 'a: 'b`
2429
|
2530
note: lifetime parameter instantiated with the lifetime `'a` as defined here
2631
--> $DIR/impl_bounds.rs:17:12

src/test/ui/generic-associated-types/issue-88595.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ trait A<'a> {
88
// FIXME(generic_associated_types): Remove one of the below bounds
99
// https://github.com/rust-lang/rust/pull/90678#discussion_r744976085
1010
where
11-
'a: 'b, Self: 'a, Self: 'b;
11+
Self: 'a, Self: 'b;
1212

1313
fn a(&'a self) -> Self::B<'a>;
1414
}
@@ -17,8 +17,7 @@ struct C;
1717

1818
impl<'a> A<'a> for C {
1919
type B<'b> = impl Clone;
20-
//~^ ERROR: lifetime bound not satisfied
21-
//~| ERROR: could not find defining uses
20+
//~^ ERROR: could not find defining uses
2221

2322
fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope
2423
}
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,5 @@
1-
error[E0478]: lifetime bound not satisfied
2-
--> $DIR/issue-88595.rs:19:18
3-
|
4-
LL | type B<'b> = impl Clone;
5-
| ^^^^^^^^^^
6-
|
7-
note: lifetime parameter instantiated with the lifetime `'a` as defined here
8-
--> $DIR/issue-88595.rs:18:6
9-
|
10-
LL | impl<'a> A<'a> for C {
11-
| ^^
12-
note: but lifetime parameter must outlive the lifetime `'b` as defined here
13-
--> $DIR/issue-88595.rs:19:12
14-
|
15-
LL | type B<'b> = impl Clone;
16-
| ^^
17-
181
error: non-defining opaque type use in defining scope
19-
--> $DIR/issue-88595.rs:23:23
2+
--> $DIR/issue-88595.rs:22:23
203
|
214
LL | fn a(&'a self) -> Self::B<'a> {}
225
| ^^^^^^^^^^^
@@ -35,6 +18,5 @@ error: could not find defining uses
3518
LL | type B<'b> = impl Clone;
3619
| ^^^^^^^^^^
3720

38-
error: aborting due to 3 previous errors
21+
error: aborting due to 2 previous errors
3922

40-
For more information about this error, try `rustc --explain E0478`.

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
error[E0477]: the type `&mut ()` does not fulfill the required lifetime
22
--> $DIR/issue-90014.rs:14:20
33
|
4+
LL | type Fut<'a> where Self: 'a;
5+
| ---------------------------- definition of `Fut` from trait
6+
...
47
LL | type Fut<'a> = impl Future<Output = ()>;
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^
8+
| - ^^^^^^^^^^^^^^^^^^^^^^^^
9+
| |
10+
| help: try copying this clause from the trait: `where Self: 'a`
611
|
712
note: type must outlive the lifetime `'a` as defined here
813
--> $DIR/issue-90014.rs:14:14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#![feature(generic_associated_types)]
2+
3+
struct Texture;
4+
5+
trait Surface {
6+
type TextureIter<'a>: Iterator<Item = &'a Texture>
7+
where
8+
Self: 'a;
9+
10+
fn get_texture(&self) -> Self::TextureIter<'_>;
11+
}
12+
13+
trait Swapchain {
14+
type Surface<'a>: Surface
15+
where
16+
Self: 'a;
17+
18+
fn get_surface(&self) -> Self::Surface<'_>;
19+
}
20+
21+
impl<'s> Surface for &'s Texture {
22+
type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
23+
//~^ ERROR the type
24+
25+
fn get_texture(&self) -> Self::TextureIter<'_> {
26+
let option: Option<&Texture> = Some(self);
27+
option.into_iter()
28+
}
29+
}
30+
31+
impl Swapchain for Texture {
32+
type Surface<'a> = &'a Texture;
33+
34+
fn get_surface(&self) -> Self::Surface<'_> {
35+
self
36+
}
37+
}
38+
39+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0477]: the type `&'s Texture` does not fulfill the required lifetime
2+
--> $DIR/issue-92033.rs:22:28
3+
|
4+
LL | / type TextureIter<'a>: Iterator<Item = &'a Texture>
5+
LL | | where
6+
LL | | Self: 'a;
7+
| |_________________- definition of `TextureIter` from trait
8+
...
9+
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
10+
| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11+
| |
12+
| help: try copying this clause from the trait: `where Self: 'a`
13+
|
14+
note: type must outlive the lifetime `'a` as defined here
15+
--> $DIR/issue-92033.rs:22:22
16+
|
17+
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
18+
| ^^
19+
20+
error: aborting due to previous error
21+
22+
For more information about this error, try `rustc --explain E0477`.

0 commit comments

Comments
 (0)