aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-04-23 13:49:31 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-04-23 13:49:31 +0100
commita094d5c621e44ff78dce953c0cae7cfba4b2840e (patch)
tree93d12337483968512db038b0b89aff7b9ef4eb20 /crates/ra_hir/src
parente2835b46f6928eda21b7edb44f305f20473a3a98 (diff)
parent1ab7066e32ab482c70ea5c9bba7585eba275476a (diff)
Merge #1147
1147: Handle macros in type checking / HIR r=matklad a=Lapz An other attempt at #1102. I will need to flatten the nested if statements and im also not sure if the way that i get the resolver and module will always work Co-authored-by: Lenard Pratt <[email protected]>
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/expr.rs72
-rw-r--r--crates/ra_hir/src/nameres.rs6
-rw-r--r--crates/ra_hir/src/nameres/collector.rs11
-rw-r--r--crates/ra_hir/src/path.rs4
-rw-r--r--crates/ra_hir/src/resolve.rs29
-rw-r--r--crates/ra_hir/src/ty/tests.rs26
6 files changed, 133 insertions, 15 deletions
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 817e660f9..db74d28e8 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -5,13 +5,14 @@ use rustc_hash::FxHashMap;
5 5
6use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 6use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
7use ra_syntax::{ 7use ra_syntax::{
8 SyntaxNodePtr, AstPtr, AstNode, 8 SyntaxNodePtr, AstPtr, AstNode,TreeArc,
9 ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind,ArrayExprKind, TypeAscriptionOwner} 9 ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind,ArrayExprKind, TypeAscriptionOwner}
10}; 10};
11 11
12use crate::{ 12use crate::{
13 Path, Name, HirDatabase, Resolver,DefWithBody, Either, 13 Path, Name, HirDatabase, Resolver,DefWithBody, Either,
14 name::AsName, 14 name::AsName,
15 ids::{MacroCallId},
15 type_ref::{Mutability, TypeRef}, 16 type_ref::{Mutability, TypeRef},
16}; 17};
17use crate::{path::GenericArgs, ty::primitive::{IntTy, UncertainIntTy, FloatTy, UncertainFloatTy}}; 18use crate::{path::GenericArgs, ty::primitive::{IntTy, UncertainIntTy, FloatTy, UncertainFloatTy}};
@@ -478,38 +479,54 @@ impl Pat {
478 479
479// Queries 480// Queries
480 481
481pub(crate) struct ExprCollector { 482pub(crate) struct ExprCollector<DB> {
483 db: DB,
482 owner: DefWithBody, 484 owner: DefWithBody,
483 exprs: Arena<ExprId, Expr>, 485 exprs: Arena<ExprId, Expr>,
484 pats: Arena<PatId, Pat>, 486 pats: Arena<PatId, Pat>,
485 source_map: BodySourceMap, 487 source_map: BodySourceMap,
486 params: Vec<PatId>, 488 params: Vec<PatId>,
487 body_expr: Option<ExprId>, 489 body_expr: Option<ExprId>,
490 resolver: Resolver,
491 // FIXEME: Its a quick hack,see issue #1196
492 is_in_macro: bool,
488} 493}
489 494
490impl ExprCollector { 495impl<'a, DB> ExprCollector<&'a DB>
491 fn new(owner: DefWithBody) -> Self { 496where
497 DB: HirDatabase,
498{
499 fn new(owner: DefWithBody, resolver: Resolver, db: &'a DB) -> Self {
492 ExprCollector { 500 ExprCollector {
493 owner, 501 owner,
502 resolver,
503 db,
494 exprs: Arena::default(), 504 exprs: Arena::default(),
495 pats: Arena::default(), 505 pats: Arena::default(),
496 source_map: BodySourceMap::default(), 506 source_map: BodySourceMap::default(),
497 params: Vec::new(), 507 params: Vec::new(),
498 body_expr: None, 508 body_expr: None,
509 is_in_macro: false,
499 } 510 }
500 } 511 }
501
502 fn alloc_expr(&mut self, expr: Expr, syntax_ptr: SyntaxNodePtr) -> ExprId { 512 fn alloc_expr(&mut self, expr: Expr, syntax_ptr: SyntaxNodePtr) -> ExprId {
503 let id = self.exprs.alloc(expr); 513 let id = self.exprs.alloc(expr);
504 self.source_map.expr_map.insert(syntax_ptr, id); 514 if !self.is_in_macro {
505 self.source_map.expr_map_back.insert(id, syntax_ptr); 515 self.source_map.expr_map.insert(syntax_ptr, id);
516 self.source_map.expr_map_back.insert(id, syntax_ptr);
517 }
518
506 id 519 id
507 } 520 }
508 521
509 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { 522 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
510 let id = self.pats.alloc(pat); 523 let id = self.pats.alloc(pat);
511 self.source_map.pat_map.insert(ptr, id); 524
512 self.source_map.pat_map_back.insert(id, ptr); 525 if !self.is_in_macro {
526 self.source_map.pat_map.insert(ptr, id);
527 self.source_map.pat_map_back.insert(id, ptr);
528 }
529
513 id 530 id
514 } 531 }
515 532
@@ -794,7 +811,26 @@ impl ExprCollector {
794 ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 811 ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
795 ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 812 ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
796 ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 813 ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
797 ast::ExprKind::MacroCall(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 814 ast::ExprKind::MacroCall(e) => {
815 // very hacky.FIXME change to use the macro resolution
816 let path = e.path().and_then(Path::from_ast);
817
818 if let Some(call_id) = self.resolver.resolve_macro_call(self.db, path, e) {
819 if let Some(expr) = expand_macro_to_expr(self.db, call_id, e.token_tree()) {
820 log::debug!("macro expansion {}", expr.syntax().debug_dump());
821 let old = std::mem::replace(&mut self.is_in_macro, true);
822 let id = self.collect_expr(&expr);
823 self.is_in_macro = old;
824 id
825 } else {
826 // FIXME: Instead of just dropping the error from expansion
827 // report it
828 self.alloc_expr(Expr::Missing, syntax_ptr)
829 }
830 } else {
831 self.alloc_expr(Expr::Missing, syntax_ptr)
832 }
833 }
798 } 834 }
799 } 835 }
800 836
@@ -952,11 +988,25 @@ impl ExprCollector {
952 } 988 }
953} 989}
954 990
991fn expand_macro_to_expr(
992 db: &impl HirDatabase,
993 macro_call: MacroCallId,
994 args: Option<&ast::TokenTree>,
995) -> Option<TreeArc<ast::Expr>> {
996 let rules = db.macro_def(macro_call.loc(db).def)?;
997
998 let args = mbe::ast_to_token_tree(args?)?.0;
999
1000 let expanded = rules.expand(&args).ok()?;
1001
1002 mbe::token_tree_to_expr(&expanded).ok()
1003}
1004
955pub(crate) fn body_with_source_map_query( 1005pub(crate) fn body_with_source_map_query(
956 db: &impl HirDatabase, 1006 db: &impl HirDatabase,
957 def: DefWithBody, 1007 def: DefWithBody,
958) -> (Arc<Body>, Arc<BodySourceMap>) { 1008) -> (Arc<Body>, Arc<BodySourceMap>) {
959 let mut collector = ExprCollector::new(def); 1009 let mut collector = ExprCollector::new(def, def.resolver(db), db);
960 1010
961 match def { 1011 match def {
962 DefWithBody::Const(ref c) => collector.collect_const_body(&c.source(db).1), 1012 DefWithBody::Const(ref c) => collector.collect_const_body(&c.source(db).1),
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index fbfff4fd7..a450d7b84 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -104,6 +104,7 @@ pub struct CrateDefMap {
104 /// However, do we want to put it as a global variable? 104 /// However, do we want to put it as a global variable?
105 poison_macros: FxHashSet<MacroDefId>, 105 poison_macros: FxHashSet<MacroDefId>,
106 106
107 local_macros: FxHashMap<Name, MacroDefId>,
107 diagnostics: Vec<DefDiagnostic>, 108 diagnostics: Vec<DefDiagnostic>,
108} 109}
109 110
@@ -209,6 +210,7 @@ impl CrateDefMap {
209 modules, 210 modules,
210 public_macros: FxHashMap::default(), 211 public_macros: FxHashMap::default(),
211 poison_macros: FxHashSet::default(), 212 poison_macros: FxHashSet::default(),
213 local_macros: FxHashMap::default(),
212 diagnostics: Vec::new(), 214 diagnostics: Vec::new(),
213 } 215 }
214 }; 216 };
@@ -270,6 +272,10 @@ impl CrateDefMap {
270 (res.resolved_def, res.segment_index) 272 (res.resolved_def, res.segment_index)
271 } 273 }
272 274
275 pub(crate) fn find_macro(&self, name: &Name) -> Option<&MacroDefId> {
276 self.public_macros.get(name).or(self.local_macros.get(name))
277 }
278
273 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 279 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
274 // the result. 280 // the result.
275 fn resolve_path_fp( 281 fn resolve_path_fp(
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 4590a5184..b34c9b8e6 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -131,6 +131,8 @@ where
131 fn define_macro(&mut self, name: Name, macro_id: MacroDefId, export: bool) { 131 fn define_macro(&mut self, name: Name, macro_id: MacroDefId, export: bool) {
132 if export { 132 if export {
133 self.def_map.public_macros.insert(name.clone(), macro_id); 133 self.def_map.public_macros.insert(name.clone(), macro_id);
134 } else {
135 self.def_map.local_macros.insert(name.clone(), macro_id);
134 } 136 }
135 self.global_macro_scope.insert(name, macro_id); 137 self.global_macro_scope.insert(name, macro_id);
136 } 138 }
@@ -517,12 +519,12 @@ where
517 519
518 // Case 2: try to expand macro_rules from this crate, triggering 520 // Case 2: try to expand macro_rules from this crate, triggering
519 // recursive item collection. 521 // recursive item collection.
520 if let Some(&macro_id) = 522 if let Some(macro_id) =
521 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name)) 523 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(&name))
522 { 524 {
523 let macro_call_id = MacroCallLoc { def: macro_id, ast_id }.id(self.def_collector.db); 525 let macro_call_id = MacroCallLoc { def: *macro_id, ast_id }.id(self.def_collector.db);
524 526
525 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_id); 527 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, *macro_id);
526 return; 528 return;
527 } 529 }
528 530
@@ -614,6 +616,7 @@ mod tests {
614 modules, 616 modules,
615 public_macros: FxHashMap::default(), 617 public_macros: FxHashMap::default(),
616 poison_macros: FxHashSet::default(), 618 poison_macros: FxHashSet::default(),
619 local_macros: FxHashMap::default(),
617 diagnostics: Vec::new(), 620 diagnostics: Vec::new(),
618 } 621 }
619 }; 622 };
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 5449cddfd..1b129c752 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -126,6 +126,10 @@ impl Path {
126 } 126 }
127 self.segments.first().map(|s| &s.name) 127 self.segments.first().map(|s| &s.name)
128 } 128 }
129
130 pub fn expand_macro_expr(&self) -> Option<Name> {
131 self.as_ident().and_then(|name| Some(name.clone()))
132 }
129} 133}
130 134
131impl GenericArgs { 135impl GenericArgs {
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index f2c85eb66..d1f97c104 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -1,11 +1,15 @@
1//! Name resolution. 1//! Name resolution.
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use ra_syntax::ast;
5
4use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
5 7
6use crate::{ 8use crate::{
7 ModuleDef, 9 ModuleDef,
8 code_model_api::Crate, 10 code_model_api::Crate,
11 MacroCallId,
12 MacroCallLoc,
9 db::HirDatabase, 13 db::HirDatabase,
10 name::{Name, KnownName}, 14 name::{Name, KnownName},
11 nameres::{PerNs, CrateDefMap, CrateModuleId}, 15 nameres::{PerNs, CrateDefMap, CrateModuleId},
@@ -130,6 +134,31 @@ impl Resolver {
130 resolution 134 resolution
131 } 135 }
132 136
137 pub fn resolve_macro_call(
138 &self,
139 db: &impl HirDatabase,
140 path: Option<Path>,
141 call: &ast::MacroCall,
142 ) -> Option<MacroCallId> {
143 let name = path.and_then(|path| path.expand_macro_expr()).unwrap_or_else(Name::missing);
144 let macro_def_id = self.module().and_then(|(module, _)| module.find_macro(&name));
145 if let Some(def_id) = macro_def_id {
146 self.module().and_then(|(module, _)| {
147 // we do this to get the ast_id for the macro call
148 // if we used the ast_id from the def_id variable
149 // it gives us the ast_id of the defenition site
150 let module = module.mk_module(module.root());
151 let hir_file_id = module.definition_source(db).0;
152 let ast_id = db.ast_id_map(hir_file_id).ast_id(call).with_file_id(hir_file_id);
153 let call_loc = MacroCallLoc { def: *def_id, ast_id }.id(db);
154
155 Some(call_loc)
156 })
157 } else {
158 None
159 }
160 }
161
133 /// Returns the resolved path segments 162 /// Returns the resolved path segments
134 /// Which may be fully resolved, empty or partially resolved. 163 /// Which may be fully resolved, empty or partially resolved.
135 pub(crate) fn resolve_path_segments(&self, db: &impl HirDatabase, path: &Path) -> PathResult { 164 pub(crate) fn resolve_path_segments(&self, db: &impl HirDatabase, path: &Path) -> PathResult {
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index a4c99528d..c76a5012f 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2417,6 +2417,30 @@ fn test() -> u64 {
2417 ); 2417 );
2418} 2418}
2419 2419
2420#[test]
2421fn infer_macros_expanded() {
2422 assert_snapshot_matches!(
2423 infer(r#"
2424struct Foo(Vec<i32>);
2425
2426macro_rules! foo {
2427 ($($item:expr),*) => {
2428 {
2429 Foo(vec![$($item,)*])
2430 }
2431 };
2432}
2433
2434fn main() {
2435 let x = foo!(1,2);
2436}
2437"#),
2438 @r###"
2439[156; 182) '{ ...,2); }': ()
2440[166; 167) 'x': Foo"###
2441 );
2442}
2443
2420#[ignore] 2444#[ignore]
2421#[test] 2445#[test]
2422fn method_resolution_trait_before_autoref() { 2446fn method_resolution_trait_before_autoref() {
@@ -2510,6 +2534,7 @@ fn type_at(content: &str) -> String {
2510fn infer(content: &str) -> String { 2534fn infer(content: &str) -> String {
2511 let (db, _, file_id) = MockDatabase::with_single_file(content); 2535 let (db, _, file_id) = MockDatabase::with_single_file(content);
2512 let source_file = db.parse(file_id); 2536 let source_file = db.parse(file_id);
2537
2513 let mut acc = String::new(); 2538 let mut acc = String::new();
2514 acc.push_str("\n"); 2539 acc.push_str("\n");
2515 2540
@@ -2532,6 +2557,7 @@ fn infer(content: &str) -> String {
2532 }; 2557 };
2533 types.push((syntax_ptr, ty)); 2558 types.push((syntax_ptr, ty));
2534 } 2559 }
2560
2535 // sort ranges for consistency 2561 // sort ranges for consistency
2536 types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end())); 2562 types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end()));
2537 for (syntax_ptr, ty) in &types { 2563 for (syntax_ptr, ty) in &types {