Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better comment for implicit captures in RPITIT #122100

Merged
merged 1 commit into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 14 additions & 45 deletions compiler/rustc_error_codes/src/error_codes/E0657.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,26 @@
A lifetime bound on a trait implementation was captured at an incorrect place.
An `impl Trait` captured a higher-ranked lifetime, which is not supported.

Currently, `impl Trait` types are only allowed to capture lifetimes from
their parent items, and not from any `for<'a>` binders in scope.

Erroneous code example:

```compile_fail,E0657
trait Id<T> {}
trait Lt<'a> {}

impl<'a> Lt<'a> for () {}
impl<T> Id<T> for T {}

fn free_fn_capture_hrtb_in_impl_trait()
-> Box<for<'a> Id<impl Lt<'a>>> // error!
{
Box::new(())
}
trait BorrowInto<'a> {
type Target;

struct Foo;
impl Foo {
fn impl_fn_capture_hrtb_in_impl_trait()
-> Box<for<'a> Id<impl Lt<'a>>> // error!
{
Box::new(())
}
fn borrow_into(&'a self) -> Self::Target;
}
```

Here, you have used the inappropriate lifetime in the `impl Trait`,
The `impl Trait` can only capture lifetimes bound at the fn or impl
level.
impl<'a> BorrowInto<'a> for () {
type Target = &'a ();

To fix this we have to define the lifetime at the function or impl
level and use that lifetime in the `impl Trait`. For example you can
define the lifetime at the function:

```
trait Id<T> {}
trait Lt<'a> {}

impl<'a> Lt<'a> for () {}
impl<T> Id<T> for T {}

fn free_fn_capture_hrtb_in_impl_trait<'b>()
-> Box<for<'a> Id<impl Lt<'b>>> // ok!
{
Box::new(())
fn borrow_into(&'a self) -> Self::Target {
self
}
}

struct Foo;
impl Foo {
fn impl_fn_capture_hrtb_in_impl_trait<'b>()
-> Box<for<'a> Id<impl Lt<'b>>> // ok!
{
Box::new(())
}
fn opaque() -> impl for<'a> BorrowInto<'a, Target = impl Sized + 'a> {
()
}
```
4 changes: 4 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,10 @@ hir_analysis_only_current_traits_primitive = only traits defined in the current

hir_analysis_only_current_traits_ty = `{$ty}` is not defined in the current crate

hir_analysis_opaque_captures_higher_ranked_lifetime = `impl Trait` cannot capture {$bad_place}
.label = `impl Trait` implicitly captures all lifetimes in scope
.note = lifetime declared here

hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it

Expand Down
68 changes: 40 additions & 28 deletions compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

use rustc_ast::visit::walk_list;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::{codes::*, struct_span_code_err};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::LocalDefId;
Expand Down Expand Up @@ -673,34 +672,47 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
// and ban them. Type variables instantiated inside binders aren't
// well-supported at the moment, so this doesn't work.
// In the future, this should be fixed and this error should be removed.
let def = self.map.defs.get(&lifetime.hir_id).cloned();
let Some(ResolvedArg::LateBound(_, _, def_id)) = def else { continue };
let Some(def_id) = def_id.as_local() else { continue };
let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
// Ensure that the parent of the def is an item, not HRTB
let parent_id = self.tcx.parent_hir_id(hir_id);
if !parent_id.is_owner() {
struct_span_code_err!(
self.tcx.dcx(),
lifetime.ident.span,
E0657,
"`impl Trait` can only capture lifetimes bound at the fn or impl level"
)
.emit();
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
}
if let hir::Node::Item(hir::Item {
kind: hir::ItemKind::OpaqueTy { .. }, ..
}) = self.tcx.hir_node(parent_id)
let def = self.map.defs.get(&lifetime.hir_id).copied();
let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue };
let Some(lifetime_def_id) = lifetime_def_id.as_local() else { continue };
let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id);

let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id))
{
self.tcx.dcx().struct_span_err(
lifetime.ident.span,
"higher kinded lifetime bounds on nested opaque types are not supported yet",
)
.with_span_note(self.tcx.def_span(def_id), "lifetime declared here")
.emit();
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
}
// Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque
// it must be a reified late-bound lifetime from a trait goal.
hir::Node::Item(hir::Item {
kind: hir::ItemKind::OpaqueTy { .. }, ..
}) => "higher-ranked lifetime from outer `impl Trait`",
// Other items are fine.
hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => {
continue;
}
hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(_), .. }) => {
"higher-ranked lifetime from function pointer"
}
hir::Node::Ty(hir::Ty { kind: hir::TyKind::TraitObject(..), .. }) => {
"higher-ranked lifetime from `dyn` type"
}
_ => "higher-ranked lifetime",
};

let (span, label) = if lifetime.ident.span == self.tcx.def_span(lifetime_def_id)
{
let opaque_span = self.tcx.def_span(item_id.owner_id);
(opaque_span, Some(opaque_span))
} else {
(lifetime.ident.span, None)
};

// Ensure that the parent of the def is an item, not HRTB
self.tcx.dcx().emit_err(errors::OpaqueCapturesHigherRankedLifetime {
span,
label,
decl_span: self.tcx.def_span(lifetime_def_id),
bad_place,
});
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
}
}
_ => intravisit::walk_ty(self, ty),
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1607,3 +1607,15 @@ pub struct UnnamedFieldsReprFieldDefined {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_opaque_captures_higher_ranked_lifetime, code = E0657)]
pub struct OpaqueCapturesHigherRankedLifetime {
#[primary_span]
pub span: Span,
#[label]
pub label: Option<Span>,
#[note]
pub decl_span: Span,
pub bad_place: &'static str,
}
4 changes: 2 additions & 2 deletions tests/ui/error-codes/E0657.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ impl<T> Id<T> for T {}

fn free_fn_capture_hrtb_in_impl_trait()
-> Box<for<'a> Id<impl Lt<'a>>>
//~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level [E0657]
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
{
Box::new(())
}
Expand All @@ -17,7 +17,7 @@ struct Foo;
impl Foo {
fn impl_fn_capture_hrtb_in_impl_trait()
-> Box<for<'a> Id<impl Lt<'a>>>
//~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
{
Box::new(())
}
Expand Down
16 changes: 14 additions & 2 deletions tests/ui/error-codes/E0657.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
--> $DIR/E0657.rs:10:31
|
LL | -> Box<for<'a> Id<impl Lt<'a>>>
| ^^
|
note: lifetime declared here
--> $DIR/E0657.rs:10:16
|
LL | -> Box<for<'a> Id<impl Lt<'a>>>
| ^^

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

error: aborting due to 2 previous errors

Expand Down
6 changes: 3 additions & 3 deletions tests/ui/impl-trait/impl-fn-hrtb-bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
use std::fmt::Debug;

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

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

fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
|x| x
//~^ ERROR lifetime may not live long enough
}
Expand Down
9 changes: 5 additions & 4 deletions tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're
LL | fn d() -> impl Fn() -> (impl Debug + 'static) {
| ~~~~~~~

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

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

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

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0106`.
Some errors have detailed explanations: E0106, E0657.
For more information about an error, try `rustc --explain E0106`.
2 changes: 1 addition & 1 deletion tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt::Debug;

fn a() -> impl Fn(&u8) -> impl Debug + '_ {
//~^ ERROR ambiguous `+` in a type
//~| ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
//~| ERROR cannot capture higher-ranked lifetime from outer `impl Trait`
|x| x
//~^ ERROR lifetime may not live long enough
}
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ error: ambiguous `+` in a type
LL | fn b() -> impl Fn() -> impl Debug + Send {
| ^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + Send)`

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

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0657`.
8 changes: 7 additions & 1 deletion tests/ui/impl-trait/implicit-capture-late.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
--> $DIR/implicit-capture-late.rs:10:55
|
LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
| ^^^^^^^^^^^ `impl Trait` implicitly captures all lifetimes in scope
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved
|
note: lifetime declared here
--> $DIR/implicit-capture-late.rs:10:36
|
LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/impl-trait/issues/issue-54895.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ impl<'a> Trait<'a> for X {
}

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

Expand Down
3 changes: 2 additions & 1 deletion tests/ui/impl-trait/issues/issue-54895.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: higher kinded lifetime bounds on nested opaque types are not supported yet
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
--> $DIR/issue-54895.rs:15:53
|
LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> {
Expand All @@ -12,3 +12,4 @@ LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> {

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0657`.
2 changes: 1 addition & 1 deletion tests/ui/impl-trait/issues/issue-67830.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ where

struct A;
fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> {
//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
Wrap(|a| Some(a).into_iter())
//~^ ERROR implementation of `FnOnce` is not general enough
//~| ERROR implementation of `FnOnce` is not general enough
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/impl-trait/issues/issue-67830.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: higher kinded lifetime bounds on nested opaque types are not supported yet
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
--> $DIR/issue-67830.rs:21:62
|
LL | fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> {
Expand Down Expand Up @@ -31,3 +31,4 @@ LL | Wrap(|a| Some(a).into_iter())

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0657`.
6 changes: 3 additions & 3 deletions tests/ui/impl-trait/issues/issue-88236-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ impl<'a> Hrtb<'a> for &'a () {
}

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

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

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