-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Implement for<>
lifetime binder for closures
#98705
Conversation
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
r? @oli-obk (rust-highfive has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
LL | for<'a, 'b> |_: &'a ()| {}; | ||
| ^^ undeclared lifetime |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @cjgillot even without an impl in ast_lowering, shouldn't this get picked up since you've moved name resolution earlier? Or is that still WIP?
Some changes occurred in src/tools/rustfmt cc @rust-lang/rustfmt Some changes occurred in src/tools/clippy cc @rust-lang/clippy |
This comment has been minimized.
This comment has been minimized.
fd56fff
to
c68cd2f
Compare
This comment has been minimized.
This comment has been minimized.
Omg, I just noticed // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
//rustc_data_structures::static_assert_size!(Expr, 104); // FIXME
impl Expr { the cfg applies to the impl block now |
This comment has been minimized.
This comment has been minimized.
@WaffleLapkin when you get a chance could you add a formatting test case for bound closure to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @WaffleLapkin. I left a few comments.
compiler/rustc_hir/src/hir.rs
Outdated
@@ -1931,6 +1931,7 @@ pub enum ExprKind<'hir> { | |||
/// This may also be a generator literal or an `async block` as indicated by the | |||
/// `Option<Movability>`. | |||
Closure { | |||
binder: &'hir ClosureBinder<'hir>, | |||
capture_clause: CaptureBy, | |||
bound_generic_params: &'hir [GenericParam<'hir>], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This field also holds generic parameters introduced by lifetime resolution. Can this and binder
be merged?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would require to distinguish somewhere the presence of the for<>
in code vs just in HIR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, I'm not sure. This can probably be binder: ClosureBinder { Present, NotPresent }
and all lifetimes stored in bound_generic_params
, but this makes it impossible to distinguish lifetimes from binder from other lifetimes... No idea if we really need to distinguish them though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bound_generic_params
is only filled by anonymous lifetimes, that you explicitly ban. So I don't think you need to worry about separating both.
Furthermore, if we ever allow anonymous lifetimes with a for<>
, we will want them to use the for<>
semantics and not the default/legacy one, won't we?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I've tried this in 27905df77fd6dd9ad6d73b7820ff3d020ec2e7b3 and... in my humble opinion the code turned out to be worse.
} | ||
} | ||
|
||
pub(crate) fn suggestion(&self, sugg: &str) -> String { | ||
match self { | ||
Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), | ||
Self::BoundTail | Self::TypeTail => format!(", {}", sugg), | ||
Self::ClosureEmpty => format!("for<{}>", sugg), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you merge this arm with the previous one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it doesn't have a trailing space.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you want to skip the trailing whitespace? I couldn't find a ui test suggesting to introduce a closure for bound.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we only suggest for<'lifetime>
when there is already for<>
. So we suggest replacing for<>
with for<'lifetime>
. In cases of BoundEmpty
and TypeEmpty
this is used when there is no for<>
at all, so in these cases it makes sense to add a trailing space.
However at closer inspection... I don't think this is ever used. This variant is added to missing_named_lifetime_spots
which is used only in add_missing_lifetime_specifiers_label
that is only used in resolve_elided_lifetimes
which, IIRC, is not called for closures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. I'll see what I will do when moving this diagnostic to AST resolution.
// NOTE(Centril, eddyb): DO NOT REMOVE! Beyond providing parser recovery, | ||
// this is an insurance policy in case we allow qpaths in (tuple-)struct patterns. | ||
// When `for <Foo as Bar>::Proj in $expr $block` is wanted, | ||
// you can disambiguate in favor of a pattern with `(...)`. | ||
self.recover_quantified_closure_expr(attrs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @eddyb is that ok to replace recovering with parsing closures?
☔ The latest upstream changes (presumably #98584) made this pull request unmergeable. Please resolve the merge conflicts. |
b8b1efd
to
bc608ac
Compare
I think this is ready for the next round of review @rustbot ready |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @WaffleLapkin. I think this looks very good. AFAICT, there is just your 2 FIXMEs to handle.
compiler/rustc_hir/src/hir.rs
Outdated
@@ -3479,7 +3491,7 @@ impl<'hir> Node<'hir> { | |||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] | |||
mod size_asserts { | |||
rustc_data_structures::static_assert_size!(super::Block<'static>, 48); | |||
rustc_data_structures::static_assert_size!(super::Expr<'static>, 64); | |||
//rustc_data_structures::static_assert_size!(super::Expr<'static>, 64); // FIXME |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise, should we box the Closure
variant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like so
// ExprKind
Closure(&'hir Closure<'hir>),
struct Closure<'hir> {
binder: &'hir ClosureBinder,
capture_clause: CaptureBy,
bound_generic_params: &'hir [GenericParam<'hir>],
fn_decl: &'hir FnDecl<'hir>,
body: BodyId,
fn_decl_span: Span,
movability: Option<Movability>,
}
?
Maybe, I'm not sure.
Some changes occurred in need_type_info.rs cc @lcnr |
This comment has been minimized.
This comment has been minimized.
This helps bring `hir::Expr` size down, `Closure` was the biggest variant, especially after `for<>` additions.
c7b33a3
to
9aa142b
Compare
@bors r=cjgillot |
@WaffleLapkin: 🔑 Insufficient privileges: Not in reviewers |
@bors r+ |
…llot Implement `for<>` lifetime binder for closures This PR implements RFC 3216 ([TI](rust-lang#97362)) and allows code like the following: ```rust let _f = for<'a, 'b> |a: &'a A, b: &'b B| -> &'b C { b.c(a) }; // ^^^^^^^^^^^--- new! ``` cc `@Aaron1011` `@cjgillot`
Rollup of 5 pull requests Successful merges: - rust-lang#97720 (Always create elided lifetime parameters for functions) - rust-lang#98315 (Stabilize `core::ffi:c_*` and rexport in `std::ffi`) - rust-lang#98705 (Implement `for<>` lifetime binder for closures) - rust-lang#99126 (remove allow(rustc::potential_query_instability) in rustc_span) - rust-lang#99139 (Give a better error when `x dist` fails for an optional tool) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
Can someone update the tracking issue now, tick the implementation and link this pr? |
…llot Implement `for<>` lifetime binder for closures This PR implements RFC 3216 ([TI](rust-lang#97362)) and allows code like the following: ```rust let _f = for<'a, 'b> |a: &'a A, b: &'b B| -> &'b C { b.c(a) }; // ^^^^^^^^^^^--- new! ``` cc ``@Aaron1011`` ``@cjgillot``
Rollup of 5 pull requests Successful merges: - rust-lang#97720 (Always create elided lifetime parameters for functions) - rust-lang#98315 (Stabilize `core::ffi:c_*` and rexport in `std::ffi`) - rust-lang#98705 (Implement `for<>` lifetime binder for closures) - rust-lang#99126 (remove allow(rustc::potential_query_instability) in rustc_span) - rust-lang#99139 (Give a better error when `x dist` fails for an optional tool) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This PR implements RFC 3216 (TI) and allows code like the following:
cc @Aaron1011 @cjgillot