diff options
Diffstat (limited to 'crates/ra_hir/src/expr.rs')
-rw-r--r-- | crates/ra_hir/src/expr.rs | 166 |
1 files changed, 34 insertions, 132 deletions
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index ddf605111..82955fa55 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -1,112 +1,52 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | pub(crate) mod lower; | ||
4 | pub(crate) mod scope; | 3 | pub(crate) mod scope; |
5 | pub(crate) mod validation; | 4 | pub(crate) mod validation; |
6 | 5 | ||
7 | use std::{ops::Index, sync::Arc}; | 6 | use std::sync::Arc; |
8 | 7 | ||
9 | use ra_arena::{map::ArenaMap, Arena}; | ||
10 | use ra_syntax::{ast, AstPtr}; | 8 | use ra_syntax::{ast, AstPtr}; |
11 | use rustc_hash::FxHashMap; | ||
12 | 9 | ||
13 | use crate::{db::HirDatabase, DefWithBody, Either, HasSource, Resolver, Source}; | 10 | use crate::{db::HirDatabase, DefWithBody, HasSource, Resolver}; |
14 | 11 | ||
15 | pub use self::scope::ExprScopes; | 12 | pub use self::scope::ExprScopes; |
16 | 13 | ||
17 | pub use hir_def::expr::{ | 14 | pub use hir_def::{ |
18 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, MatchArm, | 15 | body::{Body, BodySourceMap, ExprPtr, ExprSource, PatPtr, PatSource}, |
19 | Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, | 16 | expr::{ |
17 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, | ||
18 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, | ||
19 | }, | ||
20 | }; | 20 | }; |
21 | 21 | ||
22 | /// The body of an item (function, const etc.). | 22 | pub(crate) fn body_with_source_map_query( |
23 | #[derive(Debug, Eq, PartialEq)] | 23 | db: &impl HirDatabase, |
24 | pub struct Body { | 24 | def: DefWithBody, |
25 | exprs: Arena<ExprId, Expr>, | 25 | ) -> (Arc<Body>, Arc<BodySourceMap>) { |
26 | pats: Arena<PatId, Pat>, | 26 | let mut params = None; |
27 | /// The patterns for the function's parameters. While the parameter types are | 27 | |
28 | /// part of the function signature, the patterns are not (they don't change | 28 | let (file_id, body) = match def { |
29 | /// the external type of the function). | 29 | DefWithBody::Function(f) => { |
30 | /// | 30 | let src = f.source(db); |
31 | /// If this `Body` is for the body of a constant, this will just be | 31 | params = src.ast.param_list(); |
32 | /// empty. | 32 | (src.file_id, src.ast.body().map(ast::Expr::from)) |
33 | params: Vec<PatId>, | 33 | } |
34 | /// The `ExprId` of the actual body expression. | 34 | DefWithBody::Const(c) => { |
35 | body_expr: ExprId, | 35 | let src = c.source(db); |
36 | (src.file_id, src.ast.body()) | ||
37 | } | ||
38 | DefWithBody::Static(s) => { | ||
39 | let src = s.source(db); | ||
40 | (src.file_id, src.ast.body()) | ||
41 | } | ||
42 | }; | ||
43 | let resolver = hir_def::body::MacroResolver::new(db, def.module(db).id); | ||
44 | let (body, source_map) = Body::new(db, resolver, file_id, params, body); | ||
45 | (Arc::new(body), Arc::new(source_map)) | ||
36 | } | 46 | } |
37 | 47 | ||
38 | type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; | 48 | pub(crate) fn body_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> { |
39 | type ExprSource = Source<ExprPtr>; | 49 | db.body_with_source_map(def).0 |
40 | |||
41 | type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | ||
42 | type PatSource = Source<PatPtr>; | ||
43 | |||
44 | /// An item body together with the mapping from syntax nodes to HIR expression | ||
45 | /// IDs. This is needed to go from e.g. a position in a file to the HIR | ||
46 | /// expression containing it; but for type inference etc., we want to operate on | ||
47 | /// a structure that is agnostic to the actual positions of expressions in the | ||
48 | /// file, so that we don't recompute types whenever some whitespace is typed. | ||
49 | /// | ||
50 | /// One complication here is that, due to macro expansion, a single `Body` might | ||
51 | /// be spread across several files. So, for each ExprId and PatId, we record | ||
52 | /// both the HirFileId and the position inside the file. However, we only store | ||
53 | /// AST -> ExprId mapping for non-macro files, as it is not clear how to handle | ||
54 | /// this properly for macros. | ||
55 | #[derive(Default, Debug, Eq, PartialEq)] | ||
56 | pub struct BodySourceMap { | ||
57 | expr_map: FxHashMap<ExprPtr, ExprId>, | ||
58 | expr_map_back: ArenaMap<ExprId, ExprSource>, | ||
59 | pat_map: FxHashMap<PatPtr, PatId>, | ||
60 | pat_map_back: ArenaMap<PatId, PatSource>, | ||
61 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, | ||
62 | } | ||
63 | |||
64 | impl Body { | ||
65 | pub(crate) fn body_with_source_map_query( | ||
66 | db: &impl HirDatabase, | ||
67 | def: DefWithBody, | ||
68 | ) -> (Arc<Body>, Arc<BodySourceMap>) { | ||
69 | let mut params = None; | ||
70 | |||
71 | let (file_id, body) = match def { | ||
72 | DefWithBody::Function(f) => { | ||
73 | let src = f.source(db); | ||
74 | params = src.ast.param_list(); | ||
75 | (src.file_id, src.ast.body().map(ast::Expr::from)) | ||
76 | } | ||
77 | DefWithBody::Const(c) => { | ||
78 | let src = c.source(db); | ||
79 | (src.file_id, src.ast.body()) | ||
80 | } | ||
81 | DefWithBody::Static(s) => { | ||
82 | let src = s.source(db); | ||
83 | (src.file_id, src.ast.body()) | ||
84 | } | ||
85 | }; | ||
86 | |||
87 | let (body, source_map) = lower::lower(db, def.resolver(db), file_id, params, body); | ||
88 | (Arc::new(body), Arc::new(source_map)) | ||
89 | } | ||
90 | |||
91 | pub(crate) fn body_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> { | ||
92 | db.body_with_source_map(def).0 | ||
93 | } | ||
94 | |||
95 | pub fn params(&self) -> &[PatId] { | ||
96 | &self.params | ||
97 | } | ||
98 | |||
99 | pub fn body_expr(&self) -> ExprId { | ||
100 | self.body_expr | ||
101 | } | ||
102 | |||
103 | pub fn exprs(&self) -> impl Iterator<Item = (ExprId, &Expr)> { | ||
104 | self.exprs.iter() | ||
105 | } | ||
106 | |||
107 | pub fn pats(&self) -> impl Iterator<Item = (PatId, &Pat)> { | ||
108 | self.pats.iter() | ||
109 | } | ||
110 | } | 50 | } |
111 | 51 | ||
112 | // needs arbitrary_self_types to be a method... or maybe move to the def? | 52 | // needs arbitrary_self_types to be a method... or maybe move to the def? |
@@ -132,41 +72,3 @@ pub(crate) fn resolver_for_scope( | |||
132 | } | 72 | } |
133 | r | 73 | r |
134 | } | 74 | } |
135 | |||
136 | impl Index<ExprId> for Body { | ||
137 | type Output = Expr; | ||
138 | |||
139 | fn index(&self, expr: ExprId) -> &Expr { | ||
140 | &self.exprs[expr] | ||
141 | } | ||
142 | } | ||
143 | |||
144 | impl Index<PatId> for Body { | ||
145 | type Output = Pat; | ||
146 | |||
147 | fn index(&self, pat: PatId) -> &Pat { | ||
148 | &self.pats[pat] | ||
149 | } | ||
150 | } | ||
151 | |||
152 | impl BodySourceMap { | ||
153 | pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<ExprSource> { | ||
154 | self.expr_map_back.get(expr).copied() | ||
155 | } | ||
156 | |||
157 | pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { | ||
158 | self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() | ||
159 | } | ||
160 | |||
161 | pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatSource> { | ||
162 | self.pat_map_back.get(pat).copied() | ||
163 | } | ||
164 | |||
165 | pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { | ||
166 | self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() | ||
167 | } | ||
168 | |||
169 | pub(crate) fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { | ||
170 | self.field_map[&(expr, field)] | ||
171 | } | ||
172 | } | ||