Skip to content

Commit b6edcbd

Browse files
committed
Review comments
1 parent ef5e31a commit b6edcbd

File tree

3 files changed

+51
-22
lines changed

3 files changed

+51
-22
lines changed

compiler/rustc_typeck/src/check/wfcheck.rs

+41-14
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
263263
check_gat_where_clauses(tcx, trait_item, encl_trait_def_id);
264264
}
265265

266-
/// Require that the user writes as where clauses on GATs the implicit
266+
/// Require that the user writes where clauses on GATs for the implicit
267267
/// outlives bounds involving trait parameters in trait functions and
268268
/// lifetimes passed as GAT substs. See `self-outlives-lint` test.
269269
///
@@ -288,6 +288,7 @@ fn check_gat_where_clauses(
288288
}
289289
let generics: &ty::Generics = tcx.generics_of(trait_item.def_id);
290290
// If the current associated type doesn't have any (own) params, it's not a GAT
291+
// FIXME(jackh726): we can also warn in the more general case
291292
if generics.params.len() == 0 {
292293
return;
293294
}
@@ -311,20 +312,15 @@ fn check_gat_where_clauses(
311312
// Collect the arguments that are given to this GAT in the return type
312313
// of the function signature. In our example, the GAT in the return
313314
// type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments.
314-
let mut visitor = GATSubstCollector {
315-
tcx,
316-
gat: trait_item.def_id.to_def_id(),
317-
regions: FxHashSet::default(),
318-
types: FxHashSet::default(),
319-
};
320-
sig.output().visit_with(&mut visitor);
315+
let (regions, types) =
316+
GATSubstCollector::visit(tcx, trait_item.def_id.to_def_id(), sig.output());
321317

322318
// If both regions and types are empty, then this GAT isn't in the
323319
// return type, and we shouldn't try to do clause analysis
324320
// (particularly, doing so would end up with an empty set of clauses,
325321
// since the current method would require none, and we take the
326322
// intersection of requirements of all methods)
327-
if visitor.types.is_empty() && visitor.regions.is_empty() {
323+
if types.is_empty() && regions.is_empty() {
328324
continue;
329325
}
330326

@@ -337,8 +333,8 @@ fn check_gat_where_clauses(
337333
// relationship to the type arguments (e.g., Self). If there is an
338334
// outlives relationship (`Self: 'a`), then we want to ensure that is
339335
// reflected in a where clause on the GAT itself.
340-
for (region, region_idx) in &visitor.regions {
341-
for (ty, ty_idx) in &visitor.types {
336+
for (region, region_idx) in &regions {
337+
for (ty, ty_idx) in &types {
342338
// In our example, requires that Self: 'a
343339
if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) {
344340
debug!(?ty_idx, ?region_idx);
@@ -376,8 +372,8 @@ fn check_gat_where_clauses(
376372
// relationship to the other region arguments. If there is an
377373
// outlives relationship, then we want to ensure that is
378374
// reflected in a where clause on the GAT itself.
379-
for (region_a, region_a_idx) in &visitor.regions {
380-
for (region_b, region_b_idx) in &visitor.regions {
375+
for (region_a, region_a_idx) in &regions {
376+
for (region_b, region_b_idx) in &regions {
381377
if region_a == region_b {
382378
continue;
383379
}
@@ -412,6 +408,16 @@ fn check_gat_where_clauses(
412408
}
413409
}
414410

411+
// Imagine we have:
412+
// ```
413+
// trait Foo {
414+
// type Bar<'me>;
415+
// fn gimme(&self) -> Self::Bar<'_>;
416+
// fn gimme_default(&self) -> Self::Bar<'static>;
417+
// }
418+
// ```
419+
// We only want to require clauses on `Bar` that we can prove from *all* functions (in this
420+
// case, `'me` can be `static` from `gimme_default`)
415421
match clauses.as_mut() {
416422
Some(clauses) => {
417423
clauses.drain_filter(|p| !function_clauses.contains(p));
@@ -428,12 +434,14 @@ fn check_gat_where_clauses(
428434
if !clauses.is_empty() {
429435
let written_predicates: ty::GenericPredicates<'_> =
430436
tcx.explicit_predicates_of(trait_item.def_id);
431-
let clauses: Vec<_> = clauses
437+
let mut clauses: Vec<_> = clauses
432438
.drain_filter(|clause| {
433439
written_predicates.predicates.iter().find(|p| &p.0 == clause).is_none()
434440
})
435441
.map(|clause| format!("{}", clause))
436442
.collect();
443+
// We sort so that order is predictable
444+
clauses.sort();
437445
if !clauses.is_empty() {
438446
let mut err = tcx.sess.struct_span_err(
439447
trait_item.span,
@@ -461,6 +469,8 @@ fn check_gat_where_clauses(
461469
}
462470
}
463471

472+
// FIXME(jackh726): refactor some of the shared logic between the two functions below
473+
464474
/// Given a known `param_env` and a set of well formed types, can we prove that
465475
/// `ty` outlives `region`.
466476
fn ty_known_to_outlive<'tcx>(
@@ -564,6 +574,23 @@ struct GATSubstCollector<'tcx> {
564574
types: FxHashSet<(Ty<'tcx>, usize)>,
565575
}
566576

577+
impl<'tcx> GATSubstCollector<'tcx> {
578+
fn visit<T: TypeFoldable<'tcx>>(
579+
tcx: TyCtxt<'tcx>,
580+
gat: DefId,
581+
t: T,
582+
) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) {
583+
let mut visitor = GATSubstCollector {
584+
tcx,
585+
gat,
586+
regions: FxHashSet::default(),
587+
types: FxHashSet::default(),
588+
};
589+
t.visit_with(&mut visitor);
590+
(visitor.regions, visitor.types)
591+
}
592+
}
593+
567594
impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
568595
type BreakTy = !;
569596

src/test/ui/generic-associated-types/self-outlives-lint.rs

+2
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,15 @@ trait NoGat<'a> {
109109
}
110110

111111
// Lifetime is not on function; except `Self: 'a`
112+
// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one
112113
trait TraitLifetime<'a> {
113114
type Bar<'b>;
114115
//~^ Missing required bounds
115116
fn method(&'a self) -> Self::Bar<'a>;
116117
}
117118

118119
// Like above, but we have a where clause that can prove what we want
120+
// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one
119121
trait TraitLifetimeWhere<'a> where Self: 'a {
120122
type Bar<'b>;
121123
//~^ Missing required bounds

src/test/ui/generic-associated-types/self-outlives-lint.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ error: Missing required bounds on Out
2828
LL | type Out<'x, 'y>;
2929
| ^^^^^^^^^^^^^^^^-
3030
| |
31-
| help: add the required where clauses: `where U: 'y, T: 'x`
31+
| help: add the required where clauses: `where T: 'x, U: 'y`
3232

3333
error: Missing required bounds on Out
3434
--> $DIR/self-outlives-lint.rs:61:5
@@ -55,39 +55,39 @@ LL | type Out<'x, D>;
5555
| help: add the required where clauses: `where D: 'x`
5656

5757
error: Missing required bounds on Bar
58-
--> $DIR/self-outlives-lint.rs:113:5
58+
--> $DIR/self-outlives-lint.rs:114:5
5959
|
6060
LL | type Bar<'b>;
6161
| ^^^^^^^^^^^^-
6262
| |
63-
| help: add the required where clauses: `where Self: 'b, Self: 'a`
63+
| help: add the required where clauses: `where Self: 'a, Self: 'b`
6464

6565
error: Missing required bounds on Bar
66-
--> $DIR/self-outlives-lint.rs:120:5
66+
--> $DIR/self-outlives-lint.rs:122:5
6767
|
6868
LL | type Bar<'b>;
6969
| ^^^^^^^^^^^^-
7070
| |
71-
| help: add the required where clauses: `where Self: 'b, Self: 'a`
71+
| help: add the required where clauses: `where Self: 'a, Self: 'b`
7272

7373
error: Missing required bounds on Bar
74-
--> $DIR/self-outlives-lint.rs:127:5
74+
--> $DIR/self-outlives-lint.rs:129:5
7575
|
7676
LL | type Bar<'b>;
7777
| ^^^^^^^^^^^^-
7878
| |
7979
| help: add the required where clauses: `where Self: 'b`
8080

8181
error: Missing required bounds on Iterator
82-
--> $DIR/self-outlives-lint.rs:141:5
82+
--> $DIR/self-outlives-lint.rs:143:5
8383
|
8484
LL | type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
8585
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
8686
| |
8787
| help: add the required where clauses: `where Self: 'a`
8888

8989
error: Missing required bounds on Bar
90-
--> $DIR/self-outlives-lint.rs:148:5
90+
--> $DIR/self-outlives-lint.rs:150:5
9191
|
9292
LL | type Bar<'a, 'b>;
9393
| ^^^^^^^^^^^^^^^^-

0 commit comments

Comments
 (0)