Skip to content

Commit e391796

Browse files
committed
Better error
1 parent 82148cd commit e391796

File tree

4 files changed

+81
-45
lines changed

4 files changed

+81
-45
lines changed

compiler/rustc_typeck/src/check/wfcheck.rs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,6 @@ fn check_gat_where_clauses(
288288
associated_items.in_definition_order().filter(|item| matches!(item.kind, ty::AssocKind::Fn))
289289
{
290290
let id = hir::HirId::make_owner(item.def_id.expect_local());
291-
let span = DUMMY_SP;
292291
let param_env = tcx.param_env(item.def_id.expect_local());
293292

294293
let sig = tcx.fn_sig(item.def_id);
@@ -308,7 +307,7 @@ fn check_gat_where_clauses(
308307
for (ty, ty_idx) in &visitor.types {
309308
tcx.infer_ctxt().enter(|infcx| {
310309
let mut outlives_environment = OutlivesEnvironment::new(param_env);
311-
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, span);
310+
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
312311
outlives_environment.save_implied_bounds(id);
313312
let region_bound_pairs =
314313
outlives_environment.region_bound_pairs_map().get(&id).unwrap();
@@ -349,7 +348,6 @@ fn check_gat_where_clauses(
349348
name: ty_param.name,
350349
}));
351350
let region_param = generics.param_at(*region_idx, tcx);
352-
// Then create a clause that is required on the GAT
353351
let region_param =
354352
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
355353
def_id: region_param.def_id,
@@ -372,13 +370,35 @@ fn check_gat_where_clauses(
372370
debug!(?clauses);
373371
if !clauses.is_empty() {
374372
let written_predicates: ty::GenericPredicates<'_> = tcx.predicates_of(trait_item.def_id);
375-
for clause in clauses {
376-
let found = written_predicates.predicates.iter().find(|p| p.0 == clause).is_some();
377-
debug!(?clause, ?found);
378-
let mut error = tcx
379-
.sess
380-
.struct_span_err(trait_item.generics.span, &format!("Missing bound: {}", clause));
381-
error.emit();
373+
let clauses: Vec<_> = clauses
374+
.drain_filter(|clause| {
375+
written_predicates.predicates.iter().find(|p| &p.0 == clause).is_none()
376+
})
377+
.map(|clause| format!("{}", clause))
378+
.collect();
379+
if !clauses.is_empty() {
380+
let mut err = tcx.sess.struct_span_err(
381+
trait_item.span,
382+
&format!("Missing required bounds on {}", trait_item.ident),
383+
);
384+
385+
let suggestion = format!(
386+
"{} {}",
387+
if !trait_item.generics.where_clause.predicates.is_empty() {
388+
","
389+
} else {
390+
" where"
391+
},
392+
clauses.join(", "),
393+
);
394+
err.span_suggestion(
395+
trait_item.generics.where_clause.tail_span_for_suggestion(),
396+
"add the required where clauses",
397+
suggestion,
398+
Applicability::MachineApplicable,
399+
);
400+
401+
err.emit()
382402
}
383403
}
384404
}

compiler/rustc_typeck/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ This API is completely unstable and subject to change.
6969
#![feature(never_type)]
7070
#![feature(slice_partition_dedup)]
7171
#![feature(control_flow_enum)]
72+
#![feature(hash_drain_filter)]
7273
#![recursion_limit = "256"]
7374

7475
#[macro_use]

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

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
// check-fail
44

5+
// We have a `&'a self`, so we need a `Self: 'a`
56
trait Iterable {
67
type Item<'x>;
7-
//~^ Missing bound
8+
//~^ Missing required bounds
89
fn iter<'a>(&'a self) -> Self::Item<'a>;
910
}
1011

@@ -17,9 +18,10 @@ impl<T> Iterable for T {
1718
}
1819
*/
1920

21+
// We have a `&'a T`, so we need a `T: 'x`
2022
trait Deserializer<T> {
2123
type Out<'x>;
22-
//~^ Missing bound
24+
//~^ Missing required bounds
2325
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
2426
}
2527

@@ -30,56 +32,63 @@ impl<T> Deserializer<T> for () {
3032
}
3133
*/
3234

35+
// We have a `&'b T` and a `'b: 'a`, so it is implied that `T: 'a`. Therefore, we need a `T: 'x`
3336
trait Deserializer2<T> {
3437
type Out<'x>;
35-
//~^ Missing bound
36-
fn deserialize2<'a, 'b: 'a>(&self, input: &'a T, input2: &'b T) -> Self::Out<'a>;
38+
//~^ Missing required bounds
39+
fn deserialize2<'a, 'b: 'a>(&self, input1: &'b T) -> Self::Out<'a>;
3740
}
3841

42+
// We have a `&'a T` and a `&'b U`, so we need a `T: 'x` and a `U: 'y`
3943
trait Deserializer3<T, U> {
4044
type Out<'x, 'y>;
41-
//~^ Missing bound
42-
//~^^ Missing bound
45+
//~^ Missing required bounds
4346
fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>;
4447
}
4548

49+
// `T` is a param on the function, so it can't be named by the associated type
4650
trait Deserializer4 {
4751
type Out<'x>;
4852
fn deserialize<'a, T>(&self, input: &'a T) -> Self::Out<'a>;
4953
}
5054

5155
struct Wrap<T>(T);
5256

57+
// Even though we might theoretically want `D: 'x`, because we pass `Wrap<T>` and
58+
// we see `&'z Wrap<T>`, we are conservative and only add bounds for direct params
5359
trait Des {
5460
type Out<'x, D>;
5561
fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>;
5662
}
5763
/*
5864
impl Des for () {
59-
type Out<'x, D> = &'x D;
65+
type Out<'x, D> = &'x D; // Not okay
6066
fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, Wrap<T>> {
6167
data
6268
}
6369
}
6470
*/
6571

72+
// We have `T` and `'z` as GAT substs. Because of `&'z Wrap<T>`, there is an
73+
// implied bound that `T: 'z`, so we require `D: 'x`
6674
trait Des2 {
6775
type Out<'x, D>;
68-
//~^ Missing bound
76+
//~^ Missing required bounds
6977
fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, T>;
7078
}
7179
/*
7280
impl Des2 for () {
7381
type Out<'x, D> = &'x D;
7482
fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, T> {
75-
data
83+
&data.0
7684
}
7785
}
7886
*/
7987

88+
// We see `&'z T`, so we require `D: 'x`
8089
trait Des3 {
8190
type Out<'x, D>;
82-
//~^ Missing bound
91+
//~^ Missing required bounds
8392
fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>;
8493
}
8594
/*
Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,50 @@
1-
error: Missing bound: Self: 'x
2-
--> $DIR/self-outlives-lint.rs:6:14
1+
error: Missing required bounds on Item
2+
--> $DIR/self-outlives-lint.rs:7:5
33
|
44
LL | type Item<'x>;
5-
| ^^^^
5+
| ^^^^^^^^^^^^^-
6+
| |
7+
| help: add the required where clauses: `where Self: 'x`
68

7-
error: Missing bound: T: 'x
8-
--> $DIR/self-outlives-lint.rs:21:13
9+
error: Missing required bounds on Out
10+
--> $DIR/self-outlives-lint.rs:23:5
911
|
1012
LL | type Out<'x>;
11-
| ^^^^
13+
| ^^^^^^^^^^^^-
14+
| |
15+
| help: add the required where clauses: `where T: 'x`
1216

13-
error: Missing bound: T: 'x
14-
--> $DIR/self-outlives-lint.rs:34:13
17+
error: Missing required bounds on Out
18+
--> $DIR/self-outlives-lint.rs:37:5
1519
|
1620
LL | type Out<'x>;
17-
| ^^^^
21+
| ^^^^^^^^^^^^-
22+
| |
23+
| help: add the required where clauses: `where T: 'x`
1824

19-
error: Missing bound: U: 'y
20-
--> $DIR/self-outlives-lint.rs:40:13
25+
error: Missing required bounds on Out
26+
--> $DIR/self-outlives-lint.rs:44:5
2127
|
2228
LL | type Out<'x, 'y>;
23-
| ^^^^^^^^
29+
| ^^^^^^^^^^^^^^^^-
30+
| |
31+
| help: add the required where clauses: `where U: 'y, T: 'x`
2432

25-
error: Missing bound: T: 'x
26-
--> $DIR/self-outlives-lint.rs:40:13
27-
|
28-
LL | type Out<'x, 'y>;
29-
| ^^^^^^^^
30-
31-
error: Missing bound: D: 'x
32-
--> $DIR/self-outlives-lint.rs:67:13
33+
error: Missing required bounds on Out
34+
--> $DIR/self-outlives-lint.rs:75:5
3335
|
3436
LL | type Out<'x, D>;
35-
| ^^^^^^^
37+
| ^^^^^^^^^^^^^^^-
38+
| |
39+
| help: add the required where clauses: `where D: 'x`
3640

37-
error: Missing bound: D: 'x
38-
--> $DIR/self-outlives-lint.rs:81:13
41+
error: Missing required bounds on Out
42+
--> $DIR/self-outlives-lint.rs:90:5
3943
|
4044
LL | type Out<'x, D>;
41-
| ^^^^^^^
45+
| ^^^^^^^^^^^^^^^-
46+
| |
47+
| help: add the required where clauses: `where D: 'x`
4248

43-
error: aborting due to 7 previous errors
49+
error: aborting due to 6 previous errors
4450

0 commit comments

Comments
 (0)