Use Box'es to reduce size of hir_def::expr::Expr from 128 to 72 bytes (on 64bit systems)

Rationale: only a minority of variants used almost half the size.
By keeping large members (especially in Option) behind a box
the memory cost is only payed when the large variants are needed.

This reduces the size Vec<Expr> needs to allocate.
This commit is contained in:
Alexandru Macovei 2021-03-30 23:06:57 +03:00
parent 4bc8a01830
commit fb1f544e24
3 changed files with 22 additions and 12 deletions

View file

@ -322,8 +322,10 @@ impl ExprCollector<'_> {
Vec::new() Vec::new()
}; };
let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
let generic_args = let generic_args = e
e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); .generic_arg_list()
.and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
.map(Box::new);
self.alloc_expr( self.alloc_expr(
Expr::MethodCall { receiver, method_name, args, generic_args }, Expr::MethodCall { receiver, method_name, args, generic_args },
syntax_ptr, syntax_ptr,
@ -385,7 +387,7 @@ impl ExprCollector<'_> {
self.alloc_expr(Expr::Yield { expr }, syntax_ptr) self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
} }
ast::Expr::RecordExpr(e) => { ast::Expr::RecordExpr(e) => {
let path = e.path().and_then(|path| self.expander.parse_path(path)); let path = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
let record_lit = if let Some(nfl) = e.record_expr_field_list() { let record_lit = if let Some(nfl) = e.record_expr_field_list() {
let fields = nfl let fields = nfl
.fields() .fields()
@ -430,7 +432,7 @@ impl ExprCollector<'_> {
} }
ast::Expr::CastExpr(e) => { ast::Expr::CastExpr(e) => {
let expr = self.collect_expr_opt(e.expr()); let expr = self.collect_expr_opt(e.expr());
let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty()); let type_ref = Box::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
} }
ast::Expr::RefExpr(e) => { ast::Expr::RefExpr(e) => {
@ -469,8 +471,10 @@ impl ExprCollector<'_> {
arg_types.push(type_ref); arg_types.push(type_ref);
} }
} }
let ret_type = let ret_type = e
e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it)); .ret_type()
.and_then(|r| r.ty())
.map(|it| Box::new(TypeRef::from_ast(&self.ctx(), it)));
let body = self.collect_expr_opt(e.body()); let body = self.collect_expr_opt(e.body());
self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
} }

View file

@ -86,7 +86,7 @@ pub enum Expr {
receiver: ExprId, receiver: ExprId,
method_name: Name, method_name: Name,
args: Vec<ExprId>, args: Vec<ExprId>,
generic_args: Option<GenericArgs>, generic_args: Option<Box<GenericArgs>>,
}, },
Match { Match {
expr: ExprId, expr: ExprId,
@ -106,7 +106,7 @@ pub enum Expr {
expr: Option<ExprId>, expr: Option<ExprId>,
}, },
RecordLit { RecordLit {
path: Option<Path>, path: Option<Box<Path>>,
fields: Vec<RecordLitField>, fields: Vec<RecordLitField>,
spread: Option<ExprId>, spread: Option<ExprId>,
}, },
@ -131,7 +131,7 @@ pub enum Expr {
}, },
Cast { Cast {
expr: ExprId, expr: ExprId,
type_ref: TypeRef, type_ref: Box<TypeRef>,
}, },
Ref { Ref {
expr: ExprId, expr: ExprId,
@ -162,7 +162,7 @@ pub enum Expr {
Lambda { Lambda {
args: Vec<PatId>, args: Vec<PatId>,
arg_types: Vec<Option<TypeRef>>, arg_types: Vec<Option<TypeRef>>,
ret_type: Option<TypeRef>, ret_type: Option<Box<TypeRef>>,
body: ExprId, body: ExprId,
}, },
Tuple { Tuple {

View file

@ -317,7 +317,13 @@ impl<'a> InferenceContext<'a> {
self.normalize_associated_types_in(ret_ty) self.normalize_associated_types_in(ret_ty)
} }
Expr::MethodCall { receiver, args, method_name, generic_args } => self Expr::MethodCall { receiver, args, method_name, generic_args } => self
.infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), .infer_method_call(
tgt_expr,
*receiver,
&args,
&method_name,
generic_args.as_deref(),
),
Expr::Match { expr, arms } => { Expr::Match { expr, arms } => {
let input_ty = self.infer_expr(*expr, &Expectation::none()); let input_ty = self.infer_expr(*expr, &Expectation::none());
@ -398,7 +404,7 @@ impl<'a> InferenceContext<'a> {
TyKind::Never.intern(&Interner) TyKind::Never.intern(&Interner)
} }
Expr::RecordLit { path, fields, spread } => { Expr::RecordLit { path, fields, spread } => {
let (ty, def_id) = self.resolve_variant(path.as_ref()); let (ty, def_id) = self.resolve_variant(path.as_deref());
if let Some(variant) = def_id { if let Some(variant) = def_id {
self.write_variant_resolution(tgt_expr.into(), variant); self.write_variant_resolution(tgt_expr.into(), variant);
} }