Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
460 changes: 386 additions & 74 deletions crates/hir-def/src/expr_store/lower.rs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion crates/hir-def/src/expr_store/lower/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
hir::{AsmOperand, AsmOptions, Expr, ExprId, InlineAsm, InlineAsmKind, InlineAsmRegOrRegClass},
};

impl ExprCollector<'_> {
impl ExprCollector<'_, '_> {
pub(super) fn lower_inline_asm(
&mut self,
asm: ast::AsmExpr,
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-def/src/expr_store/lower/format_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
type_ref::{Mutability, Rawness},
};

impl<'db> ExprCollector<'db> {
impl<'db> ExprCollector<'db, '_> {
pub(super) fn collect_format_args(
&mut self,
f: ast::FormatArgsExpr,
Expand Down
65 changes: 29 additions & 36 deletions crates/hir-def/src/expr_store/lower/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
GenericDefId, TypeOrConstParamId, TypeParamId,
expr_store::{
TypePtr,
lower::{ExprCollector, LifetimeBoundScope, NamedLifetimeStore},
lower::{ExprCollector, LifetimeBoundScope},
},
hir::generics::{
ConstParamData, GenericParams, LifetimeBoundType, LifetimeParamData, TypeOrConstParamData,
Expand All @@ -23,8 +23,8 @@ use crate::{
type_ref::{LifetimeRef, LifetimeRefId, TypeBound, TypeRef, TypeRefId},
};

pub(crate) type ImplTraitLowerFn<'l> = &'l mut dyn for<'ec, 'db> FnMut(
&'ec mut ExprCollector<'db>,
pub(crate) type ImplTraitLowerFn<'l> = &'l mut dyn for<'ec, 'db, 'a> FnMut(
&'ec mut ExprCollector<'db, 'a>,
TypePtr,
ThinVec<TypeBound>,
) -> TypeRefId;
Expand All @@ -46,7 +46,7 @@ impl GenericParamsCollector {
}
}
pub(crate) fn with_self_param(
ec: &mut ExprCollector<'_>,
ec: &mut ExprCollector<'_, '_>,
parent: GenericDefId,
bounds: Option<ast::TypeBoundList>,
) -> Self {
Expand All @@ -57,7 +57,7 @@ impl GenericParamsCollector {

pub(crate) fn lower(
&mut self,
ec: &mut ExprCollector<'_>,
ec: &mut ExprCollector<'_, '_>,
generic_param_list: Option<ast::GenericParamList>,
where_clause: Option<ast::WhereClause>,
) {
Expand All @@ -69,11 +69,12 @@ impl GenericParamsCollector {
}
}

pub(crate) fn collect_impl_trait<R>(
&mut self,
ec: &mut ExprCollector<'_>,
cb: impl FnOnce(&mut ExprCollector<'_>, ImplTraitLowerFn<'_>) -> R,
pub(crate) fn collect_impl_trait<'a, R>(
&'a mut self,
ec: &mut ExprCollector<'_, 'a>,
cb: impl FnOnce(&mut ExprCollector<'_, '_>, ImplTraitLowerFn<'_>) -> R,
) -> R {
ec.elide_create_lifetime(&mut self.lifetimes, self.parent, LifetimeBoundType::LateBound);
cb(
ec,
&mut Self::lower_argument_impl_trait(
Expand All @@ -96,7 +97,11 @@ impl GenericParamsCollector {
}
}

fn lower_param_list(&mut self, ec: &mut ExprCollector<'_>, params: ast::GenericParamList) {
pub(crate) fn lifetimes_mut(&mut self) -> &mut Arena<LifetimeParamData> {
&mut self.lifetimes
}

fn lower_param_list(&mut self, ec: &mut ExprCollector<'_, '_>, params: ast::GenericParamList) {
for generic_param in params.generic_params() {
let enabled = ec.check_cfg(&generic_param);
if !enabled {
Expand Down Expand Up @@ -158,7 +163,7 @@ impl GenericParamsCollector {

fn lower_where_predicates(
&mut self,
ec: &mut ExprCollector<'_>,
ec: &mut ExprCollector<'_, '_>,
where_clause: ast::WhereClause,
) {
ec.with_lifetime_bound_scope(LifetimeBoundScope::WhereClause, |ec| {
Expand All @@ -185,6 +190,7 @@ impl GenericParamsCollector {
})
.collect()
});

for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
self.lower_type_bound_as_predicate(ec, bound, lifetimes.as_deref(), target);
}
Expand All @@ -194,7 +200,7 @@ impl GenericParamsCollector {

fn lower_bounds(
&mut self,
ec: &mut ExprCollector<'_>,
ec: &mut ExprCollector<'_, '_>,
type_bounds: Option<ast::TypeBoundList>,
target: Either<TypeRefId, LifetimeRefId>,
) {
Expand All @@ -205,7 +211,7 @@ impl GenericParamsCollector {

fn lower_type_bound_as_predicate(
&mut self,
ec: &mut ExprCollector<'_>,
ec: &mut ExprCollector<'_, '_>,
bound: ast::TypeBound,
hrtb_lifetimes: Option<&[Name]>,
target: Either<TypeRefId, LifetimeRefId>,
Expand Down Expand Up @@ -240,8 +246,11 @@ impl GenericParamsCollector {
type_or_consts: &mut Arena<TypeOrConstParamData>,
where_predicates: &mut Vec<WherePredicate>,
parent: GenericDefId,
) -> impl for<'ec, 'db> FnMut(&'ec mut ExprCollector<'db>, TypePtr, ThinVec<TypeBound>) -> TypeRefId
{
) -> impl for<'ec, 'db, 'a> FnMut(
&'ec mut ExprCollector<'db, 'a>,
TypePtr,
ThinVec<TypeBound>,
) -> TypeRefId {
move |ec, ptr, impl_trait_bounds| {
let param = TypeParamData {
name: None,
Expand All @@ -264,7 +273,11 @@ impl GenericParamsCollector {
}
}

fn fill_self_param(&mut self, ec: &mut ExprCollector<'_>, bounds: Option<ast::TypeBoundList>) {
fn fill_self_param(
&mut self,
ec: &mut ExprCollector<'_, '_>,
bounds: Option<ast::TypeBoundList>,
) {
let self_ = Name::new_symbol_root(sym::Self_);
let idx = self.type_or_consts.alloc(
TypeParamData {
Expand All @@ -284,24 +297,4 @@ impl GenericParamsCollector {
self.lower_bounds(ec, Some(bounds), Either::Left(self_));
}
}

pub(crate) fn update_to_late_bound_lifetimes(
&mut self,
named_lifetime_store: &NamedLifetimeStore,
) {
for (_param_id, lifetime) in self.lifetimes.iter_mut() {
let lifetime_name = &lifetime.name;
if named_lifetime_store.lifetimes_in_where_clause.contains(lifetime_name) {
continue;
}

if !named_lifetime_store.lifetimes_constrained_by_input.contains(lifetime_name)
&& named_lifetime_store.lifetimes_in_output.contains(lifetime_name)
{
continue;
}

lifetime.bound_type = LifetimeBoundType::LateBound
}
}
}
55 changes: 47 additions & 8 deletions crates/hir-def/src/expr_store/lower/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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);
Comment on lines +275 to +276

Copy link
Copy Markdown
Contributor

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.

Copy link
Copy Markdown
Member Author

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.

(def, is_trait_assoc_item)
};

if collector.argument_elision_context.is_some() && !is_trait_assoc_item {
Comment thread
dfireBird marked this conversation as resolved.
Outdated
let args_in_source = generic_args.last().and_then(|g| g.as_ref());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let args_in_source = generic_args.last().and_then(|g| g.as_ref());
let args_in_source = generic_args.pop();

Then push back. So collect_path_elided_liftetimes() can have an owned value to make use of.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The 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 {
Expand Down
9 changes: 8 additions & 1 deletion crates/hir-def/src/expr_store/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ fn print_generic_params(
w!(p, "<");
let mut first = true;
for (_i, param) in generic_params.iter_lt() {
if param.is_elided() {
continue;
}

if !first {
w!(p, ", ");
}
Expand Down Expand Up @@ -1267,6 +1271,7 @@ impl Printer<'_> {
}
LifetimeRef::Placeholder => w!(self, "'_"),
LifetimeRef::Error => w!(self, "'{{error}}"),
LifetimeRef::HrtbParam(_) => w!(self, "'_"), // FIXME: properly handle it, currently do not have enough data to handle
&LifetimeRef::Param(p) => self.print_lifetime_param(p),
}
}
Expand Down Expand Up @@ -1302,7 +1307,9 @@ impl Printer<'_> {
Mutability::Mut => "mut ",
};
w!(self, "&");
if let Some(lt) = &ref_.lifetime {
if let Some(lt) = &ref_.lifetime
&& !self.store[*lt].is_elided(self.db)
{
self.print_lifetime_ref(*lt);
w!(self, " ");
}
Expand Down
4 changes: 2 additions & 2 deletions crates/hir-def/src/expr_store/tests/signatures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ fn allowed3(baz: impl Baz<Assoc = Qux<impl Foo>>) {}
{...}
fn not_allowed2<Param[0]>(Param[0])
where
Param[0]: Fn::<(&{error}), Output = ()>
Param[0]: for<'_> Fn::<(&{error}), Output = ()>
{...}
fn not_allowed3<Param[0]>(Param[0])
where
Expand Down Expand Up @@ -207,7 +207,7 @@ type Alias<'a, 'b, T> = &'b T;
fn f<T>(_: Alias<T>) {}
"#,
expect![[r#"
fn f<T>(Alias::<T>) {...}
fn f<T>(Alias::<'_, '_, T>) {...}
"#]],
);
}
Expand Down
6 changes: 5 additions & 1 deletion crates/hir-def/src/hir/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,17 @@ pub struct LifetimeParamData {
pub bound_type: LifetimeBoundType,
}

#[derive(Clone, PartialEq, Eq, Debug, Hash)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum LifetimeBoundType {
EarlyBound,
LateBound,
}

impl LifetimeParamData {
pub fn is_elided(&self) -> bool {
self.name.is_anon_lifetime()
}

pub fn is_late_bound(&self) -> bool {
self.bound_type == LifetimeBoundType::LateBound
}
Expand Down
22 changes: 20 additions & 2 deletions crates/hir-def/src/hir/type_ref.rs
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)]
Expand Down Expand Up @@ -157,6 +158,7 @@ pub enum LifetimeRef {
Static,
Placeholder,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 Error.

Param(LifetimeParamId),
HrtbParam(HrtbLifetimeParamId),
Error,
}

Expand Down Expand Up @@ -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,
Expand Down
Loading
Loading