aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/expr.rs')
-rw-r--r--crates/ra_hir/src/expr.rs166
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
3pub(crate) mod lower;
4pub(crate) mod scope; 3pub(crate) mod scope;
5pub(crate) mod validation; 4pub(crate) mod validation;
6 5
7use std::{ops::Index, sync::Arc}; 6use std::sync::Arc;
8 7
9use ra_arena::{map::ArenaMap, Arena};
10use ra_syntax::{ast, AstPtr}; 8use ra_syntax::{ast, AstPtr};
11use rustc_hash::FxHashMap;
12 9
13use crate::{db::HirDatabase, DefWithBody, Either, HasSource, Resolver, Source}; 10use crate::{db::HirDatabase, DefWithBody, HasSource, Resolver};
14 11
15pub use self::scope::ExprScopes; 12pub use self::scope::ExprScopes;
16 13
17pub use hir_def::expr::{ 14pub 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.). 22pub(crate) fn body_with_source_map_query(
23#[derive(Debug, Eq, PartialEq)] 23 db: &impl HirDatabase,
24pub 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
38type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; 48pub(crate) fn body_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> {
39type ExprSource = Source<ExprPtr>; 49 db.body_with_source_map(def).0
40
41type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
42type 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)]
56pub 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
64impl 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
136impl Index<ExprId> for Body {
137 type Output = Expr;
138
139 fn index(&self, expr: ExprId) -> &Expr {
140 &self.exprs[expr]
141 }
142}
143
144impl Index<PatId> for Body {
145 type Output = Pat;
146
147 fn index(&self, pat: PatId) -> &Pat {
148 &self.pats[pat]
149 }
150}
151
152impl 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}