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.rs571
1 files changed, 35 insertions, 536 deletions
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 6e23197a4..82955fa55 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -1,549 +1,24 @@
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 hir_def::{
10 path::GenericArgs,
11 type_ref::{Mutability, TypeRef},
12};
13use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
14use ra_syntax::{ast, AstPtr}; 8use ra_syntax::{ast, AstPtr};
15use rustc_hash::FxHashMap;
16 9
17use crate::{ 10use crate::{db::HirDatabase, DefWithBody, HasSource, Resolver};
18 db::HirDatabase,
19 ty::primitive::{UncertainFloatTy, UncertainIntTy},
20 DefWithBody, Either, HasSource, Name, Path, Resolver, Source,
21};
22 11
23pub use self::scope::ExprScopes; 12pub use self::scope::ExprScopes;
24 13
25#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 14pub use hir_def::{
26pub struct ExprId(RawId); 15 body::{Body, BodySourceMap, ExprPtr, ExprSource, PatPtr, PatSource},
27impl_arena_id!(ExprId); 16 expr::{
28 17 ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp,
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 18 MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp,
30pub struct PatId(RawId);
31impl_arena_id!(PatId);
32
33/// The body of an item (function, const etc.).
34#[derive(Debug, Eq, PartialEq)]
35pub struct Body {
36 /// The def of the item this body belongs to
37 owner: DefWithBody,
38 exprs: Arena<ExprId, Expr>,
39 pats: Arena<PatId, Pat>,
40 /// The patterns for the function's parameters. While the parameter types are
41 /// part of the function signature, the patterns are not (they don't change
42 /// the external type of the function).
43 ///
44 /// If this `Body` is for the body of a constant, this will just be
45 /// empty.
46 params: Vec<PatId>,
47 /// The `ExprId` of the actual body expression.
48 body_expr: ExprId,
49}
50
51type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>;
52type ExprSource = Source<ExprPtr>;
53
54type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
55type PatSource = Source<PatPtr>;
56
57/// An item body together with the mapping from syntax nodes to HIR expression
58/// IDs. This is needed to go from e.g. a position in a file to the HIR
59/// expression containing it; but for type inference etc., we want to operate on
60/// a structure that is agnostic to the actual positions of expressions in the
61/// file, so that we don't recompute types whenever some whitespace is typed.
62///
63/// One complication here is that, due to macro expansion, a single `Body` might
64/// be spread across several files. So, for each ExprId and PatId, we record
65/// both the HirFileId and the position inside the file. However, we only store
66/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle
67/// this properly for macros.
68#[derive(Default, Debug, Eq, PartialEq)]
69pub struct BodySourceMap {
70 expr_map: FxHashMap<ExprPtr, ExprId>,
71 expr_map_back: ArenaMap<ExprId, ExprSource>,
72 pat_map: FxHashMap<PatPtr, PatId>,
73 pat_map_back: ArenaMap<PatId, PatSource>,
74 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>,
75}
76
77impl Body {
78 pub fn params(&self) -> &[PatId] {
79 &self.params
80 }
81
82 pub fn body_expr(&self) -> ExprId {
83 self.body_expr
84 }
85
86 pub fn owner(&self) -> DefWithBody {
87 self.owner
88 }
89
90 pub fn exprs(&self) -> impl Iterator<Item = (ExprId, &Expr)> {
91 self.exprs.iter()
92 }
93
94 pub fn pats(&self) -> impl Iterator<Item = (PatId, &Pat)> {
95 self.pats.iter()
96 }
97}
98
99// needs arbitrary_self_types to be a method... or maybe move to the def?
100pub(crate) fn resolver_for_expr(
101 body: Arc<Body>,
102 db: &impl HirDatabase,
103 expr_id: ExprId,
104) -> Resolver {
105 let scopes = db.expr_scopes(body.owner);
106 resolver_for_scope(body, db, scopes.scope_for(expr_id))
107}
108
109pub(crate) fn resolver_for_scope(
110 body: Arc<Body>,
111 db: &impl HirDatabase,
112 scope_id: Option<scope::ScopeId>,
113) -> Resolver {
114 let mut r = body.owner.resolver(db);
115 let scopes = db.expr_scopes(body.owner);
116 let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
117 for scope in scope_chain.into_iter().rev() {
118 r = r.push_expr_scope(Arc::clone(&scopes), scope);
119 }
120 r
121}
122
123impl Index<ExprId> for Body {
124 type Output = Expr;
125
126 fn index(&self, expr: ExprId) -> &Expr {
127 &self.exprs[expr]
128 }
129}
130
131impl Index<PatId> for Body {
132 type Output = Pat;
133
134 fn index(&self, pat: PatId) -> &Pat {
135 &self.pats[pat]
136 }
137}
138
139impl BodySourceMap {
140 pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<ExprSource> {
141 self.expr_map_back.get(expr).copied()
142 }
143
144 pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> {
145 self.expr_map.get(&Either::A(AstPtr::new(node))).cloned()
146 }
147
148 pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatSource> {
149 self.pat_map_back.get(pat).copied()
150 }
151
152 pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> {
153 self.pat_map.get(&Either::A(AstPtr::new(node))).cloned()
154 }
155
156 pub(crate) fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> {
157 self.field_map[&(expr, field)]
158 }
159}
160
161#[derive(Debug, Clone, Eq, PartialEq)]
162pub enum Literal {
163 String(String),
164 ByteString(Vec<u8>),
165 Char(char),
166 Bool(bool),
167 Int(u64, UncertainIntTy),
168 Float(u64, UncertainFloatTy), // FIXME: f64 is not Eq
169}
170
171#[derive(Debug, Clone, Eq, PartialEq)]
172pub enum Expr {
173 /// This is produced if syntax tree does not have a required expression piece.
174 Missing,
175 Path(Path),
176 If {
177 condition: ExprId,
178 then_branch: ExprId,
179 else_branch: Option<ExprId>,
180 },
181 Block {
182 statements: Vec<Statement>,
183 tail: Option<ExprId>,
184 },
185 Loop {
186 body: ExprId,
187 },
188 While {
189 condition: ExprId,
190 body: ExprId,
191 },
192 For {
193 iterable: ExprId,
194 pat: PatId,
195 body: ExprId,
196 },
197 Call {
198 callee: ExprId,
199 args: Vec<ExprId>,
200 },
201 MethodCall {
202 receiver: ExprId,
203 method_name: Name,
204 args: Vec<ExprId>,
205 generic_args: Option<GenericArgs>,
206 },
207 Match {
208 expr: ExprId,
209 arms: Vec<MatchArm>,
210 },
211 Continue,
212 Break {
213 expr: Option<ExprId>,
214 },
215 Return {
216 expr: Option<ExprId>,
217 },
218 RecordLit {
219 path: Option<Path>,
220 fields: Vec<RecordLitField>,
221 spread: Option<ExprId>,
222 },
223 Field {
224 expr: ExprId,
225 name: Name,
226 },
227 Await {
228 expr: ExprId,
229 },
230 Try {
231 expr: ExprId,
232 },
233 TryBlock {
234 body: ExprId,
235 },
236 Cast {
237 expr: ExprId,
238 type_ref: TypeRef,
239 }, 19 },
240 Ref { 20};
241 expr: ExprId,
242 mutability: Mutability,
243 },
244 Box {
245 expr: ExprId,
246 },
247 UnaryOp {
248 expr: ExprId,
249 op: UnaryOp,
250 },
251 BinaryOp {
252 lhs: ExprId,
253 rhs: ExprId,
254 op: Option<BinaryOp>,
255 },
256 Index {
257 base: ExprId,
258 index: ExprId,
259 },
260 Lambda {
261 args: Vec<PatId>,
262 arg_types: Vec<Option<TypeRef>>,
263 body: ExprId,
264 },
265 Tuple {
266 exprs: Vec<ExprId>,
267 },
268 Array(Array),
269 Literal(Literal),
270}
271
272#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
273pub enum BinaryOp {
274 LogicOp(LogicOp),
275 ArithOp(ArithOp),
276 CmpOp(CmpOp),
277 Assignment { op: Option<ArithOp> },
278}
279
280#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
281pub enum LogicOp {
282 And,
283 Or,
284}
285
286#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
287pub enum CmpOp {
288 Eq { negated: bool },
289 Ord { ordering: Ordering, strict: bool },
290}
291
292#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
293pub enum Ordering {
294 Less,
295 Greater,
296}
297
298#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
299pub enum ArithOp {
300 Add,
301 Mul,
302 Sub,
303 Div,
304 Rem,
305 Shl,
306 Shr,
307 BitXor,
308 BitOr,
309 BitAnd,
310}
311
312pub use ra_syntax::ast::PrefixOp as UnaryOp;
313#[derive(Debug, Clone, Eq, PartialEq)]
314pub enum Array {
315 ElementList(Vec<ExprId>),
316 Repeat { initializer: ExprId, repeat: ExprId },
317}
318
319#[derive(Debug, Clone, Eq, PartialEq)]
320pub struct MatchArm {
321 pub pats: Vec<PatId>,
322 pub guard: Option<ExprId>,
323 pub expr: ExprId,
324}
325
326#[derive(Debug, Clone, Eq, PartialEq)]
327pub struct RecordLitField {
328 pub name: Name,
329 pub expr: ExprId,
330}
331
332#[derive(Debug, Clone, Eq, PartialEq)]
333pub enum Statement {
334 Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> },
335 Expr(ExprId),
336}
337
338impl Expr {
339 pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
340 match self {
341 Expr::Missing => {}
342 Expr::Path(_) => {}
343 Expr::If { condition, then_branch, else_branch } => {
344 f(*condition);
345 f(*then_branch);
346 if let Some(else_branch) = else_branch {
347 f(*else_branch);
348 }
349 }
350 Expr::Block { statements, tail } => {
351 for stmt in statements {
352 match stmt {
353 Statement::Let { initializer, .. } => {
354 if let Some(expr) = initializer {
355 f(*expr);
356 }
357 }
358 Statement::Expr(e) => f(*e),
359 }
360 }
361 if let Some(expr) = tail {
362 f(*expr);
363 }
364 }
365 Expr::TryBlock { body } => f(*body),
366 Expr::Loop { body } => f(*body),
367 Expr::While { condition, body } => {
368 f(*condition);
369 f(*body);
370 }
371 Expr::For { iterable, body, .. } => {
372 f(*iterable);
373 f(*body);
374 }
375 Expr::Call { callee, args } => {
376 f(*callee);
377 for arg in args {
378 f(*arg);
379 }
380 }
381 Expr::MethodCall { receiver, args, .. } => {
382 f(*receiver);
383 for arg in args {
384 f(*arg);
385 }
386 }
387 Expr::Match { expr, arms } => {
388 f(*expr);
389 for arm in arms {
390 f(arm.expr);
391 }
392 }
393 Expr::Continue => {}
394 Expr::Break { expr } | Expr::Return { expr } => {
395 if let Some(expr) = expr {
396 f(*expr);
397 }
398 }
399 Expr::RecordLit { fields, spread, .. } => {
400 for field in fields {
401 f(field.expr);
402 }
403 if let Some(expr) = spread {
404 f(*expr);
405 }
406 }
407 Expr::Lambda { body, .. } => {
408 f(*body);
409 }
410 Expr::BinaryOp { lhs, rhs, .. } => {
411 f(*lhs);
412 f(*rhs);
413 }
414 Expr::Index { base, index } => {
415 f(*base);
416 f(*index);
417 }
418 Expr::Field { expr, .. }
419 | Expr::Await { expr }
420 | Expr::Try { expr }
421 | Expr::Cast { expr, .. }
422 | Expr::Ref { expr, .. }
423 | Expr::UnaryOp { expr, .. }
424 | Expr::Box { expr } => {
425 f(*expr);
426 }
427 Expr::Tuple { exprs } => {
428 for expr in exprs {
429 f(*expr);
430 }
431 }
432 Expr::Array(a) => match a {
433 Array::ElementList(exprs) => {
434 for expr in exprs {
435 f(*expr);
436 }
437 }
438 Array::Repeat { initializer, repeat } => {
439 f(*initializer);
440 f(*repeat)
441 }
442 },
443 Expr::Literal(_) => {}
444 }
445 }
446}
447
448/// Explicit binding annotations given in the HIR for a binding. Note
449/// that this is not the final binding *mode* that we infer after type
450/// inference.
451#[derive(Clone, PartialEq, Eq, Debug, Copy)]
452pub enum BindingAnnotation {
453 /// No binding annotation given: this means that the final binding mode
454 /// will depend on whether we have skipped through a `&` reference
455 /// when matching. For example, the `x` in `Some(x)` will have binding
456 /// mode `None`; if you do `let Some(x) = &Some(22)`, it will
457 /// ultimately be inferred to be by-reference.
458 Unannotated,
459
460 /// Annotated with `mut x` -- could be either ref or not, similar to `None`.
461 Mutable,
462
463 /// Annotated as `ref`, like `ref x`
464 Ref,
465
466 /// Annotated as `ref mut x`.
467 RefMut,
468}
469
470impl BindingAnnotation {
471 fn new(is_mutable: bool, is_ref: bool) -> Self {
472 match (is_mutable, is_ref) {
473 (true, true) => BindingAnnotation::RefMut,
474 (false, true) => BindingAnnotation::Ref,
475 (true, false) => BindingAnnotation::Mutable,
476 (false, false) => BindingAnnotation::Unannotated,
477 }
478 }
479}
480
481#[derive(Debug, Clone, Eq, PartialEq)]
482pub struct RecordFieldPat {
483 pub(crate) name: Name,
484 pub(crate) pat: PatId,
485}
486
487/// Close relative to rustc's hir::PatKind
488#[derive(Debug, Clone, Eq, PartialEq)]
489pub enum Pat {
490 Missing,
491 Wild,
492 Tuple(Vec<PatId>),
493 Record {
494 path: Option<Path>,
495 args: Vec<RecordFieldPat>,
496 // FIXME: 'ellipsis' option
497 },
498 Range {
499 start: ExprId,
500 end: ExprId,
501 },
502 Slice {
503 prefix: Vec<PatId>,
504 rest: Option<PatId>,
505 suffix: Vec<PatId>,
506 },
507 Path(Path),
508 Lit(ExprId),
509 Bind {
510 mode: BindingAnnotation,
511 name: Name,
512 subpat: Option<PatId>,
513 },
514 TupleStruct {
515 path: Option<Path>,
516 args: Vec<PatId>,
517 },
518 Ref {
519 pat: PatId,
520 mutability: Mutability,
521 },
522}
523
524impl Pat {
525 pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
526 match self {
527 Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {}
528 Pat::Bind { subpat, .. } => {
529 subpat.iter().copied().for_each(f);
530 }
531 Pat::Tuple(args) | Pat::TupleStruct { args, .. } => {
532 args.iter().copied().for_each(f);
533 }
534 Pat::Ref { pat, .. } => f(*pat),
535 Pat::Slice { prefix, rest, suffix } => {
536 let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter());
537 total_iter.copied().for_each(f);
538 }
539 Pat::Record { args, .. } => {
540 args.iter().map(|f| f.pat).for_each(f);
541 }
542 }
543 }
544}
545 21
546// Queries
547pub(crate) fn body_with_source_map_query( 22pub(crate) fn body_with_source_map_query(
548 db: &impl HirDatabase, 23 db: &impl HirDatabase,
549 def: DefWithBody, 24 def: DefWithBody,
@@ -565,11 +40,35 @@ pub(crate) fn body_with_source_map_query(
565 (src.file_id, src.ast.body()) 40 (src.file_id, src.ast.body())
566 } 41 }
567 }; 42 };
568 43 let resolver = hir_def::body::MacroResolver::new(db, def.module(db).id);
569 let (body, source_map) = lower::lower(db, def.resolver(db), file_id, def, params, body); 44 let (body, source_map) = Body::new(db, resolver, file_id, params, body);
570 (Arc::new(body), Arc::new(source_map)) 45 (Arc::new(body), Arc::new(source_map))
571} 46}
572 47
573pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> { 48pub(crate) fn body_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> {
574 db.body_with_source_map(def).0 49 db.body_with_source_map(def).0
575} 50}
51
52// needs arbitrary_self_types to be a method... or maybe move to the def?
53pub(crate) fn resolver_for_expr(
54 db: &impl HirDatabase,
55 owner: DefWithBody,
56 expr_id: ExprId,
57) -> Resolver {
58 let scopes = db.expr_scopes(owner);
59 resolver_for_scope(db, owner, scopes.scope_for(expr_id))
60}
61
62pub(crate) fn resolver_for_scope(
63 db: &impl HirDatabase,
64 owner: DefWithBody,
65 scope_id: Option<scope::ScopeId>,
66) -> Resolver {
67 let mut r = owner.resolver(db);
68 let scopes = db.expr_scopes(owner);
69 let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
70 for scope in scope_chain.into_iter().rev() {
71 r = r.push_expr_scope(Arc::clone(&scopes), scope);
72 }
73 r
74}