-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat: implement lifetime elision #22927
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
base: master
Are you sure you want to change the base?
Changes from 4 commits
54ecc5b
711812c
9ffa4fb
6526ecd
519237a
9217af3
dccc657
d1a5d86
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -6,10 +6,12 @@ mod tests; | |||||
| use std::iter; | ||||||
|
|
||||||
| use crate::{ | ||||||
| ModuleDefId, | ||||||
| expr_store::{ | ||||||
| lower::{ExprCollector, generics::ImplTraitLowerFn}, | ||||||
| lower::{ElisionBinderSource, ExprCollector, generics::ImplTraitLowerFn}, | ||||||
| path::NormalPath, | ||||||
| }, | ||||||
| item_scope::BuiltinShadowMode, | ||||||
| type_ref::LifetimeRef, | ||||||
| }; | ||||||
|
|
||||||
|
|
@@ -39,7 +41,7 @@ thread_local! { | |||||
| // If you modify the logic of the lowering, make sure to check if `hir_segment_to_ast_segment()` | ||||||
| // also needs an update. | ||||||
| pub(super) fn lower_path( | ||||||
| collector: &mut ExprCollector<'_>, | ||||||
| collector: &mut ExprCollector<'_, '_>, | ||||||
| mut path: ast::Path, | ||||||
| impl_trait_lower_fn: ImplTraitLowerFn<'_>, | ||||||
| ) -> Option<Path> { | ||||||
|
|
@@ -101,11 +103,13 @@ pub(super) fn lower_path( | |||||
| .generic_arg_list() | ||||||
| .and_then(|it| collector.lower_generic_args(it, impl_trait_lower_fn)) | ||||||
| .or_else(|| { | ||||||
| collector.lower_generic_args_from_fn_path( | ||||||
| segment.parenthesized_arg_list(), | ||||||
| segment.ret_type(), | ||||||
| impl_trait_lower_fn, | ||||||
| ) | ||||||
| collector.with_type_bound_source(ElisionBinderSource::ForBinder, |this| { | ||||||
| this.lower_generic_args_from_fn_path( | ||||||
| segment.parenthesized_arg_list(), | ||||||
| segment.ret_type(), | ||||||
| impl_trait_lower_fn, | ||||||
| ) | ||||||
| }) | ||||||
| }) | ||||||
| .or_else(|| { | ||||||
| segment.return_type_syntax().map(|_| GenericArgs::return_type_notation()) | ||||||
|
|
@@ -256,11 +260,46 @@ pub(super) fn lower_path( | |||||
| *last_segment_args = None; | ||||||
| } | ||||||
|
|
||||||
| let segments_len = segments.len(); | ||||||
| let mod_path = Interned::new(ModPath::from_segments(kind, segments)); | ||||||
|
|
||||||
| let (resolved_module_def_id, is_trait_assoc_item) = { | ||||||
| let (per_ns, remaining_idx) = collector.def_map.resolve_path( | ||||||
| collector.local_def_map, | ||||||
| collector.db, | ||||||
| collector.module, | ||||||
| &mod_path, | ||||||
| BuiltinShadowMode::Module, | ||||||
| None, | ||||||
| ); | ||||||
| let def = per_ns.types.map(|item| item.def); | ||||||
|
|
||||||
| let is_trait_assoc_item = matches!(def, Some(ModuleDefId::TraitId(..))) | ||||||
| && remaining_idx.is_some_and(|idx| idx > 0); | ||||||
| (def, is_trait_assoc_item) | ||||||
| }; | ||||||
|
|
||||||
| if collector.argument_elision_context.is_some() && !is_trait_assoc_item { | ||||||
|
dfireBird marked this conversation as resolved.
Outdated
|
||||||
| let args_in_source = generic_args.last().and_then(|g| g.as_ref()); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Then push back. So
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mush I like to do it, I can't get the resize correct with pop and push 😅 |
||||||
| let merged_args_with_elided = | ||||||
| collector.collect_path_elided_liftetimes(resolved_module_def_id, args_in_source); | ||||||
| match &merged_args_with_elided { | ||||||
| // there are elided args | ||||||
| Some(_) => { | ||||||
| if args_in_source.is_none() { | ||||||
| generic_args.resize(segments_len, None); | ||||||
| } | ||||||
| if let Some(args) = generic_args.last_mut() { | ||||||
| *args = merged_args_with_elided | ||||||
| } | ||||||
| } | ||||||
| _ => {} // there are no elided args | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| if let Some(old_lifetimes_constrained_by_input) = old_lifetimes_constrained_by_input { | ||||||
| let type_alias_constrained_lifetimes = collector.get_constrained_lifetimes_if_type_alias( | ||||||
| &mod_path, | ||||||
| resolved_module_def_id, | ||||||
| generic_args.last().and_then(|g| g.as_ref()), | ||||||
| ); | ||||||
| if let Some(lifetimes) = type_alias_constrained_lifetimes { | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,16 @@ | ||
| //! HIR for references to types. Paths in these are not yet resolved. They can | ||
| //! be directly created from an ast::TypeRef, without further queries. | ||
|
|
||
| use base_db::SourceDatabase; | ||
| use hir_expand::name::Name; | ||
| use la_arena::Idx; | ||
| use rustc_abi::ExternAbi; | ||
| use thin_vec::ThinVec; | ||
|
|
||
| use crate::{ | ||
| LifetimeParamId, TypeParamId, | ||
| HrtbLifetimeParamId, LifetimeParamId, TypeParamId, | ||
| expr_store::{ExpressionStore, path::Path}, | ||
| hir::{ExprId, PatId}, | ||
| hir::{ExprId, PatId, generics::GenericParams}, | ||
| }; | ||
|
|
||
| #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | ||
|
|
@@ -157,6 +158,7 @@ pub enum LifetimeRef { | |
| Static, | ||
| Placeholder, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should remove this. It's only used in one place that should be replaced with |
||
| Param(LifetimeParamId), | ||
| HrtbParam(HrtbLifetimeParamId), | ||
| Error, | ||
| } | ||
|
|
||
|
|
@@ -202,6 +204,22 @@ impl TypeBound { | |
| } | ||
| } | ||
|
|
||
| impl LifetimeRef { | ||
| pub fn is_elided(&self, db: &dyn SourceDatabase) -> bool { | ||
| match self { | ||
| LifetimeRef::HrtbParam(_) | LifetimeRef::Placeholder => true, | ||
| LifetimeRef::Named(name) => name.is_anon_lifetime(), // Ideally, should not be true if it's Named variant | ||
| LifetimeRef::Param(lifetime_param_id) => { | ||
| let generics = GenericParams::of(db, lifetime_param_id.parent); | ||
| let lt_param = &generics.lifetimes[lifetime_param_id.local_id]; | ||
| lt_param.name.is_anon_lifetime() | ||
| } | ||
|
|
||
| LifetimeRef::Static | LifetimeRef::Error => false, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
| pub struct ConstRef { | ||
| pub expr: ExprId, | ||
|
|
||
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.
Unfortunately this is not correct; lifetimes in trait's assoc types can still be elided, but only for the trait, not for the assoc type.
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.
Can you give an example? I have lot of unknowns here.