Pass calling span through to builtin macro expansions

This commit is contained in:
Lukas Wirth 2023-12-01 13:56:25 +01:00
parent f48fa0c6cb
commit 0003e568ca
27 changed files with 623 additions and 497 deletions

View file

@ -663,7 +663,7 @@ impl<'a> AssocItemCollector<'a> {
self.module_id.local_id, self.module_id.local_id,
MacroCallKind::Attr { MacroCallKind::Attr {
ast_id, ast_id,
attr_args: Arc::new(tt::Subtree::empty()), attr_args: None,
invoc_attr_index: attr.id, invoc_attr_index: attr.id,
}, },
attr.path().clone(), attr.path().clone(),

View file

@ -1351,11 +1351,11 @@ fn attr_macro_as_call_id(
let arg = match macro_attr.input.as_deref() { let arg = match macro_attr.input.as_deref() {
Some(AttrInput::TokenTree(tt)) => { Some(AttrInput::TokenTree(tt)) => {
let mut tt = tt.as_ref().clone(); let mut tt = tt.as_ref().clone();
tt.delimiter = tt::Delimiter::UNSPECIFIED; tt.delimiter = tt::Delimiter::DUMMY_INVISIBLE;
tt Some(tt)
} }
_ => tt::Subtree::empty(), _ => None,
}; };
def.as_lazy_macro( def.as_lazy_macro(
@ -1363,7 +1363,7 @@ fn attr_macro_as_call_id(
krate, krate,
MacroCallKind::Attr { MacroCallKind::Attr {
ast_id: item_attr.ast_id, ast_id: item_attr.ast_id,
attr_args: Arc::new(arg), attr_args: arg.map(Arc::new),
invoc_attr_index: macro_attr.id, invoc_attr_index: macro_attr.id,
}, },
macro_attr.ctxt, macro_attr.ctxt,

View file

@ -138,7 +138,7 @@ macro_rules! identity {
} }
fn main(foo: ()) { fn main(foo: ()) {
builtin#FileId(0):0@0..0\0# ##FileId(0):0@0..0\0#format_args#FileId(0):0@0..0\0# (#FileId(0):3@56..57\0#"{} {} {}"#FileId(0):3@57..67\0#,#FileId(0):3@67..68\0# format_args#FileId(0):3@69..80\0#!#FileId(0):3@80..81\0#(#FileId(0):3@81..82\0#"{}"#FileId(0):3@82..86\0#,#FileId(0):3@86..87\0# 0#FileId(0):3@88..89\0#)#FileId(0):3@89..90\0#,#FileId(0):3@90..91\0# foo#FileId(0):3@92..95\0#,#FileId(0):3@95..96\0# identity#FileId(0):3@97..105\0#!#FileId(0):3@105..106\0#(#FileId(0):3@106..107\0#10#FileId(0):3@107..109\0#)#FileId(0):3@109..110\0#,#FileId(0):3@110..111\0# "bar"#FileId(0):3@112..117\0#)#FileId(0):3@117..118\0# builtin#FileId(0):3@23..118\3# ##FileId(0):3@23..118\3#format_args#FileId(0):3@23..118\3# (#FileId(0):3@56..57\0#"{} {} {}"#FileId(0):3@57..67\0#,#FileId(0):3@67..68\0# format_args#FileId(0):3@69..80\0#!#FileId(0):3@80..81\0#(#FileId(0):3@81..82\0#"{}"#FileId(0):3@82..86\0#,#FileId(0):3@86..87\0# 0#FileId(0):3@88..89\0#)#FileId(0):3@89..90\0#,#FileId(0):3@90..91\0# foo#FileId(0):3@92..95\0#,#FileId(0):3@95..96\0# identity#FileId(0):3@97..105\0#!#FileId(0):3@105..106\0#(#FileId(0):3@106..107\0#10#FileId(0):3@107..109\0#)#FileId(0):3@109..110\0#,#FileId(0):3@110..111\0# "bar"#FileId(0):3@112..117\0#)#FileId(0):3@117..118\0#
} }
"##]], "##]],

View file

@ -5,7 +5,6 @@
use std::{cmp::Ordering, iter, mem}; use std::{cmp::Ordering, iter, mem};
use ::tt::Span;
use base_db::{span::SyntaxContextId, CrateId, Dependency, Edition, FileId}; use base_db::{span::SyntaxContextId, CrateId, Dependency, Edition, FileId};
use cfg::{CfgExpr, CfgOptions}; use cfg::{CfgExpr, CfgOptions};
use either::Either; use either::Either;
@ -85,7 +84,17 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
.enumerate() .enumerate()
.map(|(idx, it)| { .map(|(idx, it)| {
// FIXME: a hacky way to create a Name from string. // FIXME: a hacky way to create a Name from string.
let name = tt::Ident { text: it.name.clone(), span: tt::SpanData::DUMMY }; let name = tt::Ident {
text: it.name.clone(),
span: tt::SpanData {
range: syntax::TextRange::empty(syntax::TextSize::new(0)),
anchor: base_db::span::SpanAnchor {
file_id: FileId::BOGUS,
ast_id: base_db::span::ROOT_ERASED_FILE_AST_ID,
},
ctx: SyntaxContextId::ROOT,
},
};
(name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32))) (name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32)))
}) })
.collect()) .collect())
@ -476,7 +485,7 @@ impl DefCollector<'_> {
directive.module_id, directive.module_id,
MacroCallKind::Attr { MacroCallKind::Attr {
ast_id: ast_id.ast_id, ast_id: ast_id.ast_id,
attr_args: Arc::new(tt::Subtree::empty()), attr_args: None,
invoc_attr_index: attr.id, invoc_attr_index: attr.id,
}, },
attr.path().clone(), attr.path().clone(),
@ -2079,7 +2088,18 @@ impl ModCollector<'_, '_> {
let name = match attrs.by_key("rustc_builtin_macro").string_value() { let name = match attrs.by_key("rustc_builtin_macro").string_value() {
Some(it) => { Some(it) => {
// FIXME: a hacky way to create a Name from string. // FIXME: a hacky way to create a Name from string.
name = tt::Ident { text: it.clone(), span: tt::SpanData::DUMMY }.as_name(); name = tt::Ident {
text: it.clone(),
span: tt::SpanData {
range: syntax::TextRange::empty(syntax::TextSize::new(0)),
anchor: base_db::span::SpanAnchor {
file_id: FileId::BOGUS,
ast_id: base_db::span::ROOT_ERASED_FILE_AST_ID,
},
ctx: SyntaxContextId::ROOT,
},
}
.as_name();
&name &name
} }
None => { None => {

View file

@ -130,7 +130,7 @@ impl RawAttrs {
let attrs = parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map( let attrs = parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map(
|(idx, attr)| { |(idx, attr)| {
let tree = Subtree { let tree = Subtree {
delimiter: tt::Delimiter::unspecified(), delimiter: tt::Delimiter::dummy_invisible(),
token_trees: attr.to_vec(), token_trees: attr.to_vec(),
}; };
Attr::from_tt(db, &tree, index.with_cfg_attr(idx)) Attr::from_tt(db, &tree, index.with_cfg_attr(idx))
@ -296,7 +296,7 @@ impl Attr {
// FIXME: This is necessarily a hack. It'd be nice if we could avoid allocation // FIXME: This is necessarily a hack. It'd be nice if we could avoid allocation
// here or maybe just parse a mod path from a token tree directly // here or maybe just parse a mod path from a token tree directly
let subtree = tt::Subtree { let subtree = tt::Subtree {
delimiter: tt::Delimiter::unspecified(), delimiter: tt::Delimiter::dummy_invisible(),
token_trees: tts.to_vec(), token_trees: tts.to_vec(),
}; };
let (parse, span_map) = let (parse, span_map) =

View file

@ -1,18 +1,22 @@
//! Builtin attributes. //! Builtin attributes.
use ::tt::Span; use base_db::{
span::{SyntaxContextId, ROOT_ERASED_FILE_AST_ID},
FileId,
};
use syntax::{TextRange, TextSize};
use crate::{db::ExpandDatabase, name, tt, ExpandResult, MacroCallId, MacroCallKind}; use crate::{db::ExpandDatabase, name, tt, ExpandResult, MacroCallId, MacroCallKind};
macro_rules! register_builtin { macro_rules! register_builtin {
( $(($name:ident, $variant:ident) => $expand:ident),* ) => { ($expand_fn:ident: $(($name:ident, $variant:ident) => $expand:ident),* ) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BuiltinAttrExpander { pub enum BuiltinAttrExpander {
$($variant),* $($variant),*
} }
impl BuiltinAttrExpander { impl BuiltinAttrExpander {
pub fn expand( pub fn $expand_fn(
&self, &self,
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
id: MacroCallId, id: MacroCallId,
@ -47,7 +51,7 @@ impl BuiltinAttrExpander {
} }
} }
register_builtin! { register_builtin! { expand:
(bench, Bench) => dummy_attr_expand, (bench, Bench) => dummy_attr_expand,
(cfg_accessible, CfgAccessible) => dummy_attr_expand, (cfg_accessible, CfgAccessible) => dummy_attr_expand,
(cfg_eval, CfgEval) => dummy_attr_expand, (cfg_eval, CfgEval) => dummy_attr_expand,
@ -99,21 +103,31 @@ fn derive_attr_expand(
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let loc = db.lookup_intern_macro_call(id); let loc = db.lookup_intern_macro_call(id);
let derives = match &loc.kind { let derives = match &loc.kind {
MacroCallKind::Attr { attr_args, .. } if loc.def.is_attribute_derive() => attr_args, MacroCallKind::Attr { attr_args: Some(attr_args), .. } if loc.def.is_attribute_derive() => {
_ => return ExpandResult::ok(tt::Subtree::empty()), attr_args
}
_ => return ExpandResult::ok(tt::Subtree::empty(tt::DelimSpan::DUMMY)),
}; };
pseudo_derive_attr_expansion(tt, derives) pseudo_derive_attr_expansion(tt, derives, loc.call_site)
} }
pub fn pseudo_derive_attr_expansion( pub fn pseudo_derive_attr_expansion(
tt: &tt::Subtree, tt: &tt::Subtree,
args: &tt::Subtree, args: &tt::Subtree,
call_site: SyntaxContextId,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let mk_leaf = |char| { let mk_leaf = |char| {
tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
char, char,
spacing: tt::Spacing::Alone, spacing: tt::Spacing::Alone,
span: tt::SpanData::DUMMY, span: tt::SpanData {
range: TextRange::empty(TextSize::new(0)),
anchor: base_db::span::SpanAnchor {
file_id: FileId::BOGUS,
ast_id: ROOT_ERASED_FILE_AST_ID,
},
ctx: call_site,
},
})) }))
}; };

View file

@ -1,6 +1,5 @@
//! Builtin derives. //! Builtin derives.
use ::tt::Span;
use base_db::{span::SpanData, CrateOrigin, LangCrateOrigin}; use base_db::{span::SpanData, CrateOrigin, LangCrateOrigin};
use itertools::izip; use itertools::izip;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
@ -74,19 +73,19 @@ enum VariantShape {
Unit, Unit,
} }
fn tuple_field_iterator(n: usize) -> impl Iterator<Item = tt::Ident> { fn tuple_field_iterator(span: SpanData, n: usize) -> impl Iterator<Item = tt::Ident> {
(0..n).map(|it| tt::Ident::new(format!("f{it}"), tt::SpanData::DUMMY)) (0..n).map(move |it| tt::Ident::new(format!("f{it}"), span))
} }
impl VariantShape { impl VariantShape {
fn as_pattern(&self, path: tt::Subtree) -> tt::Subtree { fn as_pattern(&self, path: tt::Subtree, span: SpanData) -> tt::Subtree {
self.as_pattern_map(path, |it| quote!(#it)) self.as_pattern_map(path, span, |it| quote!(span => #it))
} }
fn field_names(&self) -> Vec<tt::Ident> { fn field_names(&self, span: SpanData) -> Vec<tt::Ident> {
match self { match self {
VariantShape::Struct(s) => s.clone(), VariantShape::Struct(s) => s.clone(),
VariantShape::Tuple(n) => tuple_field_iterator(*n).collect(), VariantShape::Tuple(n) => tuple_field_iterator(span, *n).collect(),
VariantShape::Unit => vec![], VariantShape::Unit => vec![],
} }
} }
@ -94,26 +93,27 @@ impl VariantShape {
fn as_pattern_map( fn as_pattern_map(
&self, &self,
path: tt::Subtree, path: tt::Subtree,
span: SpanData,
field_map: impl Fn(&tt::Ident) -> tt::Subtree, field_map: impl Fn(&tt::Ident) -> tt::Subtree,
) -> tt::Subtree { ) -> tt::Subtree {
match self { match self {
VariantShape::Struct(fields) => { VariantShape::Struct(fields) => {
let fields = fields.iter().map(|it| { let fields = fields.iter().map(|it| {
let mapped = field_map(it); let mapped = field_map(it);
quote! { #it : #mapped , } quote! {span => #it : #mapped , }
}); });
quote! { quote! {span =>
#path { ##fields } #path { ##fields }
} }
} }
&VariantShape::Tuple(n) => { &VariantShape::Tuple(n) => {
let fields = tuple_field_iterator(n).map(|it| { let fields = tuple_field_iterator(span, n).map(|it| {
let mapped = field_map(&it); let mapped = field_map(&it);
quote! { quote! {span =>
#mapped , #mapped ,
} }
}); });
quote! { quote! {span =>
#path ( ##fields ) #path ( ##fields )
} }
} }
@ -143,17 +143,17 @@ enum AdtShape {
} }
impl AdtShape { impl AdtShape {
fn as_pattern(&self, name: &tt::Ident) -> Vec<tt::Subtree> { fn as_pattern(&self, span: SpanData, name: &tt::Ident) -> Vec<tt::Subtree> {
self.as_pattern_map(name, |it| quote!(#it)) self.as_pattern_map(name, |it| quote!(span =>#it), span)
} }
fn field_names(&self) -> Vec<Vec<tt::Ident>> { fn field_names(&self, span: SpanData) -> Vec<Vec<tt::Ident>> {
match self { match self {
AdtShape::Struct(s) => { AdtShape::Struct(s) => {
vec![s.field_names()] vec![s.field_names(span)]
} }
AdtShape::Enum { variants, .. } => { AdtShape::Enum { variants, .. } => {
variants.iter().map(|(_, fields)| fields.field_names()).collect() variants.iter().map(|(_, fields)| fields.field_names(span)).collect()
} }
AdtShape::Union => { AdtShape::Union => {
never!("using fields of union in derive is always wrong"); never!("using fields of union in derive is always wrong");
@ -166,18 +166,21 @@ impl AdtShape {
&self, &self,
name: &tt::Ident, name: &tt::Ident,
field_map: impl Fn(&tt::Ident) -> tt::Subtree, field_map: impl Fn(&tt::Ident) -> tt::Subtree,
span: SpanData,
) -> Vec<tt::Subtree> { ) -> Vec<tt::Subtree> {
match self { match self {
AdtShape::Struct(s) => { AdtShape::Struct(s) => {
vec![s.as_pattern_map(quote! { #name }, field_map)] vec![s.as_pattern_map(quote! {span => #name }, span, field_map)]
} }
AdtShape::Enum { variants, .. } => variants AdtShape::Enum { variants, .. } => variants
.iter() .iter()
.map(|(v, fields)| fields.as_pattern_map(quote! { #name :: #v }, &field_map)) .map(|(v, fields)| {
fields.as_pattern_map(quote! {span => #name :: #v }, span, &field_map)
})
.collect(), .collect(),
AdtShape::Union => { AdtShape::Union => {
never!("pattern matching on union is always wrong"); never!("pattern matching on union is always wrong");
vec![quote! { un }] vec![quote! {span => un }]
} }
} }
} }
@ -193,7 +196,11 @@ struct BasicAdtInfo {
associated_types: Vec<tt::Subtree>, associated_types: Vec<tt::Subtree>,
} }
fn parse_adt(tm: SpanMapRef<'_>, adt: &ast::Adt) -> Result<BasicAdtInfo, ExpandError> { fn parse_adt(
tm: SpanMapRef<'_>,
adt: &ast::Adt,
call_site: SpanData,
) -> Result<BasicAdtInfo, ExpandError> {
let (name, generic_param_list, shape) = match adt { let (name, generic_param_list, shape) = match adt {
ast::Adt::Struct(it) => ( ast::Adt::Struct(it) => (
it.name(), it.name(),
@ -240,7 +247,9 @@ fn parse_adt(tm: SpanMapRef<'_>, adt: &ast::Adt) -> Result<BasicAdtInfo, ExpandE
param_type_set.insert(it.as_name()); param_type_set.insert(it.as_name());
mbe::syntax_node_to_token_tree(it.syntax(), tm) mbe::syntax_node_to_token_tree(it.syntax(), tm)
} }
None => tt::Subtree::empty(), None => {
tt::Subtree::empty(::tt::DelimSpan { open: call_site, close: call_site })
}
} }
}; };
let bounds = match &param { let bounds = match &param {
@ -253,7 +262,9 @@ fn parse_adt(tm: SpanMapRef<'_>, adt: &ast::Adt) -> Result<BasicAdtInfo, ExpandE
let ty = param let ty = param
.ty() .ty()
.map(|ty| mbe::syntax_node_to_token_tree(ty.syntax(), tm)) .map(|ty| mbe::syntax_node_to_token_tree(ty.syntax(), tm))
.unwrap_or_else(tt::Subtree::empty); .unwrap_or_else(|| {
tt::Subtree::empty(::tt::DelimSpan { open: call_site, close: call_site })
});
Some(ty) Some(ty)
} else { } else {
None None
@ -338,15 +349,20 @@ fn name_to_token(
/// therefore does not get bound by the derived trait. /// therefore does not get bound by the derived trait.
fn expand_simple_derive( fn expand_simple_derive(
// FIXME: use // FIXME: use
_invoc_span: SpanData, invoc_span: SpanData,
tt: &ast::Adt, tt: &ast::Adt,
tm: SpanMapRef<'_>, tm: SpanMapRef<'_>,
trait_path: tt::Subtree, trait_path: tt::Subtree,
make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::Subtree, make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::Subtree,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let info = match parse_adt(tm, tt) { let info = match parse_adt(tm, tt, invoc_span) {
Ok(info) => info, Ok(info) => info,
Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), Err(e) => {
return ExpandResult::new(
tt::Subtree::empty(tt::DelimSpan { open: invoc_span, close: invoc_span }),
e,
)
}
}; };
let trait_body = make_trait_body(&info); let trait_body = make_trait_body(&info);
let mut where_block = vec![]; let mut where_block = vec![];
@ -357,13 +373,13 @@ fn expand_simple_derive(
let ident_ = ident.clone(); let ident_ = ident.clone();
if let Some(b) = bound { if let Some(b) = bound {
let ident = ident.clone(); let ident = ident.clone();
where_block.push(quote! { #ident : #b , }); where_block.push(quote! {invoc_span => #ident : #b , });
} }
if let Some(ty) = param_ty { if let Some(ty) = param_ty {
(quote! { const #ident : #ty , }, quote! { #ident_ , }) (quote! {invoc_span => const #ident : #ty , }, quote! {invoc_span => #ident_ , })
} else { } else {
let bound = trait_path.clone(); let bound = trait_path.clone();
(quote! { #ident : #bound , }, quote! { #ident_ , }) (quote! {invoc_span => #ident : #bound , }, quote! {invoc_span => #ident_ , })
} }
}) })
.unzip(); .unzip();
@ -371,17 +387,17 @@ fn expand_simple_derive(
where_block.extend(info.associated_types.iter().map(|it| { where_block.extend(info.associated_types.iter().map(|it| {
let it = it.clone(); let it = it.clone();
let bound = trait_path.clone(); let bound = trait_path.clone();
quote! { #it : #bound , } quote! {invoc_span => #it : #bound , }
})); }));
let name = info.name; let name = info.name;
let expanded = quote! { let expanded = quote! {invoc_span =>
impl < ##params > #trait_path for #name < ##args > where ##where_block { #trait_body } impl < ##params > #trait_path for #name < ##args > where ##where_block { #trait_body }
}; };
ExpandResult::ok(expanded) ExpandResult::ok(expanded)
} }
fn find_builtin_crate(db: &dyn ExpandDatabase, id: MacroCallId) -> tt::TokenTree { fn find_builtin_crate(db: &dyn ExpandDatabase, id: MacroCallId, span: SpanData) -> tt::TokenTree {
// FIXME: make hygiene works for builtin derive macro // FIXME: make hygiene works for builtin derive macro
// such that $crate can be used here. // such that $crate can be used here.
let cg = db.crate_graph(); let cg = db.crate_graph();
@ -389,9 +405,9 @@ fn find_builtin_crate(db: &dyn ExpandDatabase, id: MacroCallId) -> tt::TokenTree
let tt = if matches!(cg[krate].origin, CrateOrigin::Lang(LangCrateOrigin::Core)) { let tt = if matches!(cg[krate].origin, CrateOrigin::Lang(LangCrateOrigin::Core)) {
cov_mark::hit!(test_copy_expand_in_core); cov_mark::hit!(test_copy_expand_in_core);
quote! { crate } quote! {span => crate }
} else { } else {
quote! { core } quote! {span => core }
}; };
tt.token_trees[0].clone() tt.token_trees[0].clone()
@ -404,8 +420,8 @@ fn copy_expand(
tt: &ast::Adt, tt: &ast::Adt,
tm: SpanMapRef<'_>, tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let krate = find_builtin_crate(db, id); let krate = find_builtin_crate(db, id, span);
expand_simple_derive(span, tt, tm, quote! { #krate::marker::Copy }, |_| quote! {}) expand_simple_derive(span, tt, tm, quote! {span => #krate::marker::Copy }, |_| quote! {span =>})
} }
fn clone_expand( fn clone_expand(
@ -415,37 +431,35 @@ fn clone_expand(
tt: &ast::Adt, tt: &ast::Adt,
tm: SpanMapRef<'_>, tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let krate = find_builtin_crate(db, id); let krate = find_builtin_crate(db, id, span);
expand_simple_derive(span, tt, tm, quote! { #krate::clone::Clone }, |adt| { expand_simple_derive(span, tt, tm, quote! {span => #krate::clone::Clone }, |adt| {
if matches!(adt.shape, AdtShape::Union) { if matches!(adt.shape, AdtShape::Union) {
let star = let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span: tt::SpanData::DUMMY }; return quote! {span =>
return quote! {
fn clone(&self) -> Self { fn clone(&self) -> Self {
#star self #star self
} }
}; };
} }
if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) { if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) {
let star = let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span: tt::SpanData::DUMMY }; return quote! {span =>
return quote! {
fn clone(&self) -> Self { fn clone(&self) -> Self {
match #star self {} match #star self {}
} }
}; };
} }
let name = &adt.name; let name = &adt.name;
let patterns = adt.shape.as_pattern(name); let patterns = adt.shape.as_pattern(span, name);
let exprs = adt.shape.as_pattern_map(name, |it| quote! { #it .clone() }); let exprs = adt.shape.as_pattern_map(name, |it| quote! {span => #it .clone() }, span);
let arms = patterns.into_iter().zip(exprs.into_iter()).map(|(pat, expr)| { let arms = patterns.into_iter().zip(exprs.into_iter()).map(|(pat, expr)| {
let fat_arrow = fat_arrow(); let fat_arrow = fat_arrow(span);
quote! { quote! {span =>
#pat #fat_arrow #expr, #pat #fat_arrow #expr,
} }
}); });
quote! { quote! {span =>
fn clone(&self) -> Self { fn clone(&self) -> Self {
match self { match self {
##arms ##arms
@ -455,16 +469,16 @@ fn clone_expand(
}) })
} }
/// This function exists since `quote! { => }` doesn't work. /// This function exists since `quote! {span => => }` doesn't work.
fn fat_arrow() -> tt::Subtree { fn fat_arrow(span: SpanData) -> tt::Subtree {
let eq = tt::Punct { char: '=', spacing: ::tt::Spacing::Joint, span: tt::SpanData::DUMMY }; let eq = tt::Punct { char: '=', spacing: ::tt::Spacing::Joint, span };
quote! { #eq> } quote! {span => #eq> }
} }
/// This function exists since `quote! { && }` doesn't work. /// This function exists since `quote! {span => && }` doesn't work.
fn and_and() -> tt::Subtree { fn and_and(span: SpanData) -> tt::Subtree {
let and = tt::Punct { char: '&', spacing: ::tt::Spacing::Joint, span: tt::SpanData::DUMMY }; let and = tt::Punct { char: '&', spacing: ::tt::Spacing::Joint, span };
quote! { #and& } quote! {span => #and& }
} }
fn default_expand( fn default_expand(
@ -474,33 +488,37 @@ fn default_expand(
tt: &ast::Adt, tt: &ast::Adt,
tm: SpanMapRef<'_>, tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id); let krate = &find_builtin_crate(db, id, span);
expand_simple_derive(span, tt, tm, quote! { #krate::default::Default }, |adt| { expand_simple_derive(span, tt, tm, quote! {span => #krate::default::Default }, |adt| {
let body = match &adt.shape { let body = match &adt.shape {
AdtShape::Struct(fields) => { AdtShape::Struct(fields) => {
let name = &adt.name; let name = &adt.name;
fields fields.as_pattern_map(
.as_pattern_map(quote!(#name), |_| quote!(#krate::default::Default::default())) quote!(span =>#name),
span,
|_| quote!(span =>#krate::default::Default::default()),
)
} }
AdtShape::Enum { default_variant, variants } => { AdtShape::Enum { default_variant, variants } => {
if let Some(d) = default_variant { if let Some(d) = default_variant {
let (name, fields) = &variants[*d]; let (name, fields) = &variants[*d];
let adt_name = &adt.name; let adt_name = &adt.name;
fields.as_pattern_map( fields.as_pattern_map(
quote!(#adt_name :: #name), quote!(span =>#adt_name :: #name),
|_| quote!(#krate::default::Default::default()), span,
|_| quote!(span =>#krate::default::Default::default()),
) )
} else { } else {
// FIXME: Return expand error here // FIXME: Return expand error here
quote!() quote!(span =>)
} }
} }
AdtShape::Union => { AdtShape::Union => {
// FIXME: Return expand error here // FIXME: Return expand error here
quote!() quote!(span =>)
} }
}; };
quote! { quote! {span =>
fn default() -> Self { fn default() -> Self {
#body #body
} }
@ -515,38 +533,37 @@ fn debug_expand(
tt: &ast::Adt, tt: &ast::Adt,
tm: SpanMapRef<'_>, tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id); let krate = &find_builtin_crate(db, id, span);
expand_simple_derive(span, tt, tm, quote! { #krate::fmt::Debug }, |adt| { expand_simple_derive(span, tt, tm, quote! {span => #krate::fmt::Debug }, |adt| {
let for_variant = |name: String, v: &VariantShape| match v { let for_variant = |name: String, v: &VariantShape| match v {
VariantShape::Struct(fields) => { VariantShape::Struct(fields) => {
let for_fields = fields.iter().map(|it| { let for_fields = fields.iter().map(|it| {
let x_string = it.to_string(); let x_string = it.to_string();
quote! { quote! {span =>
.field(#x_string, & #it) .field(#x_string, & #it)
} }
}); });
quote! { quote! {span =>
f.debug_struct(#name) ##for_fields .finish() f.debug_struct(#name) ##for_fields .finish()
} }
} }
VariantShape::Tuple(n) => { VariantShape::Tuple(n) => {
let for_fields = tuple_field_iterator(*n).map(|it| { let for_fields = tuple_field_iterator(span, *n).map(|it| {
quote! { quote! {span =>
.field( & #it) .field( & #it)
} }
}); });
quote! { quote! {span =>
f.debug_tuple(#name) ##for_fields .finish() f.debug_tuple(#name) ##for_fields .finish()
} }
} }
VariantShape::Unit => quote! { VariantShape::Unit => quote! {span =>
f.write_str(#name) f.write_str(#name)
}, },
}; };
if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) { if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) {
let star = let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span: tt::SpanData::DUMMY }; return quote! {span =>
return quote! {
fn fmt(&self, f: &mut #krate::fmt::Formatter) -> #krate::fmt::Result { fn fmt(&self, f: &mut #krate::fmt::Formatter) -> #krate::fmt::Result {
match #star self {} match #star self {}
} }
@ -554,20 +571,20 @@ fn debug_expand(
} }
let arms = match &adt.shape { let arms = match &adt.shape {
AdtShape::Struct(fields) => { AdtShape::Struct(fields) => {
let fat_arrow = fat_arrow(); let fat_arrow = fat_arrow(span);
let name = &adt.name; let name = &adt.name;
let pat = fields.as_pattern(quote!(#name)); let pat = fields.as_pattern(quote!(span =>#name), span);
let expr = for_variant(name.to_string(), fields); let expr = for_variant(name.to_string(), fields);
vec![quote! { #pat #fat_arrow #expr }] vec![quote! {span => #pat #fat_arrow #expr }]
} }
AdtShape::Enum { variants, .. } => variants AdtShape::Enum { variants, .. } => variants
.iter() .iter()
.map(|(name, v)| { .map(|(name, v)| {
let fat_arrow = fat_arrow(); let fat_arrow = fat_arrow(span);
let adt_name = &adt.name; let adt_name = &adt.name;
let pat = v.as_pattern(quote!(#adt_name :: #name)); let pat = v.as_pattern(quote!(span =>#adt_name :: #name), span);
let expr = for_variant(name.to_string(), v); let expr = for_variant(name.to_string(), v);
quote! { quote! {span =>
#pat #fat_arrow #expr , #pat #fat_arrow #expr ,
} }
}) })
@ -577,7 +594,7 @@ fn debug_expand(
vec![] vec![]
} }
}; };
quote! { quote! {span =>
fn fmt(&self, f: &mut #krate::fmt::Formatter) -> #krate::fmt::Result { fn fmt(&self, f: &mut #krate::fmt::Formatter) -> #krate::fmt::Result {
match self { match self {
##arms ##arms
@ -594,41 +611,42 @@ fn hash_expand(
tt: &ast::Adt, tt: &ast::Adt,
tm: SpanMapRef<'_>, tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id); let krate = &find_builtin_crate(db, id, span);
expand_simple_derive(span, tt, tm, quote! { #krate::hash::Hash }, |adt| { expand_simple_derive(span, tt, tm, quote! {span => #krate::hash::Hash }, |adt| {
if matches!(adt.shape, AdtShape::Union) { if matches!(adt.shape, AdtShape::Union) {
// FIXME: Return expand error here // FIXME: Return expand error here
return quote! {}; return quote! {span =>};
} }
if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) { if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) {
let star = let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span: tt::SpanData::DUMMY }; return quote! {span =>
return quote! {
fn hash<H: #krate::hash::Hasher>(&self, ra_expand_state: &mut H) { fn hash<H: #krate::hash::Hasher>(&self, ra_expand_state: &mut H) {
match #star self {} match #star self {}
} }
}; };
} }
let arms = adt.shape.as_pattern(&adt.name).into_iter().zip(adt.shape.field_names()).map( let arms =
|(pat, names)| { adt.shape.as_pattern(span, &adt.name).into_iter().zip(adt.shape.field_names(span)).map(
let expr = { |(pat, names)| {
let it = names.iter().map(|it| quote! { #it . hash(ra_expand_state); }); let expr = {
quote! { { let it =
##it names.iter().map(|it| quote! {span => #it . hash(ra_expand_state); });
} } quote! {span => {
}; ##it
let fat_arrow = fat_arrow(); } }
quote! { };
#pat #fat_arrow #expr , let fat_arrow = fat_arrow(span);
} quote! {span =>
}, #pat #fat_arrow #expr ,
); }
},
);
let check_discriminant = if matches!(&adt.shape, AdtShape::Enum { .. }) { let check_discriminant = if matches!(&adt.shape, AdtShape::Enum { .. }) {
quote! { #krate::mem::discriminant(self).hash(ra_expand_state); } quote! {span => #krate::mem::discriminant(self).hash(ra_expand_state); }
} else { } else {
quote! {} quote! {span =>}
}; };
quote! { quote! {span =>
fn hash<H: #krate::hash::Hasher>(&self, ra_expand_state: &mut H) { fn hash<H: #krate::hash::Hasher>(&self, ra_expand_state: &mut H) {
#check_discriminant #check_discriminant
match self { match self {
@ -646,8 +664,8 @@ fn eq_expand(
tt: &ast::Adt, tt: &ast::Adt,
tm: SpanMapRef<'_>, tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let krate = find_builtin_crate(db, id); let krate = find_builtin_crate(db, id, span);
expand_simple_derive(span, tt, tm, quote! { #krate::cmp::Eq }, |_| quote! {}) expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>})
} }
fn partial_eq_expand( fn partial_eq_expand(
@ -657,43 +675,43 @@ fn partial_eq_expand(
tt: &ast::Adt, tt: &ast::Adt,
tm: SpanMapRef<'_>, tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let krate = find_builtin_crate(db, id); let krate = find_builtin_crate(db, id, span);
expand_simple_derive(span, tt, tm, quote! { #krate::cmp::PartialEq }, |adt| { expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialEq }, |adt| {
if matches!(adt.shape, AdtShape::Union) { if matches!(adt.shape, AdtShape::Union) {
// FIXME: Return expand error here // FIXME: Return expand error here
return quote! {}; return quote! {span =>};
} }
let name = &adt.name; let name = &adt.name;
let (self_patterns, other_patterns) = self_and_other_patterns(adt, name); let (self_patterns, other_patterns) = self_and_other_patterns(adt, name, span);
let arms = izip!(self_patterns, other_patterns, adt.shape.field_names()).map( let arms = izip!(self_patterns, other_patterns, adt.shape.field_names(span)).map(
|(pat1, pat2, names)| { |(pat1, pat2, names)| {
let fat_arrow = fat_arrow(); let fat_arrow = fat_arrow(span);
let body = match &*names { let body = match &*names {
[] => { [] => {
quote!(true) quote!(span =>true)
} }
[first, rest @ ..] => { [first, rest @ ..] => {
let rest = rest.iter().map(|it| { let rest = rest.iter().map(|it| {
let t1 = tt::Ident::new(format!("{}_self", it.text), it.span); let t1 = tt::Ident::new(format!("{}_self", it.text), it.span);
let t2 = tt::Ident::new(format!("{}_other", it.text), it.span); let t2 = tt::Ident::new(format!("{}_other", it.text), it.span);
let and_and = and_and(); let and_and = and_and(span);
quote!(#and_and #t1 .eq( #t2 )) quote!(span =>#and_and #t1 .eq( #t2 ))
}); });
let first = { let first = {
let t1 = tt::Ident::new(format!("{}_self", first.text), first.span); let t1 = tt::Ident::new(format!("{}_self", first.text), first.span);
let t2 = tt::Ident::new(format!("{}_other", first.text), first.span); let t2 = tt::Ident::new(format!("{}_other", first.text), first.span);
quote!(#t1 .eq( #t2 )) quote!(span =>#t1 .eq( #t2 ))
}; };
quote!(#first ##rest) quote!(span =>#first ##rest)
} }
}; };
quote! { ( #pat1 , #pat2 ) #fat_arrow #body , } quote! {span => ( #pat1 , #pat2 ) #fat_arrow #body , }
}, },
); );
let fat_arrow = fat_arrow(); let fat_arrow = fat_arrow(span);
quote! { quote! {span =>
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
match (self, other) { match (self, other) {
##arms ##arms
@ -707,15 +725,24 @@ fn partial_eq_expand(
fn self_and_other_patterns( fn self_and_other_patterns(
adt: &BasicAdtInfo, adt: &BasicAdtInfo,
name: &tt::Ident, name: &tt::Ident,
span: SpanData,
) -> (Vec<tt::Subtree>, Vec<tt::Subtree>) { ) -> (Vec<tt::Subtree>, Vec<tt::Subtree>) {
let self_patterns = adt.shape.as_pattern_map(name, |it| { let self_patterns = adt.shape.as_pattern_map(
let t = tt::Ident::new(format!("{}_self", it.text), it.span); name,
quote!(#t) |it| {
}); let t = tt::Ident::new(format!("{}_self", it.text), it.span);
let other_patterns = adt.shape.as_pattern_map(name, |it| { quote!(span =>#t)
let t = tt::Ident::new(format!("{}_other", it.text), it.span); },
quote!(#t) span,
}); );
let other_patterns = adt.shape.as_pattern_map(
name,
|it| {
let t = tt::Ident::new(format!("{}_other", it.text), it.span);
quote!(span =>#t)
},
span,
);
(self_patterns, other_patterns) (self_patterns, other_patterns)
} }
@ -726,17 +753,18 @@ fn ord_expand(
tt: &ast::Adt, tt: &ast::Adt,
tm: SpanMapRef<'_>, tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id); let krate = &find_builtin_crate(db, id, span);
expand_simple_derive(span, tt, tm, quote! { #krate::cmp::Ord }, |adt| { expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Ord }, |adt| {
fn compare( fn compare(
krate: &tt::TokenTree, krate: &tt::TokenTree,
left: tt::Subtree, left: tt::Subtree,
right: tt::Subtree, right: tt::Subtree,
rest: tt::Subtree, rest: tt::Subtree,
span: SpanData,
) -> tt::Subtree { ) -> tt::Subtree {
let fat_arrow1 = fat_arrow(); let fat_arrow1 = fat_arrow(span);
let fat_arrow2 = fat_arrow(); let fat_arrow2 = fat_arrow(span);
quote! { quote! {span =>
match #left.cmp(&#right) { match #left.cmp(&#right) {
#krate::cmp::Ordering::Equal #fat_arrow1 { #krate::cmp::Ordering::Equal #fat_arrow1 {
#rest #rest
@ -747,34 +775,34 @@ fn ord_expand(
} }
if matches!(adt.shape, AdtShape::Union) { if matches!(adt.shape, AdtShape::Union) {
// FIXME: Return expand error here // FIXME: Return expand error here
return quote!(); return quote!(span =>);
} }
let (self_patterns, other_patterns) = self_and_other_patterns(adt, &adt.name); let (self_patterns, other_patterns) = self_and_other_patterns(adt, &adt.name, span);
let arms = izip!(self_patterns, other_patterns, adt.shape.field_names()).map( let arms = izip!(self_patterns, other_patterns, adt.shape.field_names(span)).map(
|(pat1, pat2, fields)| { |(pat1, pat2, fields)| {
let mut body = quote!(#krate::cmp::Ordering::Equal); let mut body = quote!(span =>#krate::cmp::Ordering::Equal);
for f in fields.into_iter().rev() { for f in fields.into_iter().rev() {
let t1 = tt::Ident::new(format!("{}_self", f.text), f.span); let t1 = tt::Ident::new(format!("{}_self", f.text), f.span);
let t2 = tt::Ident::new(format!("{}_other", f.text), f.span); let t2 = tt::Ident::new(format!("{}_other", f.text), f.span);
body = compare(krate, quote!(#t1), quote!(#t2), body); body = compare(krate, quote!(span =>#t1), quote!(span =>#t2), body, span);
} }
let fat_arrow = fat_arrow(); let fat_arrow = fat_arrow(span);
quote! { ( #pat1 , #pat2 ) #fat_arrow #body , } quote! {span => ( #pat1 , #pat2 ) #fat_arrow #body , }
}, },
); );
let fat_arrow = fat_arrow(); let fat_arrow = fat_arrow(span);
let mut body = quote! { let mut body = quote! {span =>
match (self, other) { match (self, other) {
##arms ##arms
_unused #fat_arrow #krate::cmp::Ordering::Equal _unused #fat_arrow #krate::cmp::Ordering::Equal
} }
}; };
if matches!(&adt.shape, AdtShape::Enum { .. }) { if matches!(&adt.shape, AdtShape::Enum { .. }) {
let left = quote!(#krate::intrinsics::discriminant_value(self)); let left = quote!(span =>#krate::intrinsics::discriminant_value(self));
let right = quote!(#krate::intrinsics::discriminant_value(other)); let right = quote!(span =>#krate::intrinsics::discriminant_value(other));
body = compare(krate, left, right, body); body = compare(krate, left, right, body, span);
} }
quote! { quote! {span =>
fn cmp(&self, other: &Self) -> #krate::cmp::Ordering { fn cmp(&self, other: &Self) -> #krate::cmp::Ordering {
#body #body
} }
@ -789,17 +817,18 @@ fn partial_ord_expand(
tt: &ast::Adt, tt: &ast::Adt,
tm: SpanMapRef<'_>, tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id); let krate = &find_builtin_crate(db, id, span);
expand_simple_derive(span, tt, tm, quote! { #krate::cmp::PartialOrd }, |adt| { expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialOrd }, |adt| {
fn compare( fn compare(
krate: &tt::TokenTree, krate: &tt::TokenTree,
left: tt::Subtree, left: tt::Subtree,
right: tt::Subtree, right: tt::Subtree,
rest: tt::Subtree, rest: tt::Subtree,
span: SpanData,
) -> tt::Subtree { ) -> tt::Subtree {
let fat_arrow1 = fat_arrow(); let fat_arrow1 = fat_arrow(span);
let fat_arrow2 = fat_arrow(); let fat_arrow2 = fat_arrow(span);
quote! { quote! {span =>
match #left.partial_cmp(&#right) { match #left.partial_cmp(&#right) {
#krate::option::Option::Some(#krate::cmp::Ordering::Equal) #fat_arrow1 { #krate::option::Option::Some(#krate::cmp::Ordering::Equal) #fat_arrow1 {
#rest #rest
@ -810,37 +839,39 @@ fn partial_ord_expand(
} }
if matches!(adt.shape, AdtShape::Union) { if matches!(adt.shape, AdtShape::Union) {
// FIXME: Return expand error here // FIXME: Return expand error here
return quote!(); return quote!(span =>);
} }
let left = quote!(#krate::intrinsics::discriminant_value(self)); let left = quote!(span =>#krate::intrinsics::discriminant_value(self));
let right = quote!(#krate::intrinsics::discriminant_value(other)); let right = quote!(span =>#krate::intrinsics::discriminant_value(other));
let (self_patterns, other_patterns) = self_and_other_patterns(adt, &adt.name); let (self_patterns, other_patterns) = self_and_other_patterns(adt, &adt.name, span);
let arms = izip!(self_patterns, other_patterns, adt.shape.field_names()).map( let arms = izip!(self_patterns, other_patterns, adt.shape.field_names(span)).map(
|(pat1, pat2, fields)| { |(pat1, pat2, fields)| {
let mut body = quote!(#krate::option::Option::Some(#krate::cmp::Ordering::Equal)); let mut body =
quote!(span =>#krate::option::Option::Some(#krate::cmp::Ordering::Equal));
for f in fields.into_iter().rev() { for f in fields.into_iter().rev() {
let t1 = tt::Ident::new(format!("{}_self", f.text), f.span); let t1 = tt::Ident::new(format!("{}_self", f.text), f.span);
let t2 = tt::Ident::new(format!("{}_other", f.text), f.span); let t2 = tt::Ident::new(format!("{}_other", f.text), f.span);
body = compare(krate, quote!(#t1), quote!(#t2), body); body = compare(krate, quote!(span =>#t1), quote!(span =>#t2), body, span);
} }
let fat_arrow = fat_arrow(); let fat_arrow = fat_arrow(span);
quote! { ( #pat1 , #pat2 ) #fat_arrow #body , } quote! {span => ( #pat1 , #pat2 ) #fat_arrow #body , }
}, },
); );
let fat_arrow = fat_arrow(); let fat_arrow = fat_arrow(span);
let body = compare( let body = compare(
krate, krate,
left, left,
right, right,
quote! { quote! {span =>
match (self, other) { match (self, other) {
##arms ##arms
_unused #fat_arrow #krate::option::Option::Some(#krate::cmp::Ordering::Equal) _unused #fat_arrow #krate::option::Option::Some(#krate::cmp::Ordering::Equal)
} }
}, },
span,
); );
quote! { quote! {span =>
fn partial_cmp(&self, other: &Self) -> #krate::option::Option::Option<#krate::cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> #krate::option::Option::Option<#krate::cmp::Ordering> {
#body #body
} }

View file

@ -1,8 +1,7 @@
//! Builtin macro //! Builtin macro
use ::tt::Span;
use base_db::{ use base_db::{
span::{SpanAnchor, ROOT_ERASED_FILE_AST_ID}, span::{SpanAnchor, SpanData, SyntaxContextId, ROOT_ERASED_FILE_AST_ID},
AnchoredPath, Edition, FileId, AnchoredPath, Edition, FileId,
}; };
use cfg::CfgExpr; use cfg::CfgExpr;
@ -15,8 +14,9 @@ use syntax::{
use crate::{ use crate::{
db::ExpandDatabase, db::ExpandDatabase,
hygiene::span_with_def_site_ctxt,
name, quote, name, quote,
tt::{self}, tt::{self, DelimSpan},
EagerCallInfo, ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroCallLoc, EagerCallInfo, ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroCallLoc,
}; };
@ -42,7 +42,10 @@ macro_rules! register_builtin {
let expander = match *self { let expander = match *self {
$( BuiltinFnLikeExpander::$kind => $expand, )* $( BuiltinFnLikeExpander::$kind => $expand, )*
}; };
expander(db, id, tt)
let span = db.lookup_intern_macro_call(id).span(db);
let span = span_with_def_site_ctxt(db, span, id);
expander(db, id, tt, span)
} }
} }
@ -50,13 +53,16 @@ macro_rules! register_builtin {
pub fn expand( pub fn expand(
&self, &self,
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
arg_id: MacroCallId, id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let expander = match *self { let expander = match *self {
$( EagerExpander::$e_kind => $e_expand, )* $( EagerExpander::$e_kind => $e_expand, )*
}; };
expander(db, arg_id, tt)
let span = db.lookup_intern_macro_call(id).span(db);
let span = span_with_def_site_ctxt(db, span, id);
expander(db, id, tt, span)
} }
} }
@ -115,29 +121,42 @@ register_builtin! {
(option_env, OptionEnv) => option_env_expand (option_env, OptionEnv) => option_env_expand
} }
const DOLLAR_CRATE: tt::Ident = fn mk_pound(span: SpanData) -> tt::Subtree {
tt::Ident { text: SmolStr::new_inline("$crate"), span: tt::SpanData::DUMMY }; crate::quote::IntoTt::to_subtree(
vec![crate::tt::Leaf::Punct(crate::tt::Punct {
char: '#',
spacing: crate::tt::Spacing::Alone,
span: span,
})
.into()],
span,
)
}
fn module_path_expand( fn module_path_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_id: MacroCallId, _id: MacroCallId,
_tt: &tt::Subtree, _tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
// Just return a dummy result. // Just return a dummy result.
ExpandResult::ok(quote! { "module::path" }) ExpandResult::ok(quote! {span =>
"module::path"
})
} }
fn line_expand( fn line_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_id: MacroCallId, _id: MacroCallId,
_tt: &tt::Subtree, _tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
// dummy implementation for type-checking purposes // dummy implementation for type-checking purposes
ExpandResult::ok(tt::Subtree { ExpandResult::ok(tt::Subtree {
delimiter: tt::Delimiter::unspecified(), delimiter: tt::Delimiter::dummy_invisible(),
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
text: "0u32".into(), text: "0u32".into(),
span: tt::SpanData::DUMMY, span,
}))], }))],
}) })
} }
@ -146,26 +165,29 @@ fn log_syntax_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_id: MacroCallId, _id: MacroCallId,
_tt: &tt::Subtree, _tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
ExpandResult::ok(quote! {}) ExpandResult::ok(quote! {span =>})
} }
fn trace_macros_expand( fn trace_macros_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_id: MacroCallId, _id: MacroCallId,
_tt: &tt::Subtree, _tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
ExpandResult::ok(quote! {}) ExpandResult::ok(quote! {span =>})
} }
fn stringify_expand( fn stringify_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_id: MacroCallId, _id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let pretty = ::tt::pretty(&tt.token_trees); let pretty = ::tt::pretty(&tt.token_trees);
let expanded = quote! { let expanded = quote! {span =>
#pretty #pretty
}; };
@ -176,27 +198,29 @@ fn assert_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_id: MacroCallId, _id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let args = parse_exprs_with_sep(tt, ','); let args = parse_exprs_with_sep(tt, ',');
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
let expanded = match &*args { let expanded = match &*args {
[cond, panic_args @ ..] => { [cond, panic_args @ ..] => {
let comma = tt::Subtree { let comma = tt::Subtree {
delimiter: tt::Delimiter::unspecified(), delimiter: tt::Delimiter::dummy_invisible(),
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
char: ',', char: ',',
spacing: tt::Spacing::Alone, spacing: tt::Spacing::Alone,
span: tt::SpanData::DUMMY, span,
}))], }))],
}; };
let cond = cond.clone(); let cond = cond.clone();
let panic_args = itertools::Itertools::intersperse(panic_args.iter().cloned(), comma); let panic_args = itertools::Itertools::intersperse(panic_args.iter().cloned(), comma);
quote! {{ quote! {span =>{
if !(#cond) { if !(#cond) {
#DOLLAR_CRATE::panic!(##panic_args); #dollar_crate::panic!(##panic_args);
} }
}} }}
} }
[] => quote! {{}}, [] => quote! {span =>{}},
}; };
ExpandResult::ok(expanded) ExpandResult::ok(expanded)
@ -206,12 +230,13 @@ fn file_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_id: MacroCallId, _id: MacroCallId,
_tt: &tt::Subtree, _tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
// FIXME: RA purposefully lacks knowledge of absolute file names // FIXME: RA purposefully lacks knowledge of absolute file names
// so just return "". // so just return "".
let file_name = ""; let file_name = "";
let expanded = quote! { let expanded = quote! {span =>
#file_name #file_name
}; };
@ -222,16 +247,18 @@ fn format_args_expand(
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
id: MacroCallId, id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
format_args_expand_general(db, id, tt, "") format_args_expand_general(db, id, tt, "", span)
} }
fn format_args_nl_expand( fn format_args_nl_expand(
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
id: MacroCallId, id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
format_args_expand_general(db, id, tt, "\\n") format_args_expand_general(db, id, tt, "\\n", span)
} }
fn format_args_expand_general( fn format_args_expand_general(
@ -240,11 +267,12 @@ fn format_args_expand_general(
tt: &tt::Subtree, tt: &tt::Subtree,
// FIXME: Make use of this so that mir interpretation works properly // FIXME: Make use of this so that mir interpretation works properly
_end_string: &str, _end_string: &str,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let pound = quote! {@PUNCT '#'}; let pound = mk_pound(span);
let mut tt = tt.clone(); let mut tt = tt.clone();
tt.delimiter.kind = tt::DelimiterKind::Parenthesis; tt.delimiter.kind = tt::DelimiterKind::Parenthesis;
return ExpandResult::ok(quote! { return ExpandResult::ok(quote! {span =>
builtin #pound format_args #tt builtin #pound format_args #tt
}); });
} }
@ -253,25 +281,25 @@ fn asm_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_id: MacroCallId, _id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
// We expand all assembly snippets to `format_args!` invocations to get format syntax // We expand all assembly snippets to `format_args!` invocations to get format syntax
// highlighting for them. // highlighting for them.
let mut literals = Vec::new(); let mut literals = Vec::new();
for tt in tt.token_trees.chunks(2) { for tt in tt.token_trees.chunks(2) {
match tt { match tt {
[tt::TokenTree::Leaf(tt::Leaf::Literal(lit))] [tt::TokenTree::Leaf(tt::Leaf::Literal(lit))]
| [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', span: _, spacing: _ }))] => | [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', span: _, spacing: _ }))] =>
{ {
let krate = DOLLAR_CRATE.clone(); let dollar_krate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
literals.push(quote!(#krate::format_args!(#lit);)); literals.push(quote!(span=>#dollar_krate::format_args!(#lit);));
} }
_ => break, _ => break,
} }
} }
let pound = quote! {@PUNCT '#'}; let pound = mk_pound(span);
let expanded = quote! { let expanded = quote! {span =>
builtin #pound asm ( builtin #pound asm (
{##literals} {##literals}
) )
@ -283,20 +311,22 @@ fn global_asm_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_id: MacroCallId, _id: MacroCallId,
_tt: &tt::Subtree, _tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
// Expand to nothing (at item-level) // Expand to nothing (at item-level)
ExpandResult::ok(quote! {}) ExpandResult::ok(quote! {span =>})
} }
fn cfg_expand( fn cfg_expand(
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
id: MacroCallId, id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let loc = db.lookup_intern_macro_call(id); let loc = db.lookup_intern_macro_call(id);
let expr = CfgExpr::parse(tt); let expr = CfgExpr::parse(tt);
let enabled = db.crate_graph()[loc.krate].cfg_options.check(&expr) != Some(false); let enabled = db.crate_graph()[loc.krate].cfg_options.check(&expr) != Some(false);
let expanded = if enabled { quote!(true) } else { quote!(false) }; let expanded = if enabled { quote!(span=>true) } else { quote!(span=>false) };
ExpandResult::ok(expanded) ExpandResult::ok(expanded)
} }
@ -304,13 +334,15 @@ fn panic_expand(
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
id: MacroCallId, id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let loc: MacroCallLoc = db.lookup_intern_macro_call(id); let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
// Expand to a macro call `$crate::panic::panic_{edition}` // Expand to a macro call `$crate::panic::panic_{edition}`
let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 { let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 {
quote!(#DOLLAR_CRATE::panic::panic_2021!) quote!(span =>#dollar_crate::panic::panic_2021!)
} else { } else {
quote!(#DOLLAR_CRATE::panic::panic_2015!) quote!(span =>#dollar_crate::panic::panic_2015!)
}; };
// Pass the original arguments // Pass the original arguments
@ -322,13 +354,15 @@ fn unreachable_expand(
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
id: MacroCallId, id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let loc: MacroCallLoc = db.lookup_intern_macro_call(id); let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
// Expand to a macro call `$crate::panic::unreachable_{edition}` // Expand to a macro call `$crate::panic::unreachable_{edition}`
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 { let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 {
quote!(#DOLLAR_CRATE::panic::unreachable_2021!) quote!(span =>#dollar_crate::panic::unreachable_2021!)
} else { } else {
quote!(#DOLLAR_CRATE::panic::unreachable_2015!) quote!(span =>#dollar_crate::panic::unreachable_2015!)
}; };
// Pass the original arguments // Pass the original arguments
@ -358,6 +392,7 @@ fn compile_error_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_id: MacroCallId, _id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let err = match &*tt.token_trees { let err = match &*tt.token_trees {
[tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => match unquote_str(it) { [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => match unquote_str(it) {
@ -367,13 +402,14 @@ fn compile_error_expand(
_ => ExpandError::other("`compile_error!` argument must be a string"), _ => ExpandError::other("`compile_error!` argument must be a string"),
}; };
ExpandResult { value: quote! {}, err: Some(err) } ExpandResult { value: quote! {span =>}, err: Some(err) }
} }
fn concat_expand( fn concat_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_arg_id: MacroCallId, _arg_id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let mut err = None; let mut err = None;
let mut text = String::new(); let mut text = String::new();
@ -413,13 +449,14 @@ fn concat_expand(
} }
} }
} }
ExpandResult { value: quote!(#text), err } ExpandResult { value: quote!(span =>#text), err }
} }
fn concat_bytes_expand( fn concat_bytes_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_arg_id: MacroCallId, _arg_id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let mut bytes = Vec::new(); let mut bytes = Vec::new();
let mut err = None; let mut err = None;
@ -452,8 +489,8 @@ fn concat_bytes_expand(
} }
} }
} }
let ident = tt::Ident { text: bytes.join(", ").into(), span: tt::SpanData::DUMMY }; let ident = tt::Ident { text: bytes.join(", ").into(), span };
ExpandResult { value: quote!([#ident]), err } ExpandResult { value: quote!(span =>[#ident]), err }
} }
fn concat_bytes_expand_subtree( fn concat_bytes_expand_subtree(
@ -486,6 +523,7 @@ fn concat_idents_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_arg_id: MacroCallId, _arg_id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let mut err = None; let mut err = None;
let mut ident = String::new(); let mut ident = String::new();
@ -500,8 +538,9 @@ fn concat_idents_expand(
} }
} }
} }
let ident = tt::Ident { text: ident.into(), span: tt::SpanData::DUMMY }; // FIXME merge spans
ExpandResult { value: quote!(#ident), err } let ident = tt::Ident { text: ident.into(), span };
ExpandResult { value: quote!(span =>#ident), err }
} }
fn relative_file( fn relative_file(
@ -537,10 +576,11 @@ fn include_expand(
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
arg_id: MacroCallId, arg_id: MacroCallId,
_tt: &tt::Subtree, _tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
match db.include_expand(arg_id) { match db.include_expand(arg_id) {
Ok((res, _)) => ExpandResult::ok(res.as_ref().clone()), Ok((res, _)) => ExpandResult::ok(res.as_ref().clone()),
Err(e) => ExpandResult::new(tt::Subtree::empty(), e), Err(e) => ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e),
} }
} }
@ -559,6 +599,8 @@ pub(crate) fn include_arg_to_tt(
// why are we not going through a SyntaxNode here? // why are we not going through a SyntaxNode here?
let subtree = parse_to_token_tree( let subtree = parse_to_token_tree(
SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID }, SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID },
// FIXME
SyntaxContextId::ROOT,
&db.file_text(file_id), &db.file_text(file_id),
) )
.ok_or(mbe::ExpandError::ConversionError)?; .ok_or(mbe::ExpandError::ConversionError)?;
@ -569,17 +611,18 @@ fn include_bytes_expand(
_db: &dyn ExpandDatabase, _db: &dyn ExpandDatabase,
_arg_id: MacroCallId, _arg_id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
if let Err(e) = parse_string(tt) { if let Err(e) = parse_string(tt) {
return ExpandResult::new(tt::Subtree::empty(), e); return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e);
} }
// FIXME: actually read the file here if the user asked for macro expansion // FIXME: actually read the file here if the user asked for macro expansion
let res = tt::Subtree { let res = tt::Subtree {
delimiter: tt::Delimiter::unspecified(), delimiter: tt::Delimiter::dummy_invisible(),
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
text: r#"b"""#.into(), text: r#"b"""#.into(),
span: tt::SpanData::DUMMY, span,
}))], }))],
}; };
ExpandResult::ok(res) ExpandResult::ok(res)
@ -589,10 +632,13 @@ fn include_str_expand(
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
arg_id: MacroCallId, arg_id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let path = match parse_string(tt) { let path = match parse_string(tt) {
Ok(it) => it, Ok(it) => it,
Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), Err(e) => {
return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
}
}; };
// FIXME: we're not able to read excluded files (which is most of them because // FIXME: we're not able to read excluded files (which is most of them because
@ -602,14 +648,14 @@ fn include_str_expand(
let file_id = match relative_file(db, arg_id, &path, true) { let file_id = match relative_file(db, arg_id, &path, true) {
Ok(file_id) => file_id, Ok(file_id) => file_id,
Err(_) => { Err(_) => {
return ExpandResult::ok(quote!("")); return ExpandResult::ok(quote!(span =>""));
} }
}; };
let text = db.file_text(file_id); let text = db.file_text(file_id);
let text = &*text; let text = &*text;
ExpandResult::ok(quote!(#text)) ExpandResult::ok(quote!(span =>#text))
} }
fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &str) -> Option<String> { fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &str) -> Option<String> {
@ -621,10 +667,13 @@ fn env_expand(
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
arg_id: MacroCallId, arg_id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let key = match parse_string(tt) { let key = match parse_string(tt) {
Ok(it) => it, Ok(it) => it,
Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), Err(e) => {
return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
}
}; };
let mut err = None; let mut err = None;
@ -641,7 +690,7 @@ fn env_expand(
// `include!("foo.rs"), which might go to infinite loop // `include!("foo.rs"), which might go to infinite loop
"UNRESOLVED_ENV_VAR".to_string() "UNRESOLVED_ENV_VAR".to_string()
}); });
let expanded = quote! { #s }; let expanded = quote! {span => #s };
ExpandResult { value: expanded, err } ExpandResult { value: expanded, err }
} }
@ -650,15 +699,18 @@ fn option_env_expand(
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
arg_id: MacroCallId, arg_id: MacroCallId,
tt: &tt::Subtree, tt: &tt::Subtree,
span: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let key = match parse_string(tt) { let key = match parse_string(tt) {
Ok(it) => it, Ok(it) => it,
Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), Err(e) => {
return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
}
}; };
// FIXME: Use `DOLLAR_CRATE` when that works in eager macros. // FIXME: Use `DOLLAR_CRATE` when that works in eager macros.
let expanded = match get_env_inner(db, arg_id, &key) { let expanded = match get_env_inner(db, arg_id, &key) {
None => quote! { ::core::option::Option::None::<&str> }, None => quote! {span => ::core::option::Option::None::<&str> },
Some(s) => quote! { ::core::option::Option::Some(#s) }, Some(s) => quote! {span => ::core::option::Option::Some(#s) },
}; };
ExpandResult::ok(expanded) ExpandResult::ok(expanded)

View file

@ -1,11 +1,6 @@
//! Defines database & queries for macro expansion. //! Defines database & queries for macro expansion.
use ::tt::{SpanAnchor as _, SyntaxContext}; use base_db::{salsa, span::SyntaxContextId, CrateId, Edition, FileId, SourceDatabase};
use base_db::{
salsa,
span::{SpanAnchor, SyntaxContextId},
CrateId, Edition, FileId, SourceDatabase,
};
use either::Either; use either::Either;
use limit::Limit; use limit::Limit;
use mbe::{syntax_node_to_token_tree, ValueResult}; use mbe::{syntax_node_to_token_tree, ValueResult};
@ -53,7 +48,7 @@ impl DeclarativeMacroExpander {
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
match self.mac.err() { match self.mac.err() {
Some(e) => ExpandResult::new( Some(e) => ExpandResult::new(
tt::Subtree::empty(), tt::Subtree::empty(tt::DelimSpan::DUMMY),
ExpandError::other(format!("invalid macro definition: {e}")), ExpandError::other(format!("invalid macro definition: {e}")),
), ),
None => self None => self
@ -66,7 +61,7 @@ impl DeclarativeMacroExpander {
pub fn expand_unhygienic(&self, tt: tt::Subtree) -> ExpandResult<tt::Subtree> { pub fn expand_unhygienic(&self, tt: tt::Subtree) -> ExpandResult<tt::Subtree> {
match self.mac.err() { match self.mac.err() {
Some(e) => ExpandResult::new( Some(e) => ExpandResult::new(
tt::Subtree::empty(), tt::Subtree::empty(tt::DelimSpan::DUMMY),
ExpandError::other(format!("invalid macro definition: {e}")), ExpandError::other(format!("invalid macro definition: {e}")),
), ),
None => self.mac.expand(&tt, |_| ()).map_err(Into::into), None => self.mac.expand(&tt, |_| ()).map_err(Into::into),
@ -191,7 +186,7 @@ pub fn expand_speculative(
) -> Option<(SyntaxNode, SyntaxToken)> { ) -> Option<(SyntaxNode, SyntaxToken)> {
let loc = db.lookup_intern_macro_call(actual_macro_call); let loc = db.lookup_intern_macro_call(actual_macro_call);
let span_map = RealSpanMap::absolute(SpanAnchor::DUMMY.file_id); let span_map = RealSpanMap::absolute(FileId::BOGUS);
let span_map = SpanMapRef::RealSpanMap(&span_map); let span_map = SpanMapRef::RealSpanMap(&span_map);
// Build the subtree and token mapping for the speculative args // Build the subtree and token mapping for the speculative args
@ -235,7 +230,7 @@ pub fn expand_speculative(
match attr.token_tree() { match attr.token_tree() {
Some(token_tree) => { Some(token_tree) => {
let mut tree = syntax_node_to_token_tree(token_tree.syntax(), span_map); let mut tree = syntax_node_to_token_tree(token_tree.syntax(), span_map);
tree.delimiter = tt::Delimiter::UNSPECIFIED; tree.delimiter = tt::Delimiter::DUMMY_INVISIBLE;
Some(tree) Some(tree)
} }
@ -249,7 +244,7 @@ pub fn expand_speculative(
// Otherwise the expand query will fetch the non speculative attribute args and pass those instead. // Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
let mut speculative_expansion = match loc.def.kind { let mut speculative_expansion = match loc.def.kind {
MacroDefKind::ProcMacro(expander, ..) => { MacroDefKind::ProcMacro(expander, ..) => {
tt.delimiter = tt::Delimiter::UNSPECIFIED; tt.delimiter = tt::Delimiter::DUMMY_INVISIBLE;
let call_site = loc.span(db); let call_site = loc.span(db);
expander.expand( expander.expand(
db, db,
@ -263,7 +258,7 @@ pub fn expand_speculative(
) )
} }
MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => { MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?) pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, loc.call_site)
} }
MacroDefKind::BuiltInDerive(expander, ..) => { MacroDefKind::BuiltInDerive(expander, ..) => {
// this cast is a bit sus, can we avoid losing the typedness here? // this cast is a bit sus, can we avoid losing the typedness here?
@ -286,11 +281,7 @@ pub fn expand_speculative(
let syntax_node = node.syntax_node(); let syntax_node = node.syntax_node();
let token = rev_tmap let token = rev_tmap
.ranges_with_span(tt::SpanData { .ranges_with_span(span_map.span_for_range(token_to_map.text_range()))
range: token_to_map.text_range(),
anchor: SpanAnchor::DUMMY,
ctx: SyntaxContextId::DUMMY,
})
.filter_map(|range| syntax_node.covering_element(range).into_token()) .filter_map(|range| syntax_node.covering_element(range).into_token())
.min_by_key(|t| { .min_by_key(|t| {
// prefer tokens of the same kind and text // prefer tokens of the same kind and text
@ -453,7 +444,7 @@ fn macro_arg(
if loc.def.is_proc_macro() { if loc.def.is_proc_macro() {
// proc macros expect their inputs without parentheses, MBEs expect it with them included // proc macros expect their inputs without parentheses, MBEs expect it with them included
tt.delimiter = tt::Delimiter::UNSPECIFIED; tt.delimiter = tt::Delimiter::DUMMY_INVISIBLE;
} }
if matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) { if matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) {
@ -611,7 +602,7 @@ fn macro_expand(
let Some((macro_arg, undo_info)) = value else { let Some((macro_arg, undo_info)) = value else {
return ExpandResult { return ExpandResult {
value: Arc::new(tt::Subtree { value: Arc::new(tt::Subtree {
delimiter: tt::Delimiter::UNSPECIFIED, delimiter: tt::Delimiter::DUMMY_INVISIBLE,
token_trees: Vec::new(), token_trees: Vec::new(),
}), }),
// FIXME: We should make sure to enforce an invariant that invalid macro // FIXME: We should make sure to enforce an invariant that invalid macro
@ -683,7 +674,7 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<A
let Some((macro_arg, undo_info)) = db.macro_arg(id).value else { let Some((macro_arg, undo_info)) = db.macro_arg(id).value else {
return ExpandResult { return ExpandResult {
value: Arc::new(tt::Subtree { value: Arc::new(tt::Subtree {
delimiter: tt::Delimiter::UNSPECIFIED, delimiter: tt::Delimiter::DUMMY_INVISIBLE,
token_trees: Vec::new(), token_trees: Vec::new(),
}), }),
// FIXME: We should make sure to enforce an invariant that invalid macro // FIXME: We should make sure to enforce an invariant that invalid macro
@ -698,7 +689,7 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<A
}; };
let attr_arg = match &loc.kind { let attr_arg = match &loc.kind {
MacroCallKind::Attr { attr_args, .. } => Some(&**attr_args), MacroCallKind::Attr { attr_args: Some(attr_args), .. } => Some(&**attr_args),
_ => None, _ => None,
}; };
@ -749,7 +740,7 @@ fn check_tt_count(tt: &tt::Subtree) -> Result<(), ExpandResult<Arc<tt::Subtree>>
if TOKEN_LIMIT.check(count).is_err() { if TOKEN_LIMIT.check(count).is_err() {
Err(ExpandResult { Err(ExpandResult {
value: Arc::new(tt::Subtree { value: Arc::new(tt::Subtree {
delimiter: tt::Delimiter::UNSPECIFIED, delimiter: tt::Delimiter::DUMMY_INVISIBLE,
token_trees: vec![], token_trees: vec![],
}), }),
err: Some(ExpandError::other(format!( err: Some(ExpandError::other(format!(

View file

@ -18,10 +18,7 @@
//! //!
//! //!
//! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros> //! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
use base_db::{ use base_db::{span::SyntaxContextId, CrateId, FileId};
span::{SpanAnchor, SyntaxContextId},
CrateId,
};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use syntax::{ted, Parse, SyntaxNode, TextRange, TextSize, WalkEvent}; use syntax::{ted, Parse, SyntaxNode, TextRange, TextSize, WalkEvent};
use triomphe::Arc; use triomphe::Arc;
@ -79,12 +76,10 @@ pub fn expand_eager_macro_input(
}; };
// FIXME: Spans! // FIXME: Spans!
let mut subtree = mbe::syntax_node_to_token_tree( let mut subtree =
&expanded_eager_input, mbe::syntax_node_to_token_tree(&expanded_eager_input, RealSpanMap::absolute(FileId::BOGUS));
RealSpanMap::absolute(<SpanAnchor as tt::SpanAnchor>::DUMMY.file_id),
);
subtree.delimiter = crate::tt::Delimiter::UNSPECIFIED; subtree.delimiter = crate::tt::Delimiter::DUMMY_INVISIBLE;
let loc = MacroCallLoc { let loc = MacroCallLoc {
def, def,

View file

@ -61,6 +61,7 @@ pub mod tt {
pub use tt::{DelimiterKind, Spacing, Span, SpanAnchor}; pub use tt::{DelimiterKind, Spacing, Span, SpanAnchor};
pub type Delimiter = ::tt::Delimiter<SpanData>; pub type Delimiter = ::tt::Delimiter<SpanData>;
pub type DelimSpan = ::tt::DelimSpan<SpanData>;
pub type Subtree = ::tt::Subtree<SpanData>; pub type Subtree = ::tt::Subtree<SpanData>;
pub type Leaf = ::tt::Leaf<SpanData>; pub type Leaf = ::tt::Leaf<SpanData>;
pub type Literal = ::tt::Literal<SpanData>; pub type Literal = ::tt::Literal<SpanData>;
@ -160,7 +161,7 @@ pub enum MacroCallKind {
}, },
Attr { Attr {
ast_id: AstId<ast::Item>, ast_id: AstId<ast::Item>,
attr_args: Arc<tt::Subtree>, attr_args: Option<Arc<tt::Subtree>>,
/// Syntactical index of the invoking `#[attribute]`. /// Syntactical index of the invoking `#[attribute]`.
/// ///
/// Outer attributes are counted first, then inner attributes. This does not support /// Outer attributes are counted first, then inner attributes. This does not support
@ -699,7 +700,7 @@ impl ExpansionInfo {
let (macro_arg, _) = db.macro_arg(macro_file.macro_call_id).value.unwrap_or_else(|| { let (macro_arg, _) = db.macro_arg(macro_file.macro_call_id).value.unwrap_or_else(|| {
( (
Arc::new(tt::Subtree { Arc::new(tt::Subtree {
delimiter: tt::Delimiter::UNSPECIFIED, delimiter: tt::Delimiter::DUMMY_INVISIBLE,
token_trees: Vec::new(), token_trees: Vec::new(),
}), }),
SyntaxFixupUndoInfo::NONE, SyntaxFixupUndoInfo::NONE,

View file

@ -38,9 +38,10 @@ impl ProcMacroExpander {
mixed_site: SpanData, mixed_site: SpanData,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
match self.proc_macro_id { match self.proc_macro_id {
ProcMacroId(DUMMY_ID) => { ProcMacroId(DUMMY_ID) => ExpandResult::new(
ExpandResult::new(tt::Subtree::empty(), ExpandError::UnresolvedProcMacro(def_crate)) tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
} ExpandError::UnresolvedProcMacro(def_crate),
),
ProcMacroId(id) => { ProcMacroId(id) => {
let proc_macros = db.proc_macros(); let proc_macros = db.proc_macros();
let proc_macros = match proc_macros.get(&def_crate) { let proc_macros = match proc_macros.get(&def_crate) {
@ -48,7 +49,7 @@ impl ProcMacroExpander {
Some(Err(_)) | None => { Some(Err(_)) | None => {
never!("Non-dummy expander even though there are no proc macros"); never!("Non-dummy expander even though there are no proc macros");
return ExpandResult::new( return ExpandResult::new(
tt::Subtree::empty(), tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
ExpandError::other("Internal error"), ExpandError::other("Internal error"),
); );
} }
@ -62,7 +63,7 @@ impl ProcMacroExpander {
id id
); );
return ExpandResult::new( return ExpandResult::new(
tt::Subtree::empty(), tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
ExpandError::other("Internal error"), ExpandError::other("Internal error"),
); );
} }
@ -82,9 +83,10 @@ impl ProcMacroExpander {
ExpandResult { value: tt.clone(), err: Some(ExpandError::other(text)) } ExpandResult { value: tt.clone(), err: Some(ExpandError::other(text)) }
} }
ProcMacroExpansionError::System(text) ProcMacroExpansionError::System(text)
| ProcMacroExpansionError::Panic(text) => { | ProcMacroExpansionError::Panic(text) => ExpandResult::new(
ExpandResult::new(tt::Subtree::empty(), ExpandError::other(text)) tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
} ExpandError::other(text),
),
}, },
} }
} }

View file

@ -1,5 +1,7 @@
//! A simplified version of quote-crate like quasi quote macro //! A simplified version of quote-crate like quasi quote macro
use base_db::span::SpanData;
// A helper macro quote macro // A helper macro quote macro
// FIXME: // FIXME:
// 1. Not all puncts are handled // 1. Not all puncts are handled
@ -8,109 +10,109 @@
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! __quote { macro_rules! __quote {
() => { ($span:ident) => {
Vec::<crate::tt::TokenTree>::new() Vec::<crate::tt::TokenTree>::new()
}; };
( @SUBTREE $delim:ident $($tt:tt)* ) => { ( @SUBTREE($span:ident) $delim:ident $($tt:tt)* ) => {
{ {
let children = $crate::__quote!($($tt)*); let children = $crate::__quote!($span $($tt)*);
crate::tt::Subtree { crate::tt::Subtree {
delimiter: crate::tt::Delimiter { delimiter: crate::tt::Delimiter {
kind: crate::tt::DelimiterKind::$delim, kind: crate::tt::DelimiterKind::$delim,
open: <crate::tt::SpanData as crate::tt::Span>::DUMMY, open: $span,
close: <crate::tt::SpanData as crate::tt::Span>::DUMMY, close: $span,
}, },
token_trees: $crate::quote::IntoTt::to_tokens(children), token_trees: $crate::quote::IntoTt::to_tokens(children),
} }
} }
}; };
( @PUNCT $first:literal ) => { ( @PUNCT($span:ident) $first:literal ) => {
{ {
vec![ vec![
crate::tt::Leaf::Punct(crate::tt::Punct { crate::tt::Leaf::Punct(crate::tt::Punct {
char: $first, char: $first,
spacing: crate::tt::Spacing::Alone, spacing: crate::tt::Spacing::Alone,
span: <crate::tt::SpanData as crate::tt::Span>::DUMMY, span: $span,
}).into() }).into()
] ]
} }
}; };
( @PUNCT $first:literal, $sec:literal ) => { ( @PUNCT($span:ident) $first:literal, $sec:literal ) => {
{ {
vec![ vec![
crate::tt::Leaf::Punct(crate::tt::Punct { crate::tt::Leaf::Punct(crate::tt::Punct {
char: $first, char: $first,
spacing: crate::tt::Spacing::Joint, spacing: crate::tt::Spacing::Joint,
span: <crate::tt::SpanData as crate::tt::Span>::DUMMY, span: $span,
}).into(), }).into(),
crate::tt::Leaf::Punct(crate::tt::Punct { crate::tt::Leaf::Punct(crate::tt::Punct {
char: $sec, char: $sec,
spacing: crate::tt::Spacing::Alone, spacing: crate::tt::Spacing::Alone,
span: <crate::tt::SpanData as crate::tt::Span>::DUMMY, span: $span,
}).into() }).into()
] ]
} }
}; };
// hash variable // hash variable
( # $first:ident $($tail:tt)* ) => { ($span:ident # $first:ident $($tail:tt)* ) => {
{ {
let token = $crate::quote::ToTokenTree::to_token($first); let token = $crate::quote::ToTokenTree::to_token($first, $span);
let mut tokens = vec![token.into()]; let mut tokens = vec![token.into()];
let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*)); let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($span $($tail)*));
tokens.append(&mut tail_tokens); tokens.append(&mut tail_tokens);
tokens tokens
} }
}; };
( ## $first:ident $($tail:tt)* ) => { ($span:ident ## $first:ident $($tail:tt)* ) => {
{ {
let mut tokens = $first.into_iter().map($crate::quote::ToTokenTree::to_token).collect::<Vec<crate::tt::TokenTree>>(); let mut tokens = $first.into_iter().map(|it| $crate::quote::ToTokenTree::to_token(it, $span)).collect::<Vec<crate::tt::TokenTree>>();
let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*)); let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($span $($tail)*));
tokens.append(&mut tail_tokens); tokens.append(&mut tail_tokens);
tokens tokens
} }
}; };
// Brace // Brace
( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) }; ($span:ident { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE($span) Brace $($tt)*) };
// Bracket // Bracket
( [ $($tt:tt)* ] ) => { $crate::__quote!(@SUBTREE Bracket $($tt)*) }; ($span:ident [ $($tt:tt)* ] ) => { $crate::__quote!(@SUBTREE($span) Bracket $($tt)*) };
// Parenthesis // Parenthesis
( ( $($tt:tt)* ) ) => { $crate::__quote!(@SUBTREE Parenthesis $($tt)*) }; ($span:ident ( $($tt:tt)* ) ) => { $crate::__quote!(@SUBTREE($span) Parenthesis $($tt)*) };
// Literal // Literal
( $tt:literal ) => { vec![$crate::quote::ToTokenTree::to_token($tt).into()] }; ($span:ident $tt:literal ) => { vec![$crate::quote::ToTokenTree::to_token($tt, $span).into()] };
// Ident // Ident
( $tt:ident ) => { ($span:ident $tt:ident ) => {
vec![ { vec![ {
crate::tt::Leaf::Ident(crate::tt::Ident { crate::tt::Leaf::Ident(crate::tt::Ident {
text: stringify!($tt).into(), text: stringify!($tt).into(),
span: <crate::tt::SpanData as crate::tt::Span>::DUMMY, span: $span,
}).into() }).into()
}] }]
}; };
// Puncts // Puncts
// FIXME: Not all puncts are handled // FIXME: Not all puncts are handled
( -> ) => {$crate::__quote!(@PUNCT '-', '>')}; ($span:ident -> ) => {$crate::__quote!(@PUNCT($span) '-', '>')};
( & ) => {$crate::__quote!(@PUNCT '&')}; ($span:ident & ) => {$crate::__quote!(@PUNCT($span) '&')};
( , ) => {$crate::__quote!(@PUNCT ',')}; ($span:ident , ) => {$crate::__quote!(@PUNCT($span) ',')};
( : ) => {$crate::__quote!(@PUNCT ':')}; ($span:ident : ) => {$crate::__quote!(@PUNCT($span) ':')};
( ; ) => {$crate::__quote!(@PUNCT ';')}; ($span:ident ; ) => {$crate::__quote!(@PUNCT($span) ';')};
( :: ) => {$crate::__quote!(@PUNCT ':', ':')}; ($span:ident :: ) => {$crate::__quote!(@PUNCT($span) ':', ':')};
( . ) => {$crate::__quote!(@PUNCT '.')}; ($span:ident . ) => {$crate::__quote!(@PUNCT($span) '.')};
( < ) => {$crate::__quote!(@PUNCT '<')}; ($span:ident < ) => {$crate::__quote!(@PUNCT($span) '<')};
( > ) => {$crate::__quote!(@PUNCT '>')}; ($span:ident > ) => {$crate::__quote!(@PUNCT($span) '>')};
( ! ) => {$crate::__quote!(@PUNCT '!')}; ($span:ident ! ) => {$crate::__quote!(@PUNCT($span) '!')};
( $first:tt $($tail:tt)+ ) => { ($span:ident $first:tt $($tail:tt)+ ) => {
{ {
let mut tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($first)); let mut tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($span $first ));
let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*)); let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($span $($tail)*));
tokens.append(&mut tail_tokens); tokens.append(&mut tail_tokens);
tokens tokens
@ -122,19 +124,22 @@ macro_rules! __quote {
/// It probably should implement in proc-macro /// It probably should implement in proc-macro
#[macro_export] #[macro_export]
macro_rules! quote { macro_rules! quote {
( $($tt:tt)* ) => { ($span:ident=> $($tt:tt)* ) => {
$crate::quote::IntoTt::to_subtree($crate::__quote!($($tt)*)) $crate::quote::IntoTt::to_subtree($crate::__quote!($span $($tt)*), $span)
} }
} }
pub(crate) trait IntoTt { pub(crate) trait IntoTt {
fn to_subtree(self) -> crate::tt::Subtree; fn to_subtree(self, span: SpanData) -> crate::tt::Subtree;
fn to_tokens(self) -> Vec<crate::tt::TokenTree>; fn to_tokens(self) -> Vec<crate::tt::TokenTree>;
} }
impl IntoTt for Vec<crate::tt::TokenTree> { impl IntoTt for Vec<crate::tt::TokenTree> {
fn to_subtree(self) -> crate::tt::Subtree { fn to_subtree(self, span: SpanData) -> crate::tt::Subtree {
crate::tt::Subtree { delimiter: crate::tt::Delimiter::unspecified(), token_trees: self } crate::tt::Subtree {
delimiter: crate::tt::Delimiter::invisible_spanned(span),
token_trees: self,
}
} }
fn to_tokens(self) -> Vec<crate::tt::TokenTree> { fn to_tokens(self) -> Vec<crate::tt::TokenTree> {
@ -143,7 +148,7 @@ impl IntoTt for Vec<crate::tt::TokenTree> {
} }
impl IntoTt for crate::tt::Subtree { impl IntoTt for crate::tt::Subtree {
fn to_subtree(self) -> crate::tt::Subtree { fn to_subtree(self, _: SpanData) -> crate::tt::Subtree {
self self
} }
@ -153,39 +158,39 @@ impl IntoTt for crate::tt::Subtree {
} }
pub(crate) trait ToTokenTree { pub(crate) trait ToTokenTree {
fn to_token(self) -> crate::tt::TokenTree; fn to_token(self, span: SpanData) -> crate::tt::TokenTree;
} }
impl ToTokenTree for crate::tt::TokenTree { impl ToTokenTree for crate::tt::TokenTree {
fn to_token(self) -> crate::tt::TokenTree { fn to_token(self, _: SpanData) -> crate::tt::TokenTree {
self self
} }
} }
impl ToTokenTree for &crate::tt::TokenTree { impl ToTokenTree for &crate::tt::TokenTree {
fn to_token(self) -> crate::tt::TokenTree { fn to_token(self, _: SpanData) -> crate::tt::TokenTree {
self.clone() self.clone()
} }
} }
impl ToTokenTree for crate::tt::Subtree { impl ToTokenTree for crate::tt::Subtree {
fn to_token(self) -> crate::tt::TokenTree { fn to_token(self, _: SpanData) -> crate::tt::TokenTree {
self.into() self.into()
} }
} }
macro_rules! impl_to_to_tokentrees { macro_rules! impl_to_to_tokentrees {
($($ty:ty => $this:ident $im:block);*) => { ($($span:ident: $ty:ty => $this:ident $im:block);*) => {
$( $(
impl ToTokenTree for $ty { impl ToTokenTree for $ty {
fn to_token($this) -> crate::tt::TokenTree { fn to_token($this, $span: SpanData) -> crate::tt::TokenTree {
let leaf: crate::tt::Leaf = $im.into(); let leaf: crate::tt::Leaf = $im.into();
leaf.into() leaf.into()
} }
} }
impl ToTokenTree for &$ty { impl ToTokenTree for &$ty {
fn to_token($this) -> crate::tt::TokenTree { fn to_token($this, $span: SpanData) -> crate::tt::TokenTree {
let leaf: crate::tt::Leaf = $im.clone().into(); let leaf: crate::tt::Leaf = $im.clone().into();
leaf.into() leaf.into()
} }
@ -195,41 +200,45 @@ macro_rules! impl_to_to_tokentrees {
} }
impl_to_to_tokentrees! { impl_to_to_tokentrees! {
u32 => self { crate::tt::Literal{text: self.to_string().into(), span: <crate::tt::SpanData as crate::tt::Span>::DUMMY} }; span: u32 => self { crate::tt::Literal{text: self.to_string().into(), span} };
usize => self { crate::tt::Literal{text: self.to_string().into(), span: <crate::tt::SpanData as crate::tt::Span>::DUMMY} }; span: usize => self { crate::tt::Literal{text: self.to_string().into(), span} };
i32 => self { crate::tt::Literal{text: self.to_string().into(), span: <crate::tt::SpanData as crate::tt::Span>::DUMMY} }; span: i32 => self { crate::tt::Literal{text: self.to_string().into(), span} };
bool => self { crate::tt::Ident{text: self.to_string().into(), span: <crate::tt::SpanData as crate::tt::Span>::DUMMY} }; span: bool => self { crate::tt::Ident{text: self.to_string().into(), span} };
crate::tt::Leaf => self { self }; _span: crate::tt::Leaf => self { self };
crate::tt::Literal => self { self }; _span: crate::tt::Literal => self { self };
crate::tt::Ident => self { self }; _span: crate::tt::Ident => self { self };
crate::tt::Punct => self { self }; _span: crate::tt::Punct => self { self };
&str => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span: <crate::tt::SpanData as crate::tt::Span>::DUMMY}}; span: &str => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span}};
String => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span: <crate::tt::SpanData as crate::tt::Span>::DUMMY}} span: String => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span}}
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tt;
use ::tt::Span;
use expect_test::expect; use expect_test::expect;
const DUMMY: tt::SpanData = tt::SpanData::DUMMY;
#[test] #[test]
fn test_quote_delimiters() { fn test_quote_delimiters() {
assert_eq!(quote!({}).to_string(), "{}"); assert_eq!(quote!(DUMMY =>{}).to_string(), "{}");
assert_eq!(quote!(()).to_string(), "()"); assert_eq!(quote!(DUMMY =>()).to_string(), "()");
assert_eq!(quote!([]).to_string(), "[]"); assert_eq!(quote!(DUMMY =>[]).to_string(), "[]");
} }
#[test] #[test]
fn test_quote_idents() { fn test_quote_idents() {
assert_eq!(quote!(32).to_string(), "32"); assert_eq!(quote!(DUMMY =>32).to_string(), "32");
assert_eq!(quote!(struct).to_string(), "struct"); assert_eq!(quote!(DUMMY =>struct).to_string(), "struct");
} }
#[test] #[test]
fn test_quote_hash_simple_literal() { fn test_quote_hash_simple_literal() {
let a = 20; let a = 20;
assert_eq!(quote!(#a).to_string(), "20"); assert_eq!(quote!(DUMMY =>#a).to_string(), "20");
let s: String = "hello".into(); let s: String = "hello".into();
assert_eq!(quote!(#s).to_string(), "\"hello\""); assert_eq!(quote!(DUMMY =>#s).to_string(), "\"hello\"");
} }
fn mk_ident(name: &str) -> crate::tt::Ident { fn mk_ident(name: &str) -> crate::tt::Ident {
@ -243,7 +252,7 @@ mod tests {
fn test_quote_hash_token_tree() { fn test_quote_hash_token_tree() {
let a = mk_ident("hello"); let a = mk_ident("hello");
let quoted = quote!(#a); let quoted = quote!(DUMMY =>#a);
assert_eq!(quoted.to_string(), "hello"); assert_eq!(quoted.to_string(), "hello");
let t = format!("{quoted:?}"); let t = format!("{quoted:?}");
expect![[r#" expect![[r#"
@ -255,7 +264,7 @@ mod tests {
fn test_quote_simple_derive_copy() { fn test_quote_simple_derive_copy() {
let name = mk_ident("Foo"); let name = mk_ident("Foo");
let quoted = quote! { let quoted = quote! {DUMMY =>
impl Clone for #name { impl Clone for #name {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self {} Self {}
@ -275,7 +284,8 @@ mod tests {
// } // }
let struct_name = mk_ident("Foo"); let struct_name = mk_ident("Foo");
let fields = [mk_ident("name"), mk_ident("id")]; let fields = [mk_ident("name"), mk_ident("id")];
let fields = fields.iter().flat_map(|it| quote!(#it: self.#it.clone(), ).token_trees); let fields =
fields.iter().flat_map(|it| quote!(DUMMY =>#it: self.#it.clone(), ).token_trees);
let list = crate::tt::Subtree { let list = crate::tt::Subtree {
delimiter: crate::tt::Delimiter { delimiter: crate::tt::Delimiter {
@ -286,7 +296,7 @@ mod tests {
token_trees: fields.collect(), token_trees: fields.collect(),
}; };
let quoted = quote! { let quoted = quote! {DUMMY =>
impl Clone for #struct_name { impl Clone for #struct_name {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self #list Self #list

View file

@ -16,6 +16,7 @@ use ide_db::{
use itertools::Itertools; use itertools::Itertools;
use proc_macro_api::{MacroDylib, ProcMacroServer}; use proc_macro_api::{MacroDylib, ProcMacroServer};
use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace}; use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace};
use tt::DelimSpan;
use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf, VfsPath}; use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf, VfsPath};
pub struct LoadCargoConfig { pub struct LoadCargoConfig {
@ -417,11 +418,11 @@ impl ProcMacroExpander for EmptyExpander {
_: &tt::Subtree<SpanData>, _: &tt::Subtree<SpanData>,
_: Option<&tt::Subtree<SpanData>>, _: Option<&tt::Subtree<SpanData>>,
_: &Env, _: &Env,
_: SpanData, call_site: SpanData,
_: SpanData, _: SpanData,
_: SpanData, _: SpanData,
) -> Result<tt::Subtree<SpanData>, ProcMacroExpansionError> { ) -> Result<tt::Subtree<SpanData>, ProcMacroExpansionError> {
Ok(tt::Subtree::empty()) Ok(tt::Subtree::empty(DelimSpan { open: call_site, close: call_site }))
} }
} }

View file

@ -49,7 +49,7 @@ pub(crate) fn expand_rules<S: Span>(
ExpandResult { value, err: match_.err.or(transcribe_err) } ExpandResult { value, err: match_.err.or(transcribe_err) }
} else { } else {
ExpandResult::new( ExpandResult::new(
tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: vec![] }, tt::Subtree { delimiter: tt::Delimiter::DUMMY_INVISIBLE, token_trees: vec![] },
ExpandError::NoMatchingRule, ExpandError::NoMatchingRule,
) )
} }

View file

@ -76,7 +76,8 @@ impl<S: Span> Bindings<S> {
fn push_optional(&mut self, name: &SmolStr) { fn push_optional(&mut self, name: &SmolStr) {
// FIXME: Do we have a better way to represent an empty token ? // FIXME: Do we have a better way to represent an empty token ?
// Insert an empty subtree for empty token // Insert an empty subtree for empty token
let tt = tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: vec![] }.into(); let tt =
tt::Subtree { delimiter: tt::Delimiter::DUMMY_INVISIBLE, token_trees: vec![] }.into();
self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt))); self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt)));
} }
@ -816,7 +817,7 @@ fn match_meta_var<S: Span>(
match neg { match neg {
None => lit.into(), None => lit.into(),
Some(neg) => tt::TokenTree::Subtree(tt::Subtree { Some(neg) => tt::TokenTree::Subtree(tt::Subtree {
delimiter: tt::Delimiter::unspecified(), delimiter: tt::Delimiter::dummy_invisible(),
token_trees: vec![neg, lit.into()], token_trees: vec![neg, lit.into()],
}), }),
} }
@ -849,7 +850,7 @@ impl<S: Span> MetaTemplate<S> {
OpDelimitedIter { OpDelimitedIter {
inner: &self.0, inner: &self.0,
idx: 0, idx: 0,
delimited: delimited.unwrap_or(tt::Delimiter::UNSPECIFIED), delimited: delimited.unwrap_or(tt::Delimiter::DUMMY_INVISIBLE),
} }
} }
} }
@ -947,7 +948,7 @@ impl<S: Span> TtIter<'_, S> {
let puncts = self.expect_glued_punct()?; let puncts = self.expect_glued_punct()?;
let token_trees = puncts.into_iter().map(|p| tt::Leaf::Punct(p).into()).collect(); let token_trees = puncts.into_iter().map(|p| tt::Leaf::Punct(p).into()).collect();
Ok(tt::TokenTree::Subtree(tt::Subtree { Ok(tt::TokenTree::Subtree(tt::Subtree {
delimiter: tt::Delimiter::unspecified(), delimiter: tt::Delimiter::dummy_invisible(),
token_trees, token_trees,
})) }))
} }
@ -964,7 +965,7 @@ impl<S: Span> TtIter<'_, S> {
let ident = self.expect_ident_or_underscore()?; let ident = self.expect_ident_or_underscore()?;
Ok(tt::Subtree { Ok(tt::Subtree {
delimiter: tt::Delimiter::unspecified(), delimiter: tt::Delimiter::dummy_invisible(),
token_trees: vec![ token_trees: vec![
tt::Leaf::Punct(*punct).into(), tt::Leaf::Punct(*punct).into(),
tt::Leaf::Ident(ident.clone()).into(), tt::Leaf::Ident(ident.clone()).into(),

View file

@ -88,7 +88,7 @@ impl<S: Span> Bindings<S> {
// FIXME: Meta and Item should get proper defaults // FIXME: Meta and Item should get proper defaults
MetaVarKind::Meta | MetaVarKind::Item | MetaVarKind::Tt | MetaVarKind::Vis => { MetaVarKind::Meta | MetaVarKind::Item | MetaVarKind::Tt | MetaVarKind::Vis => {
Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree { Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree {
delimiter: tt::Delimiter::UNSPECIFIED, delimiter: tt::Delimiter::DUMMY_INVISIBLE,
token_trees: vec![], token_trees: vec![],
})) }))
} }
@ -292,7 +292,7 @@ fn expand_subtree<S: Span>(
let tts = arena.drain(start_elements..).collect(); let tts = arena.drain(start_elements..).collect();
ExpandResult { ExpandResult {
value: tt::Subtree { value: tt::Subtree {
delimiter: delimiter.unwrap_or_else(tt::Delimiter::unspecified), delimiter: delimiter.unwrap_or_else(tt::Delimiter::dummy_invisible),
token_trees: tts, token_trees: tts,
}, },
err, err,
@ -325,7 +325,7 @@ fn expand_var<S: Span>(
// ``` // ```
// We just treat it a normal tokens // We just treat it a normal tokens
let tt = tt::Subtree { let tt = tt::Subtree {
delimiter: tt::Delimiter::UNSPECIFIED, delimiter: tt::Delimiter::DUMMY_INVISIBLE,
token_trees: vec![ token_trees: vec![
tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, span: id }) tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, span: id })
.into(), .into(),
@ -336,7 +336,10 @@ fn expand_var<S: Span>(
ExpandResult::ok(Fragment::Tokens(tt)) ExpandResult::ok(Fragment::Tokens(tt))
} }
Err(e) => ExpandResult { Err(e) => ExpandResult {
value: Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree::empty())), value: Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree::empty(tt::DelimSpan {
open: S::DUMMY,
close: S::DUMMY,
}))),
err: Some(e), err: Some(e),
}, },
} }
@ -378,8 +381,11 @@ fn expand_repeat<S: Span>(
); );
return ExpandResult { return ExpandResult {
value: Fragment::Tokens( value: Fragment::Tokens(
tt::Subtree { delimiter: tt::Delimiter::unspecified(), token_trees: vec![] } tt::Subtree {
.into(), delimiter: tt::Delimiter::dummy_invisible(),
token_trees: vec![],
}
.into(),
), ),
err: Some(ExpandError::LimitExceeded), err: Some(ExpandError::LimitExceeded),
}; };
@ -390,7 +396,7 @@ fn expand_repeat<S: Span>(
continue; continue;
} }
t.delimiter = tt::Delimiter::UNSPECIFIED; t.delimiter = tt::Delimiter::DUMMY_INVISIBLE;
push_subtree(&mut buf, t); push_subtree(&mut buf, t);
if let Some(sep) = separator { if let Some(sep) = separator {
@ -424,7 +430,7 @@ fn expand_repeat<S: Span>(
// Check if it is a single token subtree without any delimiter // Check if it is a single token subtree without any delimiter
// e.g {Delimiter:None> ['>'] /Delimiter:None>} // e.g {Delimiter:None> ['>'] /Delimiter:None>}
let tt = tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: buf }.into(); let tt = tt::Subtree { delimiter: tt::Delimiter::DUMMY_INVISIBLE, token_trees: buf }.into();
if RepeatKind::OneOrMore == kind && counter == 0 { if RepeatKind::OneOrMore == kind && counter == 0 {
return ExpandResult { return ExpandResult {

View file

@ -34,9 +34,9 @@ pub use tt::{Delimiter, DelimiterKind, Punct, SyntaxContext};
pub use crate::{ pub use crate::{
syntax_bridge::{ syntax_bridge::{
map_from_syntax_node, parse_exprs_with_sep, parse_to_token_tree, parse_exprs_with_sep, parse_to_token_tree, parse_to_token_tree_static_span,
parse_to_token_tree_static_span, syntax_node_to_token_tree, syntax_node_to_token_tree, syntax_node_to_token_tree_modified, token_tree_to_syntax_node,
syntax_node_to_token_tree_modified, token_tree_to_syntax_node, SpanMapper, SpanMapper,
}, },
token_map::TokenMap, token_map::TokenMap,
}; };

View file

@ -4,7 +4,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
use stdx::{never, non_empty_vec::NonEmptyVec}; use stdx::{never, non_empty_vec::NonEmptyVec};
use syntax::{ use syntax::{
ast::{self, make::tokens::doc_comment}, ast::{self, make::tokens::doc_comment},
AstToken, NodeOrToken, Parse, PreorderWithTokens, SmolStr, SyntaxElement, SyntaxKind, AstToken, Parse, PreorderWithTokens, SmolStr, SyntaxElement, SyntaxKind,
SyntaxKind::*, SyntaxKind::*,
SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextSize, WalkEvent, T, SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextSize, WalkEvent, T,
}; };
@ -142,30 +142,10 @@ where
tree_sink.finish() tree_sink.finish()
} }
pub fn map_from_syntax_node<Anchor, Ctx>(
node: &SyntaxNode,
anchor: Anchor,
anchor_offset: TextSize,
) -> TokenMap<SpanData<Anchor, Ctx>>
where
Anchor: Copy,
SpanData<Anchor, Ctx>: Span,
Ctx: SyntaxContext,
{
let mut map = TokenMap::empty();
node.descendants_with_tokens().filter_map(NodeOrToken::into_token).for_each(|t| {
map.push(
t.text_range().start(),
SpanData { range: t.text_range() - anchor_offset, anchor, ctx: Ctx::DUMMY },
);
});
map.finish();
map
}
/// Convert a string to a `TokenTree` /// Convert a string to a `TokenTree`
pub fn parse_to_token_tree<Anchor, Ctx>( pub fn parse_to_token_tree<Anchor, Ctx>(
anchor: Anchor, anchor: Anchor,
ctx: Ctx,
text: &str, text: &str,
) -> Option<tt::Subtree<SpanData<Anchor, Ctx>>> ) -> Option<tt::Subtree<SpanData<Anchor, Ctx>>>
where where
@ -177,7 +157,7 @@ where
if lexed.errors().next().is_some() { if lexed.errors().next().is_some() {
return None; return None;
} }
let mut conv = RawConverter { lexed, pos: 0, anchor }; let mut conv = RawConverter { lexed, pos: 0, anchor, ctx };
Some(convert_tokens(&mut conv)) Some(convert_tokens(&mut conv))
} }
@ -220,7 +200,7 @@ pub fn parse_exprs_with_sep<S: Span>(tt: &tt::Subtree<S>, sep: char) -> Vec<tt::
if iter.peek_n(0).is_some() { if iter.peek_n(0).is_some() {
res.push(tt::Subtree { res.push(tt::Subtree {
delimiter: tt::Delimiter::unspecified(), delimiter: tt::Delimiter::DUMMY_INVISIBLE,
token_trees: iter.cloned().collect(), token_trees: iter.cloned().collect(),
}); });
} }
@ -233,7 +213,7 @@ where
C: TokenConverter<S>, C: TokenConverter<S>,
S: Span, S: Span,
{ {
let entry = tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: vec![] }; let entry = tt::Subtree { delimiter: tt::Delimiter::DUMMY_INVISIBLE, token_trees: vec![] };
let mut stack = NonEmptyVec::new(entry); let mut stack = NonEmptyVec::new(entry);
while let Some((token, abs_range)) = conv.bump() { while let Some((token, abs_range)) = conv.bump() {
@ -463,10 +443,11 @@ fn convert_doc_comment<S: Copy>(
} }
/// A raw token (straight from lexer) converter /// A raw token (straight from lexer) converter
struct RawConverter<'a, Anchor> { struct RawConverter<'a, Anchor, Ctx> {
lexed: parser::LexedStr<'a>, lexed: parser::LexedStr<'a>,
pos: usize, pos: usize,
anchor: Anchor, anchor: Anchor,
ctx: Ctx,
} }
/// A raw token (straight from lexer) converter that gives every token the same span. /// A raw token (straight from lexer) converter that gives every token the same span.
struct StaticRawConverter<'a, S> { struct StaticRawConverter<'a, S> {
@ -499,16 +480,16 @@ trait TokenConverter<S>: Sized {
fn span_for(&self, range: TextRange) -> S; fn span_for(&self, range: TextRange) -> S;
} }
impl<Anchor, S> SrcToken<RawConverter<'_, Anchor>, S> for usize { impl<Anchor, S, Ctx> SrcToken<RawConverter<'_, Anchor, Ctx>, S> for usize {
fn kind(&self, ctx: &RawConverter<'_, Anchor>) -> SyntaxKind { fn kind(&self, ctx: &RawConverter<'_, Anchor, Ctx>) -> SyntaxKind {
ctx.lexed.kind(*self) ctx.lexed.kind(*self)
} }
fn to_char(&self, ctx: &RawConverter<'_, Anchor>) -> Option<char> { fn to_char(&self, ctx: &RawConverter<'_, Anchor, Ctx>) -> Option<char> {
ctx.lexed.text(*self).chars().next() ctx.lexed.text(*self).chars().next()
} }
fn to_text(&self, ctx: &RawConverter<'_, Anchor>) -> SmolStr { fn to_text(&self, ctx: &RawConverter<'_, Anchor, Ctx>) -> SmolStr {
ctx.lexed.text(*self).into() ctx.lexed.text(*self).into()
} }
} }
@ -528,7 +509,7 @@ impl<S: Span> SrcToken<StaticRawConverter<'_, S>, S> for usize {
} }
impl<Anchor: Copy, Ctx: SyntaxContext> TokenConverter<SpanData<Anchor, Ctx>> impl<Anchor: Copy, Ctx: SyntaxContext> TokenConverter<SpanData<Anchor, Ctx>>
for RawConverter<'_, Anchor> for RawConverter<'_, Anchor, Ctx>
where where
SpanData<Anchor, Ctx>: Span, SpanData<Anchor, Ctx>: Span,
{ {
@ -563,7 +544,7 @@ where
} }
fn span_for(&self, range: TextRange) -> SpanData<Anchor, Ctx> { fn span_for(&self, range: TextRange) -> SpanData<Anchor, Ctx> {
SpanData { range, anchor: self.anchor, ctx: Ctx::DUMMY } SpanData { range, anchor: self.anchor, ctx: self.ctx }
} }
} }

View file

@ -175,7 +175,7 @@ impl<'a, S: Span> TtIter<'a, S> {
let res = match res.len() { let res = match res.len() {
0 | 1 => res.pop(), 0 | 1 => res.pop(),
_ => Some(tt::TokenTree::Subtree(tt::Subtree { _ => Some(tt::TokenTree::Subtree(tt::Subtree {
delimiter: tt::Delimiter::unspecified(), delimiter: tt::Delimiter::DUMMY_INVISIBLE,
token_trees: res, token_trees: res,
})), })),
}; };

View file

@ -62,12 +62,14 @@ pub struct ExpandMacro {
pub current_dir: Option<String>, pub current_dir: Option<String>,
/// marker for serde skip stuff /// marker for serde skip stuff
#[serde(skip_serializing_if = "ExpnGlobals::skip_serializing_if")] #[serde(skip_serializing_if = "ExpnGlobals::skip_serializing_if")]
#[serde(default)]
pub has_global_spans: ExpnGlobals, pub has_global_spans: ExpnGlobals,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Default, Debug, Serialize, Deserialize)]
pub struct ExpnGlobals { pub struct ExpnGlobals {
#[serde(skip_serializing)] #[serde(skip_serializing)]
#[serde(default)]
pub serialize: bool, pub serialize: bool,
pub def_site: usize, pub def_site: usize,
pub call_site: usize, pub call_site: usize,

View file

@ -56,16 +56,6 @@ impl std::fmt::Debug for TokenId {
impl tt::Span for TokenId { impl tt::Span for TokenId {
const DUMMY: Self = TokenId(!0); const DUMMY: Self = TokenId(!0);
type Anchor = ();
fn anchor(self) -> Self::Anchor {
()
}
fn mk(_: Self::Anchor, _: text_size::TextRange) -> Self {
Self::DUMMY
}
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]

View file

@ -426,8 +426,6 @@ impl LiteralFormatter {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ::tt::Span;
use super::*; use super::*;
#[test] #[test]
@ -436,16 +434,16 @@ mod tests {
token_trees: vec![ token_trees: vec![
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "struct".into(), text: "struct".into(),
span: tt::TokenId::DUMMY, span: tt::TokenId(0),
})), })),
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "T".into(), text: "T".into(),
span: tt::TokenId::DUMMY, span: tt::TokenId(0),
})), })),
tt::TokenTree::Subtree(tt::Subtree { tt::TokenTree::Subtree(tt::Subtree {
delimiter: tt::Delimiter { delimiter: tt::Delimiter {
open: tt::TokenId::DUMMY, open: tt::TokenId(0),
close: tt::TokenId::DUMMY, close: tt::TokenId(0),
kind: tt::DelimiterKind::Brace, kind: tt::DelimiterKind::Brace,
}, },
token_trees: vec![], token_trees: vec![],
@ -460,30 +458,30 @@ mod tests {
fn test_ra_server_from_str() { fn test_ra_server_from_str() {
let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree { let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
delimiter: tt::Delimiter { delimiter: tt::Delimiter {
open: tt::TokenId::DUMMY, open: tt::TokenId(0),
close: tt::TokenId::DUMMY, close: tt::TokenId(0),
kind: tt::DelimiterKind::Parenthesis, kind: tt::DelimiterKind::Parenthesis,
}, },
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "a".into(), text: "a".into(),
span: tt::TokenId::DUMMY, span: tt::TokenId(0),
}))], }))],
}); });
let t1 = TokenStream::from_str("(a)", tt::TokenId::DUMMY).unwrap(); let t1 = TokenStream::from_str("(a)", tt::TokenId(0)).unwrap();
assert_eq!(t1.token_trees.len(), 1); assert_eq!(t1.token_trees.len(), 1);
assert_eq!(t1.token_trees[0], subtree_paren_a); assert_eq!(t1.token_trees[0], subtree_paren_a);
let t2 = TokenStream::from_str("(a);", tt::TokenId::DUMMY).unwrap(); let t2 = TokenStream::from_str("(a);", tt::TokenId(0)).unwrap();
assert_eq!(t2.token_trees.len(), 2); assert_eq!(t2.token_trees.len(), 2);
assert_eq!(t2.token_trees[0], subtree_paren_a); assert_eq!(t2.token_trees[0], subtree_paren_a);
let underscore = TokenStream::from_str("_", tt::TokenId::DUMMY).unwrap(); let underscore = TokenStream::from_str("_", tt::TokenId(0)).unwrap();
assert_eq!( assert_eq!(
underscore.token_trees[0], underscore.token_trees[0],
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
text: "_".into(), text: "_".into(),
span: tt::TokenId::DUMMY, span: tt::TokenId(0),
})) }))
); );
} }

View file

@ -8,7 +8,7 @@ use expect_test::expect;
#[test] #[test]
fn test_derive_empty() { fn test_derive_empty() {
assert_expand("DeriveEmpty", r#"struct S;"#, expect!["SUBTREE $$ 4294967295 4294967295"]); assert_expand("DeriveEmpty", r#"struct S;"#, expect!["SUBTREE $$ 1 1"]);
} }
#[test] #[test]
@ -17,12 +17,12 @@ fn test_derive_error() {
"DeriveError", "DeriveError",
r#"struct S;"#, r#"struct S;"#,
expect![[r##" expect![[r##"
SUBTREE $$ 4294967295 4294967295 SUBTREE $$ 1 1
IDENT compile_error 4294967295 IDENT compile_error 1
PUNCH ! [alone] 4294967295 PUNCH ! [alone] 1
SUBTREE () 4294967295 4294967295 SUBTREE () 1 1
LITERAL "#[derive(DeriveError)] struct S ;" 4294967295 LITERAL "#[derive(DeriveError)] struct S ;" 1
PUNCH ; [alone] 4294967295"##]], PUNCH ; [alone] 1"##]],
); );
} }
@ -32,14 +32,14 @@ fn test_fn_like_macro_noop() {
"fn_like_noop", "fn_like_noop",
r#"ident, 0, 1, []"#, r#"ident, 0, 1, []"#,
expect![[r#" expect![[r#"
SUBTREE $$ 4294967295 4294967295 SUBTREE $$ 1 1
IDENT ident 4294967295 IDENT ident 1
PUNCH , [alone] 4294967295 PUNCH , [alone] 1
LITERAL 0 4294967295 LITERAL 0 1
PUNCH , [alone] 4294967295 PUNCH , [alone] 1
LITERAL 1 4294967295 LITERAL 1 1
PUNCH , [alone] 4294967295 PUNCH , [alone] 1
SUBTREE [] 4294967295 4294967295"#]], SUBTREE [] 1 1"#]],
); );
} }
@ -49,10 +49,10 @@ fn test_fn_like_macro_clone_ident_subtree() {
"fn_like_clone_tokens", "fn_like_clone_tokens",
r#"ident, []"#, r#"ident, []"#,
expect![[r#" expect![[r#"
SUBTREE $$ 4294967295 4294967295 SUBTREE $$ 1 1
IDENT ident 4294967295 IDENT ident 1
PUNCH , [alone] 4294967295 PUNCH , [alone] 1
SUBTREE [] 4294967295 4294967295"#]], SUBTREE [] 1 1"#]],
); );
} }
@ -62,8 +62,8 @@ fn test_fn_like_macro_clone_raw_ident() {
"fn_like_clone_tokens", "fn_like_clone_tokens",
"r#async", "r#async",
expect![[r#" expect![[r#"
SUBTREE $$ 4294967295 4294967295 SUBTREE $$ 1 1
IDENT r#async 4294967295"#]], IDENT r#async 1"#]],
); );
} }
@ -73,14 +73,14 @@ fn test_fn_like_mk_literals() {
"fn_like_mk_literals", "fn_like_mk_literals",
r#""#, r#""#,
expect![[r#" expect![[r#"
SUBTREE $$ 4294967295 4294967295 SUBTREE $$ 1 1
LITERAL b"byte_string" 4294967295 LITERAL b"byte_string" 1
LITERAL 'c' 4294967295 LITERAL 'c' 1
LITERAL "string" 4294967295 LITERAL "string" 1
LITERAL 3.14f64 4294967295 LITERAL 3.14f64 1
LITERAL 3.14 4294967295 LITERAL 3.14 1
LITERAL 123i64 4294967295 LITERAL 123i64 1
LITERAL 123 4294967295"#]], LITERAL 123 1"#]],
); );
} }
@ -90,9 +90,9 @@ fn test_fn_like_mk_idents() {
"fn_like_mk_idents", "fn_like_mk_idents",
r#""#, r#""#,
expect![[r#" expect![[r#"
SUBTREE $$ 4294967295 4294967295 SUBTREE $$ 1 1
IDENT standard 4294967295 IDENT standard 1
IDENT r#raw 4294967295"#]], IDENT r#raw 1"#]],
); );
} }
@ -102,17 +102,17 @@ fn test_fn_like_macro_clone_literals() {
"fn_like_clone_tokens", "fn_like_clone_tokens",
r#"1u16, 2_u32, -4i64, 3.14f32, "hello bridge""#, r#"1u16, 2_u32, -4i64, 3.14f32, "hello bridge""#,
expect![[r#" expect![[r#"
SUBTREE $$ 4294967295 4294967295 SUBTREE $$ 1 1
LITERAL 1u16 4294967295 LITERAL 1u16 1
PUNCH , [alone] 4294967295 PUNCH , [alone] 1
LITERAL 2_u32 4294967295 LITERAL 2_u32 1
PUNCH , [alone] 4294967295 PUNCH , [alone] 1
PUNCH - [alone] 4294967295 PUNCH - [alone] 1
LITERAL 4i64 4294967295 LITERAL 4i64 1
PUNCH , [alone] 4294967295 PUNCH , [alone] 1
LITERAL 3.14f32 4294967295 LITERAL 3.14f32 1
PUNCH , [alone] 4294967295 PUNCH , [alone] 1
LITERAL "hello bridge" 4294967295"#]], LITERAL "hello bridge" 1"#]],
); );
} }
@ -126,12 +126,12 @@ fn test_attr_macro() {
r#"mod m {}"#, r#"mod m {}"#,
r#"some arguments"#, r#"some arguments"#,
expect![[r##" expect![[r##"
SUBTREE $$ 4294967295 4294967295 SUBTREE $$ 1 1
IDENT compile_error 4294967295 IDENT compile_error 1
PUNCH ! [alone] 4294967295 PUNCH ! [alone] 1
SUBTREE () 4294967295 4294967295 SUBTREE () 1 1
LITERAL "#[attr_error(some arguments)] mod m {}" 4294967295 LITERAL "#[attr_error(some arguments)] mod m {}" 1
PUNCH ; [alone] 4294967295"##]], PUNCH ; [alone] 1"##]],
); );
} }

View file

@ -2,7 +2,6 @@
use expect_test::Expect; use expect_test::Expect;
use proc_macro_api::msg::TokenId; use proc_macro_api::msg::TokenId;
use tt::Span;
use crate::{dylib, proc_macro_test_dylib_path, ProcMacroSrv}; use crate::{dylib, proc_macro_test_dylib_path, ProcMacroSrv};
@ -25,7 +24,9 @@ pub fn assert_expand_attr(macro_name: &str, ra_fixture: &str, attr_args: &str, e
} }
fn assert_expand_impl(macro_name: &str, input: &str, attr: Option<&str>, expect: Expect) { fn assert_expand_impl(macro_name: &str, input: &str, attr: Option<&str>, expect: Expect) {
let call_site = TokenId::DUMMY; let def_site = TokenId(0);
let call_site = TokenId(1);
let mixed_site = TokenId(2);
let path = proc_macro_test_dylib_path(); let path = proc_macro_test_dylib_path();
let expander = dylib::Expander::new(&path).unwrap(); let expander = dylib::Expander::new(&path).unwrap();
let fixture = parse_string(input, call_site).unwrap(); let fixture = parse_string(input, call_site).unwrap();
@ -36,9 +37,9 @@ fn assert_expand_impl(macro_name: &str, input: &str, attr: Option<&str>, expect:
macro_name, macro_name,
&fixture.into_subtree(call_site), &fixture.into_subtree(call_site),
attr.as_ref(), attr.as_ref(),
TokenId::DUMMY, def_site,
TokenId::DUMMY, call_site,
TokenId::DUMMY, mixed_site,
) )
.unwrap(); .unwrap();
expect.assert_eq(&format!("{res:?}")); expect.assert_eq(&format!("{res:?}"));

View file

@ -23,18 +23,11 @@ pub struct SpanData<Anchor, Ctx> {
} }
impl<Anchor: SpanAnchor, Ctx: SyntaxContext> Span for SpanData<Anchor, Ctx> { impl<Anchor: SpanAnchor, Ctx: SyntaxContext> Span for SpanData<Anchor, Ctx> {
type Anchor = Anchor;
const DUMMY: Self = SpanData { const DUMMY: Self = SpanData {
range: TextRange::empty(TextSize::new(0)), range: TextRange::empty(TextSize::new(0)),
anchor: Anchor::DUMMY, anchor: Anchor::DUMMY,
ctx: Ctx::DUMMY, ctx: Ctx::DUMMY,
}; };
fn anchor(self) -> Self::Anchor {
self.anchor
}
fn mk(anchor: Self::Anchor, range: TextRange) -> Self {
SpanData { anchor, range, ctx: Ctx::DUMMY }
}
} }
pub trait SpanAnchor: pub trait SpanAnchor:
@ -46,9 +39,6 @@ pub trait SpanAnchor:
// FIXME: Get rid of this trait? // FIXME: Get rid of this trait?
pub trait Span: std::fmt::Debug + Copy + Sized + Eq { pub trait Span: std::fmt::Debug + Copy + Sized + Eq {
const DUMMY: Self; const DUMMY: Self;
type Anchor: Copy + fmt::Debug + Eq + std::hash::Hash;
fn anchor(self) -> Self::Anchor;
fn mk(anchor: Self::Anchor, range: TextRange) -> Self;
} }
pub trait SyntaxContext: std::fmt::Debug + Copy + Sized + Eq { pub trait SyntaxContext: std::fmt::Debug + Copy + Sized + Eq {
@ -62,18 +52,30 @@ pub enum TokenTree<S> {
} }
impl_from!(Leaf<S>, Subtree<S> for TokenTree); impl_from!(Leaf<S>, Subtree<S> for TokenTree);
impl<S: Span> TokenTree<S> { impl<S: Span> TokenTree<S> {
pub const fn empty() -> Self { pub const fn empty(span: S) -> Self {
Self::Subtree(Subtree { delimiter: Delimiter::UNSPECIFIED, token_trees: vec![] }) Self::Subtree(Subtree {
delimiter: Delimiter::invisible_spanned(span),
token_trees: vec![],
})
} }
pub fn subtree_or_wrap(self) -> Subtree<S> { pub fn subtree_or_wrap(self) -> Subtree<S> {
match self { match self {
TokenTree::Leaf(_) => { TokenTree::Leaf(_) => {
Subtree { delimiter: Delimiter::UNSPECIFIED, token_trees: vec![self] } Subtree { delimiter: Delimiter::DUMMY_INVISIBLE, token_trees: vec![self] }
} }
TokenTree::Subtree(s) => s, TokenTree::Subtree(s) => s,
} }
} }
pub fn subtree_or_wrap2(self, span: DelimSpan<S>) -> Subtree<S> {
match self {
TokenTree::Leaf(_) => Subtree {
delimiter: Delimiter::invisible_delim_spanned(span),
token_trees: vec![self],
},
TokenTree::Subtree(s) => s,
}
}
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -101,8 +103,8 @@ pub struct Subtree<S> {
} }
impl<S: Span> Subtree<S> { impl<S: Span> Subtree<S> {
pub const fn empty() -> Self { pub const fn empty(span: DelimSpan<S>) -> Self {
Subtree { delimiter: Delimiter::unspecified(), token_trees: vec![] } Subtree { delimiter: Delimiter::invisible_delim_spanned(span), token_trees: vec![] }
} }
pub fn visit_ids(&mut self, f: &mut impl FnMut(S) -> S) { pub fn visit_ids(&mut self, f: &mut impl FnMut(S) -> S) {
@ -119,6 +121,16 @@ impl<S: Span> Subtree<S> {
} }
} }
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DelimSpan<S> {
pub open: S,
pub close: S,
}
impl<S: Span> DelimSpan<S> {
pub const DUMMY: Self = Self { open: S::DUMMY, close: S::DUMMY };
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Delimiter<S> { pub struct Delimiter<S> {
pub open: S, pub open: S,
@ -127,10 +139,23 @@ pub struct Delimiter<S> {
} }
impl<S: Span> Delimiter<S> { impl<S: Span> Delimiter<S> {
pub const UNSPECIFIED: Self = pub const DUMMY_INVISIBLE: Self =
Self { open: S::DUMMY, close: S::DUMMY, kind: DelimiterKind::Invisible }; Self { open: S::DUMMY, close: S::DUMMY, kind: DelimiterKind::Invisible };
pub const fn unspecified() -> Self {
Self::UNSPECIFIED pub const fn dummy_invisible() -> Self {
Self::DUMMY_INVISIBLE
}
pub const fn invisible_spanned(span: S) -> Self {
Delimiter { open: span, close: span, kind: DelimiterKind::Invisible }
}
pub const fn invisible_delim_spanned(span: DelimSpan<S>) -> Self {
Delimiter { open: span.open, close: span.close, kind: DelimiterKind::Invisible }
}
pub fn delim_span(&self) -> DelimSpan<S> {
DelimSpan { open: self.open, close: self.close }
} }
} }

View file

@ -62,6 +62,11 @@ pub use paths::{AbsPath, AbsPathBuf};
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct FileId(pub u32); pub struct FileId(pub u32);
impl FileId {
/// Think twice about using this. If this ends up in a wrong place it will cause panics!
pub const BOGUS: FileId = FileId(u32::MAX);
}
/// safe because `FileId` is a newtype of `u32` /// safe because `FileId` is a newtype of `u32`
impl nohash_hasher::IsEnabled for FileId {} impl nohash_hasher::IsEnabled for FileId {}