mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 21:43:37 +00:00
Auto merge of #17671 - Veykril:binding-size, r=Veykril
internal: Shrink size of `Binding` This should save a bit of memory now that we LRU the source map
This commit is contained in:
commit
329adb5ab1
15 changed files with 94 additions and 56 deletions
|
@ -6,13 +6,14 @@ pub mod scope;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::ops::Index;
|
||||
use std::ops::{Deref, Index};
|
||||
|
||||
use base_db::CrateId;
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
use hir_expand::{name::Name, InFile};
|
||||
use la_arena::{Arena, ArenaMap};
|
||||
use rustc_hash::FxHashMap;
|
||||
use smallvec::SmallVec;
|
||||
use span::MacroFileId;
|
||||
use syntax::{ast, AstPtr, SyntaxNodePtr};
|
||||
use triomphe::Arc;
|
||||
|
@ -91,6 +92,7 @@ pub struct BodySourceMap {
|
|||
label_map_back: ArenaMap<LabelId, LabelSource>,
|
||||
|
||||
self_param: Option<InFile<AstPtr<ast::SelfParam>>>,
|
||||
binding_definitions: FxHashMap<BindingId, SmallVec<[PatId; 4]>>,
|
||||
|
||||
/// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
|
||||
/// Instead, we use id of expression (`92`) to identify the field.
|
||||
|
@ -377,6 +379,10 @@ impl BodySourceMap {
|
|||
self.label_map_back[label]
|
||||
}
|
||||
|
||||
pub fn patterns_for_binding(&self, binding: BindingId) -> &[PatId] {
|
||||
self.binding_definitions.get(&binding).map_or(&[], Deref::deref)
|
||||
}
|
||||
|
||||
pub fn node_label(&self, node: InFile<&ast::Label>) -> Option<LabelId> {
|
||||
let src = node.map(AstPtr::new);
|
||||
self.label_map.get(&src).cloned()
|
||||
|
@ -428,6 +434,7 @@ impl BodySourceMap {
|
|||
expansions,
|
||||
format_args_template_map,
|
||||
diagnostics,
|
||||
binding_definitions,
|
||||
} = self;
|
||||
format_args_template_map.shrink_to_fit();
|
||||
expr_map.shrink_to_fit();
|
||||
|
@ -440,5 +447,6 @@ impl BodySourceMap {
|
|||
pat_field_map_back.shrink_to_fit();
|
||||
expansions.shrink_to_fit();
|
||||
diagnostics.shrink_to_fit();
|
||||
binding_definitions.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ use hir_expand::{
|
|||
};
|
||||
use intern::{sym, Interned, Symbol};
|
||||
use rustc_hash::FxHashMap;
|
||||
use smallvec::SmallVec;
|
||||
use span::AstIdMap;
|
||||
use stdx::never;
|
||||
use syntax::{
|
||||
|
@ -1437,11 +1436,12 @@ impl ExprCollector<'_> {
|
|||
args: AstChildren<ast::Pat>,
|
||||
has_leading_comma: bool,
|
||||
binding_list: &mut BindingList,
|
||||
) -> (Box<[PatId]>, Option<usize>) {
|
||||
) -> (Box<[PatId]>, Option<u32>) {
|
||||
let args: Vec<_> = args.map(|p| self.collect_pat_possibly_rest(p, binding_list)).collect();
|
||||
// Find the location of the `..`, if there is one. Note that we do not
|
||||
// consider the possibility of there being multiple `..` here.
|
||||
let ellipsis = args.iter().position(|p| p.is_right());
|
||||
let ellipsis = args.iter().position(|p| p.is_right()).map(|it| it as u32);
|
||||
|
||||
// We want to skip the `..` pattern here, since we account for it above.
|
||||
let mut args: Vec<_> = args.into_iter().filter_map(Either::left).collect();
|
||||
// if there is a leading comma, the user is most likely to type out a leading pattern
|
||||
|
@ -1512,7 +1512,7 @@ impl ExprCollector<'_> {
|
|||
}
|
||||
|
||||
fn add_definition_to_binding(&mut self, binding_id: BindingId, pat_id: PatId) {
|
||||
self.body.bindings[binding_id].definitions.push(pat_id);
|
||||
self.source_map.binding_definitions.entry(binding_id).or_default().push(pat_id);
|
||||
}
|
||||
|
||||
// region: labels
|
||||
|
@ -2058,12 +2058,7 @@ impl ExprCollector<'_> {
|
|||
}
|
||||
|
||||
fn alloc_binding(&mut self, name: Name, mode: BindingAnnotation) -> BindingId {
|
||||
let binding = self.body.bindings.alloc(Binding {
|
||||
name,
|
||||
mode,
|
||||
definitions: SmallVec::new(),
|
||||
problems: None,
|
||||
});
|
||||
let binding = self.body.bindings.alloc(Binding { name, mode, problems: None });
|
||||
if let Some(owner) = self.current_binding_owner {
|
||||
self.body.binding_owners.insert(binding, owner);
|
||||
}
|
||||
|
|
|
@ -517,7 +517,7 @@ impl Printer<'_> {
|
|||
if i != 0 {
|
||||
w!(self, ", ");
|
||||
}
|
||||
if *ellipsis == Some(i) {
|
||||
if *ellipsis == Some(i as u32) {
|
||||
w!(self, ".., ");
|
||||
}
|
||||
self.print_pat(*pat);
|
||||
|
@ -595,7 +595,7 @@ impl Printer<'_> {
|
|||
if i != 0 {
|
||||
w!(self, ", ");
|
||||
}
|
||||
if *ellipsis == Some(i) {
|
||||
if *ellipsis == Some(i as u32) {
|
||||
w!(self, ", ..");
|
||||
}
|
||||
self.print_pat(*arg);
|
||||
|
|
|
@ -484,7 +484,7 @@ fn foo() {
|
|||
let function = find_function(&db, file_id.file_id());
|
||||
|
||||
let scopes = db.expr_scopes(function.into());
|
||||
let (body, source_map) = db.body_with_source_map(function.into());
|
||||
let (_, source_map) = db.body_with_source_map(function.into());
|
||||
|
||||
let expr_scope = {
|
||||
let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap();
|
||||
|
@ -495,7 +495,7 @@ fn foo() {
|
|||
|
||||
let resolved = scopes.resolve_name_in_scope(expr_scope, &name_ref.as_name()).unwrap();
|
||||
let pat_src = source_map
|
||||
.pat_syntax(*body.bindings[resolved.binding()].definitions.first().unwrap())
|
||||
.pat_syntax(*source_map.binding_definitions[&resolved.binding()].first().unwrap())
|
||||
.unwrap();
|
||||
|
||||
let local_name = pat_src.value.syntax_node_ptr().to_node(file.syntax());
|
||||
|
|
|
@ -21,7 +21,6 @@ use hir_expand::name::Name;
|
|||
use intern::{Interned, Symbol};
|
||||
use la_arena::{Idx, RawIdx};
|
||||
use rustc_apfloat::ieee::{Half as f16, Quad as f128};
|
||||
use smallvec::SmallVec;
|
||||
use syntax::ast;
|
||||
|
||||
use crate::{
|
||||
|
@ -525,7 +524,6 @@ pub enum BindingProblems {
|
|||
pub struct Binding {
|
||||
pub name: Name,
|
||||
pub mode: BindingAnnotation,
|
||||
pub definitions: SmallVec<[PatId; 1]>,
|
||||
pub problems: Option<BindingProblems>,
|
||||
}
|
||||
|
||||
|
@ -540,7 +538,7 @@ pub struct RecordFieldPat {
|
|||
pub enum Pat {
|
||||
Missing,
|
||||
Wild,
|
||||
Tuple { args: Box<[PatId]>, ellipsis: Option<usize> },
|
||||
Tuple { args: Box<[PatId]>, ellipsis: Option<u32> },
|
||||
Or(Box<[PatId]>),
|
||||
Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
|
||||
Range { start: Option<Box<LiteralOrConst>>, end: Option<Box<LiteralOrConst>> },
|
||||
|
@ -548,7 +546,7 @@ pub enum Pat {
|
|||
Path(Box<Path>),
|
||||
Lit(ExprId),
|
||||
Bind { id: BindingId, subpat: Option<PatId> },
|
||||
TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<usize> },
|
||||
TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<u32> },
|
||||
Ref { pat: PatId, mutability: Mutability },
|
||||
Box { inner: PatId },
|
||||
ConstBlock(ExprId),
|
||||
|
|
|
@ -206,7 +206,7 @@ impl<'a> PatCtxt<'a> {
|
|||
&mut self,
|
||||
pats: &[PatId],
|
||||
expected_len: usize,
|
||||
ellipsis: Option<usize>,
|
||||
ellipsis: Option<u32>,
|
||||
) -> Vec<FieldPat> {
|
||||
if pats.len() > expected_len {
|
||||
self.errors.push(PatternError::ExtraFields);
|
||||
|
@ -214,7 +214,7 @@ impl<'a> PatCtxt<'a> {
|
|||
}
|
||||
|
||||
pats.iter()
|
||||
.enumerate_and_adjust(expected_len, ellipsis)
|
||||
.enumerate_and_adjust(expected_len, ellipsis.map(|it| it as usize))
|
||||
.map(|(i, &subpattern)| FieldPat {
|
||||
field: LocalFieldId::from_raw((i as u32).into()),
|
||||
pattern: self.lower_pattern(subpattern),
|
||||
|
|
|
@ -889,7 +889,7 @@ impl InferenceContext<'_> {
|
|||
match &self.body[pat] {
|
||||
Pat::Missing | Pat::Wild => (),
|
||||
Pat::Tuple { args, ellipsis } => {
|
||||
let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len()));
|
||||
let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize));
|
||||
let field_count = match self.result[pat].kind(Interner) {
|
||||
TyKind::Tuple(_, s) => s.len(Interner),
|
||||
_ => return,
|
||||
|
@ -964,7 +964,7 @@ impl InferenceContext<'_> {
|
|||
}
|
||||
VariantId::StructId(s) => {
|
||||
let vd = &*self.db.struct_data(s).variant_data;
|
||||
let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len()));
|
||||
let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize));
|
||||
let fields = vd.fields().iter();
|
||||
let it =
|
||||
al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev()));
|
||||
|
|
|
@ -1170,7 +1170,7 @@ impl InferenceContext<'_> {
|
|||
Expr::Tuple { exprs, .. } => {
|
||||
// We don't consider multiple ellipses. This is analogous to
|
||||
// `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
|
||||
let ellipsis = exprs.iter().position(|e| is_rest_expr(*e));
|
||||
let ellipsis = exprs.iter().position(|e| is_rest_expr(*e)).map(|it| it as u32);
|
||||
let exprs: Vec<_> = exprs.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
|
||||
|
||||
self.infer_tuple_pat_like(&rhs_ty, (), ellipsis, &exprs)
|
||||
|
@ -1184,7 +1184,7 @@ impl InferenceContext<'_> {
|
|||
|
||||
// We don't consider multiple ellipses. This is analogous to
|
||||
// `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
|
||||
let ellipsis = args.iter().position(|e| is_rest_expr(*e));
|
||||
let ellipsis = args.iter().position(|e| is_rest_expr(*e)).map(|it| it as u32);
|
||||
let args: Vec<_> = args.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
|
||||
|
||||
self.infer_tuple_struct_pat_like(path, &rhs_ty, (), lhs, ellipsis, &args)
|
||||
|
|
|
@ -68,7 +68,7 @@ impl InferenceContext<'_> {
|
|||
expected: &Ty,
|
||||
default_bm: T::BindingMode,
|
||||
id: T,
|
||||
ellipsis: Option<usize>,
|
||||
ellipsis: Option<u32>,
|
||||
subs: &[T],
|
||||
) -> Ty {
|
||||
let (ty, def) = self.resolve_variant(path, true);
|
||||
|
@ -98,7 +98,7 @@ impl InferenceContext<'_> {
|
|||
let visibilities = self.db.field_visibilities(def);
|
||||
|
||||
let (pre, post) = match ellipsis {
|
||||
Some(idx) => subs.split_at(idx),
|
||||
Some(idx) => subs.split_at(idx as usize),
|
||||
None => (subs, &[][..]),
|
||||
};
|
||||
let post_idx_offset = field_types.iter().count().saturating_sub(post.len());
|
||||
|
@ -219,7 +219,7 @@ impl InferenceContext<'_> {
|
|||
&mut self,
|
||||
expected: &Ty,
|
||||
default_bm: T::BindingMode,
|
||||
ellipsis: Option<usize>,
|
||||
ellipsis: Option<u32>,
|
||||
subs: &[T],
|
||||
) -> Ty {
|
||||
let expected = self.resolve_ty_shallow(expected);
|
||||
|
@ -229,7 +229,9 @@ impl InferenceContext<'_> {
|
|||
};
|
||||
|
||||
let ((pre, post), n_uncovered_patterns) = match ellipsis {
|
||||
Some(idx) => (subs.split_at(idx), expectations.len().saturating_sub(subs.len())),
|
||||
Some(idx) => {
|
||||
(subs.split_at(idx as usize), expectations.len().saturating_sub(subs.len()))
|
||||
}
|
||||
None => ((subs, &[][..]), 0),
|
||||
};
|
||||
let mut expectations_iter = expectations
|
||||
|
|
|
@ -1164,6 +1164,7 @@ impl MirBody {
|
|||
pub enum MirSpan {
|
||||
ExprId(ExprId),
|
||||
PatId(PatId),
|
||||
BindingId(BindingId),
|
||||
SelfParam,
|
||||
Unknown,
|
||||
}
|
||||
|
|
|
@ -388,6 +388,16 @@ impl MirEvalError {
|
|||
Ok(s) => s.map(|it| it.syntax_node_ptr()),
|
||||
Err(_) => continue,
|
||||
},
|
||||
MirSpan::BindingId(b) => {
|
||||
match source_map
|
||||
.patterns_for_binding(*b)
|
||||
.iter()
|
||||
.find_map(|p| source_map.pat_syntax(*p).ok())
|
||||
{
|
||||
Some(s) => s.map(|it| it.syntax_node_ptr()),
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
MirSpan::SelfParam => match source_map.self_param_syntax() {
|
||||
Some(s) => s.map(|it| it.syntax_node_ptr()),
|
||||
None => continue,
|
||||
|
|
|
@ -1720,14 +1720,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
/// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` and
|
||||
/// `Drop` in the appropriated places.
|
||||
fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) -> Result<()> {
|
||||
let span = self.body.bindings[b]
|
||||
.definitions
|
||||
.first()
|
||||
.copied()
|
||||
.map(MirSpan::PatId)
|
||||
.unwrap_or(MirSpan::Unknown);
|
||||
let l = self.binding_local(b)?;
|
||||
self.push_storage_live_for_local(l, current, span)
|
||||
self.push_storage_live_for_local(l, current, MirSpan::BindingId(b))
|
||||
}
|
||||
|
||||
fn push_storage_live_for_local(
|
||||
|
|
|
@ -23,7 +23,7 @@ macro_rules! not_supported {
|
|||
}
|
||||
|
||||
pub(super) enum AdtPatternShape<'a> {
|
||||
Tuple { args: &'a [PatId], ellipsis: Option<usize> },
|
||||
Tuple { args: &'a [PatId], ellipsis: Option<u32> },
|
||||
Record { args: &'a [RecordFieldPat] },
|
||||
Unit,
|
||||
}
|
||||
|
@ -627,12 +627,12 @@ impl MirLowerCtx<'_> {
|
|||
current: BasicBlockId,
|
||||
current_else: Option<BasicBlockId>,
|
||||
args: &[PatId],
|
||||
ellipsis: Option<usize>,
|
||||
ellipsis: Option<u32>,
|
||||
fields: impl DoubleEndedIterator<Item = PlaceElem> + Clone,
|
||||
cond_place: &Place,
|
||||
mode: MatchingMode,
|
||||
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
|
||||
let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len()));
|
||||
let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize));
|
||||
let it = al
|
||||
.iter()
|
||||
.zip(fields.clone())
|
||||
|
|
|
@ -1806,6 +1806,16 @@ impl DefWithBody {
|
|||
Some(s) => s.map(|it| it.into()),
|
||||
None => continue,
|
||||
},
|
||||
mir::MirSpan::BindingId(b) => {
|
||||
match source_map
|
||||
.patterns_for_binding(b)
|
||||
.iter()
|
||||
.find_map(|p| source_map.pat_syntax(*p).ok())
|
||||
{
|
||||
Some(s) => s.map(|it| it.into()),
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
mir::MirSpan::Unknown => continue,
|
||||
};
|
||||
acc.push(
|
||||
|
@ -1822,8 +1832,8 @@ impl DefWithBody {
|
|||
let Some(&local) = mir_body.binding_locals.get(binding_id) else {
|
||||
continue;
|
||||
};
|
||||
if body[binding_id]
|
||||
.definitions
|
||||
if source_map
|
||||
.patterns_for_binding(binding_id)
|
||||
.iter()
|
||||
.any(|&pat| source_map.pat_syntax(pat).is_err())
|
||||
{
|
||||
|
@ -1859,6 +1869,16 @@ impl DefWithBody {
|
|||
Ok(s) => s.map(|it| it.into()),
|
||||
Err(_) => continue,
|
||||
},
|
||||
mir::MirSpan::BindingId(b) => {
|
||||
match source_map
|
||||
.patterns_for_binding(*b)
|
||||
.iter()
|
||||
.find_map(|p| source_map.pat_syntax(*p).ok())
|
||||
{
|
||||
Some(s) => s.map(|it| it.into()),
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
mir::MirSpan::SelfParam => match source_map.self_param_syntax()
|
||||
{
|
||||
Some(s) => s.map(|it| it.into()),
|
||||
|
@ -3291,8 +3311,8 @@ impl Local {
|
|||
source: source.map(|ast| Either::Right(ast.to_node(&root))),
|
||||
}]
|
||||
}
|
||||
_ => body[self.binding_id]
|
||||
.definitions
|
||||
_ => source_map
|
||||
.patterns_for_binding(self.binding_id)
|
||||
.iter()
|
||||
.map(|&definition| {
|
||||
let src = source_map.pat_syntax(definition).unwrap(); // Hmm...
|
||||
|
@ -3320,8 +3340,8 @@ impl Local {
|
|||
source: source.map(|ast| Either::Right(ast.to_node(&root))),
|
||||
}
|
||||
}
|
||||
_ => body[self.binding_id]
|
||||
.definitions
|
||||
_ => source_map
|
||||
.patterns_for_binding(self.binding_id)
|
||||
.first()
|
||||
.map(|&definition| {
|
||||
let src = source_map.pat_syntax(definition).unwrap(); // Hmm...
|
||||
|
|
|
@ -32,9 +32,8 @@ pub(super) fn hints(
|
|||
let def = sema.to_def(def)?;
|
||||
let def: DefWithBody = def.into();
|
||||
|
||||
let source_map = sema.db.body_with_source_map(def.into()).1;
|
||||
let (hir, source_map) = sema.db.body_with_source_map(def.into());
|
||||
|
||||
let hir = sema.db.body(def.into());
|
||||
let mir = sema.db.mir_body(def.into()).ok()?;
|
||||
|
||||
let local_to_binding = mir.local_to_binding_map();
|
||||
|
@ -74,22 +73,33 @@ pub(super) fn hints(
|
|||
Ok(s) => s.value.text_range(),
|
||||
Err(_) => continue,
|
||||
},
|
||||
MirSpan::BindingId(b) => {
|
||||
match source_map
|
||||
.patterns_for_binding(b)
|
||||
.iter()
|
||||
.find_map(|p| source_map.pat_syntax(*p).ok())
|
||||
{
|
||||
Some(s) => s.value.text_range(),
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
MirSpan::SelfParam => match source_map.self_param_syntax() {
|
||||
Some(s) => s.value.text_range(),
|
||||
None => continue,
|
||||
},
|
||||
MirSpan::Unknown => continue,
|
||||
};
|
||||
let binding_source = source_map
|
||||
.patterns_for_binding(*binding)
|
||||
.first()
|
||||
.and_then(|d| source_map.pat_syntax(*d).ok())
|
||||
.and_then(|d| {
|
||||
Some(FileRange {
|
||||
file_id: d.file_id.file_id()?.into(),
|
||||
range: d.value.text_range(),
|
||||
})
|
||||
});
|
||||
let binding = &hir.bindings[*binding];
|
||||
let binding_source =
|
||||
binding.definitions.first().and_then(|d| source_map.pat_syntax(*d).ok()).and_then(
|
||||
|d| {
|
||||
Some(FileRange {
|
||||
file_id: d.file_id.file_id()?.into(),
|
||||
range: d.value.text_range(),
|
||||
})
|
||||
},
|
||||
);
|
||||
let name = binding.name.display_no_db().to_smolstr();
|
||||
if name.starts_with("<ra@") {
|
||||
continue; // Ignore desugared variables
|
||||
|
|
Loading…
Reference in a new issue