aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/body.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/body.rs')
-rw-r--r--crates/ra_hir_def/src/body.rs136
1 files changed, 115 insertions, 21 deletions
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index ac8f8261b..85dc4feb0 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -1,11 +1,15 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2mod lower; 2mod lower;
3pub mod scope;
3 4
4use std::{ops::Index, sync::Arc}; 5use std::{ops::Index, sync::Arc};
5 6
6use hir_expand::{either::Either, HirFileId, MacroDefId, Source}; 7use hir_expand::{
8 either::Either, hygiene::Hygiene, AstId, HirFileId, MacroCallLoc, MacroDefId, MacroFileKind,
9 Source,
10};
7use ra_arena::{map::ArenaMap, Arena}; 11use ra_arena::{map::ArenaMap, Arena};
8use ra_syntax::{ast, AstPtr}; 12use ra_syntax::{ast, AstNode, AstPtr};
9use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
10 14
11use crate::{ 15use crate::{
@@ -13,28 +17,87 @@ use crate::{
13 expr::{Expr, ExprId, Pat, PatId}, 17 expr::{Expr, ExprId, Pat, PatId},
14 nameres::CrateDefMap, 18 nameres::CrateDefMap,
15 path::Path, 19 path::Path,
16 ModuleId, 20 AstItemDef, DefWithBodyId, ModuleId,
17}; 21};
18 22
19pub struct MacroResolver { 23pub struct Expander {
20 crate_def_map: Arc<CrateDefMap>, 24 crate_def_map: Arc<CrateDefMap>,
25 current_file_id: HirFileId,
26 hygiene: Hygiene,
21 module: ModuleId, 27 module: ModuleId,
22} 28}
23 29
24impl MacroResolver { 30impl Expander {
25 pub fn new(db: &impl DefDatabase2, module: ModuleId) -> MacroResolver { 31 pub fn new(db: &impl DefDatabase2, current_file_id: HirFileId, module: ModuleId) -> Expander {
26 MacroResolver { crate_def_map: db.crate_def_map(module.krate), module } 32 let crate_def_map = db.crate_def_map(module.krate);
33 let hygiene = Hygiene::new(db, current_file_id);
34 Expander { crate_def_map, current_file_id, hygiene, module }
27 } 35 }
28 36
29 pub(crate) fn resolve_path_as_macro( 37 fn enter_expand(
30 &self, 38 &mut self,
31 db: &impl DefDatabase2, 39 db: &impl DefDatabase2,
32 path: &Path, 40 macro_call: ast::MacroCall,
33 ) -> Option<MacroDefId> { 41 ) -> Option<(Mark, ast::Expr)> {
42 let ast_id = AstId::new(
43 self.current_file_id,
44 db.ast_id_map(self.current_file_id).ast_id(&macro_call),
45 );
46
47 if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) {
48 if let Some(def) = self.resolve_path_as_macro(db, &path) {
49 let call_id = db.intern_macro(MacroCallLoc { def, ast_id });
50 let file_id = call_id.as_file(MacroFileKind::Expr);
51 if let Some(node) = db.parse_or_expand(file_id) {
52 if let Some(expr) = ast::Expr::cast(node) {
53 log::debug!("macro expansion {:#?}", expr.syntax());
54
55 let mark = Mark { file_id: self.current_file_id };
56 self.hygiene = Hygiene::new(db, file_id);
57 self.current_file_id = file_id;
58
59 return Some((mark, expr));
60 }
61 }
62 }
63 }
64
65 // FIXME: Instead of just dropping the error from expansion
66 // report it
67 None
68 }
69
70 fn exit(&mut self, db: &impl DefDatabase2, mark: Mark) {
71 self.hygiene = Hygiene::new(db, mark.file_id);
72 self.current_file_id = mark.file_id;
73 std::mem::forget(mark);
74 }
75
76 fn to_source<T>(&self, ast: T) -> Source<T> {
77 Source { file_id: self.current_file_id, ast }
78 }
79
80 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
81 Path::from_src(path, &self.hygiene)
82 }
83
84 fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option<MacroDefId> {
34 self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros() 85 self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros()
35 } 86 }
36} 87}
37 88
89struct Mark {
90 file_id: HirFileId,
91}
92
93impl Drop for Mark {
94 fn drop(&mut self) {
95 if !std::thread::panicking() {
96 panic!("dropped mark")
97 }
98 }
99}
100
38/// The body of an item (function, const etc.). 101/// The body of an item (function, const etc.).
39#[derive(Debug, Eq, PartialEq)] 102#[derive(Debug, Eq, PartialEq)]
40pub struct Body { 103pub struct Body {
@@ -70,22 +133,51 @@ pub type PatSource = Source<PatPtr>;
70/// this properly for macros. 133/// this properly for macros.
71#[derive(Default, Debug, Eq, PartialEq)] 134#[derive(Default, Debug, Eq, PartialEq)]
72pub struct BodySourceMap { 135pub struct BodySourceMap {
73 expr_map: FxHashMap<ExprPtr, ExprId>, 136 expr_map: FxHashMap<ExprSource, ExprId>,
74 expr_map_back: ArenaMap<ExprId, ExprSource>, 137 expr_map_back: ArenaMap<ExprId, ExprSource>,
75 pat_map: FxHashMap<PatPtr, PatId>, 138 pat_map: FxHashMap<PatSource, PatId>,
76 pat_map_back: ArenaMap<PatId, PatSource>, 139 pat_map_back: ArenaMap<PatId, PatSource>,
77 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, 140 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>,
78} 141}
79 142
80impl Body { 143impl Body {
81 pub fn new( 144 pub(crate) fn body_with_source_map_query(
145 db: &impl DefDatabase2,
146 def: DefWithBodyId,
147 ) -> (Arc<Body>, Arc<BodySourceMap>) {
148 let mut params = None;
149
150 let (file_id, module, body) = match def {
151 DefWithBodyId::FunctionId(f) => {
152 let src = f.source(db);
153 params = src.ast.param_list();
154 (src.file_id, f.module(db), src.ast.body().map(ast::Expr::from))
155 }
156 DefWithBodyId::ConstId(c) => {
157 let src = c.source(db);
158 (src.file_id, c.module(db), src.ast.body())
159 }
160 DefWithBodyId::StaticId(s) => {
161 let src = s.source(db);
162 (src.file_id, s.module(db), src.ast.body())
163 }
164 };
165 let expander = Expander::new(db, file_id, module);
166 let (body, source_map) = Body::new(db, expander, params, body);
167 (Arc::new(body), Arc::new(source_map))
168 }
169
170 pub(crate) fn body_query(db: &impl DefDatabase2, def: DefWithBodyId) -> Arc<Body> {
171 db.body_with_source_map(def).0
172 }
173
174 fn new(
82 db: &impl DefDatabase2, 175 db: &impl DefDatabase2,
83 resolver: MacroResolver, 176 expander: Expander,
84 file_id: HirFileId,
85 params: Option<ast::ParamList>, 177 params: Option<ast::ParamList>,
86 body: Option<ast::Expr>, 178 body: Option<ast::Expr>,
87 ) -> (Body, BodySourceMap) { 179 ) -> (Body, BodySourceMap) {
88 lower::lower(db, resolver, file_id, params, body) 180 lower::lower(db, expander, params, body)
89 } 181 }
90 182
91 pub fn params(&self) -> &[PatId] { 183 pub fn params(&self) -> &[PatId] {
@@ -126,16 +218,18 @@ impl BodySourceMap {
126 self.expr_map_back.get(expr).copied() 218 self.expr_map_back.get(expr).copied()
127 } 219 }
128 220
129 pub fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { 221 pub fn node_expr(&self, node: Source<&ast::Expr>) -> Option<ExprId> {
130 self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() 222 let src = node.map(|it| Either::A(AstPtr::new(it)));
223 self.expr_map.get(&src).cloned()
131 } 224 }
132 225
133 pub fn pat_syntax(&self, pat: PatId) -> Option<PatSource> { 226 pub fn pat_syntax(&self, pat: PatId) -> Option<PatSource> {
134 self.pat_map_back.get(pat).copied() 227 self.pat_map_back.get(pat).copied()
135 } 228 }
136 229
137 pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { 230 pub fn node_pat(&self, node: Source<&ast::Pat>) -> Option<PatId> {
138 self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() 231 let src = node.map(|it| Either::A(AstPtr::new(it)));
232 self.pat_map.get(&src).cloned()
139 } 233 }
140 234
141 pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { 235 pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> {