aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-12-02 15:52:14 +0000
committerJonas Schievink <[email protected]>2020-12-03 14:48:29 +0000
commita6342436343e01b32d4482a48994b8c22bcbe659 (patch)
tree1fd4c71c6b203417c64b9ffb31221242d6f1a270 /crates
parent5a1306a43652d914035b2cf0b703f4bfd3451a33 (diff)
Propagate eager expansion errors
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_def/src/body.rs20
-rw-r--r--crates/hir_def/src/lib.rs51
-rw-r--r--crates/hir_expand/src/eager.rs115
3 files changed, 153 insertions, 33 deletions
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 33eb5e78c..92bcc1705 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -120,18 +120,24 @@ impl Expander {
120 self.resolve_path_as_macro(db, &path) 120 self.resolve_path_as_macro(db, &path)
121 }; 121 };
122 122
123 let call_id = match macro_call.as_call_id(db, self.crate_def_map.krate, resolver) { 123 let mut err = None;
124 let call_id =
125 macro_call.as_call_id_with_errors(db, self.crate_def_map.krate, resolver, &mut |e| {
126 err.get_or_insert(e);
127 });
128 let call_id = match call_id {
124 Some(it) => it, 129 Some(it) => it,
125 None => { 130 None => {
126 // FIXME: this can mean other things too, but `as_call_id` doesn't provide enough 131 if err.is_none() {
127 // info. 132 eprintln!("no error despite `as_call_id_with_errors` returning `None`");
128 return ExpandResult::only_err(mbe::ExpandError::Other( 133 }
129 "failed to parse or resolve macro invocation".into(), 134 return ExpandResult { value: None, err };
130 ));
131 } 135 }
132 }; 136 };
133 137
134 let err = db.macro_expand_error(call_id); 138 if err.is_none() {
139 err = db.macro_expand_error(call_id);
140 }
135 141
136 let file_id = call_id.as_file(); 142 let file_id = call_id.as_file();
137 143
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 1b22d1eec..ce2be8e2b 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -465,21 +465,37 @@ pub trait AsMacroCall {
465 db: &dyn db::DefDatabase, 465 db: &dyn db::DefDatabase,
466 krate: CrateId, 466 krate: CrateId,
467 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 467 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
468 ) -> Option<MacroCallId> {
469 self.as_call_id_with_errors(db, krate, resolver, &mut |_| ())
470 }
471
472 fn as_call_id_with_errors(
473 &self,
474 db: &dyn db::DefDatabase,
475 krate: CrateId,
476 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
477 error_sink: &mut dyn FnMut(mbe::ExpandError),
468 ) -> Option<MacroCallId>; 478 ) -> Option<MacroCallId>;
469} 479}
470 480
471impl AsMacroCall for InFile<&ast::MacroCall> { 481impl AsMacroCall for InFile<&ast::MacroCall> {
472 fn as_call_id( 482 fn as_call_id_with_errors(
473 &self, 483 &self,
474 db: &dyn db::DefDatabase, 484 db: &dyn db::DefDatabase,
475 krate: CrateId, 485 krate: CrateId,
476 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 486 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
487 error_sink: &mut dyn FnMut(mbe::ExpandError),
477 ) -> Option<MacroCallId> { 488 ) -> Option<MacroCallId> {
478 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); 489 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
479 let h = Hygiene::new(db.upcast(), self.file_id); 490 let h = Hygiene::new(db.upcast(), self.file_id);
480 let path = path::ModPath::from_src(self.value.path()?, &h)?; 491 let path = self.value.path().and_then(|path| path::ModPath::from_src(path, &h));
492
493 if path.is_none() {
494 error_sink(mbe::ExpandError::Other("malformed macro invocation".into()));
495 }
481 496
482 AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, krate, resolver) 497 AstIdWithPath::new(ast_id.file_id, ast_id.value, path?)
498 .as_call_id_with_errors(db, krate, resolver, error_sink)
483 } 499 }
484} 500}
485 501
@@ -497,22 +513,32 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
497} 513}
498 514
499impl AsMacroCall for AstIdWithPath<ast::MacroCall> { 515impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
500 fn as_call_id( 516 fn as_call_id_with_errors(
501 &self, 517 &self,
502 db: &dyn db::DefDatabase, 518 db: &dyn db::DefDatabase,
503 krate: CrateId, 519 krate: CrateId,
504 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 520 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
521 error_sink: &mut dyn FnMut(mbe::ExpandError),
505 ) -> Option<MacroCallId> { 522 ) -> Option<MacroCallId> {
506 let def: MacroDefId = resolver(self.path.clone())?; 523 let def: MacroDefId = resolver(self.path.clone()).or_else(|| {
524 error_sink(mbe::ExpandError::Other("could not resolve macro".into()));
525 None
526 })?;
507 527
508 if let MacroDefKind::BuiltInEager(_) = def.kind { 528 if let MacroDefKind::BuiltInEager(_) = def.kind {
509 let macro_call = InFile::new(self.ast_id.file_id, self.ast_id.to_node(db.upcast())); 529 let macro_call = InFile::new(self.ast_id.file_id, self.ast_id.to_node(db.upcast()));
510 let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id); 530 let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id);
511 531
512 Some( 532 Some(
513 expand_eager_macro(db.upcast(), krate, macro_call, def, &|path: ast::Path| { 533 expand_eager_macro(
514 resolver(path::ModPath::from_src(path, &hygiene)?) 534 db.upcast(),
515 })? 535 krate,
536 macro_call,
537 def,
538 &|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?),
539 error_sink,
540 )
541 .ok()?
516 .into(), 542 .into(),
517 ) 543 )
518 } else { 544 } else {
@@ -522,13 +548,18 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
522} 548}
523 549
524impl AsMacroCall for AstIdWithPath<ast::Item> { 550impl AsMacroCall for AstIdWithPath<ast::Item> {
525 fn as_call_id( 551 fn as_call_id_with_errors(
526 &self, 552 &self,
527 db: &dyn db::DefDatabase, 553 db: &dyn db::DefDatabase,
528 krate: CrateId, 554 krate: CrateId,
529 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 555 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
556 error_sink: &mut dyn FnMut(mbe::ExpandError),
530 ) -> Option<MacroCallId> { 557 ) -> Option<MacroCallId> {
531 let def = resolver(self.path.clone())?; 558 let def: MacroDefId = resolver(self.path.clone()).or_else(|| {
559 error_sink(mbe::ExpandError::Other("could not resolve macro".into()));
560 None
561 })?;
562
532 Some( 563 Some(
533 def.as_lazy_macro( 564 def.as_lazy_macro(
534 db.upcast(), 565 db.upcast(),
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index ab6b4477c..a48d08f3b 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -26,19 +26,89 @@ use crate::{
26}; 26};
27 27
28use base_db::CrateId; 28use base_db::CrateId;
29use mbe::ExpandResult;
29use parser::FragmentKind; 30use parser::FragmentKind;
30use std::sync::Arc; 31use std::sync::Arc;
31use syntax::{algo::SyntaxRewriter, SyntaxNode}; 32use syntax::{algo::SyntaxRewriter, SyntaxNode};
32 33
34pub struct ErrorEmitted {
35 _private: (),
36}
37
38trait ErrorSink {
39 fn emit(&mut self, err: mbe::ExpandError);
40
41 fn option<T>(
42 &mut self,
43 opt: Option<T>,
44 error: impl FnOnce() -> mbe::ExpandError,
45 ) -> Result<T, ErrorEmitted> {
46 match opt {
47 Some(it) => Ok(it),
48 None => {
49 self.emit(error());
50 Err(ErrorEmitted { _private: () })
51 }
52 }
53 }
54
55 fn option_with<T>(
56 &mut self,
57 opt: impl FnOnce() -> Option<T>,
58 error: impl FnOnce() -> mbe::ExpandError,
59 ) -> Result<T, ErrorEmitted> {
60 self.option(opt(), error)
61 }
62
63 fn result<T>(&mut self, res: Result<T, mbe::ExpandError>) -> Result<T, ErrorEmitted> {
64 match res {
65 Ok(it) => Ok(it),
66 Err(e) => {
67 self.emit(e);
68 Err(ErrorEmitted { _private: () })
69 }
70 }
71 }
72
73 fn expand_result_option<T>(&mut self, res: ExpandResult<Option<T>>) -> Result<T, ErrorEmitted> {
74 match (res.value, res.err) {
75 (None, Some(err)) => {
76 self.emit(err);
77 Err(ErrorEmitted { _private: () })
78 }
79 (Some(value), opt_err) => {
80 if let Some(err) = opt_err {
81 self.emit(err);
82 }
83 Ok(value)
84 }
85 (None, None) => unreachable!("`ExpandResult` without value or error"),
86 }
87 }
88}
89
90impl ErrorSink for &'_ mut dyn FnMut(mbe::ExpandError) {
91 fn emit(&mut self, err: mbe::ExpandError) {
92 self(err);
93 }
94}
95
96fn err(msg: impl Into<String>) -> mbe::ExpandError {
97 mbe::ExpandError::Other(msg.into())
98}
99
33pub fn expand_eager_macro( 100pub fn expand_eager_macro(
34 db: &dyn AstDatabase, 101 db: &dyn AstDatabase,
35 krate: CrateId, 102 krate: CrateId,
36 macro_call: InFile<ast::MacroCall>, 103 macro_call: InFile<ast::MacroCall>,
37 def: MacroDefId, 104 def: MacroDefId,
38 resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, 105 resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
39) -> Option<EagerMacroId> { 106 mut error_sink: &mut dyn FnMut(mbe::ExpandError),
40 let args = macro_call.value.token_tree()?; 107) -> Result<EagerMacroId, ErrorEmitted> {
41 let parsed_args = mbe::ast_to_token_tree(&args)?.0; 108 let parsed_args = error_sink.option_with(
109 || Some(mbe::ast_to_token_tree(&macro_call.value.token_tree()?)?.0),
110 || err("malformed macro invocation"),
111 )?;
42 112
43 // Note: 113 // Note:
44 // When `lazy_expand` is called, its *parent* file must be already exists. 114 // When `lazy_expand` is called, its *parent* file must be already exists.
@@ -55,17 +125,21 @@ pub fn expand_eager_macro(
55 }); 125 });
56 let arg_file_id: MacroCallId = arg_id.into(); 126 let arg_file_id: MacroCallId = arg_id.into();
57 127
58 let parsed_args = mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr).ok()?.0; 128 let parsed_args =
129 error_sink.result(mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr))?.0;
59 let result = eager_macro_recur( 130 let result = eager_macro_recur(
60 db, 131 db,
61 InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()), 132 InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()),
62 krate, 133 krate,
63 resolver, 134 resolver,
135 error_sink,
64 )?; 136 )?;
65 let subtree = to_subtree(&result)?; 137 let subtree = error_sink.option(to_subtree(&result), || err("failed to parse macro result"))?;
66 138
67 if let MacroDefKind::BuiltInEager(eager) = def.kind { 139 if let MacroDefKind::BuiltInEager(eager) = def.kind {
68 let (subtree, fragment) = eager.expand(db, arg_id, &subtree).value?; 140 let res = eager.expand(db, arg_id, &subtree);
141
142 let (subtree, fragment) = error_sink.expand_result_option(res)?;
69 let eager = EagerCallLoc { 143 let eager = EagerCallLoc {
70 def, 144 def,
71 fragment, 145 fragment,
@@ -74,9 +148,9 @@ pub fn expand_eager_macro(
74 file_id: macro_call.file_id, 148 file_id: macro_call.file_id,
75 }; 149 };
76 150
77 Some(db.intern_eager_expansion(eager)) 151 Ok(db.intern_eager_expansion(eager))
78 } else { 152 } else {
79 None 153 panic!("called `expand_eager_macro` on non-eager macro def {:?}", def);
80 } 154 }
81} 155}
82 156
@@ -91,13 +165,16 @@ fn lazy_expand(
91 def: &MacroDefId, 165 def: &MacroDefId,
92 macro_call: InFile<ast::MacroCall>, 166 macro_call: InFile<ast::MacroCall>,
93 krate: CrateId, 167 krate: CrateId,
94) -> Option<InFile<SyntaxNode>> { 168) -> ExpandResult<Option<InFile<SyntaxNode>>> {
95 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value); 169 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
96 170
97 let id: MacroCallId = 171 let id: MacroCallId =
98 def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); 172 def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into();
99 173
100 db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)) 174 let err = db.macro_expand_error(id);
175 let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node));
176
177 ExpandResult { value, err }
101} 178}
102 179
103fn eager_macro_recur( 180fn eager_macro_recur(
@@ -105,7 +182,8 @@ fn eager_macro_recur(
105 curr: InFile<SyntaxNode>, 182 curr: InFile<SyntaxNode>,
106 krate: CrateId, 183 krate: CrateId,
107 macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, 184 macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
108) -> Option<SyntaxNode> { 185 mut error_sink: &mut dyn FnMut(mbe::ExpandError),
186) -> Result<SyntaxNode, ErrorEmitted> {
109 let original = curr.value.clone(); 187 let original = curr.value.clone();
110 188
111 let children = curr.value.descendants().filter_map(ast::MacroCall::cast); 189 let children = curr.value.descendants().filter_map(ast::MacroCall::cast);
@@ -113,7 +191,8 @@ fn eager_macro_recur(
113 191
114 // Collect replacement 192 // Collect replacement
115 for child in children { 193 for child in children {
116 let def: MacroDefId = macro_resolver(child.path()?)?; 194 let def = error_sink
195 .option_with(|| macro_resolver(child.path()?), || err("failed to resolve macro"))?;
117 let insert = match def.kind { 196 let insert = match def.kind {
118 MacroDefKind::BuiltInEager(_) => { 197 MacroDefKind::BuiltInEager(_) => {
119 let id: MacroCallId = expand_eager_macro( 198 let id: MacroCallId = expand_eager_macro(
@@ -122,17 +201,21 @@ fn eager_macro_recur(
122 curr.with_value(child.clone()), 201 curr.with_value(child.clone()),
123 def, 202 def,
124 macro_resolver, 203 macro_resolver,
204 error_sink,
125 )? 205 )?
126 .into(); 206 .into();
127 db.parse_or_expand(id.as_file())? 207 db.parse_or_expand(id.as_file())
208 .expect("successful macro expansion should be parseable")
128 } 209 }
129 MacroDefKind::Declarative 210 MacroDefKind::Declarative
130 | MacroDefKind::BuiltIn(_) 211 | MacroDefKind::BuiltIn(_)
131 | MacroDefKind::BuiltInDerive(_) 212 | MacroDefKind::BuiltInDerive(_)
132 | MacroDefKind::ProcMacro(_) => { 213 | MacroDefKind::ProcMacro(_) => {
133 let expanded = lazy_expand(db, &def, curr.with_value(child.clone()), krate)?; 214 let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate);
215 let val = error_sink.expand_result_option(res)?;
216
134 // replace macro inside 217 // replace macro inside
135 eager_macro_recur(db, expanded, krate, macro_resolver)? 218 eager_macro_recur(db, val, krate, macro_resolver, error_sink)?
136 } 219 }
137 }; 220 };
138 221
@@ -140,5 +223,5 @@ fn eager_macro_recur(
140 } 223 }
141 224
142 let res = rewriter.rewrite(&original); 225 let res = rewriter.rewrite(&original);
143 Some(res) 226 Ok(res)
144} 227}