aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/assists/add_explicit_type.rs18
-rw-r--r--crates/ra_hir/src/source_binder.rs26
-rw-r--r--crates/ra_hir_def/src/body.rs6
-rw-r--r--crates/ra_hir_def/src/body/lower.rs20
4 files changed, 62 insertions, 8 deletions
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs
index eeb4ff39f..2c602a79e 100644
--- a/crates/ra_assists/src/assists/add_explicit_type.rs
+++ b/crates/ra_assists/src/assists/add_explicit_type.rs
@@ -74,6 +74,24 @@ mod tests {
74 } 74 }
75 75
76 #[test] 76 #[test]
77 fn add_explicit_type_works_for_macro_call() {
78 check_assist(
79 add_explicit_type,
80 "macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }",
81 "macro_rules! v { () => {0u64} } fn f() { let a<|>: u64 = v!(); }",
82 );
83 }
84
85 #[test]
86 fn add_explicit_type_works_for_macro_call_recursive() {
87 check_assist(
88 add_explicit_type,
89 "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|> = v!(); }",
90 "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|>: u64 = v!(); }",
91 );
92 }
93
94 #[test]
77 fn add_explicit_type_not_applicable_if_ty_not_inferred() { 95 fn add_explicit_type_not_applicable_if_ty_not_inferred() {
78 check_assist_not_applicable(add_explicit_type, "fn f() { let a<|> = None; }"); 96 check_assist_not_applicable(add_explicit_type, "fn f() { let a<|> = None; }");
79 } 97 }
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 85b378483..2c422af8b 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -215,8 +215,32 @@ impl SourceAnalyzer {
215 self.body_source_map.as_ref()?.node_pat(src) 215 self.body_source_map.as_ref()?.node_pat(src)
216 } 216 }
217 217
218 fn expand_expr(
219 &self,
220 db: &impl HirDatabase,
221 expr: InFile<&ast::Expr>,
222 ) -> Option<InFile<ast::Expr>> {
223 let macro_call = ast::MacroCall::cast(expr.value.syntax().clone())?;
224 let macro_file =
225 self.body_source_map.as_ref()?.node_macro_file(expr.with_value(&macro_call))?;
226 let expanded = db.parse_or_expand(macro_file)?;
227 let kind = expanded.kind();
228 let expr = InFile::new(macro_file, ast::Expr::cast(expanded)?);
229
230 if ast::MacroCall::can_cast(kind) {
231 self.expand_expr(db, expr.as_ref())
232 } else {
233 Some(expr)
234 }
235 }
236
218 pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option<Type> { 237 pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option<Type> {
219 let expr_id = self.expr_id(expr)?; 238 let expr_id = if let Some(expr) = self.expand_expr(db, InFile::new(self.file_id, expr)) {
239 self.body_source_map.as_ref()?.node_expr(expr.as_ref())?
240 } else {
241 self.expr_id(expr)?
242 };
243
220 let ty = self.infer.as_ref()?[expr_id].clone(); 244 let ty = self.infer.as_ref()?[expr_id].clone();
221 let environment = TraitEnvironment::lower(db, &self.resolver); 245 let environment = TraitEnvironment::lower(db, &self.resolver);
222 Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) 246 Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index d3e4c50ae..142c52d35 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -163,6 +163,7 @@ pub struct BodySourceMap {
163 pat_map: FxHashMap<PatSource, PatId>, 163 pat_map: FxHashMap<PatSource, PatId>,
164 pat_map_back: ArenaMap<PatId, PatSource>, 164 pat_map_back: ArenaMap<PatId, PatSource>,
165 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, 165 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>,
166 expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
166} 167}
167 168
168impl Body { 169impl Body {
@@ -237,6 +238,11 @@ impl BodySourceMap {
237 self.expr_map.get(&src).cloned() 238 self.expr_map.get(&src).cloned()
238 } 239 }
239 240
241 pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId> {
242 let src = node.map(|it| AstPtr::new(it));
243 self.expansions.get(&src).cloned()
244 }
245
240 pub fn field_init_shorthand_expr(&self, node: InFile<&ast::RecordField>) -> Option<ExprId> { 246 pub fn field_init_shorthand_expr(&self, node: InFile<&ast::RecordField>) -> Option<ExprId> {
241 let src = node.map(|it| Either::Right(AstPtr::new(it))); 247 let src = node.map(|it| Either::Right(AstPtr::new(it)));
242 self.expr_map.get(&src).cloned() 248 self.expr_map.get(&src).cloned()
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index fc3a028e0..e656f9a41 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -446,14 +446,20 @@ where
446 } 446 }
447 } 447 }
448 // FIXME expand to statements in statement position 448 // FIXME expand to statements in statement position
449 ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) { 449 ast::Expr::MacroCall(e) => {
450 Some((mark, expansion)) => { 450 let macro_call = self.expander.to_source(AstPtr::new(&e));
451 let id = self.collect_expr(expansion); 451 match self.expander.enter_expand(self.db, e.clone()) {
452 self.expander.exit(self.db, mark); 452 Some((mark, expansion)) => {
453 id 453 self.source_map
454 .expansions
455 .insert(macro_call, self.expander.current_file_id);
456 let id = self.collect_expr(expansion);
457 self.expander.exit(self.db, mark);
458 id
459 }
460 None => self.alloc_expr(Expr::Missing, syntax_ptr),
454 } 461 }
455 None => self.alloc_expr(Expr::Missing, syntax_ptr), 462 }
456 },
457 463
458 // FIXME implement HIR for these: 464 // FIXME implement HIR for these:
459 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 465 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),