Skip to content

Commit e76bd62

Browse files
authored
Rollup merge of #122100 - compiler-errors:better-capture, r=oli-obk
Better comment for implicit captures in RPITIT Improve the error message for implicit captures. Also always set E0657. r? oli-obk
2 parents 2c3ca09 + ffd30e0 commit e76bd62

25 files changed

+150
-116
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,26 @@
1-
A lifetime bound on a trait implementation was captured at an incorrect place.
1+
An `impl Trait` captured a higher-ranked lifetime, which is not supported.
2+
3+
Currently, `impl Trait` types are only allowed to capture lifetimes from
4+
their parent items, and not from any `for<'a>` binders in scope.
25

36
Erroneous code example:
47

58
```compile_fail,E0657
6-
trait Id<T> {}
7-
trait Lt<'a> {}
8-
9-
impl<'a> Lt<'a> for () {}
10-
impl<T> Id<T> for T {}
11-
12-
fn free_fn_capture_hrtb_in_impl_trait()
13-
-> Box<for<'a> Id<impl Lt<'a>>> // error!
14-
{
15-
Box::new(())
16-
}
9+
trait BorrowInto<'a> {
10+
type Target;
1711
18-
struct Foo;
19-
impl Foo {
20-
fn impl_fn_capture_hrtb_in_impl_trait()
21-
-> Box<for<'a> Id<impl Lt<'a>>> // error!
22-
{
23-
Box::new(())
24-
}
12+
fn borrow_into(&'a self) -> Self::Target;
2513
}
26-
```
2714
28-
Here, you have used the inappropriate lifetime in the `impl Trait`,
29-
The `impl Trait` can only capture lifetimes bound at the fn or impl
30-
level.
15+
impl<'a> BorrowInto<'a> for () {
16+
type Target = &'a ();
3117
32-
To fix this we have to define the lifetime at the function or impl
33-
level and use that lifetime in the `impl Trait`. For example you can
34-
define the lifetime at the function:
35-
36-
```
37-
trait Id<T> {}
38-
trait Lt<'a> {}
39-
40-
impl<'a> Lt<'a> for () {}
41-
impl<T> Id<T> for T {}
42-
43-
fn free_fn_capture_hrtb_in_impl_trait<'b>()
44-
-> Box<for<'a> Id<impl Lt<'b>>> // ok!
45-
{
46-
Box::new(())
18+
fn borrow_into(&'a self) -> Self::Target {
19+
self
20+
}
4721
}
4822
49-
struct Foo;
50-
impl Foo {
51-
fn impl_fn_capture_hrtb_in_impl_trait<'b>()
52-
-> Box<for<'a> Id<impl Lt<'b>>> // ok!
53-
{
54-
Box::new(())
55-
}
23+
fn opaque() -> impl for<'a> BorrowInto<'a, Target = impl Sized + 'a> {
24+
()
5625
}
5726
```

compiler/rustc_hir_analysis/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ hir_analysis_only_current_traits_primitive = only traits defined in the current
312312
313313
hir_analysis_only_current_traits_ty = `{$ty}` is not defined in the current crate
314314
315+
hir_analysis_opaque_captures_higher_ranked_lifetime = `impl Trait` cannot capture {$bad_place}
316+
.label = `impl Trait` implicitly captures all lifetimes in scope
317+
.note = lifetime declared here
318+
315319
hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
316320
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
317321

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

+40-28
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use core::ops::ControlFlow;
1010
use rustc_ast::visit::walk_list;
1111
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
12-
use rustc_errors::{codes::*, struct_span_code_err};
1312
use rustc_hir as hir;
1413
use rustc_hir::def::{DefKind, Res};
1514
use rustc_hir::def_id::LocalDefId;
@@ -669,34 +668,47 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
669668
// and ban them. Type variables instantiated inside binders aren't
670669
// well-supported at the moment, so this doesn't work.
671670
// In the future, this should be fixed and this error should be removed.
672-
let def = self.map.defs.get(&lifetime.hir_id).cloned();
673-
let Some(ResolvedArg::LateBound(_, _, def_id)) = def else { continue };
674-
let Some(def_id) = def_id.as_local() else { continue };
675-
let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
676-
// Ensure that the parent of the def is an item, not HRTB
677-
let parent_id = self.tcx.parent_hir_id(hir_id);
678-
if !parent_id.is_owner() {
679-
struct_span_code_err!(
680-
self.tcx.dcx(),
681-
lifetime.ident.span,
682-
E0657,
683-
"`impl Trait` can only capture lifetimes bound at the fn or impl level"
684-
)
685-
.emit();
686-
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
687-
}
688-
if let hir::Node::Item(hir::Item {
689-
kind: hir::ItemKind::OpaqueTy { .. }, ..
690-
}) = self.tcx.hir_node(parent_id)
671+
let def = self.map.defs.get(&lifetime.hir_id).copied();
672+
let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue };
673+
let Some(lifetime_def_id) = lifetime_def_id.as_local() else { continue };
674+
let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id);
675+
676+
let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id))
691677
{
692-
self.tcx.dcx().struct_span_err(
693-
lifetime.ident.span,
694-
"higher kinded lifetime bounds on nested opaque types are not supported yet",
695-
)
696-
.with_span_note(self.tcx.def_span(def_id), "lifetime declared here")
697-
.emit();
698-
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
699-
}
678+
// Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque
679+
// it must be a reified late-bound lifetime from a trait goal.
680+
hir::Node::Item(hir::Item {
681+
kind: hir::ItemKind::OpaqueTy { .. }, ..
682+
}) => "higher-ranked lifetime from outer `impl Trait`",
683+
// Other items are fine.
684+
hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => {
685+
continue;
686+
}
687+
hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(_), .. }) => {
688+
"higher-ranked lifetime from function pointer"
689+
}
690+
hir::Node::Ty(hir::Ty { kind: hir::TyKind::TraitObject(..), .. }) => {
691+
"higher-ranked lifetime from `dyn` type"
692+
}
693+
_ => "higher-ranked lifetime",
694+
};
695+
696+
let (span, label) = if lifetime.ident.span == self.tcx.def_span(lifetime_def_id)
697+
{
698+
let opaque_span = self.tcx.def_span(item_id.owner_id);
699+
(opaque_span, Some(opaque_span))
700+
} else {
701+
(lifetime.ident.span, None)
702+
};
703+
704+
// Ensure that the parent of the def is an item, not HRTB
705+
self.tcx.dcx().emit_err(errors::OpaqueCapturesHigherRankedLifetime {
706+
span,
707+
label,
708+
decl_span: self.tcx.def_span(lifetime_def_id),
709+
bad_place,
710+
});
711+
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
700712
}
701713
}
702714
_ => intravisit::walk_ty(self, ty),

compiler/rustc_hir_analysis/src/errors.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1607,3 +1607,15 @@ pub struct UnnamedFieldsReprFieldDefined {
16071607
#[primary_span]
16081608
pub span: Span,
16091609
}
1610+
1611+
#[derive(Diagnostic)]
1612+
#[diag(hir_analysis_opaque_captures_higher_ranked_lifetime, code = E0657)]
1613+
pub struct OpaqueCapturesHigherRankedLifetime {
1614+
#[primary_span]
1615+
pub span: Span,
1616+
#[label]
1617+
pub label: Option<Span>,
1618+
#[note]
1619+
pub decl_span: Span,
1620+
pub bad_place: &'static str,
1621+
}

tests/ui/error-codes/E0657.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ impl<T> Id<T> for T {}
88

99
fn free_fn_capture_hrtb_in_impl_trait()
1010
-> Box<for<'a> Id<impl Lt<'a>>>
11-
//~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level [E0657]
11+
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
1212
{
1313
Box::new(())
1414
}
@@ -17,7 +17,7 @@ struct Foo;
1717
impl Foo {
1818
fn impl_fn_capture_hrtb_in_impl_trait()
1919
-> Box<for<'a> Id<impl Lt<'a>>>
20-
//~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level
20+
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
2121
{
2222
Box::new(())
2323
}

tests/ui/error-codes/E0657.stderr

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
1-
error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level
1+
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
22
--> $DIR/E0657.rs:10:31
33
|
44
LL | -> Box<for<'a> Id<impl Lt<'a>>>
55
| ^^
6+
|
7+
note: lifetime declared here
8+
--> $DIR/E0657.rs:10:16
9+
|
10+
LL | -> Box<for<'a> Id<impl Lt<'a>>>
11+
| ^^
612

7-
error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level
13+
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
814
--> $DIR/E0657.rs:19:35
915
|
1016
LL | -> Box<for<'a> Id<impl Lt<'a>>>
1117
| ^^
18+
|
19+
note: lifetime declared here
20+
--> $DIR/E0657.rs:19:20
21+
|
22+
LL | -> Box<for<'a> Id<impl Lt<'a>>>
23+
| ^^
1224

1325
error: aborting due to 2 previous errors
1426

tests/ui/impl-trait/impl-fn-hrtb-bounds.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22
use std::fmt::Debug;
33

44
fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
5-
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
5+
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
66
|x| x
77
//~^ ERROR lifetime may not live long enough
88
}
99

1010
fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
11-
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
11+
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
1212
|x| x
1313
//~^ ERROR lifetime may not live long enough
1414
}
1515

1616
fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
17-
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
17+
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
1818
|x| x
1919
//~^ ERROR lifetime may not live long enough
2020
}

tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr

+5-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're
1010
LL | fn d() -> impl Fn() -> (impl Debug + 'static) {
1111
| ~~~~~~~
1212

13-
error: higher kinded lifetime bounds on nested opaque types are not supported yet
13+
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
1414
--> $DIR/impl-fn-hrtb-bounds.rs:4:41
1515
|
1616
LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
@@ -31,7 +31,7 @@ LL | |x| x
3131
| |return type of closure is impl Debug + '2
3232
| has type `&'1 u8`
3333

34-
error: higher kinded lifetime bounds on nested opaque types are not supported yet
34+
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
3535
--> $DIR/impl-fn-hrtb-bounds.rs:10:52
3636
|
3737
LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
@@ -52,7 +52,7 @@ LL | |x| x
5252
| |return type of closure is impl Debug + '2
5353
| has type `&'1 u8`
5454

55-
error: higher kinded lifetime bounds on nested opaque types are not supported yet
55+
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
5656
--> $DIR/impl-fn-hrtb-bounds.rs:16:52
5757
|
5858
LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
@@ -75,4 +75,5 @@ LL | |x| x
7575

7676
error: aborting due to 7 previous errors
7777

78-
For more information about this error, try `rustc --explain E0106`.
78+
Some errors have detailed explanations: E0106, E0657.
79+
For more information about an error, try `rustc --explain E0106`.

tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::fmt::Debug;
33

44
fn a() -> impl Fn(&u8) -> impl Debug + '_ {
55
//~^ ERROR ambiguous `+` in a type
6-
//~| ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
6+
//~| ERROR cannot capture higher-ranked lifetime from outer `impl Trait`
77
|x| x
88
//~^ ERROR lifetime may not live long enough
99
}

tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ error: ambiguous `+` in a type
1010
LL | fn b() -> impl Fn() -> impl Debug + Send {
1111
| ^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + Send)`
1212

13-
error: higher kinded lifetime bounds on nested opaque types are not supported yet
13+
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
1414
--> $DIR/impl-fn-parsing-ambiguities.rs:4:40
1515
|
1616
LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ {
@@ -33,3 +33,4 @@ LL | |x| x
3333

3434
error: aborting due to 4 previous errors
3535

36+
For more information about this error, try `rustc --explain E0657`.

tests/ui/impl-trait/implicit-capture-late.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level
1+
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
2+
--> $DIR/implicit-capture-late.rs:10:55
3+
|
4+
LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
5+
| ^^^^^^^^^^^ `impl Trait` implicitly captures all lifetimes in scope
6+
|
7+
note: lifetime declared here
28
--> $DIR/implicit-capture-late.rs:10:36
39
|
410
LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {

tests/ui/impl-trait/issues/issue-54895.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ impl<'a> Trait<'a> for X {
1313
}
1414

1515
fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> {
16-
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
16+
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
1717
X(())
1818
}
1919

tests/ui/impl-trait/issues/issue-54895.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: higher kinded lifetime bounds on nested opaque types are not supported yet
1+
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
22
--> $DIR/issue-54895.rs:15:53
33
|
44
LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> {
@@ -12,3 +12,4 @@ LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> {
1212

1313
error: aborting due to 1 previous error
1414

15+
For more information about this error, try `rustc --explain E0657`.

tests/ui/impl-trait/issues/issue-67830.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ where
1919

2020
struct A;
2121
fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> {
22-
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
22+
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
2323
Wrap(|a| Some(a).into_iter())
2424
//~^ ERROR implementation of `FnOnce` is not general enough
2525
//~| ERROR implementation of `FnOnce` is not general enough

tests/ui/impl-trait/issues/issue-67830.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: higher kinded lifetime bounds on nested opaque types are not supported yet
1+
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
22
--> $DIR/issue-67830.rs:21:62
33
|
44
LL | fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> {
@@ -31,3 +31,4 @@ LL | Wrap(|a| Some(a).into_iter())
3131

3232
error: aborting due to 3 previous errors
3333

34+
For more information about this error, try `rustc --explain E0657`.

tests/ui/impl-trait/issues/issue-88236-2.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@ impl<'a> Hrtb<'a> for &'a () {
1313
}
1414

1515
fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {}
16-
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
16+
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
1717

1818
fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
19-
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
19+
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
2020
&()
2121
//~^ ERROR implementation of `Hrtb` is not general enough
2222
//~| ERROR implementation of `Hrtb` is not general enough
2323
}
2424

2525
fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
26-
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
26+
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
2727
x
2828
//~^ ERROR implementation of `Hrtb` is not general enough
2929
//~| ERROR implementation of `Hrtb` is not general enough

0 commit comments

Comments
 (0)