mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
Merge #8364
8364: Memory usage improvements r=jonas-schievink a=alexmaco These are mostly focused on splitting up enum variants with large size differences between variants by `Box`-ing things up. In my testing this reduces the memory usage somewhere in the low percentages, even though the measurements are quite noisy. Co-authored-by: Alexandru Macovei <alexnmaco@gmail.com>
This commit is contained in:
commit
7d39b13996
8 changed files with 54 additions and 33 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1867,6 +1867,7 @@ name = "vfs"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"fst",
|
||||
"indexmap",
|
||||
"paths",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
|
|
@ -322,8 +322,10 @@ impl ExprCollector<'_> {
|
|||
Vec::new()
|
||||
};
|
||||
let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
|
||||
let generic_args =
|
||||
e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it));
|
||||
let generic_args = e
|
||||
.generic_arg_list()
|
||||
.and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
|
||||
.map(Box::new);
|
||||
self.alloc_expr(
|
||||
Expr::MethodCall { receiver, method_name, args, generic_args },
|
||||
syntax_ptr,
|
||||
|
@ -385,7 +387,7 @@ impl ExprCollector<'_> {
|
|||
self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
|
||||
}
|
||||
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 fields = nfl
|
||||
.fields()
|
||||
|
@ -430,7 +432,7 @@ impl ExprCollector<'_> {
|
|||
}
|
||||
ast::Expr::CastExpr(e) => {
|
||||
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)
|
||||
}
|
||||
ast::Expr::RefExpr(e) => {
|
||||
|
@ -469,8 +471,10 @@ impl ExprCollector<'_> {
|
|||
arg_types.push(type_ref);
|
||||
}
|
||||
}
|
||||
let ret_type =
|
||||
e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it));
|
||||
let ret_type = e
|
||||
.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());
|
||||
self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
|
||||
}
|
||||
|
@ -755,7 +759,7 @@ impl ExprCollector<'_> {
|
|||
}
|
||||
}
|
||||
ast::Pat::TupleStructPat(p) => {
|
||||
let path = p.path().and_then(|path| self.expander.parse_path(path));
|
||||
let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
|
||||
let (args, ellipsis) = self.collect_tuple_pat(p.fields());
|
||||
Pat::TupleStruct { path, args, ellipsis }
|
||||
}
|
||||
|
@ -765,7 +769,7 @@ impl ExprCollector<'_> {
|
|||
Pat::Ref { pat, mutability }
|
||||
}
|
||||
ast::Pat::PathPat(p) => {
|
||||
let path = p.path().and_then(|path| self.expander.parse_path(path));
|
||||
let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
|
||||
path.map(Pat::Path).unwrap_or(Pat::Missing)
|
||||
}
|
||||
ast::Pat::OrPat(p) => {
|
||||
|
@ -779,7 +783,7 @@ impl ExprCollector<'_> {
|
|||
}
|
||||
ast::Pat::WildcardPat(_) => Pat::Wild,
|
||||
ast::Pat::RecordPat(p) => {
|
||||
let path = p.path().and_then(|path| self.expander.parse_path(path));
|
||||
let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
|
||||
let args: Vec<_> = p
|
||||
.record_pat_field_list()
|
||||
.expect("every struct should have a field list")
|
||||
|
|
|
@ -86,7 +86,7 @@ pub enum Expr {
|
|||
receiver: ExprId,
|
||||
method_name: Name,
|
||||
args: Vec<ExprId>,
|
||||
generic_args: Option<GenericArgs>,
|
||||
generic_args: Option<Box<GenericArgs>>,
|
||||
},
|
||||
Match {
|
||||
expr: ExprId,
|
||||
|
@ -106,7 +106,7 @@ pub enum Expr {
|
|||
expr: Option<ExprId>,
|
||||
},
|
||||
RecordLit {
|
||||
path: Option<Path>,
|
||||
path: Option<Box<Path>>,
|
||||
fields: Vec<RecordLitField>,
|
||||
spread: Option<ExprId>,
|
||||
},
|
||||
|
@ -131,7 +131,7 @@ pub enum Expr {
|
|||
},
|
||||
Cast {
|
||||
expr: ExprId,
|
||||
type_ref: TypeRef,
|
||||
type_ref: Box<TypeRef>,
|
||||
},
|
||||
Ref {
|
||||
expr: ExprId,
|
||||
|
@ -162,7 +162,7 @@ pub enum Expr {
|
|||
Lambda {
|
||||
args: Vec<PatId>,
|
||||
arg_types: Vec<Option<TypeRef>>,
|
||||
ret_type: Option<TypeRef>,
|
||||
ret_type: Option<Box<TypeRef>>,
|
||||
body: ExprId,
|
||||
},
|
||||
Tuple {
|
||||
|
@ -412,13 +412,13 @@ pub enum Pat {
|
|||
Wild,
|
||||
Tuple { args: Vec<PatId>, ellipsis: Option<usize> },
|
||||
Or(Vec<PatId>),
|
||||
Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool },
|
||||
Record { path: Option<Box<Path>>, args: Vec<RecordFieldPat>, ellipsis: bool },
|
||||
Range { start: ExprId, end: ExprId },
|
||||
Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> },
|
||||
Path(Path),
|
||||
Path(Box<Path>),
|
||||
Lit(ExprId),
|
||||
Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
|
||||
TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> },
|
||||
TupleStruct { path: Option<Box<Path>>, args: Vec<PatId>, ellipsis: Option<usize> },
|
||||
Ref { pat: PatId, mutability: Mutability },
|
||||
Box { inner: PatId },
|
||||
ConstBlock(ExprId),
|
||||
|
|
|
@ -289,6 +289,12 @@ impl From<Name> for Path {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Name> for Box<Path> {
|
||||
fn from(name: Name) -> Box<Path> {
|
||||
Box::new(Path::from(name))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Name> for ModPath {
|
||||
fn from(name: Name) -> ModPath {
|
||||
ModPath::from_segments(PathKind::Plain, iter::once(name))
|
||||
|
|
|
@ -318,7 +318,13 @@ impl<'a> InferenceContext<'a> {
|
|||
self.normalize_associated_types_in(ret_ty)
|
||||
}
|
||||
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 } => {
|
||||
let input_ty = self.infer_expr(*expr, &Expectation::none());
|
||||
|
||||
|
@ -399,7 +405,7 @@ impl<'a> InferenceContext<'a> {
|
|||
TyKind::Never.intern(&Interner)
|
||||
}
|
||||
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 {
|
||||
self.write_variant_resolution(tgt_expr.into(), variant);
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ impl<'a> InferenceContext<'a> {
|
|||
TyKind::Ref(mutability, static_lifetime(), subty).intern(&Interner)
|
||||
}
|
||||
Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat(
|
||||
p.as_ref(),
|
||||
p.as_deref(),
|
||||
subpats,
|
||||
expected,
|
||||
default_bm,
|
||||
|
@ -182,7 +182,7 @@ impl<'a> InferenceContext<'a> {
|
|||
*ellipsis,
|
||||
),
|
||||
Pat::Record { path: p, args: fields, ellipsis: _ } => {
|
||||
self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat)
|
||||
self.infer_record_pat(p.as_deref(), fields, expected, default_bm, pat)
|
||||
}
|
||||
Pat::Path(path) => {
|
||||
// FIXME use correct resolver for the surrounding expression
|
||||
|
|
|
@ -14,3 +14,4 @@ rustc-hash = "1.0"
|
|||
fst = "0.4"
|
||||
|
||||
paths = { path = "../paths", version = "0.0.0" }
|
||||
indexmap = "1.6.2"
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
//! Maps paths to compact integer ids. We don't care about clearings paths which
|
||||
//! no longer exist -- the assumption is total size of paths we ever look at is
|
||||
//! not too big.
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::hash::BuildHasherDefault;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use rustc_hash::FxHasher;
|
||||
|
||||
use crate::{FileId, VfsPath};
|
||||
|
||||
/// Structure to map between [`VfsPath`] and [`FileId`].
|
||||
#[derive(Default)]
|
||||
pub(crate) struct PathInterner {
|
||||
map: FxHashMap<VfsPath, FileId>,
|
||||
vec: Vec<VfsPath>,
|
||||
map: IndexSet<VfsPath, BuildHasherDefault<FxHasher>>,
|
||||
}
|
||||
|
||||
impl Default for PathInterner {
|
||||
fn default() -> Self {
|
||||
Self { map: IndexSet::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl PathInterner {
|
||||
|
@ -17,7 +24,7 @@ impl PathInterner {
|
|||
///
|
||||
/// If `path` does not exists in `self`, returns [`None`].
|
||||
pub(crate) fn get(&self, path: &VfsPath) -> Option<FileId> {
|
||||
self.map.get(path).copied()
|
||||
self.map.get_index_of(path).map(|i| FileId(i as u32))
|
||||
}
|
||||
|
||||
/// Insert `path` in `self`.
|
||||
|
@ -25,13 +32,9 @@ impl PathInterner {
|
|||
/// - If `path` already exists in `self`, returns its associated id;
|
||||
/// - Else, returns a newly allocated id.
|
||||
pub(crate) fn intern(&mut self, path: VfsPath) -> FileId {
|
||||
if let Some(id) = self.get(&path) {
|
||||
return id;
|
||||
}
|
||||
let id = FileId(self.vec.len() as u32);
|
||||
self.map.insert(path.clone(), id);
|
||||
self.vec.push(path);
|
||||
id
|
||||
let (id, _added) = self.map.insert_full(path);
|
||||
assert!(id < u32::MAX as usize);
|
||||
FileId(id as u32)
|
||||
}
|
||||
|
||||
/// Returns the path corresponding to `id`.
|
||||
|
@ -40,6 +43,6 @@ impl PathInterner {
|
|||
///
|
||||
/// Panics if `id` does not exists in `self`.
|
||||
pub(crate) fn lookup(&self, id: FileId) -> &VfsPath {
|
||||
&self.vec[id.0 as usize]
|
||||
self.map.get_index(id.0 as usize).unwrap()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue