Skip to content

Commit 11bca6b

Browse files
authored
Rollup merge of #79588 - estebank:issue-79187, r=oli-obk
Provide more information for HRTB lifetime errors involving closures
2 parents 45ba015 + a8a9742 commit 11bca6b

18 files changed

+392
-25
lines changed

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

+11-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ pub(super) fn note_and_explain_region(
9898
// uh oh, hope no user ever sees THIS
9999
ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None),
100100

101-
ty::RePlaceholder(_) => ("any other region".to_string(), None),
101+
ty::RePlaceholder(_) => return,
102102

103103
// FIXME(#13998) RePlaceholder should probably print like
104104
// ReFree rather than dumping Debug output on the user.
@@ -1675,6 +1675,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16751675
self.check_and_note_conflicting_crates(diag, terr);
16761676
self.tcx.note_and_explain_type_err(diag, terr, cause, span, body_owner_def_id.to_def_id());
16771677

1678+
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values {
1679+
if let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind() {
1680+
if let Some(def_id) = def_id.as_local() {
1681+
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
1682+
let span = self.tcx.hir().span(hir_id);
1683+
diag.span_note(span, "this closure does not fulfill the lifetime requirements");
1684+
}
1685+
}
1686+
}
1687+
16781688
// It reads better to have the error origin as the final
16791689
// thing.
16801690
self.note_error_origin(diag, cause, exp_found);

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

+53-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt};
22
use crate::infer::{self, InferCtxt, SubregionOrigin};
33
use rustc_errors::{struct_span_err, DiagnosticBuilder};
4+
use rustc_middle::traits::ObligationCauseCode;
45
use rustc_middle::ty::error::TypeError;
56
use rustc_middle::ty::{self, Region};
67

@@ -107,14 +108,37 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
107108
infer::Subtype(box trace) => {
108109
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
109110
let mut err = self.report_and_explain_type_error(trace, &terr);
110-
note_and_explain_region(self.tcx, &mut err, "", sup, "...");
111-
note_and_explain_region(
112-
self.tcx,
113-
&mut err,
114-
"...does not necessarily outlive ",
115-
sub,
116-
"",
117-
);
111+
match (sub, sup) {
112+
(ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
113+
(ty::RePlaceholder(_), _) => {
114+
note_and_explain_region(
115+
self.tcx,
116+
&mut err,
117+
"",
118+
sup,
119+
" doesn't meet the lifetime requirements",
120+
);
121+
}
122+
(_, ty::RePlaceholder(_)) => {
123+
note_and_explain_region(
124+
self.tcx,
125+
&mut err,
126+
"the required lifetime does not necessarily outlive ",
127+
sub,
128+
"",
129+
);
130+
}
131+
_ => {
132+
note_and_explain_region(self.tcx, &mut err, "", sup, "...");
133+
note_and_explain_region(
134+
self.tcx,
135+
&mut err,
136+
"...does not necessarily outlive ",
137+
sub,
138+
"",
139+
);
140+
}
141+
}
118142
err
119143
}
120144
infer::Reborrow(span) => {
@@ -286,13 +310,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
286310
sup: Region<'tcx>,
287311
) -> DiagnosticBuilder<'tcx> {
288312
// I can't think how to do better than this right now. -nikomatsakis
313+
debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
289314
match placeholder_origin {
315+
infer::Subtype(box ref trace)
316+
if matches!(
317+
&trace.cause.code.peel_derives(),
318+
ObligationCauseCode::BindingObligation(..)
319+
) =>
320+
{
321+
// Hack to get around the borrow checker because trace.cause has an `Rc`.
322+
if let ObligationCauseCode::BindingObligation(_, span) =
323+
&trace.cause.code.peel_derives()
324+
{
325+
let span = *span;
326+
let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);
327+
err.span_note(span, "the lifetime requirement is introduced here");
328+
err
329+
} else {
330+
unreachable!()
331+
}
332+
}
290333
infer::Subtype(box trace) => {
291334
let terr = TypeError::RegionsPlaceholderMismatch;
292-
self.report_and_explain_type_error(trace, &terr)
335+
return self.report_and_explain_type_error(trace, &terr);
293336
}
294-
295-
_ => self.report_concrete_failure(placeholder_origin, sub, sup),
337+
_ => return self.report_concrete_failure(placeholder_origin, sub, sup),
296338
}
297339
}
298340
}

src/test/ui/associated-types/higher-ranked-projection.bad.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ error[E0308]: mismatched types
22
--> $DIR/higher-ranked-projection.rs:25:5
33
|
44
LL | foo(());
5-
| ^^^ one type is more general than the other
5+
| ^^^ lifetime mismatch
66
|
77
= note: expected type `&'a ()`
88
found type `&()`
9+
note: the lifetime requirement is introduced here
10+
--> $DIR/higher-ranked-projection.rs:15:33
11+
|
12+
LL | where for<'a> &'a T: Mirror<Image=U>
13+
| ^^^^^^^
914

1015
error: aborting due to previous error
1116

src/test/ui/generator/resume-arg-late-bound.stderr

+30-2
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,47 @@ error[E0308]: mismatched types
22
--> $DIR/resume-arg-late-bound.rs:15:5
33
|
44
LL | test(gen);
5-
| ^^^^ one type is more general than the other
5+
| ^^^^ lifetime mismatch
66
|
77
= note: expected type `for<'a> Generator<&'a mut bool>`
88
found type `Generator<&mut bool>`
9+
note: the required lifetime does not necessarily outlive the anonymous lifetime #1 defined on the body at 11:15
10+
--> $DIR/resume-arg-late-bound.rs:11:15
11+
|
12+
LL | let gen = |arg: &mut bool| {
13+
| _______________^
14+
LL | | yield ();
15+
LL | | *arg = true;
16+
LL | | };
17+
| |_____^
18+
note: the lifetime requirement is introduced here
19+
--> $DIR/resume-arg-late-bound.rs:8:17
20+
|
21+
LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {}
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
923

1024
error[E0308]: mismatched types
1125
--> $DIR/resume-arg-late-bound.rs:15:5
1226
|
1327
LL | test(gen);
14-
| ^^^^ one type is more general than the other
28+
| ^^^^ lifetime mismatch
1529
|
1630
= note: expected type `for<'a> Generator<&'a mut bool>`
1731
found type `Generator<&mut bool>`
32+
note: the anonymous lifetime #1 defined on the body at 11:15 doesn't meet the lifetime requirements
33+
--> $DIR/resume-arg-late-bound.rs:11:15
34+
|
35+
LL | let gen = |arg: &mut bool| {
36+
| _______________^
37+
LL | | yield ();
38+
LL | | *arg = true;
39+
LL | | };
40+
| |_____^
41+
note: the lifetime requirement is introduced here
42+
--> $DIR/resume-arg-late-bound.rs:8:17
43+
|
44+
LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {}
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1846

1947
error: aborting due to 2 previous errors
2048

src/test/ui/hrtb/hrtb-perfect-forwarding.stderr

+22-2
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,39 @@ error[E0308]: mismatched types
22
--> $DIR/hrtb-perfect-forwarding.rs:46:5
33
|
44
LL | foo_hrtb_bar_not(&mut t);
5-
| ^^^^^^^^^^^^^^^^ one type is more general than the other
5+
| ^^^^^^^^^^^^^^^^ lifetime mismatch
66
|
77
= note: expected type `Bar<&'a isize>`
88
found type `Bar<&'b isize>`
9+
note: the required lifetime does not necessarily outlive the lifetime `'b` as defined on the function body at 39:21
10+
--> $DIR/hrtb-perfect-forwarding.rs:39:21
11+
|
12+
LL | fn foo_hrtb_bar_not<'b,T>(mut t: T)
13+
| ^^
14+
note: the lifetime requirement is introduced here
15+
--> $DIR/hrtb-perfect-forwarding.rs:40:15
16+
|
17+
LL | where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
18+
| ^^^^^^^^^^^^^^^^^^^^^^
919

1020
error[E0308]: mismatched types
1121
--> $DIR/hrtb-perfect-forwarding.rs:46:5
1222
|
1323
LL | foo_hrtb_bar_not(&mut t);
14-
| ^^^^^^^^^^^^^^^^ one type is more general than the other
24+
| ^^^^^^^^^^^^^^^^ lifetime mismatch
1525
|
1626
= note: expected type `Bar<&'a isize>`
1727
found type `Bar<&'b isize>`
28+
note: the lifetime `'b` as defined on the function body at 39:21 doesn't meet the lifetime requirements
29+
--> $DIR/hrtb-perfect-forwarding.rs:39:21
30+
|
31+
LL | fn foo_hrtb_bar_not<'b,T>(mut t: T)
32+
| ^^
33+
note: the lifetime requirement is introduced here
34+
--> $DIR/hrtb-perfect-forwarding.rs:40:15
35+
|
36+
LL | where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
37+
| ^^^^^^^^^^^^^^^^^^^^^^
1838

1939
error: aborting due to 2 previous errors
2040

src/test/ui/issues/issue-26217.stderr

-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ error[E0477]: the type `&'a i32` does not fulfill the required lifetime
33
|
44
LL | foo::<&'a i32>();
55
| ^^^^^^^^^^^^^^
6-
|
7-
= note: type must outlive any other region
86

97
error: aborting due to previous error
108

src/test/ui/issues/issue-57843.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ LL | Foo(Box::new(|_| ()));
66
|
77
= note: expected type `FnOnce<(&'a bool,)>`
88
found type `FnOnce<(&bool,)>`
9+
note: this closure does not fulfill the lifetime requirements
10+
--> $DIR/issue-57843.rs:23:18
11+
|
12+
LL | Foo(Box::new(|_| ()));
13+
| ^^^^^^
914

1015
error: aborting due to previous error
1116

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/issue-79187-2.rs:9:24
3+
|
4+
LL | take_foo(|a: &i32| a);
5+
| - - ^ returning this value requires that `'1` must outlive `'2`
6+
| | |
7+
| | return type of closure is &'2 i32
8+
| let's call the lifetime of this reference `'1`
9+
10+
error: lifetime may not live long enough
11+
--> $DIR/issue-79187-2.rs:10:34
12+
|
13+
LL | take_foo(|a: &i32| -> &i32 { a });
14+
| - - ^ returning this value requires that `'1` must outlive `'2`
15+
| | |
16+
| | let's call the lifetime of this reference `'2`
17+
| let's call the lifetime of this reference `'1`
18+
19+
error: higher-ranked subtype error
20+
--> $DIR/issue-79187-2.rs:8:5
21+
|
22+
LL | take_foo(|a| a);
23+
| ^^^^^^^^^^^^^^^
24+
25+
error: higher-ranked subtype error
26+
--> $DIR/issue-79187-2.rs:8:5
27+
|
28+
LL | take_foo(|a| a);
29+
| ^^^^^^^^^^^^^^^
30+
31+
error: higher-ranked subtype error
32+
--> $DIR/issue-79187-2.rs:9:5
33+
|
34+
LL | take_foo(|a: &i32| a);
35+
| ^^^^^^^^^^^^^^^^^^^^^
36+
37+
error: higher-ranked subtype error
38+
--> $DIR/issue-79187-2.rs:10:5
39+
|
40+
LL | take_foo(|a: &i32| -> &i32 { a });
41+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42+
43+
error: aborting due to 6 previous errors
44+
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
trait Foo {}
2+
3+
impl<F> Foo for F where F: Fn(&i32) -> &i32 {}
4+
5+
fn take_foo(_: impl Foo) {}
6+
7+
fn main() {
8+
take_foo(|a| a); //~ ERROR mismatched types
9+
take_foo(|a: &i32| a); //~ ERROR mismatched types
10+
take_foo(|a: &i32| -> &i32 { a }); //~ ERROR mismatched types
11+
12+
// OK
13+
take_foo(identity(|a| a));
14+
take_foo(identity(|a: &i32| a));
15+
take_foo(identity(|a: &i32| -> &i32 { a }));
16+
17+
fn identity<F>(t: F) -> F
18+
where
19+
F: Fn(&i32) -> &i32,
20+
{
21+
t
22+
}
23+
}
+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-79187-2.rs:8:5
3+
|
4+
LL | take_foo(|a| a);
5+
| ^^^^^^^^ lifetime mismatch
6+
|
7+
= note: expected type `for<'r> Fn<(&'r i32,)>`
8+
found type `Fn<(&i32,)>`
9+
note: this closure does not fulfill the lifetime requirements
10+
--> $DIR/issue-79187-2.rs:8:14
11+
|
12+
LL | take_foo(|a| a);
13+
| ^^^^^
14+
note: the lifetime requirement is introduced here
15+
--> $DIR/issue-79187-2.rs:5:21
16+
|
17+
LL | fn take_foo(_: impl Foo) {}
18+
| ^^^
19+
20+
error[E0308]: mismatched types
21+
--> $DIR/issue-79187-2.rs:9:5
22+
|
23+
LL | take_foo(|a: &i32| a);
24+
| ^^^^^^^^ lifetime mismatch
25+
|
26+
= note: expected reference `&i32`
27+
found reference `&i32`
28+
note: the anonymous lifetime #1 defined on the body at 9:14 doesn't meet the lifetime requirements
29+
--> $DIR/issue-79187-2.rs:9:14
30+
|
31+
LL | take_foo(|a: &i32| a);
32+
| ^^^^^^^^^^^
33+
note: the lifetime requirement is introduced here
34+
--> $DIR/issue-79187-2.rs:5:21
35+
|
36+
LL | fn take_foo(_: impl Foo) {}
37+
| ^^^
38+
39+
error[E0308]: mismatched types
40+
--> $DIR/issue-79187-2.rs:10:5
41+
|
42+
LL | take_foo(|a: &i32| -> &i32 { a });
43+
| ^^^^^^^^ lifetime mismatch
44+
|
45+
= note: expected reference `&i32`
46+
found reference `&i32`
47+
note: the anonymous lifetime #1 defined on the body at 10:14 doesn't meet the lifetime requirements
48+
--> $DIR/issue-79187-2.rs:10:14
49+
|
50+
LL | take_foo(|a: &i32| -> &i32 { a });
51+
| ^^^^^^^^^^^^^^^^^^^^^^^
52+
note: the lifetime requirement is introduced here
53+
--> $DIR/issue-79187-2.rs:5:21
54+
|
55+
LL | fn take_foo(_: impl Foo) {}
56+
| ^^^
57+
58+
error: aborting due to 3 previous errors
59+
60+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: higher-ranked subtype error
2+
--> $DIR/issue-79187.rs:5:5
3+
|
4+
LL | thing(f);
5+
| ^^^^^^^^
6+
7+
error: higher-ranked subtype error
8+
--> $DIR/issue-79187.rs:5:5
9+
|
10+
LL | thing(f);
11+
| ^^^^^^^^
12+
13+
error: aborting due to 2 previous errors
14+

src/test/ui/lifetimes/issue-79187.rs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fn thing(x: impl FnOnce(&u32)) {}
2+
3+
fn main() {
4+
let f = |_| ();
5+
thing(f); //~ERROR mismatched types
6+
}

0 commit comments

Comments
 (0)