internal: remove accidental code re-use

FragmentKind played two roles:

* entry point to the parser
* syntactic category of a macro call

These are different use-cases, and warrant different types. For example,
macro can't expand to visibility, but we have such fragment today.

This PR introduces `ExpandsTo` enum to separate this two use-cases.

I suspect we might further split `FragmentKind` into `$x:specifier` enum
specific to MBE, and a general parser entry point, but that's for
another PR!
This commit is contained in:
Aleksey Kladov 2021-09-05 22:30:06 +03:00
parent 847d0faf92
commit dbb702cfc1
18 changed files with 168 additions and 135 deletions

View file

@ -3,7 +3,6 @@
use tracing::debug;
use mbe::ExpandResult;
use parser::FragmentKind;
use syntax::{
ast::{self, AstNode, GenericParamsOwner, ModuleItemOwner, NameOwner},
match_ast,
@ -73,7 +72,7 @@ struct BasicAdtInfo {
}
fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> {
let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, FragmentKind::Items)?; // FragmentKind::Items doesn't parse attrs?
let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::FragmentKind::Items)?; // FragmentKind::Items doesn't parse attrs?
let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| {
debug!("derive node didn't parse");
mbe::ExpandError::UnexpectedToken

View file

@ -554,17 +554,19 @@ fn option_env_expand(
#[cfg(test)]
mod tests {
use super::*;
use crate::{
name::AsName, test_db::TestDB, AstNode, EagerCallInfo, MacroCallId, MacroCallKind,
MacroCallLoc,
};
use std::sync::Arc;
use base_db::{fixture::WithFixture, SourceDatabase};
use expect_test::{expect, Expect};
use parser::FragmentKind;
use std::sync::Arc;
use syntax::ast::NameOwner;
use crate::{
name::AsName, test_db::TestDB, AstNode, EagerCallInfo, ExpandTo, MacroCallId,
MacroCallKind, MacroCallLoc,
};
use super::*;
fn expand_builtin_macro(ra_fixture: &str) -> String {
let (db, file_id) = TestDB::with_single_file(ra_fixture);
let parsed = db.parse(file_id);
@ -599,7 +601,7 @@ mod tests {
eager: None,
kind: MacroCallKind::FnLike {
ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_call)),
fragment: FragmentKind::Expr,
expand_to: ExpandTo::Expr,
},
};
@ -614,7 +616,6 @@ mod tests {
local_inner: false,
};
let fragment = crate::to_fragment_kind(&macro_call);
let args = macro_call.token_tree().unwrap();
let parsed_args = mbe::syntax_node_to_token_tree(args.syntax()).0;
let call_id = AstId::new(file_id.into(), ast_id_map.ast_id(&macro_call));
@ -626,10 +627,11 @@ mod tests {
arg_or_expansion: Arc::new(parsed_args.clone()),
included_file: None,
}),
kind: MacroCallKind::FnLike { ast_id: call_id, fragment: FragmentKind::Expr },
kind: MacroCallKind::FnLike { ast_id: call_id, expand_to: ExpandTo::Expr },
});
let expanded = expander.expand(&db, arg_id, &parsed_args).value.unwrap();
let expand_to = crate::ExpandTo::from_call_site(&macro_call);
let loc = MacroCallLoc {
def,
krate,
@ -637,7 +639,7 @@ mod tests {
arg_or_expansion: Arc::new(expanded.subtree),
included_file: expanded.included_file,
}),
kind: MacroCallKind::FnLike { ast_id: call_id, fragment },
kind: MacroCallKind::FnLike { ast_id: call_id, expand_to },
};
let id: MacroCallId = db.intern_macro(loc);

View file

@ -6,17 +6,16 @@ use base_db::{salsa, SourceDatabase};
use itertools::Itertools;
use limit::Limit;
use mbe::{ExpandError, ExpandResult};
use parser::{FragmentKind, T};
use syntax::{
algo::diff,
ast::{self, AttrsOwner, NameOwner},
AstNode, GreenNode, Parse, SyntaxNode, SyntaxToken, TextRange,
AstNode, GreenNode, Parse, SyntaxNode, SyntaxToken, TextRange, T,
};
use crate::{
ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander,
BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc,
MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander,
BuiltinFnLikeExpander, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind,
MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander,
};
/// Total limit on the number of tokens produced by any macro invocation.
@ -157,10 +156,9 @@ pub fn expand_speculative(
let speculative_expansion = macro_def.expand(db, actual_macro_call, &tt);
let fragment_kind = macro_fragment_kind(db, actual_macro_call);
let expand_to = macro_expand_to(db, actual_macro_call);
let (node, tmap_2) =
mbe::token_tree_to_syntax_node(&speculative_expansion.value, fragment_kind).ok()?;
let (node, tmap_2) = token_tree_to_syntax_node(&speculative_expansion.value, expand_to).ok()?;
let token_id = macro_def.map_id_down(token_id);
let range = tmap_2.first_range_by_token(token_id, token_to_map.kind())?;
@ -215,17 +213,17 @@ fn parse_macro_expansion(
None => return ExpandResult { value: None, err: result.err },
};
let fragment_kind = macro_fragment_kind(db, macro_file.macro_call_id);
let expand_to = macro_expand_to(db, macro_file.macro_call_id);
tracing::debug!("expanded = {}", tt.as_debug_string());
tracing::debug!("kind = {:?}", fragment_kind);
tracing::debug!("kind = {:?}", expand_to);
let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) {
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 {:?} = {}",
fragment_kind,
expand_to,
tt.as_debug_string()
);
return ExpandResult::only_err(err);
@ -437,7 +435,21 @@ fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame>
Arc::new(HygieneFrame::new(db, file_id))
}
fn macro_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
fn macro_expand_to(db: &dyn AstDatabase, id: MacroCallId) -> ExpandTo {
let loc: MacroCallLoc = db.lookup_intern_macro(id);
loc.kind.fragment_kind()
loc.kind.expand_to()
}
fn token_tree_to_syntax_node(
tt: &tt::Subtree,
expand_to: ExpandTo,
) -> Result<(Parse<SyntaxNode>, mbe::TokenMap), ExpandError> {
let fragment = match expand_to {
ExpandTo::Statements => mbe::FragmentKind::Statements,
ExpandTo::Items => mbe::FragmentKind::Items,
ExpandTo::Pattern => mbe::FragmentKind::Pattern,
ExpandTo::Type => mbe::FragmentKind::Type,
ExpandTo::Expr => mbe::FragmentKind::Expr,
};
mbe::token_tree_to_syntax_node(tt, fragment)
}

View file

@ -18,19 +18,19 @@
//!
//!
//! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
use std::sync::Arc;
use base_db::CrateId;
use mbe::ExpandResult;
use syntax::{ted, SyntaxNode};
use crate::{
ast::{self, AstNode},
db::AstDatabase,
EagerCallInfo, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
EagerCallInfo, ExpandTo, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId,
MacroDefKind,
};
use base_db::CrateId;
use mbe::ExpandResult;
use parser::FragmentKind;
use std::sync::Arc;
use syntax::{ted, SyntaxNode};
#[derive(Debug)]
pub struct ErrorEmitted {
_private: (),
@ -113,7 +113,7 @@ pub fn expand_eager_macro(
let ast_map = db.ast_id_map(macro_call.file_id);
let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(&macro_call.value));
let fragment = crate::to_fragment_kind(&macro_call.value);
let expand_to = ExpandTo::from_call_site(&macro_call.value);
// Note:
// When `lazy_expand` is called, its *parent* file must be already exists.
@ -126,12 +126,13 @@ pub fn expand_eager_macro(
arg_or_expansion: Arc::new(parsed_args.clone()),
included_file: None,
}),
kind: MacroCallKind::FnLike { ast_id: call_id, fragment: FragmentKind::Expr },
kind: MacroCallKind::FnLike { ast_id: call_id, expand_to: ExpandTo::Expr },
});
let arg_file_id = arg_id;
let parsed_args =
diagnostic_sink.result(mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr))?.0;
let parsed_args = diagnostic_sink
.result(mbe::token_tree_to_syntax_node(&parsed_args, mbe::FragmentKind::Expr))?
.0;
let result = eager_macro_recur(
db,
InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()),
@ -153,7 +154,7 @@ pub fn expand_eager_macro(
arg_or_expansion: Arc::new(expanded.subtree),
included_file: expanded.included_file,
}),
kind: MacroCallKind::FnLike { ast_id: call_id, fragment },
kind: MacroCallKind::FnLike { ast_id: call_id, expand_to },
};
Ok(db.intern_macro(loc))
@ -176,11 +177,11 @@ fn lazy_expand(
) -> ExpandResult<Option<InFile<SyntaxNode>>> {
let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
let fragment = crate::to_fragment_kind(&macro_call.value);
let expand_to = ExpandTo::from_call_site(&macro_call.value);
let id = def.as_lazy_macro(
db,
krate,
MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), fragment },
MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), expand_to },
);
let err = db.macro_expand_error(id);

View file

@ -8,10 +8,9 @@ use base_db::CrateId;
use db::TokenExpander;
use either::Either;
use mbe::Origin;
use parser::SyntaxKind;
use syntax::{
ast::{self, AttrsOwner},
AstNode, SyntaxNode, TextRange, TextSize,
AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize,
};
use crate::{

View file

@ -19,7 +19,6 @@ use base_db::ProcMacroKind;
use either::Either;
pub use mbe::{ExpandError, ExpandResult};
pub use parser::FragmentKind;
use std::{hash::Hash, iter, sync::Arc};
@ -268,7 +267,7 @@ pub struct MacroCallLoc {
pub enum MacroCallKind {
FnLike {
ast_id: AstId<ast::MacroCall>,
fragment: FragmentKind,
expand_to: ExpandTo,
},
Derive {
ast_id: AstId<ast::Item>,
@ -327,11 +326,11 @@ impl MacroCallKind {
}
}
fn fragment_kind(&self) -> FragmentKind {
fn expand_to(&self) -> ExpandTo {
match self {
MacroCallKind::FnLike { fragment, .. } => *fragment,
MacroCallKind::Derive { .. } => FragmentKind::Items,
MacroCallKind::Attr { .. } => FragmentKind::Items, // is this always correct?
MacroCallKind::FnLike { expand_to, .. } => *expand_to,
MacroCallKind::Derive { .. } => ExpandTo::Items,
MacroCallKind::Attr { .. } => ExpandTo::Items, // is this always correct?
}
}
}
@ -653,38 +652,61 @@ impl<N: AstNode> InFile<N> {
}
}
/// Given a `MacroCallId`, return what `FragmentKind` it belongs to.
/// FIXME: Not completed
pub fn to_fragment_kind(call: &ast::MacroCall) -> FragmentKind {
use syntax::SyntaxKind::*;
/// In Rust, macros expand token trees to token trees. When we want to turn a
/// token tree into an AST node, we need to figure out what kind of AST node we
/// want: something like `foo` can be a type, an expression, or a pattern.
///
/// Naively, one would think that "what this expands to" is a property of a
/// particular macro: macro `m1` returns an item, while macro `m2` returns an
/// expression, etc. That's not the case -- macros are polymorphic in the
/// result, and can expand to any type of the AST node.
///
/// What defines the actual AST node is the syntactic context of the macro
/// invocation. As a contrived example, in `let T![*] = T![*];` the first `T`
/// expands to a pattern, while the second one expands to an expression.
///
/// `ExpandTo` captures this bit of information about a particular macro call
/// site.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ExpandTo {
Statements,
Items,
Pattern,
Type,
Expr,
}
let syn = call.syntax();
impl ExpandTo {
pub fn from_call_site(call: &ast::MacroCall) -> ExpandTo {
use syntax::SyntaxKind::*;
let parent = match syn.parent() {
Some(it) => it,
None => return FragmentKind::Statements,
};
let syn = call.syntax();
match parent.kind() {
MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => FragmentKind::Items,
MACRO_STMTS | EXPR_STMT | BLOCK_EXPR => FragmentKind::Statements,
MACRO_PAT => FragmentKind::Pattern,
MACRO_TYPE => FragmentKind::Type,
let parent = match syn.parent() {
Some(it) => it,
None => return ExpandTo::Statements,
};
ARG_LIST | TRY_EXPR | TUPLE_EXPR | PAREN_EXPR | ARRAY_EXPR | FOR_EXPR | PATH_EXPR
| CLOSURE_EXPR | CONDITION | BREAK_EXPR | RETURN_EXPR | MATCH_EXPR | MATCH_ARM
| MATCH_GUARD | RECORD_EXPR_FIELD | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR
| FIELD_EXPR | AWAIT_EXPR | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR => {
FragmentKind::Expr
}
LET_STMT => {
// FIXME: Handle LHS Pattern
FragmentKind::Expr
}
match parent.kind() {
MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => ExpandTo::Items,
MACRO_STMTS | EXPR_STMT | BLOCK_EXPR => ExpandTo::Statements,
MACRO_PAT => ExpandTo::Pattern,
MACRO_TYPE => ExpandTo::Type,
_ => {
// Unknown , Just guess it is `Items`
FragmentKind::Items
ARG_LIST | TRY_EXPR | TUPLE_EXPR | PAREN_EXPR | ARRAY_EXPR | FOR_EXPR | PATH_EXPR
| CLOSURE_EXPR | CONDITION | BREAK_EXPR | RETURN_EXPR | MATCH_EXPR | MATCH_ARM
| MATCH_GUARD | RECORD_EXPR_FIELD | CALL_EXPR | INDEX_EXPR | METHOD_CALL_EXPR
| FIELD_EXPR | AWAIT_EXPR | CAST_EXPR | REF_EXPR | PREFIX_EXPR | RANGE_EXPR
| BIN_EXPR => ExpandTo::Expr,
LET_STMT => {
// FIXME: Handle LHS Pattern
ExpandTo::Expr
}
_ => {
// Unknown , Just guess it is `Items`
ExpandTo::Items
}
}
}
}