diff options
Diffstat (limited to 'crates/ra_hir/src/expr')
-rw-r--r-- | crates/ra_hir/src/expr/lower.rs | 238 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/validation.rs | 47 |
2 files changed, 130 insertions, 155 deletions
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index f6a75a379..6afd80989 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs | |||
@@ -1,5 +1,3 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use ra_arena::Arena; | 1 | use ra_arena::Arena; |
4 | use ra_syntax::{ | 2 | use ra_syntax::{ |
5 | ast::{ | 3 | ast::{ |
@@ -15,8 +13,8 @@ use crate::{ | |||
15 | path::GenericArgs, | 13 | path::GenericArgs, |
16 | ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, | 14 | ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, |
17 | type_ref::TypeRef, | 15 | type_ref::TypeRef, |
18 | DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, | 16 | DefWithBody, Either, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, |
19 | Mutability, Path, Resolver, | 17 | Resolver, Source, |
20 | }; | 18 | }; |
21 | 19 | ||
22 | use super::{ | 20 | use super::{ |
@@ -24,14 +22,33 @@ use super::{ | |||
24 | LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement, | 22 | LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement, |
25 | }; | 23 | }; |
26 | 24 | ||
27 | pub(crate) struct ExprCollector<DB> { | 25 | pub(super) fn lower( |
28 | db: DB, | 26 | db: &impl HirDatabase, |
27 | resolver: Resolver, | ||
28 | file_id: HirFileId, | ||
29 | owner: DefWithBody, | 29 | owner: DefWithBody, |
30 | exprs: Arena<ExprId, Expr>, | 30 | params: Option<ast::ParamList>, |
31 | pats: Arena<PatId, Pat>, | 31 | body: Option<ast::Expr>, |
32 | source_map: BodySourceMap, | 32 | ) -> (Body, BodySourceMap) { |
33 | params: Vec<PatId>, | 33 | ExprCollector { |
34 | body_expr: Option<ExprId>, | 34 | resolver, |
35 | db, | ||
36 | original_file_id: file_id, | ||
37 | current_file_id: file_id, | ||
38 | source_map: BodySourceMap::default(), | ||
39 | body: Body { | ||
40 | owner, | ||
41 | exprs: Arena::default(), | ||
42 | pats: Arena::default(), | ||
43 | params: Vec::new(), | ||
44 | body_expr: ExprId((!0).into()), | ||
45 | }, | ||
46 | } | ||
47 | .collect(params, body) | ||
48 | } | ||
49 | |||
50 | struct ExprCollector<DB> { | ||
51 | db: DB, | ||
35 | resolver: Resolver, | 52 | resolver: Resolver, |
36 | // Expr collector expands macros along the way. original points to the file | 53 | // Expr collector expands macros along the way. original points to the file |
37 | // we started with, current points to the current macro expansion. source | 54 | // we started with, current points to the current macro expansion. source |
@@ -39,50 +56,95 @@ pub(crate) struct ExprCollector<DB> { | |||
39 | // current == original (see #1196) | 56 | // current == original (see #1196) |
40 | original_file_id: HirFileId, | 57 | original_file_id: HirFileId, |
41 | current_file_id: HirFileId, | 58 | current_file_id: HirFileId, |
59 | |||
60 | body: Body, | ||
61 | source_map: BodySourceMap, | ||
42 | } | 62 | } |
43 | 63 | ||
44 | impl<'a, DB> ExprCollector<&'a DB> | 64 | impl<'a, DB> ExprCollector<&'a DB> |
45 | where | 65 | where |
46 | DB: HirDatabase, | 66 | DB: HirDatabase, |
47 | { | 67 | { |
48 | fn new(owner: DefWithBody, file_id: HirFileId, resolver: Resolver, db: &'a DB) -> Self { | 68 | fn collect( |
49 | ExprCollector { | 69 | mut self, |
50 | owner, | 70 | param_list: Option<ast::ParamList>, |
51 | resolver, | 71 | body: Option<ast::Expr>, |
52 | db, | 72 | ) -> (Body, BodySourceMap) { |
53 | exprs: Arena::default(), | 73 | if let Some(param_list) = param_list { |
54 | pats: Arena::default(), | 74 | if let Some(self_param) = param_list.self_param() { |
55 | source_map: BodySourceMap::default(), | 75 | let ptr = AstPtr::new(&self_param); |
56 | params: Vec::new(), | 76 | let param_pat = self.alloc_pat( |
57 | body_expr: None, | 77 | Pat::Bind { |
58 | original_file_id: file_id, | 78 | name: SELF_PARAM, |
59 | current_file_id: file_id, | 79 | mode: BindingAnnotation::Unannotated, |
60 | } | 80 | subpat: None, |
81 | }, | ||
82 | Either::B(ptr), | ||
83 | ); | ||
84 | self.body.params.push(param_pat); | ||
85 | } | ||
86 | |||
87 | for param in param_list.params() { | ||
88 | let pat = match param.pat() { | ||
89 | None => continue, | ||
90 | Some(pat) => pat, | ||
91 | }; | ||
92 | let param_pat = self.collect_pat(pat); | ||
93 | self.body.params.push(param_pat); | ||
94 | } | ||
95 | }; | ||
96 | |||
97 | self.body.body_expr = self.collect_expr_opt(body); | ||
98 | (self.body, self.source_map) | ||
61 | } | 99 | } |
100 | |||
62 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { | 101 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { |
63 | let ptr = Either::A(ptr); | 102 | let ptr = Either::A(ptr); |
64 | let id = self.exprs.alloc(expr); | 103 | let id = self.body.exprs.alloc(expr); |
65 | if self.current_file_id == self.original_file_id { | 104 | if self.current_file_id == self.original_file_id { |
66 | self.source_map.expr_map.insert(ptr, id); | 105 | self.source_map.expr_map.insert(ptr, id); |
67 | self.source_map.expr_map_back.insert(id, ptr); | ||
68 | } | 106 | } |
107 | self.source_map | ||
108 | .expr_map_back | ||
109 | .insert(id, Source { file_id: self.current_file_id, ast: ptr }); | ||
110 | id | ||
111 | } | ||
112 | // desugared exprs don't have ptr, that's wrong and should be fixed | ||
113 | // somehow. | ||
114 | fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { | ||
115 | self.body.exprs.alloc(expr) | ||
116 | } | ||
117 | fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { | ||
118 | let ptr = Either::B(ptr); | ||
119 | let id = self.body.exprs.alloc(expr); | ||
120 | if self.current_file_id == self.original_file_id { | ||
121 | self.source_map.expr_map.insert(ptr, id); | ||
122 | } | ||
123 | self.source_map | ||
124 | .expr_map_back | ||
125 | .insert(id, Source { file_id: self.current_file_id, ast: ptr }); | ||
69 | id | 126 | id |
70 | } | 127 | } |
71 | |||
72 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { | 128 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { |
73 | let id = self.pats.alloc(pat); | 129 | let id = self.body.pats.alloc(pat); |
74 | |||
75 | if self.current_file_id == self.original_file_id { | 130 | if self.current_file_id == self.original_file_id { |
76 | self.source_map.pat_map.insert(ptr, id); | 131 | self.source_map.pat_map.insert(ptr, id); |
77 | self.source_map.pat_map_back.insert(id, ptr); | ||
78 | } | 132 | } |
79 | 133 | self.source_map.pat_map_back.insert(id, Source { file_id: self.current_file_id, ast: ptr }); | |
80 | id | 134 | id |
81 | } | 135 | } |
82 | 136 | ||
83 | fn empty_block(&mut self) -> ExprId { | 137 | fn empty_block(&mut self) -> ExprId { |
84 | let block = Expr::Block { statements: Vec::new(), tail: None }; | 138 | let block = Expr::Block { statements: Vec::new(), tail: None }; |
85 | self.exprs.alloc(block) | 139 | self.body.exprs.alloc(block) |
140 | } | ||
141 | |||
142 | fn missing_expr(&mut self) -> ExprId { | ||
143 | self.body.exprs.alloc(Expr::Missing) | ||
144 | } | ||
145 | |||
146 | fn missing_pat(&mut self) -> PatId { | ||
147 | self.body.pats.alloc(Pat::Missing) | ||
86 | } | 148 | } |
87 | 149 | ||
88 | fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { | 150 | fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { |
@@ -100,14 +162,14 @@ where | |||
100 | }); | 162 | }); |
101 | 163 | ||
102 | let condition = match e.condition() { | 164 | let condition = match e.condition() { |
103 | None => self.exprs.alloc(Expr::Missing), | 165 | None => self.missing_expr(), |
104 | Some(condition) => match condition.pat() { | 166 | Some(condition) => match condition.pat() { |
105 | None => self.collect_expr_opt(condition.expr()), | 167 | None => self.collect_expr_opt(condition.expr()), |
106 | // if let -- desugar to match | 168 | // if let -- desugar to match |
107 | Some(pat) => { | 169 | Some(pat) => { |
108 | let pat = self.collect_pat(pat); | 170 | let pat = self.collect_pat(pat); |
109 | let match_expr = self.collect_expr_opt(condition.expr()); | 171 | let match_expr = self.collect_expr_opt(condition.expr()); |
110 | let placeholder_pat = self.pats.alloc(Pat::Missing); | 172 | let placeholder_pat = self.missing_pat(); |
111 | let arms = vec![ | 173 | let arms = vec![ |
112 | MatchArm { pats: vec![pat], expr: then_branch, guard: None }, | 174 | MatchArm { pats: vec![pat], expr: then_branch, guard: None }, |
113 | MatchArm { | 175 | MatchArm { |
@@ -137,7 +199,7 @@ where | |||
137 | let body = self.collect_block_opt(e.loop_body()); | 199 | let body = self.collect_block_opt(e.loop_body()); |
138 | 200 | ||
139 | let condition = match e.condition() { | 201 | let condition = match e.condition() { |
140 | None => self.exprs.alloc(Expr::Missing), | 202 | None => self.missing_expr(), |
141 | Some(condition) => match condition.pat() { | 203 | Some(condition) => match condition.pat() { |
142 | None => self.collect_expr_opt(condition.expr()), | 204 | None => self.collect_expr_opt(condition.expr()), |
143 | // if let -- desugar to match | 205 | // if let -- desugar to match |
@@ -145,14 +207,14 @@ where | |||
145 | tested_by!(infer_while_let); | 207 | tested_by!(infer_while_let); |
146 | let pat = self.collect_pat(pat); | 208 | let pat = self.collect_pat(pat); |
147 | let match_expr = self.collect_expr_opt(condition.expr()); | 209 | let match_expr = self.collect_expr_opt(condition.expr()); |
148 | let placeholder_pat = self.pats.alloc(Pat::Missing); | 210 | let placeholder_pat = self.missing_pat(); |
149 | let break_ = self.exprs.alloc(Expr::Break { expr: None }); | 211 | let break_ = self.alloc_expr_desugared(Expr::Break { expr: None }); |
150 | let arms = vec![ | 212 | let arms = vec![ |
151 | MatchArm { pats: vec![pat], expr: body, guard: None }, | 213 | MatchArm { pats: vec![pat], expr: body, guard: None }, |
152 | MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None }, | 214 | MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None }, |
153 | ]; | 215 | ]; |
154 | let match_expr = | 216 | let match_expr = |
155 | self.exprs.alloc(Expr::Match { expr: match_expr, arms }); | 217 | self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); |
156 | return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr); | 218 | return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr); |
157 | } | 219 | } |
158 | }, | 220 | }, |
@@ -247,13 +309,12 @@ where | |||
247 | self.collect_expr(e) | 309 | self.collect_expr(e) |
248 | } else if let Some(nr) = field.name_ref() { | 310 | } else if let Some(nr) = field.name_ref() { |
249 | // field shorthand | 311 | // field shorthand |
250 | let id = self.exprs.alloc(Expr::Path(Path::from_name_ref(&nr))); | 312 | self.alloc_expr_field_shorthand( |
251 | let ptr = Either::B(AstPtr::new(&field)); | 313 | Expr::Path(Path::from_name_ref(&nr)), |
252 | self.source_map.expr_map.insert(ptr, id); | 314 | AstPtr::new(&field), |
253 | self.source_map.expr_map_back.insert(id, ptr); | 315 | ) |
254 | id | ||
255 | } else { | 316 | } else { |
256 | self.exprs.alloc(Expr::Missing) | 317 | self.missing_expr() |
257 | }, | 318 | }, |
258 | }) | 319 | }) |
259 | .collect(); | 320 | .collect(); |
@@ -420,7 +481,7 @@ where | |||
420 | if let Some(expr) = expr { | 481 | if let Some(expr) = expr { |
421 | self.collect_expr(expr) | 482 | self.collect_expr(expr) |
422 | } else { | 483 | } else { |
423 | self.exprs.alloc(Expr::Missing) | 484 | self.missing_expr() |
424 | } | 485 | } |
425 | } | 486 | } |
426 | 487 | ||
@@ -450,7 +511,7 @@ where | |||
450 | if let Some(block) = expr { | 511 | if let Some(block) = expr { |
451 | self.collect_block(block) | 512 | self.collect_block(block) |
452 | } else { | 513 | } else { |
453 | self.exprs.alloc(Expr::Missing) | 514 | self.missing_expr() |
454 | } | 515 | } |
455 | } | 516 | } |
456 | 517 | ||
@@ -519,60 +580,9 @@ where | |||
519 | if let Some(pat) = pat { | 580 | if let Some(pat) = pat { |
520 | self.collect_pat(pat) | 581 | self.collect_pat(pat) |
521 | } else { | 582 | } else { |
522 | self.pats.alloc(Pat::Missing) | 583 | self.missing_pat() |
523 | } | 584 | } |
524 | } | 585 | } |
525 | |||
526 | fn collect_const_body(&mut self, node: ast::ConstDef) { | ||
527 | let body = self.collect_expr_opt(node.body()); | ||
528 | self.body_expr = Some(body); | ||
529 | } | ||
530 | |||
531 | fn collect_static_body(&mut self, node: ast::StaticDef) { | ||
532 | let body = self.collect_expr_opt(node.body()); | ||
533 | self.body_expr = Some(body); | ||
534 | } | ||
535 | |||
536 | fn collect_fn_body(&mut self, node: ast::FnDef) { | ||
537 | if let Some(param_list) = node.param_list() { | ||
538 | if let Some(self_param) = param_list.self_param() { | ||
539 | let ptr = AstPtr::new(&self_param); | ||
540 | let param_pat = self.alloc_pat( | ||
541 | Pat::Bind { | ||
542 | name: SELF_PARAM, | ||
543 | mode: BindingAnnotation::Unannotated, | ||
544 | subpat: None, | ||
545 | }, | ||
546 | Either::B(ptr), | ||
547 | ); | ||
548 | self.params.push(param_pat); | ||
549 | } | ||
550 | |||
551 | for param in param_list.params() { | ||
552 | let pat = if let Some(pat) = param.pat() { | ||
553 | pat | ||
554 | } else { | ||
555 | continue; | ||
556 | }; | ||
557 | let param_pat = self.collect_pat(pat); | ||
558 | self.params.push(param_pat); | ||
559 | } | ||
560 | }; | ||
561 | |||
562 | let body = self.collect_block_opt(node.body()); | ||
563 | self.body_expr = Some(body); | ||
564 | } | ||
565 | |||
566 | fn finish(self) -> (Body, BodySourceMap) { | ||
567 | let body = Body { | ||
568 | owner: self.owner, | ||
569 | exprs: self.exprs, | ||
570 | pats: self.pats, | ||
571 | params: self.params, | ||
572 | body_expr: self.body_expr.expect("A body should have been collected"), | ||
573 | }; | ||
574 | (body, self.source_map) | ||
575 | } | ||
576 | } | 586 | } |
577 | 587 | ||
578 | impl From<ast::BinOp> for BinaryOp { | 588 | impl From<ast::BinOp> for BinaryOp { |
@@ -618,35 +628,3 @@ impl From<ast::BinOp> for BinaryOp { | |||
618 | } | 628 | } |
619 | } | 629 | } |
620 | } | 630 | } |
621 | |||
622 | pub(crate) fn body_with_source_map_query( | ||
623 | db: &impl HirDatabase, | ||
624 | def: DefWithBody, | ||
625 | ) -> (Arc<Body>, Arc<BodySourceMap>) { | ||
626 | let mut collector; | ||
627 | |||
628 | match def { | ||
629 | DefWithBody::Const(ref c) => { | ||
630 | let src = c.source(db); | ||
631 | collector = ExprCollector::new(def, src.file_id, def.resolver(db), db); | ||
632 | collector.collect_const_body(src.ast) | ||
633 | } | ||
634 | DefWithBody::Function(ref f) => { | ||
635 | let src = f.source(db); | ||
636 | collector = ExprCollector::new(def, src.file_id, def.resolver(db), db); | ||
637 | collector.collect_fn_body(src.ast) | ||
638 | } | ||
639 | DefWithBody::Static(ref s) => { | ||
640 | let src = s.source(db); | ||
641 | collector = ExprCollector::new(def, src.file_id, def.resolver(db), db); | ||
642 | collector.collect_static_body(src.ast) | ||
643 | } | ||
644 | } | ||
645 | |||
646 | let (body, source_map) = collector.finish(); | ||
647 | (Arc::new(body), Arc::new(source_map)) | ||
648 | } | ||
649 | |||
650 | pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> { | ||
651 | db.body_with_source_map(def).0 | ||
652 | } | ||
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs index 6fdaf1fce..1202913e2 100644 --- a/crates/ra_hir/src/expr/validation.rs +++ b/crates/ra_hir/src/expr/validation.rs | |||
@@ -1,9 +1,8 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::ast::{self, AstNode}; | 3 | use ra_syntax::ast; |
4 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
5 | 5 | ||
6 | use super::{Expr, ExprId, RecordLitField}; | ||
7 | use crate::{ | 6 | use crate::{ |
8 | adt::AdtDef, | 7 | adt::AdtDef, |
9 | diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, | 8 | diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, |
@@ -11,9 +10,11 @@ use crate::{ | |||
11 | name, | 10 | name, |
12 | path::{PathKind, PathSegment}, | 11 | path::{PathKind, PathSegment}, |
13 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, | 12 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, |
14 | Function, HasSource, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution, | 13 | Function, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution, |
15 | }; | 14 | }; |
16 | 15 | ||
16 | use super::{Expr, ExprId, RecordLitField}; | ||
17 | |||
17 | pub(crate) struct ExprValidator<'a, 'b: 'a> { | 18 | pub(crate) struct ExprValidator<'a, 'b: 'a> { |
18 | func: Function, | 19 | func: Function, |
19 | infer: Arc<InferenceResult>, | 20 | infer: Arc<InferenceResult>, |
@@ -78,25 +79,20 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
78 | return; | 79 | return; |
79 | } | 80 | } |
80 | let source_map = self.func.body_source_map(db); | 81 | let source_map = self.func.body_source_map(db); |
81 | let file_id = self.func.source(db).file_id; | 82 | |
82 | let parse = db.parse(file_id.original_file(db)); | 83 | if let Some(source_ptr) = source_map.expr_syntax(id) { |
83 | let source_file = parse.tree(); | 84 | if let Some(expr) = source_ptr.ast.a() { |
84 | if let Some(field_list_node) = source_map | 85 | let root = source_ptr.file_syntax(db); |
85 | .expr_syntax(id) | 86 | if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { |
86 | .and_then(|ptr| ptr.a()) | 87 | if let Some(field_list) = record_lit.record_field_list() { |
87 | .map(|ptr| ptr.to_node(source_file.syntax())) | 88 | self.sink.push(MissingFields { |
88 | .and_then(|expr| match expr { | 89 | file: source_ptr.file_id, |
89 | ast::Expr::RecordLit(it) => Some(it), | 90 | field_list: AstPtr::new(&field_list), |
90 | _ => None, | 91 | missed_fields, |
91 | }) | 92 | }) |
92 | .and_then(|lit| lit.record_field_list()) | 93 | } |
93 | { | 94 | } |
94 | let field_list_ptr = AstPtr::new(&field_list_node); | 95 | } |
95 | self.sink.push(MissingFields { | ||
96 | file: file_id, | ||
97 | field_list: field_list_ptr, | ||
98 | missed_fields, | ||
99 | }) | ||
100 | } | 96 | } |
101 | } | 97 | } |
102 | 98 | ||
@@ -136,10 +132,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
136 | 132 | ||
137 | if params.len() == 2 && ¶ms[0] == &mismatch.actual { | 133 | if params.len() == 2 && ¶ms[0] == &mismatch.actual { |
138 | let source_map = self.func.body_source_map(db); | 134 | let source_map = self.func.body_source_map(db); |
139 | let file_id = self.func.source(db).file_id; | ||
140 | 135 | ||
141 | if let Some(expr) = source_map.expr_syntax(id).and_then(|n| n.a()) { | 136 | if let Some(source_ptr) = source_map.expr_syntax(id) { |
142 | self.sink.push(MissingOkInTailExpr { file: file_id, expr }); | 137 | if let Some(expr) = source_ptr.ast.a() { |
138 | self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); | ||
139 | } | ||
143 | } | 140 | } |
144 | } | 141 | } |
145 | } | 142 | } |