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.rs131
1 files changed, 92 insertions, 39 deletions
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs
index 5ff6a7ffe5..e3775c4931 100644
--- a/crates/hir-def/src/expr_store.rs
+++ b/crates/hir-def/src/expr_store.rs
@@ -1,10 +1,11 @@
//! Defines `ExpressionStore`: a lowered representation of functions, statics and
//! consts.
-mod body;
-mod lower;
-mod pretty;
+pub mod body;
+mod expander;
+pub mod lower;
+pub mod path;
+pub mod pretty;
pub mod scope;
-
#[cfg(test)]
mod tests;
@@ -12,45 +13,49 @@ use std::ops::{Deref, Index};
use cfg::{CfgExpr, CfgOptions};
use either::Either;
-use hir_expand::{name::Name, ExpandError, InFile};
+use hir_expand::{ExpandError, InFile, MacroCallId, mod_path::ModPath, name::Name};
use la_arena::{Arena, ArenaMap};
use rustc_hash::FxHashMap;
use smallvec::SmallVec;
-use span::{Edition, MacroFileId, SyntaxContextData};
-use syntax::{ast, AstPtr, SyntaxNodePtr};
+use span::{Edition, SyntaxContext};
+use syntax::{AstPtr, SyntaxNodePtr, ast};
use triomphe::Arc;
use tt::TextRange;
use crate::{
+ BlockId, SyntheticSyntax,
db::DefDatabase,
+ expr_store::path::Path,
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,
+ type_ref::{LifetimeRef, LifetimeRefId, PathId, TypeRef, TypeRefId},
};
pub use self::body::{Body, BodySourceMap};
+pub use self::lower::{
+ hir_assoc_type_binding_to_ast, hir_generic_arg_to_ast, hir_segment_to_ast_segment,
+};
/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct HygieneId(span::SyntaxContextId);
+pub struct HygieneId(span::SyntaxContext);
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 const ROOT: Self = Self(span::SyntaxContext::root(Edition::Edition2015));
- pub fn new(mut ctx: span::SyntaxContextId) -> Self {
+ pub fn new(mut ctx: span::SyntaxContext) -> 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)
+ // FIXME: Inline this
+ pub(crate) fn lookup(self) -> SyntaxContext {
+ self.0
}
pub(crate) fn is_root(self) -> bool {
@@ -79,27 +84,26 @@ pub type ExprOrPatSource = InFile<ExprOrPatPtr>;
pub type SelfParamPtr = AstPtr<ast::SelfParam>;
pub type MacroCallPtr = AstPtr<ast::MacroCall>;
+pub type TypePtr = AstPtr<ast::Type>;
+pub type TypeSource = InFile<TypePtr>;
+
+pub type LifetimePtr = AstPtr<ast::Lifetime>;
+pub type LifetimeSource = InFile<LifetimePtr>;
+
#[derive(Debug, Eq, PartialEq)]
pub struct ExpressionStore {
pub exprs: Arena<Expr>,
pub pats: Arena<Pat>,
pub bindings: Arena<Binding>,
pub labels: Arena<Label>,
+ pub types: Arena<TypeRef>,
+ pub lifetimes: Arena<LifetimeRef>,
/// 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
@@ -127,15 +131,19 @@ pub struct ExpressionStoreSourceMap {
field_map_back: FxHashMap<ExprId, FieldSource>,
pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
- pub types: TypesSourceMap,
+ types_map_back: ArenaMap<TypeRefId, TypeSource>,
+ types_map: FxHashMap<TypeSource, TypeRefId>,
+
+ lifetime_map_back: ArenaMap<LifetimeRefId, LifetimeSource>,
+ lifetime_map: FxHashMap<LifetimeSource, LifetimeRefId>,
template_map: Option<Box<FormatTemplate>>,
- expansions: FxHashMap<InFile<MacroCallPtr>, MacroFileId>,
+ pub expansions: FxHashMap<InFile<MacroCallPtr>, MacroCallId>,
/// 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>,
+ pub diagnostics: Vec<ExpressionStoreDiagnostics>,
}
/// The body of an item (function, const etc.).
@@ -145,10 +153,10 @@ pub struct ExpressionStoreBuilder {
pub pats: Arena<Pat>,
pub bindings: Arena<Binding>,
pub labels: Arena<Label>,
+ pub lifetimes: Arena<LifetimeRef>,
pub binding_owners: FxHashMap<BindingId, ExprId>,
- pub types: TypesMap,
+ pub types: Arena<TypeRef>,
block_scopes: Vec<BlockId>,
- binding_hygiene: FxHashMap<BindingId, HygieneId>,
ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>,
}
@@ -177,7 +185,7 @@ pub enum ExpressionStoreDiagnostics {
}
impl ExpressionStoreBuilder {
- fn finish(self) -> ExpressionStore {
+ pub fn finish(self) -> ExpressionStore {
let Self {
block_scopes,
mut exprs,
@@ -185,18 +193,18 @@ impl ExpressionStoreBuilder {
mut pats,
mut bindings,
mut binding_owners,
- mut binding_hygiene,
mut ident_hygiene,
mut types,
+ mut lifetimes,
} = 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();
+ lifetimes.shrink_to_fit();
ExpressionStore {
exprs,
@@ -205,8 +213,8 @@ impl ExpressionStoreBuilder {
labels,
binding_owners,
types,
+ lifetimes,
block_scopes: block_scopes.into_boxed_slice(),
- binding_hygiene,
ident_hygiene,
}
}
@@ -275,6 +283,9 @@ impl ExpressionStore {
}
}
+ /// Walks the immediate children expressions and calls `f` for each child expression.
+ ///
+ /// Note that this does not walk const blocks.
pub fn walk_child_exprs(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) {
let expr = &self[expr_id];
match expr {
@@ -408,6 +419,10 @@ impl ExpressionStore {
}
}
+ /// Walks the immediate children expressions and calls `f` for each child expression but does
+ /// not walk expressions within patterns.
+ ///
+ /// Note that this does not walk const blocks.
pub fn walk_child_exprs_without_pats(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) {
let expr = &self[expr_id];
match expr {
@@ -542,7 +557,7 @@ impl ExpressionStore {
}
fn binding_hygiene(&self, binding: BindingId) -> HygieneId {
- self.binding_hygiene.get(&binding).copied().unwrap_or(HygieneId::ROOT)
+ self.bindings[binding].hygiene
}
pub fn expr_path_hygiene(&self, expr: ExprId) -> HygieneId {
@@ -601,6 +616,26 @@ impl Index<TypeRefId> for ExpressionStore {
}
}
+impl Index<LifetimeRefId> for ExpressionStore {
+ type Output = LifetimeRef;
+
+ fn index(&self, b: LifetimeRefId) -> &LifetimeRef {
+ &self.lifetimes[b]
+ }
+}
+
+impl Index<PathId> for ExpressionStore {
+ type Output = Path;
+
+ #[inline]
+ fn index(&self, index: PathId) -> &Self::Output {
+ let TypeRef::Path(path) = &self[index.type_ref()] else {
+ unreachable!("`PathId` always points to `TypeRef::Path`");
+ };
+ path
+ }
+}
+
// FIXME: Change `node_` prefix to something more reasonable.
// Perhaps `expr_syntax` and `expr_id`?
impl ExpressionStoreSourceMap {
@@ -620,12 +655,12 @@ impl ExpressionStoreSourceMap {
self.expr_map.get(&src).cloned()
}
- pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<MacroFileId> {
+ pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<MacroCallId> {
let src = node.map(AstPtr::new);
self.expansions.get(&src).cloned()
}
- pub fn macro_calls(&self) -> impl Iterator<Item = (InFile<MacroCallPtr>, MacroFileId)> + '_ {
+ pub fn macro_calls(&self) -> impl Iterator<Item = (InFile<MacroCallPtr>, MacroCallId)> + '_ {
self.expansions.iter().map(|(&a, &b)| (a, b))
}
@@ -637,6 +672,14 @@ impl ExpressionStoreSourceMap {
self.pat_map.get(&node.map(AstPtr::new)).cloned()
}
+ pub fn type_syntax(&self, id: TypeRefId) -> Result<TypeSource, SyntheticSyntax> {
+ self.types_map_back.get(id).cloned().ok_or(SyntheticSyntax)
+ }
+
+ pub fn node_type(&self, node: InFile<&ast::Type>) -> Option<TypeRefId> {
+ self.types_map.get(&node.map(AstPtr::new)).cloned()
+ }
+
pub fn label_syntax(&self, label: LabelId) -> LabelSource {
self.label_map_back[label]
}
@@ -663,10 +706,14 @@ impl ExpressionStoreSourceMap {
self.expr_map.get(&src).copied()
}
- pub fn expansions(&self) -> impl Iterator<Item = (&InFile<MacroCallPtr>, &MacroFileId)> {
+ pub fn expansions(&self) -> impl Iterator<Item = (&InFile<MacroCallPtr>, &MacroCallId)> {
self.expansions.iter()
}
+ pub fn expansion(&self, node: InFile<&ast::MacroCall>) -> Option<MacroCallId> {
+ self.expansions.get(&node.map(AstPtr::new)).copied()
+ }
+
pub fn implicit_format_args(
&self,
node: InFile<&ast::FormatArgsExpr>,
@@ -716,7 +763,10 @@ impl ExpressionStoreSourceMap {
template_map,
diagnostics,
binding_definitions,
- types,
+ types_map,
+ types_map_back,
+ lifetime_map_back,
+ lifetime_map,
} = self;
if let Some(template_map) = template_map {
let FormatTemplate {
@@ -739,6 +789,9 @@ impl ExpressionStoreSourceMap {
expansions.shrink_to_fit();
diagnostics.shrink_to_fit();
binding_definitions.shrink_to_fit();
- types.shrink_to_fit();
+ types_map.shrink_to_fit();
+ types_map_back.shrink_to_fit();
+ lifetime_map.shrink_to_fit();
+ lifetime_map_back.shrink_to_fit();
}
}