internal: Shrink size of Binding

This commit is contained in:
Lukas Wirth 2024-07-22 17:12:55 +02:00
parent 36f58f5fff
commit 7c374a10bd
15 changed files with 94 additions and 56 deletions

View file

@ -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();
}
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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());

View file

@ -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),

View file

@ -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),

View file

@ -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()));

View file

@ -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)

View file

@ -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

View file

@ -1164,6 +1164,7 @@ impl MirBody {
pub enum MirSpan {
ExprId(ExprId),
PatId(PatId),
BindingId(BindingId),
SelfParam,
Unknown,
}

View file

@ -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,

View file

@ -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(

View file

@ -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())

View file

@ -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...

View file

@ -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