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

feat: Implement default-field-values #19001

Merged
merged 8 commits into from
Jan 27, 2025
2 changes: 2 additions & 0 deletions crates/hir-def/src/data/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ pub struct FieldData {
pub name: Name,
pub type_ref: TypeRefId,
pub visibility: RawVisibility,
pub has_default: bool,
}

fn repr_from_value(
Expand Down Expand Up @@ -478,5 +479,6 @@ fn lower_field(
name: field.name.clone(),
type_ref: field.type_ref,
visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
has_default: field.has_default,
}
}
6 changes: 3 additions & 3 deletions crates/hir-def/src/expr_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::{
db::DefDatabase,
hir::{
Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat,
PatId, RecordFieldPat, Statement,
PatId, RecordFieldPat, Spread, Statement,
},
nameres::DefMap,
path::{ModPath, Path},
Expand Down Expand Up @@ -362,7 +362,7 @@ impl ExpressionStore {
for field in fields.iter() {
f(field.expr);
}
if let &Some(expr) = spread {
if let &Spread::Base(expr) = spread {
f(expr);
}
}
Expand Down Expand Up @@ -490,7 +490,7 @@ impl ExpressionStore {
for field in fields.iter() {
f(field.expr);
}
if let &Some(expr) = spread {
if let &Spread::Base(expr) = spread {
f(expr);
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/hir-def/src/expr_store/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ impl Body {
src.map(|it| it.expr())
}
DefWithBodyId::InTypeConstId(c) => c.lookup(db).id.map(|_| c.source(db).expr()),
DefWithBodyId::FieldId(f) => {
f.record_field_source(db).map(|it| it.and_then(|it| it.expr()))
}
}
};
let module = def.module(db);
Expand Down
11 changes: 8 additions & 3 deletions crates/hir-def/src/expr_store/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ use crate::{
},
Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,
Expr, ExprId, Item, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Spread, Statement,
},
item_scope::BuiltinShadowMode,
lang_item::LangItem,
Expand Down Expand Up @@ -90,6 +90,7 @@ pub(super) fn lower_body(
DefWithBodyId::ConstId(it) => db.attrs(it.into()),
DefWithBodyId::InTypeConstId(_) => Attrs::EMPTY,
DefWithBodyId::VariantId(it) => db.attrs(it.into()),
DefWithBodyId::FieldId(it) => db.attrs(it.into()),
}
.rust_analyzer_tool()
.any(|attr| *attr.path() == tool_path![skip]);
Expand Down Expand Up @@ -168,6 +169,7 @@ pub(super) fn lower_body(
Awaitable::No("constant")
}
DefWithBodyId::VariantId(..) => Awaitable::No("enum variant"),
DefWithBodyId::FieldId(..) => Awaitable::No("field"),
}
},
);
Expand Down Expand Up @@ -600,10 +602,13 @@ impl ExprCollector<'_> {
Some(RecordLitField { name, expr })
})
.collect();
let spread = nfl.spread().map(|s| self.collect_expr(s));
let spread = nfl.spread().map(|s| self.collect_expr(s)).map_or_else(
|| if nfl.dotdot_token().is_some() { Spread::Yes } else { Spread::No },
Spread::Base,
);
Expr::RecordLit { path, fields, spread }
} else {
Expr::RecordLit { path, fields: Box::default(), spread: None }
Expr::RecordLit { path, fields: Box::default(), spread: Spread::No }
};

self.alloc_expr(record_lit, syntax_ptr)
Expand Down
43 changes: 38 additions & 5 deletions crates/hir-def/src/expr_store/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ use span::Edition;
use crate::{
hir::{
Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, LiteralOrConst, Movability,
Statement,
Spread, Statement,
},
pretty::{print_generic_args, print_path, print_type_ref},
VariantId,
};

use super::*;
Expand Down Expand Up @@ -56,6 +57,32 @@ pub(super) fn print_body_hir(
loc.id.item_tree(db)[loc.id.value].name.display(db.upcast(), edition),
)
}
DefWithBodyId::FieldId(it) => {
let parent_name: String = match it.parent {
VariantId::EnumVariantId(it) => {
let loc = it.lookup(db);
let enum_loc = loc.parent.lookup(db);
format!(
"{}::{}",
enum_loc.id.item_tree(db)[enum_loc.id.value]
.name
.display(db.upcast(), edition),
loc.id.item_tree(db)[loc.id.value].name.display(db.upcast(), edition),
)
}
VariantId::StructId(it) => it
.lookup(db)
.id
.resolved(db, |it| it.name.display(db.upcast(), edition).to_string()),
VariantId::UnionId(it) => it
.lookup(db)
.id
.resolved(db, |it| it.name.display(db.upcast(), edition).to_string()),
};
let variant_data = it.parent.variant_data(db);
let field_name = &variant_data.fields()[it.local_id].name;
format!("field {}.{}", parent_name, field_name.display(db.upcast(), edition),)
}
};

let mut p = Printer {
Expand Down Expand Up @@ -385,10 +412,16 @@ impl Printer<'_> {
p.print_expr(field.expr);
wln!(p, ",");
}
if let Some(spread) = spread {
w!(p, "..");
p.print_expr(*spread);
wln!(p);
match spread {
Spread::No => {}
Spread::Yes => {
w!(p, "..");
}
Spread::Base(expr) => {
w!(p, "..");
p.print_expr(*expr);
wln!(p);
}
}
});
w!(self, "}}");
Expand Down
9 changes: 8 additions & 1 deletion crates/hir-def/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ pub enum Expr {
RecordLit {
path: Option<Box<Path>>,
fields: Box<[RecordLitField]>,
spread: Option<ExprId>,
spread: Spread,
},
Field {
expr: ExprId,
Expand Down Expand Up @@ -478,6 +478,13 @@ pub struct RecordLitField {
pub expr: ExprId,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Spread {
No,
Yes,
Base(ExprId),
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Statement {
Let {
Expand Down
1 change: 1 addition & 0 deletions crates/hir-def/src/item_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,7 @@ pub struct Field {
pub name: Name,
pub type_ref: TypeRefId,
pub visibility: RawVisibilityId,
pub has_default: bool,
}

#[derive(Debug, Clone, Eq, PartialEq)]
Expand Down
5 changes: 3 additions & 2 deletions crates/hir-def/src/item_tree/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,9 @@ impl<'a> Ctx<'a> {
};
let visibility = self.lower_visibility(field);
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
let has_default = field.expr().is_some();

Field { name, type_ref, visibility }
Field { name, type_ref, visibility, has_default }
}

fn lower_tuple_field(
Expand All @@ -332,7 +333,7 @@ impl<'a> Ctx<'a> {
let name = Name::new_tuple_field(idx);
let visibility = self.lower_visibility(field);
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
Field { name, type_ref, visibility }
Field { name, type_ref, visibility, has_default: false }
}

fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
Expand Down
8 changes: 6 additions & 2 deletions crates/hir-def/src/item_tree/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ impl Printer<'_> {
self.whitespace();
w!(self, "{{");
self.indented(|this| {
for (idx, Field { name, type_ref, visibility }) in fields.iter().enumerate() {
for (idx, Field { name, type_ref, visibility, has_default: _ }) in
fields.iter().enumerate()
{
this.print_attrs_of(
AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
"\n",
Expand All @@ -151,7 +153,9 @@ impl Printer<'_> {
FieldsShape::Tuple => {
w!(self, "(");
self.indented(|this| {
for (idx, Field { name, type_ref, visibility }) in fields.iter().enumerate() {
for (idx, Field { name, type_ref, visibility, has_default: _ }) in
fields.iter().enumerate()
{
this.print_attrs_of(
AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
"\n",
Expand Down
57 changes: 56 additions & 1 deletion crates/hir-def/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub mod visibility;

use intern::Interned;
pub use rustc_abi as layout;
use src::HasSource;
use triomphe::Arc;

#[cfg(test)]
Expand All @@ -77,6 +78,7 @@ use hir_expand::{
builtin::{BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander},
db::ExpandDatabase,
eager::expand_eager_macro_input,
files::InFileWrapper,
impl_intern_lookup,
name::Name,
proc_macro::{CustomProcMacroExpander, ProcMacroKind},
Expand Down Expand Up @@ -519,6 +521,41 @@ pub struct FieldId {
pub local_id: LocalFieldId,
}

impl FieldId {
pub fn record_field_source(
&self,
db: &dyn DefDatabase,
) -> InFileWrapper<HirFileId, Option<ast::RecordField>> {
let field_list = match self.parent {
crate::VariantId::EnumVariantId(it) => {
let s = it.lookup(db);
s.source(db).map(|it| {
it.field_list().and_then(|it| match it {
ast::FieldList::RecordFieldList(it) => Some(it),
_ => None,
})
})
}
crate::VariantId::StructId(it) => {
let s = it.lookup(db);
s.source(db).map(|it| {
it.field_list().and_then(|it| match it {
ast::FieldList::RecordFieldList(it) => Some(it),
_ => None,
})
})
}
crate::VariantId::UnionId(it) => {
let s = it.lookup(db);
s.source(db).map(|it| it.record_field_list())
}
};
field_list.map(|it| {
it.and_then(|it| it.fields().nth(self.local_id.into_raw().into_u32() as usize))
})
}
}

pub type LocalFieldId = Idx<data::adt::FieldData>;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -686,6 +723,7 @@ pub enum TypeOwnerId {
TypeAliasId(TypeAliasId),
ImplId(ImplId),
EnumVariantId(EnumVariantId),
FieldId(FieldId),
}

impl TypeOwnerId {
Expand All @@ -703,6 +741,11 @@ impl TypeOwnerId {
GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent))
}
TypeOwnerId::InTypeConstId(_) => return None,
TypeOwnerId::FieldId(it) => GenericDefId::AdtId(match it.parent {
VariantId::EnumVariantId(it) => AdtId::EnumId(it.lookup(db).parent),
VariantId::StructId(it) => it.into(),
VariantId::UnionId(it) => it.into(),
}),
})
}
}
Expand All @@ -717,7 +760,8 @@ impl_from!(
TraitAliasId,
TypeAliasId,
ImplId,
EnumVariantId
EnumVariantId,
FieldId
for TypeOwnerId
);

Expand All @@ -730,6 +774,7 @@ impl From<DefWithBodyId> for TypeOwnerId {
DefWithBodyId::ConstId(it) => it.into(),
DefWithBodyId::InTypeConstId(it) => it.into(),
DefWithBodyId::VariantId(it) => it.into(),
DefWithBodyId::FieldId(it) => it.into(),
}
}
}
Expand Down Expand Up @@ -885,6 +930,7 @@ pub enum DefWithBodyId {
ConstId(ConstId),
InTypeConstId(InTypeConstId),
VariantId(EnumVariantId),
FieldId(FieldId),
}

impl_from!(FunctionId, ConstId, StaticId, InTypeConstId for DefWithBodyId);
Expand All @@ -905,6 +951,7 @@ impl DefWithBodyId {
// FIXME: stable rust doesn't allow generics in constants, but we should
// use `TypeOwnerId::as_generic_def_id` when it does.
DefWithBodyId::InTypeConstId(_) => None,
DefWithBodyId::FieldId(_) => None,
}
}
}
Expand Down Expand Up @@ -1309,6 +1356,12 @@ impl HasModule for VariantId {
}
}

impl HasModule for FieldId {
fn module(&self, db: &dyn DefDatabase) -> ModuleId {
self.parent.module(db)
}
}

impl HasModule for MacroId {
fn module(&self, db: &dyn DefDatabase) -> ModuleId {
match *self {
Expand All @@ -1332,6 +1385,7 @@ impl HasModule for TypeOwnerId {
TypeOwnerId::ImplId(it) => it.module(db),
TypeOwnerId::EnumVariantId(it) => it.module(db),
TypeOwnerId::InTypeConstId(it) => it.lookup(db).owner.module(db),
TypeOwnerId::FieldId(it) => it.module(db),
}
}
}
Expand All @@ -1344,6 +1398,7 @@ impl HasModule for DefWithBodyId {
DefWithBodyId::ConstId(it) => it.module(db),
DefWithBodyId::VariantId(it) => it.module(db),
DefWithBodyId::InTypeConstId(it) => it.lookup(db).owner.module(db),
DefWithBodyId::FieldId(it) => it.module(db),
}
}
}
Expand Down
Loading
Loading