internal: implement lifetime elision - #22927
Conversation
|
Not sure why this fails in CI and passes in my system? |
You need to set an extra env var to run slow tests |
|
Oh I didn't know, we ran slow tests. My bad 😅 |
06a014c to
88e02b3
Compare
| if let Some(binder) = &fn_.binder | ||
| && !binder.is_empty() |
There was a problem hiding this comment.
nit, lets drop the is_empty check. Ideally we'd just lower to None when binder is empty
There was a problem hiding this comment.
Yeah I guess, I should've kept None if the binder is empty after fn ptr lowering instead of this and that makes sense as well.
| pub scope: GenericDefId, | ||
| pub local_id: usize, | ||
| } | ||
| pub struct HrtbLifetimeParamId(pub usize); |
There was a problem hiding this comment.
| pub struct HrtbLifetimeParamId(pub usize); | |
| pub struct HrtbLifetimeParamId(pub u32); |
We wont ever have that many lifetimes, so being conservative for memory usage won't hurt here
| LifetimeRef::Param(lifetime_param_id) => { | ||
| Some(LifetimeNs::LifetimeParam(*lifetime_param_id)) | ||
| } | ||
| LifetimeRef::HrtbParam(_) => None, // this should be unreachable, should we panic? |
There was a problem hiding this comment.
| LifetimeRef::HrtbParam(_) => None, // this should be unreachable, should we panic? | |
| LifetimeRef::HrtbParam(_) => { | |
| never!(); | |
| None | |
| } |
| TypeRef::Fn(fn_) => { | ||
| if let Some(binder) = &fn_.binder { | ||
| if let Some(binder) = &fn_.binder | ||
| && !binder.is_empty() |
| fn bar(x: &u32) {} | ||
| "#, | ||
| expect!["ty: &'_ &'_ u32, name: x"], | ||
| expect!["ty: &'_ &'<erased> u32, name: x"], |
There was a problem hiding this comment.
we probably need to check our rendering now, we shouldn't show erased lifetimes to the user
There was a problem hiding this comment.
I could make the RegionKind::ReErased to display '_ for now, would that be fine?
| lc world &WorldSnapshot [type_could_unify+name+local] | ||
| ex world [type_could_unify] |
There was a problem hiding this comment.
Interesting, so we lose a lot of type equality now which I guess makes sense. Worth to keep in mind if we want t o have something like type-equal module lifetimes
There was a problem hiding this comment.
We should definitely not render '_ in the generic param list 🙈 if we can't yet render the elided lifetimes nicely here we should probably hide them wholesale
There was a problem hiding this comment.
Would it be fine, if we still showed them in the argument list?
|
Very excited for this, I've been wanting this for so long! |
|
|
||
| ```rust | ||
| pub fn foo(_: &Path) | ||
| pub fn foo<'_>(_: &'_ Path) |
There was a problem hiding this comment.
IMO this is worse display. I think we should omit '_ generics, and omit them for references as well. For non-references - I'm not sure.
There was a problem hiding this comment.
Agree'd, this should mimic the lint. So rendering '_ for paths is good, for references we should skip as its always implied.
There was a problem hiding this comment.
I think it comes down to what I was saying before in zulip chat #t-compiler/rust-analyzer > Lifetime elision @ 💬, have a way to determine if a LifetimeRef is elided or not, provided we have ExpressionStore.
There was a problem hiding this comment.
You could check the name for '_, or add another way to differentiate.
There was a problem hiding this comment.
I could indeed check for LifetimeRef::Param, but if it's going to be used in other places, it's going to be a bit of problem.
There was a problem hiding this comment.
But only elided lifetimes can have name '_.
There was a problem hiding this comment.
Oh I realized something that I can do, I'll try that.
|
|
||
| #[inline] | ||
| pub fn anon_lifetime() -> Name { | ||
| Self::new_text("'_") |
There was a problem hiding this comment.
This should be a predefined symbol.
| ModuleDefId::StaticId(id) => Some(id.into()), | ||
| ModuleDefId::TraitId(id) => Some(id.into()), | ||
| ModuleDefId::TypeAliasId(id) => Some(id.into()), | ||
| _ => None, |
There was a problem hiding this comment.
Use exhaustive matching here.
| self.lower_type_ref( | ||
| it, | ||
| impl_trait_lower_fn, | ||
| &mut Self::elided_lifetime_placeholder_allocator, |
There was a problem hiding this comment.
This does not look correct. We should first lower the arguments. If there is exactly one HRTB lifetime in them, any elided lifetime in the return type should refer to it. Otherwise, it's an error lifetime (plus a diagnostic). In fact, I'm pretty sure we should remove LifetimeRef::Placeholder.
There was a problem hiding this comment.
I use LifetimeRef::Placeholder for return types, so that I can resolve it correctly during hir-ty lowering. But I missed to copy from my old WIP of the lifetime elision.
There was a problem hiding this comment.
I see no reason to resolve it during hir-ty lowering and complicate the code with additional variant when we can resolve it during hir lowering instead.
| &mut self, | ||
| node: ast::Type, | ||
| impl_trait_lower_fn: ImplTraitLowerFn<'_>, | ||
| lifetime_elision_fn: LifetimeElisionFn<'_>, |
There was a problem hiding this comment.
I'm not pleased with passing another callback everywhere. I would prefer an enum field saying what to do: an error, a 'static lifetime (for const and static types), a specific lifetime, or a new anonymous lifetime. In fact you can look at the old LifetimeElisionKind, which implements this (but only for diagnostics) and was copied from rustc.
There was a problem hiding this comment.
I would anyways need access to lifetime Arena in GenericParamCollector.
There was a problem hiding this comment.
The callback works by pushing a '_ and using that Idx to create the LifetimeParamId.
There was a problem hiding this comment.
So? Why can't this be done via an enum field?
There was a problem hiding this comment.
You mean to say use a mutable reference of the arena inside one of enum variant.
There was a problem hiding this comment.
I don't understand what you mean.
What I'm proposing is, instead of accepting a callback for what to do when encountering an elided lifetime, keep a field lifetime_elision_kind of type LifetimeElisionKind in ExpressionStore, similar to (in fact replacing) LifetimeElisionKind in TyLoweringContext, and act according to it.
There was a problem hiding this comment.
The primary purpose of it being a callback here is to have a mutable access to the lifetime arena, but otherwise, I can indeed do what you suggest.
There was a problem hiding this comment.
Hmm, I think it will be better if the enum LifetimeElisionKind will have a variant AsLifetimeParam { collector: &mut GenericParamsCollector, ... }. This does mean introducing another lifetime to ExprCollector, but that's not so bad.
There was a problem hiding this comment.
Yeah, I can do that. Let me do it along with some other review comments over the weekend..
| { | ||
| TypeBound::ForLifetime(binder, path) | ||
| } else { | ||
| TypeBound::Path(path, m) |
There was a problem hiding this comment.
Do we even need TypeBound::Path now? After all in rustc_type_ir every predicate has a binder. We could just always produce ForLifetime.
No description provided.