X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=crates%2Fhir_expand%2Fsrc%2Fdb.rs;h=d6d33b4cd724f144e336c27e9fb91e67863a4cdc;hb=7b89d5ede23cbbbf4bef37b43e0d2d99752ddb51;hp=63b5022ae837d19405387e6a40ec3a8f197010c8;hpb=f87debcf87c16690e8d5e185a35d03a402a2d5bf;p=rust.git diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 63b5022ae83..d6d33b4cd72 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs @@ -3,19 +3,21 @@ use std::sync::Arc; use base_db::{salsa, SourceDatabase}; +use either::Either; use limit::Limit; -use mbe::{syntax_node_to_token_tree, ExpandError, ExpandResult}; +use mbe::syntax_node_to_token_tree; use rustc_hash::FxHashSet; use syntax::{ algo::diff, - ast::{self, HasAttrs}, + ast::{self, HasAttrs, HasDocComments}, AstNode, GreenNode, Parse, SyntaxNode, SyntaxToken, T, }; use crate::{ - ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander, - BuiltinFnLikeExpander, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, - MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, + ast_id_map::AstIdMap, fixup, hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander, + BuiltinFnLikeExpander, ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, + MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, + ProcMacroExpander, }; /// Total limit on the number of tokens produced by any macro invocation. @@ -46,10 +48,10 @@ fn expand( db: &dyn AstDatabase, id: MacroCallId, tt: &tt::Subtree, - ) -> mbe::ExpandResult { + ) -> ExpandResult { match self { - TokenExpander::DeclarativeMacro { mac, .. } => mac.expand(tt), - TokenExpander::Builtin(it) => it.expand(db, id, tt), + TokenExpander::DeclarativeMacro { mac, .. } => mac.expand(tt).map_err(Into::into), + TokenExpander::Builtin(it) => it.expand(db, id, tt).map_err(Into::into), TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt), TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt), TokenExpander::ProcMacro(_) => { @@ -103,11 +105,14 @@ fn parse_macro_expansion( /// We encode macro definitions into ids of macro calls, this what allows us /// to be incremental. #[salsa::interned] - fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId; + fn intern_macro_call(&self, macro_call: MacroCallLoc) -> MacroCallId; /// Lowers syntactic macro call to a token tree representation. #[salsa::transparent] - fn macro_arg(&self, id: MacroCallId) -> Option>; + fn macro_arg( + &self, + id: MacroCallId, + ) -> Option>; /// Extracts syntax node, corresponding to a macro call. That's a firewall /// query, only typing in the macro call itself changes the returned /// subtree. @@ -139,21 +144,31 @@ pub fn expand_speculative( speculative_args: &SyntaxNode, token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, SyntaxToken)> { - let loc = db.lookup_intern_macro(actual_macro_call); + let loc = db.lookup_intern_macro_call(actual_macro_call); let macro_def = db.macro_def(loc.def).ok()?; let token_range = token_to_map.text_range(); // Build the subtree and token mapping for the speculative args let censor = censor_for_macro_input(&loc, &speculative_args); - let (mut tt, spec_args_tmap) = - mbe::syntax_node_to_token_tree_censored(&speculative_args, &censor); + let mut fixups = fixup::fixup_syntax(&speculative_args); + fixups.replace.extend(censor.into_iter().map(|node| (node, Vec::new()))); + let (mut tt, spec_args_tmap, _) = mbe::syntax_node_to_token_tree_with_modifications( + &speculative_args, + fixups.token_map, + fixups.next_id, + fixups.replace, + fixups.append, + ); let (attr_arg, token_id) = match loc.kind { MacroCallKind::Attr { invoc_attr_index, .. } => { // Attributes may have an input token tree, build the subtree and map for this as well // then try finding a token id for our token if it is inside this input subtree. let item = ast::Item::cast(speculative_args.clone())?; - let attr = item.attrs().nth(invoc_attr_index as usize)?; + let attr = item + .doc_comments_and_attrs() + .nth(invoc_attr_index as usize) + .and_then(Either::left)?; match attr.token_tree() { Some(token_tree) => { let (mut tree, map) = syntax_node_to_token_tree(attr.token_tree()?.syntax()); @@ -190,7 +205,7 @@ pub fn expand_speculative( // Do the actual expansion, we need to directly expand the proc macro due to the attribute args // Otherwise the expand query will fetch the non speculative attribute args and pass those instead. - let speculative_expansion = if let MacroDefKind::ProcMacro(expander, ..) = loc.def.kind { + let mut speculative_expansion = if let MacroDefKind::ProcMacro(expander, ..) = loc.def.kind { tt.delimiter = None; expander.expand(db, loc.krate, &tt, attr_arg.as_ref()) } else { @@ -198,8 +213,8 @@ pub fn expand_speculative( }; let expand_to = macro_expand_to(db, actual_macro_call); - let (node, rev_tmap) = - token_tree_to_syntax_node(&speculative_expansion.value, expand_to).ok()?; + fixup::reverse_fixups(&mut speculative_expansion.value, &spec_args_tmap, &fixups.undo_info); + let (node, rev_tmap) = token_tree_to_syntax_node(&speculative_expansion.value, expand_to); let range = rev_tmap.first_range_by_token(token_id, token_to_map.kind())?; let token = node.syntax_node().covering_element(range).into_token()?; @@ -215,6 +230,8 @@ fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option Some(db.parse(file_id).tree().syntax().clone()), HirFileIdRepr::MacroFile(macro_file) => { + // FIXME: Note how we convert from `Parse` to `SyntaxNode` here, + // forgetting about parse errors. db.parse_macro_expansion(macro_file).value.map(|(it, _)| it.syntax_node()) } } @@ -231,7 +248,7 @@ fn parse_macro_expansion( // Note: // The final goal we would like to make all parse_macro success, // such that the following log will not call anyway. - let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id); + let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); let node = loc.kind.to_node(db); // collect parent information for warning log @@ -258,17 +275,7 @@ fn parse_macro_expansion( tracing::debug!("expanded = {}", tt.as_debug_string()); tracing::debug!("kind = {:?}", expand_to); - let (parse, rev_token_map) = match token_tree_to_syntax_node(&tt, expand_to) { - Ok(it) => it, - Err(err) => { - tracing::debug!( - "failed to parse expansion to {:?} = {}", - expand_to, - tt.as_debug_string() - ); - return ExpandResult::only_err(err); - } - }; + let (parse, rev_token_map) = token_tree_to_syntax_node(&tt, expand_to); match result.err { Some(err) => { @@ -294,20 +301,31 @@ fn parse_macro_expansion( } } -fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option> { +fn macro_arg( + db: &dyn AstDatabase, + id: MacroCallId, +) -> Option> { let arg = db.macro_arg_text(id)?; - let loc = db.lookup_intern_macro(id); + let loc = db.lookup_intern_macro_call(id); let node = SyntaxNode::new_root(arg); let censor = censor_for_macro_input(&loc, &node); - let (mut tt, tmap) = mbe::syntax_node_to_token_tree_censored(&node, &censor); + let mut fixups = fixup::fixup_syntax(&node); + fixups.replace.extend(censor.into_iter().map(|node| (node, Vec::new()))); + let (mut tt, tmap, _) = mbe::syntax_node_to_token_tree_with_modifications( + &node, + fixups.token_map, + fixups.next_id, + fixups.replace, + fixups.append, + ); if loc.def.is_proc_macro() { // proc macros expect their inputs without parentheses, MBEs expect it with them included tt.delimiter = None; } - Some(Arc::new((tt, tmap))) + Some(Arc::new((tt, tmap, fixups.undo_info))) } fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet { @@ -319,15 +337,18 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet return None, MacroCallKind::Attr { invoc_attr_index, .. } => { cov_mark::hit!(attribute_macro_attr_censoring); ast::Item::cast(node.clone())? - .attrs() + .doc_comments_and_attrs() .nth(invoc_attr_index as usize) + .and_then(Either::left) .map(|attr| attr.syntax().clone()) .into_iter() .collect() @@ -339,7 +360,7 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet Option { - let loc = db.lookup_intern_macro(id); + let loc = db.lookup_intern_macro_call(id); let arg = loc.kind.arg(db)?; if matches!(loc.kind, MacroCallKind::FnLike { .. }) { let first = arg.first_child_or_token().map_or(T![.], |it| it.kind()); @@ -394,7 +415,7 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Result, MacroDefKind::BuiltInEager(..) => { // FIXME: Return a random error here just to make the types align. // This obviously should do something real instead. - Err(mbe::ParseError::UnexpectedToken("unexpected eager macro".to_string())) + Err(mbe::ParseError::UnexpectedToken("unexpected eager macro".into())) } MacroDefKind::ProcMacro(expander, ..) => Ok(Arc::new(TokenExpander::ProcMacro(expander))), } @@ -402,7 +423,7 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Result, fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult>> { let _p = profile::span("macro_expand"); - let loc: MacroCallLoc = db.lookup_intern_macro(id); + let loc: MacroCallLoc = db.lookup_intern_macro_call(id); if let Some(eager) = &loc.eager { return ExpandResult { value: Some(eager.arg_or_expansion.clone()), @@ -413,7 +434,11 @@ fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult it, - None => return ExpandResult::str_err("Failed to lower macro args to token tree".into()), + None => { + return ExpandResult::only_err(ExpandError::Other( + "Failed to lower macro args to token tree".into(), + )) + } }; let expander = match db.macro_def(loc.def) { @@ -421,20 +446,28 @@ fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult return ExpandResult::str_err(format!("invalid macro definition: {}", err)), + Err(err) => { + return ExpandResult::only_err(ExpandError::Other( + format!("invalid macro definition: {}", err).into(), + )) + } }; - let ExpandResult { value: tt, err } = expander.expand(db, id, ¯o_arg.0); + let ExpandResult { value: mut tt, err } = expander.expand(db, id, ¯o_arg.0); // Set a hard limit for the expanded tt let count = tt.count(); - // XXX: Make ExpandResult a real error and use .map_err instead? if TOKEN_LIMIT.check(count).is_err() { - return ExpandResult::str_err(format!( - "macro invocation exceeds token limit: produced {} tokens, limit is {}", - count, - TOKEN_LIMIT.inner(), + return ExpandResult::only_err(ExpandError::Other( + format!( + "macro invocation exceeds token limit: produced {} tokens, limit is {}", + count, + TOKEN_LIMIT.inner(), + ) + .into(), )); } + fixup::reverse_fixups(&mut tt, ¯o_arg.1, ¯o_arg.2); + ExpandResult { value: Some(Arc::new(tt)), err } } @@ -443,10 +476,12 @@ fn macro_expand_error(db: &dyn AstDatabase, macro_call: MacroCallId) -> Option ExpandResult { - let loc: MacroCallLoc = db.lookup_intern_macro(id); + let loc: MacroCallLoc = db.lookup_intern_macro_call(id); let macro_arg = match db.macro_arg(id) { Some(it) => it, - None => return ExpandResult::str_err("No arguments for proc-macro".to_string()), + None => { + return ExpandResult::only_err(ExpandError::Other("No arguments for proc-macro".into())) + } }; let expander = match loc.def.kind { @@ -488,20 +523,20 @@ fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc } fn macro_expand_to(db: &dyn AstDatabase, id: MacroCallId) -> ExpandTo { - let loc: MacroCallLoc = db.lookup_intern_macro(id); + let loc: MacroCallLoc = db.lookup_intern_macro_call(id); loc.kind.expand_to() } fn token_tree_to_syntax_node( tt: &tt::Subtree, expand_to: ExpandTo, -) -> Result<(Parse, mbe::TokenMap), ExpandError> { +) -> (Parse, mbe::TokenMap) { let entry_point = match expand_to { - ExpandTo::Statements => mbe::ParserEntryPoint::Statements, - ExpandTo::Items => mbe::ParserEntryPoint::Items, - ExpandTo::Pattern => mbe::ParserEntryPoint::Pattern, - ExpandTo::Type => mbe::ParserEntryPoint::Type, - ExpandTo::Expr => mbe::ParserEntryPoint::Expr, + ExpandTo::Statements => mbe::TopEntryPoint::MacroStmts, + ExpandTo::Items => mbe::TopEntryPoint::MacroItems, + ExpandTo::Pattern => mbe::TopEntryPoint::Pattern, + ExpandTo::Type => mbe::TopEntryPoint::Type, + ExpandTo::Expr => mbe::TopEntryPoint::Expr, }; mbe::token_tree_to_syntax_node(tt, entry_point) }