Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/expr_store.rs')
| -rw-r--r-- | crates/hir-def/src/expr_store.rs | 744 |
1 files changed, 744 insertions, 0 deletions
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs new file mode 100644 index 0000000000..9df6eaade7 --- /dev/null +++ b/crates/hir-def/src/expr_store.rs @@ -0,0 +1,744 @@ +//! Defines `ExpressionStore`: a lowered representation of functions, statics and +//! consts. +mod body; +mod lower; +mod pretty; +pub mod scope; + +#[cfg(test)] +mod tests; + +use std::ops::{Deref, Index}; + +use cfg::{CfgExpr, CfgOptions}; +use either::Either; +use hir_expand::{name::Name, ExpandError, InFile}; +use la_arena::{Arena, ArenaMap}; +use rustc_hash::FxHashMap; +use smallvec::SmallVec; +use span::{Edition, MacroFileId, SyntaxContextData}; +use syntax::{ast, AstPtr, SyntaxNodePtr}; +use triomphe::Arc; +use tt::TextRange; + +use crate::{ + db::DefDatabase, + hir::{ + Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat, + PatId, RecordFieldPat, Statement, + }, + nameres::DefMap, + path::{ModPath, Path}, + type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap}, + BlockId, DefWithBodyId, Lookup, SyntheticSyntax, +}; + +pub use self::body::{Body, BodySourceMap}; + +/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct HygieneId(span::SyntaxContextId); + +impl HygieneId { + // The edition doesn't matter here, we only use this for comparisons and to lookup the macro. + pub const ROOT: Self = Self(span::SyntaxContextId::root(Edition::Edition2015)); + + pub fn new(mut ctx: span::SyntaxContextId) -> Self { + // See `Name` for why we're doing that. + ctx.remove_root_edition(); + Self(ctx) + } + + pub(crate) fn lookup(self, db: &dyn DefDatabase) -> SyntaxContextData { + db.lookup_intern_syntax_context(self.0) + } + + pub(crate) fn is_root(self) -> bool { + self.0.is_root() + } +} + +pub type ExprPtr = AstPtr<ast::Expr>; +pub type ExprSource = InFile<ExprPtr>; + +pub type PatPtr = AstPtr<ast::Pat>; +pub type PatSource = InFile<PatPtr>; + +pub type LabelPtr = AstPtr<ast::Label>; +pub type LabelSource = InFile<LabelPtr>; + +pub type FieldPtr = AstPtr<ast::RecordExprField>; +pub type FieldSource = InFile<FieldPtr>; + +pub type PatFieldPtr = AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>; +pub type PatFieldSource = InFile<PatFieldPtr>; + +pub type ExprOrPatPtr = AstPtr<Either<ast::Expr, ast::Pat>>; +pub type ExprOrPatSource = InFile<ExprOrPatPtr>; + +pub type SelfParamPtr = AstPtr<ast::SelfParam>; +pub type MacroCallPtr = AstPtr<ast::MacroCall>; + +#[derive(Debug, Eq, PartialEq)] +pub struct ExpressionStore { + pub exprs: Arena<Expr>, + pub pats: Arena<Pat>, + pub bindings: Arena<Binding>, + pub labels: Arena<Label>, + /// Id of the closure/coroutine that owns the corresponding binding. If a binding is owned by the + /// top level expression, it will not be listed in here. + pub binding_owners: FxHashMap<BindingId, ExprId>, + pub types: TypesMap, + /// Block expressions in this store that may contain inner items. + block_scopes: Box<[BlockId]>, + + /// A map from binding to its hygiene ID. + /// + /// Bindings that don't come from macro expansion are not allocated to save space, so not all bindings appear here. + /// If a binding does not appear here it has `SyntaxContextId::ROOT`. + /// + /// Note that this may not be the direct `SyntaxContextId` of the binding's expansion, because transparent + /// expansions are attributed to their parent expansion (recursively). + binding_hygiene: FxHashMap<BindingId, HygieneId>, + /// A map from an variable usages to their hygiene ID. + /// + /// Expressions (and destructuing patterns) that can be recorded here are single segment path, although not all single segments path refer + /// to variables and have hygiene (some refer to items, we don't know at this stage). + ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>, +} + +#[derive(Debug, Eq, PartialEq, Default)] +pub struct ExpressionStoreSourceMap { + // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map + // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected). + expr_map: FxHashMap<ExprSource, ExprOrPatId>, + expr_map_back: ArenaMap<ExprId, ExprSource>, + + pat_map: FxHashMap<PatSource, PatId>, + pat_map_back: ArenaMap<PatId, ExprOrPatSource>, + + label_map: FxHashMap<LabelSource, LabelId>, + label_map_back: ArenaMap<LabelId, LabelSource>, + + 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. + field_map_back: FxHashMap<ExprId, FieldSource>, + pat_field_map_back: FxHashMap<PatId, PatFieldSource>, + + pub types: TypesSourceMap, + + template_map: Option<Box<FormatTemplate>>, + + expansions: FxHashMap<InFile<MacroCallPtr>, MacroFileId>, + + /// Diagnostics accumulated during lowering. These contain `AstPtr`s and so are stored in + /// the source map (since they're just as volatile). + diagnostics: Vec<ExpressionStoreDiagnostics>, +} + +/// The body of an item (function, const etc.). +#[derive(Debug, Eq, PartialEq, Default)] +pub struct ExpressionStoreBuilder { + pub exprs: Arena<Expr>, + pub pats: Arena<Pat>, + pub bindings: Arena<Binding>, + pub labels: Arena<Label>, + pub binding_owners: FxHashMap<BindingId, ExprId>, + pub types: TypesMap, + block_scopes: Vec<BlockId>, + binding_hygiene: FxHashMap<BindingId, HygieneId>, + ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>, +} + +#[derive(Default, Debug, Eq, PartialEq)] +struct FormatTemplate { + /// A map from `format_args!()` expressions to their captures. + format_args_to_captures: FxHashMap<ExprId, (HygieneId, Vec<(syntax::TextRange, Name)>)>, + /// A map from `asm!()` expressions to their captures. + asm_to_captures: FxHashMap<ExprId, Vec<Vec<(syntax::TextRange, usize)>>>, + /// A map from desugared expressions of implicit captures to their source. + /// + /// The value stored for each capture is its template literal and offset inside it. The template literal + /// is from the `format_args[_nl]!()` macro and so needs to be mapped up once to go to the user-written + /// template. + implicit_capture_to_source: FxHashMap<ExprId, InFile<(ExprPtr, TextRange)>>, +} + +#[derive(Debug, Eq, PartialEq)] +pub enum ExpressionStoreDiagnostics { + InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions }, + MacroError { node: InFile<MacroCallPtr>, err: ExpandError }, + UnresolvedMacroCall { node: InFile<MacroCallPtr>, path: ModPath }, + UnreachableLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name }, + AwaitOutsideOfAsync { node: InFile<AstPtr<ast::AwaitExpr>>, location: String }, + UndeclaredLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name }, +} + +impl ExpressionStoreBuilder { + fn finish(self) -> ExpressionStore { + let Self { + block_scopes, + mut exprs, + mut labels, + mut pats, + mut bindings, + mut binding_owners, + mut binding_hygiene, + mut ident_hygiene, + mut types, + } = self; + exprs.shrink_to_fit(); + labels.shrink_to_fit(); + pats.shrink_to_fit(); + bindings.shrink_to_fit(); + binding_owners.shrink_to_fit(); + binding_hygiene.shrink_to_fit(); + ident_hygiene.shrink_to_fit(); + types.shrink_to_fit(); + + ExpressionStore { + exprs, + pats, + bindings, + labels, + binding_owners, + types, + block_scopes: block_scopes.into_boxed_slice(), + binding_hygiene, + ident_hygiene, + } + } +} + +impl ExpressionStore { + /// Returns an iterator over all block expressions in this store that define inner items. + pub fn blocks<'a>( + &'a self, + db: &'a dyn DefDatabase, + ) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + 'a { + self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block))) + } + + pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) { + self.walk_pats(pat_id, &mut |pat| { + if let Pat::Bind { id, .. } = &self[pat] { + f(*id); + } + }); + } + + pub fn walk_pats_shallow(&self, pat_id: PatId, mut f: impl FnMut(PatId)) { + let pat = &self[pat_id]; + match pat { + Pat::Range { .. } + | Pat::Lit(..) + | Pat::Path(..) + | Pat::ConstBlock(..) + | Pat::Wild + | Pat::Missing + | Pat::Expr(_) => {} + &Pat::Bind { subpat, .. } => { + if let Some(subpat) = subpat { + f(subpat); + } + } + Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => { + args.iter().copied().for_each(f); + } + Pat::Ref { pat, .. } => f(*pat), + Pat::Slice { prefix, slice, suffix } => { + let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter()); + total_iter.copied().for_each(f); + } + Pat::Record { args, .. } => { + args.iter().for_each(|RecordFieldPat { pat, .. }| f(*pat)); + } + Pat::Box { inner } => f(*inner), + } + } + + pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(PatId)) { + f(pat_id); + self.walk_pats_shallow(pat_id, |p| self.walk_pats(p, f)); + } + + pub fn is_binding_upvar(&self, binding: BindingId, relative_to: ExprId) -> bool { + match self.binding_owners.get(&binding) { + Some(it) => { + // We assign expression ids in a way that outer closures will receive + // a lower id + it.into_raw() < relative_to.into_raw() + } + None => true, + } + } + + pub fn walk_child_exprs(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) { + let expr = &self[expr_id]; + match expr { + Expr::Continue { .. } + | Expr::Const(_) + | Expr::Missing + | Expr::Path(_) + | Expr::OffsetOf(_) + | Expr::Literal(_) + | Expr::Underscore => {} + Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op { + AsmOperand::In { expr, .. } + | AsmOperand::Out { expr: Some(expr), .. } + | AsmOperand::InOut { expr, .. } => f(*expr), + AsmOperand::SplitInOut { in_expr, out_expr, .. } => { + f(*in_expr); + if let Some(out_expr) = out_expr { + f(*out_expr); + } + } + AsmOperand::Out { expr: None, .. } + | AsmOperand::Const(_) + | AsmOperand::Label(_) + | AsmOperand::Sym(_) => (), + }), + Expr::If { condition, then_branch, else_branch } => { + f(*condition); + f(*then_branch); + if let &Some(else_branch) = else_branch { + f(else_branch); + } + } + Expr::Let { expr, pat } => { + self.walk_exprs_in_pat(*pat, &mut f); + f(*expr); + } + Expr::Block { statements, tail, .. } + | Expr::Unsafe { statements, tail, .. } + | Expr::Async { statements, tail, .. } => { + for stmt in statements.iter() { + match stmt { + Statement::Let { initializer, else_branch, pat, .. } => { + if let &Some(expr) = initializer { + f(expr); + } + if let &Some(expr) = else_branch { + f(expr); + } + self.walk_exprs_in_pat(*pat, &mut f); + } + Statement::Expr { expr: expression, .. } => f(*expression), + Statement::Item(_) => (), + } + } + if let &Some(expr) = tail { + f(expr); + } + } + Expr::Loop { body, .. } => f(*body), + Expr::Call { callee, args, .. } => { + f(*callee); + args.iter().copied().for_each(f); + } + Expr::MethodCall { receiver, args, .. } => { + f(*receiver); + args.iter().copied().for_each(f); + } + Expr::Match { expr, arms } => { + f(*expr); + arms.iter().for_each(|arm| { + f(arm.expr); + self.walk_exprs_in_pat(arm.pat, &mut f); + }); + } + Expr::Break { expr, .. } + | Expr::Return { expr } + | Expr::Yield { expr } + | Expr::Yeet { expr } => { + if let &Some(expr) = expr { + f(expr); + } + } + Expr::Become { expr } => f(*expr), + Expr::RecordLit { fields, spread, .. } => { + for field in fields.iter() { + f(field.expr); + } + if let &Some(expr) = spread { + f(expr); + } + } + Expr::Closure { body, .. } => { + f(*body); + } + Expr::BinaryOp { lhs, rhs, .. } => { + f(*lhs); + f(*rhs); + } + Expr::Range { lhs, rhs, .. } => { + if let &Some(lhs) = rhs { + f(lhs); + } + if let &Some(rhs) = lhs { + f(rhs); + } + } + Expr::Index { base, index, .. } => { + f(*base); + f(*index); + } + Expr::Field { expr, .. } + | Expr::Await { expr } + | Expr::Cast { expr, .. } + | Expr::Ref { expr, .. } + | Expr::UnaryOp { expr, .. } + | Expr::Box { expr } => { + f(*expr); + } + Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f), + Expr::Array(a) => match a { + Array::ElementList { elements, .. } => elements.iter().copied().for_each(f), + Array::Repeat { initializer, repeat } => { + f(*initializer); + f(*repeat) + } + }, + &Expr::Assignment { target, value } => { + self.walk_exprs_in_pat(target, &mut f); + f(value); + } + } + } + + pub fn walk_child_exprs_without_pats(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) { + let expr = &self[expr_id]; + match expr { + Expr::Continue { .. } + | Expr::Const(_) + | Expr::Missing + | Expr::Path(_) + | Expr::OffsetOf(_) + | Expr::Literal(_) + | Expr::Underscore => {} + Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op { + AsmOperand::In { expr, .. } + | AsmOperand::Out { expr: Some(expr), .. } + | AsmOperand::InOut { expr, .. } => f(*expr), + AsmOperand::SplitInOut { in_expr, out_expr, .. } => { + f(*in_expr); + if let Some(out_expr) = out_expr { + f(*out_expr); + } + } + AsmOperand::Out { expr: None, .. } + | AsmOperand::Const(_) + | AsmOperand::Label(_) + | AsmOperand::Sym(_) => (), + }), + Expr::If { condition, then_branch, else_branch } => { + f(*condition); + f(*then_branch); + if let &Some(else_branch) = else_branch { + f(else_branch); + } + } + Expr::Let { expr, .. } => { + f(*expr); + } + Expr::Block { statements, tail, .. } + | Expr::Unsafe { statements, tail, .. } + | Expr::Async { statements, tail, .. } => { + for stmt in statements.iter() { + match stmt { + Statement::Let { initializer, else_branch, .. } => { + if let &Some(expr) = initializer { + f(expr); + } + if let &Some(expr) = else_branch { + f(expr); + } + } + Statement::Expr { expr: expression, .. } => f(*expression), + Statement::Item(_) => (), + } + } + if let &Some(expr) = tail { + f(expr); + } + } + Expr::Loop { body, .. } => f(*body), + Expr::Call { callee, args, .. } => { + f(*callee); + args.iter().copied().for_each(f); + } + Expr::MethodCall { receiver, args, .. } => { + f(*receiver); + args.iter().copied().for_each(f); + } + Expr::Match { expr, arms } => { + f(*expr); + arms.iter().map(|arm| arm.expr).for_each(f); + } + Expr::Break { expr, .. } + | Expr::Return { expr } + | Expr::Yield { expr } + | Expr::Yeet { expr } => { + if let &Some(expr) = expr { + f(expr); + } + } + Expr::Become { expr } => f(*expr), + Expr::RecordLit { fields, spread, .. } => { + for field in fields.iter() { + f(field.expr); + } + if let &Some(expr) = spread { + f(expr); + } + } + Expr::Closure { body, .. } => { + f(*body); + } + Expr::BinaryOp { lhs, rhs, .. } => { + f(*lhs); + f(*rhs); + } + Expr::Range { lhs, rhs, .. } => { + if let &Some(lhs) = rhs { + f(lhs); + } + if let &Some(rhs) = lhs { + f(rhs); + } + } + Expr::Index { base, index, .. } => { + f(*base); + f(*index); + } + Expr::Field { expr, .. } + | Expr::Await { expr } + | Expr::Cast { expr, .. } + | Expr::Ref { expr, .. } + | Expr::UnaryOp { expr, .. } + | Expr::Box { expr } => { + f(*expr); + } + Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f), + Expr::Array(a) => match a { + Array::ElementList { elements, .. } => elements.iter().copied().for_each(f), + Array::Repeat { initializer, repeat } => { + f(*initializer); + f(*repeat) + } + }, + &Expr::Assignment { target: _, value } => f(value), + } + } + + pub fn walk_exprs_in_pat(&self, pat_id: PatId, f: &mut impl FnMut(ExprId)) { + self.walk_pats(pat_id, &mut |pat| { + if let Pat::Expr(expr) | Pat::ConstBlock(expr) = self[pat] { + f(expr); + } + }); + } + + fn binding_hygiene(&self, binding: BindingId) -> HygieneId { + self.binding_hygiene.get(&binding).copied().unwrap_or(HygieneId::ROOT) + } + + pub fn expr_path_hygiene(&self, expr: ExprId) -> HygieneId { + self.ident_hygiene.get(&expr.into()).copied().unwrap_or(HygieneId::ROOT) + } + + pub fn pat_path_hygiene(&self, pat: PatId) -> HygieneId { + self.ident_hygiene.get(&pat.into()).copied().unwrap_or(HygieneId::ROOT) + } + + pub fn expr_or_pat_path_hygiene(&self, id: ExprOrPatId) -> HygieneId { + match id { + ExprOrPatId::ExprId(id) => self.expr_path_hygiene(id), + ExprOrPatId::PatId(id) => self.pat_path_hygiene(id), + } + } +} + +impl Index<ExprId> for ExpressionStore { + type Output = Expr; + + fn index(&self, expr: ExprId) -> &Expr { + &self.exprs[expr] + } +} + +impl Index<PatId> for ExpressionStore { + type Output = Pat; + + fn index(&self, pat: PatId) -> &Pat { + &self.pats[pat] + } +} + +impl Index<LabelId> for ExpressionStore { + type Output = Label; + + fn index(&self, label: LabelId) -> &Label { + &self.labels[label] + } +} + +impl Index<BindingId> for ExpressionStore { + type Output = Binding; + + fn index(&self, b: BindingId) -> &Binding { + &self.bindings[b] + } +} + +impl Index<TypeRefId> for ExpressionStore { + type Output = TypeRef; + + fn index(&self, b: TypeRefId) -> &TypeRef { + &self.types[b] + } +} + +// FIXME: Change `node_` prefix to something more reasonable. +// Perhaps `expr_syntax` and `expr_id`? +impl ExpressionStoreSourceMap { + pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> { + match id { + ExprOrPatId::ExprId(id) => self.expr_syntax(id).map(|it| it.map(AstPtr::wrap_left)), + ExprOrPatId::PatId(id) => self.pat_syntax(id), + } + } + + pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { + self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax) + } + + pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprOrPatId> { + let src = node.map(AstPtr::new); + self.expr_map.get(&src).cloned() + } + + pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<MacroFileId> { + let src = node.map(AstPtr::new); + self.expansions.get(&src).cloned() + } + + pub fn macro_calls(&self) -> impl Iterator<Item = (InFile<MacroCallPtr>, MacroFileId)> + '_ { + self.expansions.iter().map(|(&a, &b)| (a, b)) + } + + pub fn pat_syntax(&self, pat: PatId) -> Result<ExprOrPatSource, SyntheticSyntax> { + self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax) + } + + pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> { + self.pat_map.get(&node.map(AstPtr::new)).cloned() + } + + pub fn label_syntax(&self, label: LabelId) -> LabelSource { + 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() + } + + pub fn field_syntax(&self, expr: ExprId) -> FieldSource { + self.field_map_back[&expr] + } + + pub fn pat_field_syntax(&self, pat: PatId) -> PatFieldSource { + self.pat_field_map_back[&pat] + } + + pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprOrPatId> { + let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::MacroExpr>).map(AstPtr::upcast); + self.expr_map.get(&src).copied() + } + + pub fn expansions(&self) -> impl Iterator<Item = (&InFile<MacroCallPtr>, &MacroFileId)> { + self.expansions.iter() + } + + pub fn implicit_format_args( + &self, + node: InFile<&ast::FormatArgsExpr>, + ) -> Option<(HygieneId, &[(syntax::TextRange, Name)])> { + let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>); + let (hygiene, names) = self + .template_map + .as_ref()? + .format_args_to_captures + .get(&self.expr_map.get(&src)?.as_expr()?)?; + Some((*hygiene, &**names)) + } + + pub fn format_args_implicit_capture( + &self, + capture_expr: ExprId, + ) -> Option<InFile<(ExprPtr, TextRange)>> { + self.template_map.as_ref()?.implicit_capture_to_source.get(&capture_expr).copied() + } + + pub fn asm_template_args( + &self, + node: InFile<&ast::AsmExpr>, + ) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> { + let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>); + let expr = self.expr_map.get(&src)?.as_expr()?; + Some(expr) + .zip(self.template_map.as_ref()?.asm_to_captures.get(&expr).map(std::ops::Deref::deref)) + } + + /// Get a reference to the source map's diagnostics. + pub fn diagnostics(&self) -> &[ExpressionStoreDiagnostics] { + &self.diagnostics + } + + fn shrink_to_fit(&mut self) { + let Self { + expr_map, + expr_map_back, + pat_map, + pat_map_back, + label_map, + label_map_back, + field_map_back, + pat_field_map_back, + expansions, + template_map, + diagnostics, + binding_definitions, + types, + } = self; + if let Some(template_map) = template_map { + let FormatTemplate { + format_args_to_captures, + asm_to_captures, + implicit_capture_to_source, + } = &mut **template_map; + format_args_to_captures.shrink_to_fit(); + asm_to_captures.shrink_to_fit(); + implicit_capture_to_source.shrink_to_fit(); + } + expr_map.shrink_to_fit(); + expr_map_back.shrink_to_fit(); + pat_map.shrink_to_fit(); + pat_map_back.shrink_to_fit(); + label_map.shrink_to_fit(); + label_map_back.shrink_to_fit(); + field_map_back.shrink_to_fit(); + pat_field_map_back.shrink_to_fit(); + expansions.shrink_to_fit(); + diagnostics.shrink_to_fit(); + binding_definitions.shrink_to_fit(); + types.shrink_to_fit(); + } +} |