Skip to content

Commit 6c15dff

Browse files
committed
Auto merge of #47791 - estebank:mismatched-trait-impl, r=nikomatsakis
Tweak presentation on lifetime trait mismatch - On trait/impl method discrepancy, add label pointing at trait signature. - Point only at method definition when referring to named lifetimes on lifetime mismatch. - When the sub and sup expectations are the same, tweak the output to avoid repeated spans. Fix #30790, CC #18759.
2 parents 616b66d + 67696be commit 6c15dff

18 files changed

+212
-129
lines changed

src/librustc/infer/error_reporting/mod.rs

+48-23
Original file line numberDiff line numberDiff line change
@@ -175,25 +175,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
175175
ty::ReEarlyBound(_) |
176176
ty::ReFree(_) => {
177177
let scope = region.free_region_binding_scope(self);
178-
let prefix = match *region {
179-
ty::ReEarlyBound(ref br) => {
180-
format!("the lifetime {} as defined on", br.name)
181-
}
182-
ty::ReFree(ref fr) => {
183-
match fr.bound_region {
184-
ty::BrAnon(idx) => {
185-
format!("the anonymous lifetime #{} defined on", idx + 1)
186-
}
187-
ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
188-
_ => {
189-
format!("the lifetime {} as defined on",
190-
fr.bound_region)
191-
}
192-
}
193-
}
194-
_ => bug!()
195-
};
196-
197178
let node = self.hir.as_local_node_id(scope)
198179
.unwrap_or(DUMMY_NODE_ID);
199180
let unknown;
@@ -218,7 +199,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
218199
&unknown
219200
}
220201
};
221-
let (msg, opt_span) = explain_span(self, tag, self.hir.span(node));
202+
let (prefix, span) = match *region {
203+
ty::ReEarlyBound(ref br) => {
204+
(format!("the lifetime {} as defined on", br.name),
205+
self.sess.codemap().def_span(self.hir.span(node)))
206+
}
207+
ty::ReFree(ref fr) => {
208+
match fr.bound_region {
209+
ty::BrAnon(idx) => {
210+
(format!("the anonymous lifetime #{} defined on", idx + 1),
211+
self.hir.span(node))
212+
}
213+
ty::BrFresh(_) => ("an anonymous lifetime defined on".to_owned(),
214+
self.hir.span(node)),
215+
_ => (format!("the lifetime {} as defined on", fr.bound_region),
216+
self.sess.codemap().def_span(self.hir.span(node))),
217+
}
218+
}
219+
_ => bug!()
220+
};
221+
let (msg, opt_span) = explain_span(self, tag, span);
222222
(format!("{} {}", prefix, msg), opt_span)
223223
}
224224

@@ -807,7 +807,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
807807
}
808808
};
809809

810-
let span = cause.span;
810+
let span = cause.span(&self.tcx);
811811

812812
diag.span_label(span, terr.to_string());
813813
if let Some((sp, msg)) = secondary_span {
@@ -842,7 +842,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
842842
"did you mean `{}(/* fields */)`?",
843843
self.tcx.item_path_str(def_id)
844844
);
845-
diag.span_label(cause.span, message);
845+
diag.span_label(span, message);
846846
}
847847
}
848848
}
@@ -870,7 +870,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
870870
trace,
871871
terr);
872872

873-
let span = trace.cause.span;
873+
let span = trace.cause.span(&self.tcx);
874874
let failure_code = trace.cause.as_failure_code(terr);
875875
let mut diag = match failure_code {
876876
FailureCode::Error0317(failure_str) => {
@@ -1076,6 +1076,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
10761076
sup_region,
10771077
"...");
10781078

1079+
match (&sup_origin, &sub_origin) {
1080+
(&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => {
1081+
if let (Some((sup_expected, sup_found)),
1082+
Some((sub_expected, sub_found))) = (self.values_str(&sup_trace.values),
1083+
self.values_str(&sub_trace.values)) {
1084+
if sub_expected == sup_expected && sub_found == sup_found {
1085+
self.tcx.note_and_explain_region(
1086+
region_scope_tree,
1087+
&mut err,
1088+
"...but the lifetime must also be valid for ",
1089+
sub_region,
1090+
"...",
1091+
);
1092+
err.note(&format!("...so that the {}:\nexpected {}\n found {}",
1093+
sup_trace.cause.as_requirement_str(),
1094+
sup_expected.content(),
1095+
sup_found.content()));
1096+
err.emit();
1097+
return;
1098+
}
1099+
}
1100+
}
1101+
_ => {}
1102+
}
1103+
10791104
self.note_region_origin(&mut err, &sup_origin);
10801105

10811106
self.tcx.note_and_explain_region(region_scope_tree, &mut err,

src/librustc/infer/error_reporting/note.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
2323
if let Some((expected, found)) = self.values_str(&trace.values) {
2424
let expected = expected.content();
2525
let found = found.content();
26-
// FIXME: do we want a "the" here?
27-
err.span_note(trace.cause.span,
28-
&format!("...so that {} (expected {}, found {})",
29-
trace.cause.as_requirement_str(),
30-
expected,
31-
found));
26+
err.note(&format!("...so that the {}:\nexpected {}\n found {}",
27+
trace.cause.as_requirement_str(),
28+
expected,
29+
found));
3230
} else {
3331
// FIXME: this really should be handled at some earlier stage. Our
3432
// handling of region checking when type errors are present is

src/librustc/traits/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,19 @@ pub struct ObligationCause<'tcx> {
100100
pub code: ObligationCauseCode<'tcx>
101101
}
102102

103+
impl<'tcx> ObligationCause<'tcx> {
104+
pub fn span<'a, 'gcx>(&self, tcx: &TyCtxt<'a, 'gcx, 'tcx>) -> Span {
105+
match self.code {
106+
ObligationCauseCode::CompareImplMethodObligation { .. } |
107+
ObligationCauseCode::MainFunctionType |
108+
ObligationCauseCode::StartFunctionType => {
109+
tcx.sess.codemap().def_span(self.span)
110+
}
111+
_ => self.span,
112+
}
113+
}
114+
}
115+
103116
#[derive(Clone, Debug, PartialEq, Eq)]
104117
pub enum ObligationCauseCode<'tcx> {
105118
/// Not well classified or should be obvious from span.

src/librustc_typeck/check/compare_method.rs

+23-14
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
4040
debug!("compare_impl_method(impl_trait_ref={:?})",
4141
impl_trait_ref);
4242

43+
let impl_m_span = tcx.sess.codemap().def_span(impl_m_span);
44+
4345
if let Err(ErrorReported) = compare_self_type(tcx,
4446
impl_m,
4547
impl_m_span,
@@ -186,6 +188,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
186188
check_region_bounds_on_impl_method(tcx,
187189
impl_m_span,
188190
impl_m,
191+
trait_m,
189192
&trait_m_generics,
190193
&impl_m_generics,
191194
trait_to_skol_substs)?;
@@ -310,7 +313,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
310313
};
311314

312315
let mut diag = struct_span_err!(tcx.sess,
313-
cause.span,
316+
cause.span(&tcx),
314317
E0053,
315318
"method `{}` has an incompatible type for trait",
316319
trait_m.name);
@@ -346,10 +349,12 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
346349
fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
347350
span: Span,
348351
impl_m: &ty::AssociatedItem,
352+
trait_m: &ty::AssociatedItem,
349353
trait_generics: &ty::Generics,
350354
impl_generics: &ty::Generics,
351355
trait_to_skol_substs: &Substs<'tcx>)
352356
-> Result<(), ErrorReported> {
357+
let span = tcx.sess.codemap().def_span(span);
353358
let trait_params = &trait_generics.regions[..];
354359
let impl_params = &impl_generics.regions[..];
355360

@@ -371,14 +376,18 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
371376
// are zero. Since I don't quite know how to phrase things at
372377
// the moment, give a kind of vague error message.
373378
if trait_params.len() != impl_params.len() {
374-
struct_span_err!(tcx.sess,
375-
span,
376-
E0195,
377-
"lifetime parameters or bounds on method `{}` do not match the \
378-
trait declaration",
379-
impl_m.name)
380-
.span_label(span, "lifetimes do not match trait")
381-
.emit();
379+
let mut err = struct_span_err!(tcx.sess,
380+
span,
381+
E0195,
382+
"lifetime parameters or bounds on method `{}` do not match \
383+
the trait declaration",
384+
impl_m.name);
385+
err.span_label(span, "lifetimes do not match method in trait");
386+
if let Some(sp) = tcx.hir.span_if_local(trait_m.def_id) {
387+
err.span_label(tcx.sess.codemap().def_span(sp),
388+
"lifetimes in impl do not match this method in trait");
389+
}
390+
err.emit();
382391
return Err(ErrorReported);
383392
}
384393

@@ -424,9 +433,9 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
424433
}).map(|(ref impl_arg, ref trait_arg)| {
425434
(impl_arg.span, Some(trait_arg.span))
426435
})
427-
.unwrap_or_else(|| (cause.span, tcx.hir.span_if_local(trait_m.def_id)))
436+
.unwrap_or_else(|| (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id)))
428437
} else {
429-
(cause.span, tcx.hir.span_if_local(trait_m.def_id))
438+
(cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))
430439
}
431440
}
432441
TypeError::Sorts(ExpectedFound { .. }) => {
@@ -459,14 +468,14 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
459468
{
460469
(impl_m_output.span(), Some(trait_m_output.span()))
461470
} else {
462-
(cause.span, tcx.hir.span_if_local(trait_m.def_id))
471+
(cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))
463472
}
464473
})
465474
} else {
466-
(cause.span, tcx.hir.span_if_local(trait_m.def_id))
475+
(cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))
467476
}
468477
}
469-
_ => (cause.span, tcx.hir.span_if_local(trait_m.def_id)),
478+
_ => (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id)),
470479
}
471480
}
472481

src/test/compile-fail/E0195.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010

1111
trait Trait {
1212
fn bar<'a,'b:'a>(x: &'a str, y: &'b str);
13+
//~^ NOTE lifetimes in impl do not match this method in trait
1314
}
1415

1516
struct Foo;
1617

1718
impl Trait for Foo {
1819
fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195
19-
//~^ lifetimes do not match trait
20+
//~^ NOTE lifetimes do not match method in trait
2021
}
2122
}
2223

src/test/compile-fail/issue-16048.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
trait NoLifetime {
1212
fn get<'p, T : Test<'p>>(&self) -> T;
13+
//~^ NOTE lifetimes in impl do not match this method in trait
1314
}
1415

1516
trait Test<'p> {
@@ -28,8 +29,8 @@ impl<'a> Test<'a> for Foo<'a> {
2829

2930
impl<'a> NoLifetime for Foo<'a> {
3031
fn get<'p, T : Test<'a>>(&self) -> T {
31-
//~^ ERROR E0195
32-
//~| lifetimes do not match trait
32+
//~^ ERROR E0195
33+
//~| NOTE lifetimes do not match method in trait
3334
return *self as T;
3435
}
3536
}

src/test/ui/associated-const-impl-wrong-lifetime.stderr

+2-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@ error[E0308]: mismatched types
99
note: the lifetime 'a as defined on the impl at 17:1...
1010
--> $DIR/associated-const-impl-wrong-lifetime.rs:17:1
1111
|
12-
17 | / impl<'a> Foo for &'a () {
13-
18 | | const NAME: &'a str = "unit";
14-
19 | | //~^ ERROR mismatched types [E0308]
15-
20 | | }
16-
| |_^
12+
17 | impl<'a> Foo for &'a () {
13+
| ^^^^^^^^^^^^^^^^^^^^^^^
1714
= note: ...does not necessarily outlive the static lifetime
1815

1916
error: aborting due to previous error
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
error[E0195]: lifetime parameters or bounds on method `no_bound` do not match the trait declaration
2+
--> $DIR/regions-bound-missing-bound-in-impl.rs:28:5
3+
|
4+
20 | fn no_bound<'b>(self, b: Inv<'b>);
5+
| ---------------------------------- lifetimes in impl do not match this method in trait
6+
...
7+
28 | fn no_bound<'b:'a>(self, b: Inv<'b>) {
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
9+
10+
error[E0195]: lifetime parameters or bounds on method `has_bound` do not match the trait declaration
11+
--> $DIR/regions-bound-missing-bound-in-impl.rs:32:5
12+
|
13+
21 | fn has_bound<'b:'a>(self, b: Inv<'b>);
14+
| -------------------------------------- lifetimes in impl do not match this method in trait
15+
...
16+
32 | fn has_bound<'b>(self, b: Inv<'b>) {
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
18+
19+
error[E0308]: method not compatible with trait
20+
--> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
21+
|
22+
36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
24+
|
25+
= note: expected type `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'d>)`
26+
found type `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'d>)`
27+
note: the lifetime 'c as defined on the method body at 36:5...
28+
--> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
29+
|
30+
36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32+
note: ...does not necessarily outlive the lifetime 'c as defined on the method body at 36:5
33+
--> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
34+
|
35+
36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
36+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
37+
38+
error[E0276]: impl has stricter requirements than trait
39+
--> $DIR/regions-bound-missing-bound-in-impl.rs:53:5
40+
|
41+
24 | fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
42+
| ------------------------------------------------------- definition of `another_bound` from trait
43+
...
44+
53 | fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'x: 't`
46+
47+
error: aborting due to 4 previous errors
48+

src/test/ui/closure-expected-type/expect-region-supply-region.stderr

+4-16
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,8 @@ note: the anonymous lifetime #2 defined on the body at 47:29...
4141
note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 42:1
4242
--> $DIR/expect-region-supply-region.rs:42:1
4343
|
44-
42 | / fn expect_bound_supply_named<'x>() {
45-
43 | | let mut f: Option<&u32> = None;
46-
44 | |
47-
45 | | // Here we give a type annotation that `x` should be free. We get
48-
... |
49-
54 | | });
50-
55 | | }
51-
| |_^
44+
42 | fn expect_bound_supply_named<'x>() {
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5246

5347
error[E0308]: mismatched types
5448
--> $DIR/expect-region-supply-region.rs:47:33
@@ -61,14 +55,8 @@ error[E0308]: mismatched types
6155
note: the lifetime 'x as defined on the function body at 42:1...
6256
--> $DIR/expect-region-supply-region.rs:42:1
6357
|
64-
42 | / fn expect_bound_supply_named<'x>() {
65-
43 | | let mut f: Option<&u32> = None;
66-
44 | |
67-
45 | | // Here we give a type annotation that `x` should be free. We get
68-
... |
69-
54 | | });
70-
55 | | }
71-
| |_^
58+
42 | fn expect_bound_supply_named<'x>() {
59+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7260
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 47:29
7361
--> $DIR/expect-region-supply-region.rs:47:29
7462
|

src/test/ui/impl-trait/trait_type.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0053]: method `fmt` has an incompatible type for trait
22
--> $DIR/trait_type.rs:17:4
33
|
44
17 | fn fmt(&self, x: &str) -> () { }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
66
|
77
= note: expected type `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
88
found type `fn(&MyType, &str)`
@@ -19,7 +19,7 @@ error[E0186]: method `fmt` has a `&self` declaration in the trait, but not in th
1919
--> $DIR/trait_type.rs:27:4
2020
|
2121
27 | fn fmt() -> () { }
22-
| ^^^^^^^^^^^^^^^^^^ expected `&self` in impl
22+
| ^^^^^^^^^^^^^^ expected `&self` in impl
2323
|
2424
= note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
2525

0 commit comments

Comments
 (0)