diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-04-23 13:49:31 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-04-23 13:49:31 +0100 |
commit | a094d5c621e44ff78dce953c0cae7cfba4b2840e (patch) | |
tree | 93d12337483968512db038b0b89aff7b9ef4eb20 /crates/ra_hir/src | |
parent | e2835b46f6928eda21b7edb44f305f20473a3a98 (diff) | |
parent | 1ab7066e32ab482c70ea5c9bba7585eba275476a (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.rs | 72 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 29 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 26 |
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 | ||
6 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; | 6 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; |
7 | use ra_syntax::{ | 7 | use 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 | ||
12 | use crate::{ | 12 | use 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 | }; |
17 | use crate::{path::GenericArgs, ty::primitive::{IntTy, UncertainIntTy, FloatTy, UncertainFloatTy}}; | 18 | use crate::{path::GenericArgs, ty::primitive::{IntTy, UncertainIntTy, FloatTy, UncertainFloatTy}}; |
@@ -478,38 +479,54 @@ impl Pat { | |||
478 | 479 | ||
479 | // Queries | 480 | // Queries |
480 | 481 | ||
481 | pub(crate) struct ExprCollector { | 482 | pub(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 | ||
490 | impl ExprCollector { | 495 | impl<'a, DB> ExprCollector<&'a DB> |
491 | fn new(owner: DefWithBody) -> Self { | 496 | where |
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 | ||
991 | fn 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 | |||
955 | pub(crate) fn body_with_source_map_query( | 1005 | pub(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(¯o_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 | ||
131 | impl GenericArgs { | 135 | impl 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. |
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use ra_syntax::ast; | ||
5 | |||
4 | use rustc_hash::FxHashMap; | 6 | use rustc_hash::FxHashMap; |
5 | 7 | ||
6 | use crate::{ | 8 | use 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] | ||
2421 | fn infer_macros_expanded() { | ||
2422 | assert_snapshot_matches!( | ||
2423 | infer(r#" | ||
2424 | struct Foo(Vec<i32>); | ||
2425 | |||
2426 | macro_rules! foo { | ||
2427 | ($($item:expr),*) => { | ||
2428 | { | ||
2429 | Foo(vec![$($item,)*]) | ||
2430 | } | ||
2431 | }; | ||
2432 | } | ||
2433 | |||
2434 | fn 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] |
2422 | fn method_resolution_trait_before_autoref() { | 2446 | fn method_resolution_trait_before_autoref() { |
@@ -2510,6 +2534,7 @@ fn type_at(content: &str) -> String { | |||
2510 | fn infer(content: &str) -> String { | 2534 | fn 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 { |