diff options
Diffstat (limited to 'crates/ra_hir_def/src/body.rs')
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 7447904ea..ac8f8261b 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -1,2 +1,144 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | mod lower; | 2 | mod lower; |
3 | |||
4 | use std::{ops::Index, sync::Arc}; | ||
5 | |||
6 | use hir_expand::{either::Either, HirFileId, MacroDefId, Source}; | ||
7 | use ra_arena::{map::ArenaMap, Arena}; | ||
8 | use ra_syntax::{ast, AstPtr}; | ||
9 | use rustc_hash::FxHashMap; | ||
10 | |||
11 | use crate::{ | ||
12 | db::DefDatabase2, | ||
13 | expr::{Expr, ExprId, Pat, PatId}, | ||
14 | nameres::CrateDefMap, | ||
15 | path::Path, | ||
16 | ModuleId, | ||
17 | }; | ||
18 | |||
19 | pub struct MacroResolver { | ||
20 | crate_def_map: Arc<CrateDefMap>, | ||
21 | module: ModuleId, | ||
22 | } | ||
23 | |||
24 | impl MacroResolver { | ||
25 | pub fn new(db: &impl DefDatabase2, module: ModuleId) -> MacroResolver { | ||
26 | MacroResolver { crate_def_map: db.crate_def_map(module.krate), module } | ||
27 | } | ||
28 | |||
29 | pub(crate) fn resolve_path_as_macro( | ||
30 | &self, | ||
31 | db: &impl DefDatabase2, | ||
32 | path: &Path, | ||
33 | ) -> Option<MacroDefId> { | ||
34 | self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros() | ||
35 | } | ||
36 | } | ||
37 | |||
38 | /// The body of an item (function, const etc.). | ||
39 | #[derive(Debug, Eq, PartialEq)] | ||
40 | pub struct Body { | ||
41 | exprs: Arena<ExprId, Expr>, | ||
42 | pats: Arena<PatId, Pat>, | ||
43 | /// The patterns for the function's parameters. While the parameter types are | ||
44 | /// part of the function signature, the patterns are not (they don't change | ||
45 | /// the external type of the function). | ||
46 | /// | ||
47 | /// If this `Body` is for the body of a constant, this will just be | ||
48 | /// empty. | ||
49 | params: Vec<PatId>, | ||
50 | /// The `ExprId` of the actual body expression. | ||
51 | body_expr: ExprId, | ||
52 | } | ||
53 | |||
54 | pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; | ||
55 | pub type ExprSource = Source<ExprPtr>; | ||
56 | |||
57 | pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | ||
58 | pub type PatSource = Source<PatPtr>; | ||
59 | |||
60 | /// An item body together with the mapping from syntax nodes to HIR expression | ||
61 | /// IDs. This is needed to go from e.g. a position in a file to the HIR | ||
62 | /// expression containing it; but for type inference etc., we want to operate on | ||
63 | /// a structure that is agnostic to the actual positions of expressions in the | ||
64 | /// file, so that we don't recompute types whenever some whitespace is typed. | ||
65 | /// | ||
66 | /// One complication here is that, due to macro expansion, a single `Body` might | ||
67 | /// be spread across several files. So, for each ExprId and PatId, we record | ||
68 | /// both the HirFileId and the position inside the file. However, we only store | ||
69 | /// AST -> ExprId mapping for non-macro files, as it is not clear how to handle | ||
70 | /// this properly for macros. | ||
71 | #[derive(Default, Debug, Eq, PartialEq)] | ||
72 | pub struct BodySourceMap { | ||
73 | expr_map: FxHashMap<ExprPtr, ExprId>, | ||
74 | expr_map_back: ArenaMap<ExprId, ExprSource>, | ||
75 | pat_map: FxHashMap<PatPtr, PatId>, | ||
76 | pat_map_back: ArenaMap<PatId, PatSource>, | ||
77 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, | ||
78 | } | ||
79 | |||
80 | impl Body { | ||
81 | pub fn new( | ||
82 | db: &impl DefDatabase2, | ||
83 | resolver: MacroResolver, | ||
84 | file_id: HirFileId, | ||
85 | params: Option<ast::ParamList>, | ||
86 | body: Option<ast::Expr>, | ||
87 | ) -> (Body, BodySourceMap) { | ||
88 | lower::lower(db, resolver, file_id, params, body) | ||
89 | } | ||
90 | |||
91 | pub fn params(&self) -> &[PatId] { | ||
92 | &self.params | ||
93 | } | ||
94 | |||
95 | pub fn body_expr(&self) -> ExprId { | ||
96 | self.body_expr | ||
97 | } | ||
98 | |||
99 | pub fn exprs(&self) -> impl Iterator<Item = (ExprId, &Expr)> { | ||
100 | self.exprs.iter() | ||
101 | } | ||
102 | |||
103 | pub fn pats(&self) -> impl Iterator<Item = (PatId, &Pat)> { | ||
104 | self.pats.iter() | ||
105 | } | ||
106 | } | ||
107 | |||
108 | impl Index<ExprId> for Body { | ||
109 | type Output = Expr; | ||
110 | |||
111 | fn index(&self, expr: ExprId) -> &Expr { | ||
112 | &self.exprs[expr] | ||
113 | } | ||
114 | } | ||
115 | |||
116 | impl Index<PatId> for Body { | ||
117 | type Output = Pat; | ||
118 | |||
119 | fn index(&self, pat: PatId) -> &Pat { | ||
120 | &self.pats[pat] | ||
121 | } | ||
122 | } | ||
123 | |||
124 | impl BodySourceMap { | ||
125 | pub fn expr_syntax(&self, expr: ExprId) -> Option<ExprSource> { | ||
126 | self.expr_map_back.get(expr).copied() | ||
127 | } | ||
128 | |||
129 | pub fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { | ||
130 | self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() | ||
131 | } | ||
132 | |||
133 | pub fn pat_syntax(&self, pat: PatId) -> Option<PatSource> { | ||
134 | self.pat_map_back.get(pat).copied() | ||
135 | } | ||
136 | |||
137 | pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { | ||
138 | self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() | ||
139 | } | ||
140 | |||
141 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { | ||
142 | self.field_map[&(expr, field)] | ||
143 | } | ||
144 | } | ||