diff options
Diffstat (limited to 'crates/hir_expand')
-rw-r--r-- | crates/hir_expand/src/db.rs | 119 | ||||
-rw-r--r-- | crates/hir_expand/src/hygiene.rs | 2 | ||||
-rw-r--r-- | crates/hir_expand/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/hir_expand/src/name.rs | 13 |
4 files changed, 94 insertions, 42 deletions
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index fc73e435b..c0ab70b60 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -3,9 +3,15 @@ | |||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use base_db::{salsa, SourceDatabase}; | 5 | use base_db::{salsa, SourceDatabase}; |
6 | use mbe::{ExpandError, ExpandResult, MacroRules}; | 6 | use mbe::{ExpandError, ExpandResult, MacroDef, MacroRules}; |
7 | use parser::FragmentKind; | 7 | use parser::FragmentKind; |
8 | use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; | 8 | use syntax::{ |
9 | algo::diff, | ||
10 | ast::{MacroStmts, NameOwner}, | ||
11 | AstNode, GreenNode, Parse, | ||
12 | SyntaxKind::*, | ||
13 | SyntaxNode, | ||
14 | }; | ||
9 | 15 | ||
10 | use crate::{ | 16 | use crate::{ |
11 | ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander, | 17 | ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander, |
@@ -22,6 +28,7 @@ const TOKEN_LIMIT: usize = 524288; | |||
22 | #[derive(Debug, Clone, Eq, PartialEq)] | 28 | #[derive(Debug, Clone, Eq, PartialEq)] |
23 | pub enum TokenExpander { | 29 | pub enum TokenExpander { |
24 | MacroRules(mbe::MacroRules), | 30 | MacroRules(mbe::MacroRules), |
31 | MacroDef(mbe::MacroDef), | ||
25 | Builtin(BuiltinFnLikeExpander), | 32 | Builtin(BuiltinFnLikeExpander), |
26 | BuiltinDerive(BuiltinDeriveExpander), | 33 | BuiltinDerive(BuiltinDeriveExpander), |
27 | ProcMacro(ProcMacroExpander), | 34 | ProcMacro(ProcMacroExpander), |
@@ -36,6 +43,7 @@ impl TokenExpander { | |||
36 | ) -> mbe::ExpandResult<tt::Subtree> { | 43 | ) -> mbe::ExpandResult<tt::Subtree> { |
37 | match self { | 44 | match self { |
38 | TokenExpander::MacroRules(it) => it.expand(tt), | 45 | TokenExpander::MacroRules(it) => it.expand(tt), |
46 | TokenExpander::MacroDef(it) => it.expand(tt), | ||
39 | TokenExpander::Builtin(it) => it.expand(db, id, tt), | 47 | TokenExpander::Builtin(it) => it.expand(db, id, tt), |
40 | // FIXME switch these to ExpandResult as well | 48 | // FIXME switch these to ExpandResult as well |
41 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), | 49 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), |
@@ -51,6 +59,7 @@ impl TokenExpander { | |||
51 | pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { | 59 | pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { |
52 | match self { | 60 | match self { |
53 | TokenExpander::MacroRules(it) => it.map_id_down(id), | 61 | TokenExpander::MacroRules(it) => it.map_id_down(id), |
62 | TokenExpander::MacroDef(it) => it.map_id_down(id), | ||
54 | TokenExpander::Builtin(..) => id, | 63 | TokenExpander::Builtin(..) => id, |
55 | TokenExpander::BuiltinDerive(..) => id, | 64 | TokenExpander::BuiltinDerive(..) => id, |
56 | TokenExpander::ProcMacro(..) => id, | 65 | TokenExpander::ProcMacro(..) => id, |
@@ -60,6 +69,7 @@ impl TokenExpander { | |||
60 | pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { | 69 | pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { |
61 | match self { | 70 | match self { |
62 | TokenExpander::MacroRules(it) => it.map_id_up(id), | 71 | TokenExpander::MacroRules(it) => it.map_id_up(id), |
72 | TokenExpander::MacroDef(it) => it.map_id_up(id), | ||
63 | TokenExpander::Builtin(..) => (id, mbe::Origin::Call), | 73 | TokenExpander::Builtin(..) => (id, mbe::Origin::Call), |
64 | TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call), | 74 | TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call), |
65 | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), | 75 | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), |
@@ -130,26 +140,40 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { | |||
130 | 140 | ||
131 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { | 141 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { |
132 | match id.kind { | 142 | match id.kind { |
133 | MacroDefKind::Declarative(ast_id) => { | 143 | MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) { |
134 | let macro_rules = match ast_id.to_node(db) { | 144 | syntax::ast::Macro::MacroRules(macro_rules) => { |
135 | syntax::ast::Macro::MacroRules(mac) => mac, | 145 | let arg = macro_rules.token_tree()?; |
136 | syntax::ast::Macro::MacroDef(_) => return None, | 146 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { |
137 | }; | 147 | log::warn!("fail on macro_rules to token tree: {:#?}", arg); |
138 | let arg = macro_rules.token_tree()?; | 148 | None |
139 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { | 149 | })?; |
140 | log::warn!("fail on macro_def to token tree: {:#?}", arg); | 150 | let rules = match MacroRules::parse(&tt) { |
141 | None | 151 | Ok(it) => it, |
142 | })?; | 152 | Err(err) => { |
143 | let rules = match MacroRules::parse(&tt) { | 153 | let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default(); |
144 | Ok(it) => it, | 154 | log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt); |
145 | Err(err) => { | 155 | return None; |
146 | let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default(); | 156 | } |
147 | log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt); | 157 | }; |
148 | return None; | 158 | Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) |
149 | } | 159 | } |
150 | }; | 160 | syntax::ast::Macro::MacroDef(macro_def) => { |
151 | Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) | 161 | let arg = macro_def.body()?; |
152 | } | 162 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { |
163 | log::warn!("fail on macro_def to token tree: {:#?}", arg); | ||
164 | None | ||
165 | })?; | ||
166 | let rules = match MacroDef::parse(&tt) { | ||
167 | Ok(it) => it, | ||
168 | Err(err) => { | ||
169 | let name = macro_def.name().map(|n| n.to_string()).unwrap_or_default(); | ||
170 | log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt); | ||
171 | return None; | ||
172 | } | ||
173 | }; | ||
174 | Some(Arc::new((TokenExpander::MacroDef(rules), tmap))) | ||
175 | } | ||
176 | }, | ||
153 | MacroDefKind::BuiltIn(expander, _) => { | 177 | MacroDefKind::BuiltIn(expander, _) => { |
154 | Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default()))) | 178 | Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default()))) |
155 | } | 179 | } |
@@ -340,13 +364,19 @@ fn parse_macro_with_arg( | |||
340 | None => return ExpandResult { value: None, err: result.err }, | 364 | None => return ExpandResult { value: None, err: result.err }, |
341 | }; | 365 | }; |
342 | 366 | ||
343 | log::debug!("expanded = {}", tt.as_debug_string()); | ||
344 | |||
345 | let fragment_kind = to_fragment_kind(db, macro_call_id); | 367 | let fragment_kind = to_fragment_kind(db, macro_call_id); |
346 | 368 | ||
369 | log::debug!("expanded = {}", tt.as_debug_string()); | ||
370 | log::debug!("kind = {:?}", fragment_kind); | ||
371 | |||
347 | let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { | 372 | let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { |
348 | Ok(it) => it, | 373 | Ok(it) => it, |
349 | Err(err) => { | 374 | Err(err) => { |
375 | log::debug!( | ||
376 | "failed to parse expanstion to {:?} = {}", | ||
377 | fragment_kind, | ||
378 | tt.as_debug_string() | ||
379 | ); | ||
350 | return ExpandResult::only_err(err); | 380 | return ExpandResult::only_err(err); |
351 | } | 381 | } |
352 | }; | 382 | }; |
@@ -362,15 +392,34 @@ fn parse_macro_with_arg( | |||
362 | return ExpandResult::only_err(err); | 392 | return ExpandResult::only_err(err); |
363 | } | 393 | } |
364 | }; | 394 | }; |
365 | 395 | if is_self_replicating(&node, &call_node.value) { | |
366 | if !diff(&node, &call_node.value).is_empty() { | ||
367 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) } | ||
368 | } else { | ||
369 | return ExpandResult::only_err(err); | 396 | return ExpandResult::only_err(err); |
397 | } else { | ||
398 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) } | ||
399 | } | ||
400 | } | ||
401 | None => { | ||
402 | log::debug!("parse = {:?}", parse.syntax_node().kind()); | ||
403 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None } | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | |||
408 | fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool { | ||
409 | if diff(from, to).is_empty() { | ||
410 | return true; | ||
411 | } | ||
412 | if let Some(stmts) = MacroStmts::cast(from.clone()) { | ||
413 | if stmts.statements().any(|stmt| diff(stmt.syntax(), to).is_empty()) { | ||
414 | return true; | ||
415 | } | ||
416 | if let Some(expr) = stmts.expr() { | ||
417 | if diff(expr.syntax(), to).is_empty() { | ||
418 | return true; | ||
370 | } | 419 | } |
371 | } | 420 | } |
372 | None => ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None }, | ||
373 | } | 421 | } |
422 | false | ||
374 | } | 423 | } |
375 | 424 | ||
376 | fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> { | 425 | fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> { |
@@ -390,21 +439,15 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { | |||
390 | 439 | ||
391 | let parent = match syn.parent() { | 440 | let parent = match syn.parent() { |
392 | Some(it) => it, | 441 | Some(it) => it, |
393 | None => { | 442 | None => return FragmentKind::Statements, |
394 | // FIXME: | ||
395 | // If it is root, which means the parent HirFile | ||
396 | // MacroKindFile must be non-items | ||
397 | // return expr now. | ||
398 | return FragmentKind::Expr; | ||
399 | } | ||
400 | }; | 443 | }; |
401 | 444 | ||
402 | match parent.kind() { | 445 | match parent.kind() { |
403 | MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, | 446 | MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, |
404 | MACRO_STMTS => FragmentKind::Statement, | 447 | MACRO_STMTS => FragmentKind::Statements, |
405 | ITEM_LIST => FragmentKind::Items, | 448 | ITEM_LIST => FragmentKind::Items, |
406 | LET_STMT => { | 449 | LET_STMT => { |
407 | // FIXME: Handle Pattern | 450 | // FIXME: Handle LHS Pattern |
408 | FragmentKind::Expr | 451 | FragmentKind::Expr |
409 | } | 452 | } |
410 | EXPR_STMT => FragmentKind::Statements, | 453 | EXPR_STMT => FragmentKind::Statements, |
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index 0e0f7214a..779725629 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -148,7 +148,7 @@ fn make_hygiene_info( | |||
148 | let def_offset = loc.def.ast_id().left().and_then(|id| { | 148 | let def_offset = loc.def.ast_id().left().and_then(|id| { |
149 | let def_tt = match id.to_node(db) { | 149 | let def_tt = match id.to_node(db) { |
150 | ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), | 150 | ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), |
151 | ast::Macro::MacroDef(_) => return None, | 151 | ast::Macro::MacroDef(mac) => mac.body()?.syntax().text_range().start(), |
152 | }; | 152 | }; |
153 | Some(InFile::new(id.file_id, def_tt)) | 153 | Some(InFile::new(id.file_id, def_tt)) |
154 | }); | 154 | }); |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index b8045fda9..3e332ee47 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -151,7 +151,7 @@ impl HirFileId { | |||
151 | let def = loc.def.ast_id().left().and_then(|id| { | 151 | let def = loc.def.ast_id().left().and_then(|id| { |
152 | let def_tt = match id.to_node(db) { | 152 | let def_tt = match id.to_node(db) { |
153 | ast::Macro::MacroRules(mac) => mac.token_tree()?, | 153 | ast::Macro::MacroRules(mac) => mac.token_tree()?, |
154 | ast::Macro::MacroDef(_) => return None, | 154 | ast::Macro::MacroDef(mac) => mac.body()?, |
155 | }; | 155 | }; |
156 | Some(InFile::new(id.file_id, def_tt)) | 156 | Some(InFile::new(id.file_id, def_tt)) |
157 | }); | 157 | }); |
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index 0aeea48d5..203ebbe85 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs | |||
@@ -55,6 +55,15 @@ impl Name { | |||
55 | } | 55 | } |
56 | } | 56 | } |
57 | 57 | ||
58 | /// A fake name for things missing in the source code. | ||
59 | /// | ||
60 | /// For example, `impl Foo for {}` should be treated as a trait impl for a | ||
61 | /// type with a missing name. Similarly, `struct S { : u32 }` should have a | ||
62 | /// single field with a missing name. | ||
63 | /// | ||
64 | /// Ideally, we want a `gensym` semantics for missing names -- each missing | ||
65 | /// name is equal only to itself. It's not clear how to implement this in | ||
66 | /// salsa though, so we punt on that bit for a moment. | ||
58 | pub fn missing() -> Name { | 67 | pub fn missing() -> Name { |
59 | Name::new_text("[missing name]".into()) | 68 | Name::new_text("[missing name]".into()) |
60 | } | 69 | } |
@@ -75,14 +84,14 @@ impl AsName for ast::NameRef { | |||
75 | fn as_name(&self) -> Name { | 84 | fn as_name(&self) -> Name { |
76 | match self.as_tuple_field() { | 85 | match self.as_tuple_field() { |
77 | Some(idx) => Name::new_tuple_field(idx), | 86 | Some(idx) => Name::new_tuple_field(idx), |
78 | None => Name::resolve(self.text()), | 87 | None => Name::resolve(&self.text()), |
79 | } | 88 | } |
80 | } | 89 | } |
81 | } | 90 | } |
82 | 91 | ||
83 | impl AsName for ast::Name { | 92 | impl AsName for ast::Name { |
84 | fn as_name(&self) -> Name { | 93 | fn as_name(&self) -> Name { |
85 | Name::resolve(self.text()) | 94 | Name::resolve(&self.text()) |
86 | } | 95 | } |
87 | } | 96 | } |
88 | 97 | ||