mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 21:35:20 +00:00
Switch token trees to use Symbols
This commit is contained in:
parent
0c95aaa08e
commit
93024ad411
51 changed files with 593 additions and 399 deletions
|
@ -62,7 +62,7 @@ impl RawAttrs {
|
|||
Attr {
|
||||
id,
|
||||
input: Some(Box::new(AttrInput::Literal(tt::Literal {
|
||||
text,
|
||||
symbol: text,
|
||||
span,
|
||||
kind,
|
||||
suffix: None,
|
||||
|
@ -243,7 +243,7 @@ impl Attr {
|
|||
let span = span_map.span_for_range(range);
|
||||
let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
|
||||
let token = lit.token();
|
||||
Some(Box::new(AttrInput::Literal(token_to_literal(token.text().into(), span))))
|
||||
Some(Box::new(AttrInput::Literal(token_to_literal(token.text(), span))))
|
||||
} else if let Some(tt) = ast.token_tree() {
|
||||
let tree = syntax_node_to_token_tree(
|
||||
tt.syntax(),
|
||||
|
@ -260,8 +260,8 @@ impl Attr {
|
|||
|
||||
fn from_tt(db: &dyn ExpandDatabase, mut tt: &[tt::TokenTree], id: AttrId) -> Option<Attr> {
|
||||
if matches!(tt,
|
||||
[tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text, .. })), ..]
|
||||
if text == "unsafe"
|
||||
[tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym, .. })), ..]
|
||||
if *sym == sym::unsafe_
|
||||
) {
|
||||
match tt.get(1) {
|
||||
Some(tt::TokenTree::Subtree(subtree)) => tt = &subtree.token_trees,
|
||||
|
@ -313,10 +313,10 @@ impl Attr {
|
|||
pub fn string_value(&self) -> Option<&str> {
|
||||
match self.input.as_deref()? {
|
||||
AttrInput::Literal(tt::Literal {
|
||||
text,
|
||||
symbol: text,
|
||||
kind: tt::LitKind::Str | tt::LitKind::StrRaw(_),
|
||||
..
|
||||
}) => Some(text),
|
||||
}) => Some(text.as_str()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -324,23 +324,24 @@ impl Attr {
|
|||
/// #[path = "string"]
|
||||
pub fn string_value_with_span(&self) -> Option<(&str, span::Span)> {
|
||||
match self.input.as_deref()? {
|
||||
AttrInput::Literal(it) => match it.text.strip_prefix('r') {
|
||||
Some(it) => it.trim_matches('#'),
|
||||
None => it.text.as_str(),
|
||||
}
|
||||
.strip_prefix('"')?
|
||||
.strip_suffix('"')
|
||||
.zip(Some(it.span)),
|
||||
AttrInput::Literal(tt::Literal {
|
||||
symbol: text,
|
||||
kind: tt::LitKind::Str | tt::LitKind::StrRaw(_),
|
||||
span,
|
||||
suffix: _,
|
||||
}) => Some((text.as_str(), *span)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string_value_unescape(&self) -> Option<Cow<'_, str>> {
|
||||
match self.input.as_deref()? {
|
||||
AttrInput::Literal(tt::Literal { text, kind: tt::LitKind::StrRaw(_), .. }) => {
|
||||
Some(Cow::Borrowed(text))
|
||||
AttrInput::Literal(tt::Literal {
|
||||
symbol: text, kind: tt::LitKind::StrRaw(_), ..
|
||||
}) => Some(Cow::Borrowed(text.as_str())),
|
||||
AttrInput::Literal(tt::Literal { symbol: text, kind: tt::LitKind::Str, .. }) => {
|
||||
unescape(text.as_str())
|
||||
}
|
||||
AttrInput::Literal(tt::Literal { text, kind: tt::LitKind::Str, .. }) => unescape(text),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ enum VariantShape {
|
|||
}
|
||||
|
||||
fn tuple_field_iterator(span: Span, n: usize) -> impl Iterator<Item = tt::Ident> {
|
||||
(0..n).map(move |it| tt::Ident::new(format!("f{it}"), span))
|
||||
(0..n).map(move |it| tt::Ident::new(&format!("f{it}"), span))
|
||||
}
|
||||
|
||||
impl VariantShape {
|
||||
|
@ -693,14 +693,14 @@ fn partial_eq_expand(span: Span, tt: &tt::Subtree) -> ExpandResult<tt::Subtree>
|
|||
}
|
||||
[first, rest @ ..] => {
|
||||
let rest = rest.iter().map(|it| {
|
||||
let t1 = tt::Ident::new(format!("{}_self", it.text), it.span);
|
||||
let t2 = tt::Ident::new(format!("{}_other", it.text), it.span);
|
||||
let t1 = tt::Ident::new(&format!("{}_self", it.sym), it.span);
|
||||
let t2 = tt::Ident::new(&format!("{}_other", it.sym), it.span);
|
||||
let and_and = and_and(span);
|
||||
quote!(span =>#and_and #t1 .eq( #t2 ))
|
||||
});
|
||||
let first = {
|
||||
let t1 = tt::Ident::new(format!("{}_self", first.text), first.span);
|
||||
let t2 = tt::Ident::new(format!("{}_other", first.text), first.span);
|
||||
let t1 = tt::Ident::new(&format!("{}_self", first.sym), first.span);
|
||||
let t2 = tt::Ident::new(&format!("{}_other", first.sym), first.span);
|
||||
quote!(span =>#t1 .eq( #t2 ))
|
||||
};
|
||||
quote!(span =>#first ##rest)
|
||||
|
@ -730,7 +730,7 @@ fn self_and_other_patterns(
|
|||
let self_patterns = adt.shape.as_pattern_map(
|
||||
name,
|
||||
|it| {
|
||||
let t = tt::Ident::new(format!("{}_self", it.text), it.span);
|
||||
let t = tt::Ident::new(&format!("{}_self", it.sym), it.span);
|
||||
quote!(span =>#t)
|
||||
},
|
||||
span,
|
||||
|
@ -738,7 +738,7 @@ fn self_and_other_patterns(
|
|||
let other_patterns = adt.shape.as_pattern_map(
|
||||
name,
|
||||
|it| {
|
||||
let t = tt::Ident::new(format!("{}_other", it.text), it.span);
|
||||
let t = tt::Ident::new(&format!("{}_other", it.sym), it.span);
|
||||
quote!(span =>#t)
|
||||
},
|
||||
span,
|
||||
|
@ -776,8 +776,8 @@ fn ord_expand(span: Span, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> {
|
|||
|(pat1, pat2, fields)| {
|
||||
let mut body = quote!(span =>#krate::cmp::Ordering::Equal);
|
||||
for f in fields.into_iter().rev() {
|
||||
let t1 = tt::Ident::new(format!("{}_self", f.text), f.span);
|
||||
let t2 = tt::Ident::new(format!("{}_other", f.text), f.span);
|
||||
let t1 = tt::Ident::new(&format!("{}_self", f.sym), f.span);
|
||||
let t2 = tt::Ident::new(&format!("{}_other", f.sym), f.span);
|
||||
body = compare(krate, quote!(span =>#t1), quote!(span =>#t2), body, span);
|
||||
}
|
||||
let fat_arrow = fat_arrow(span);
|
||||
|
@ -838,8 +838,8 @@ fn partial_ord_expand(span: Span, tt: &tt::Subtree) -> ExpandResult<tt::Subtree>
|
|||
let mut body =
|
||||
quote!(span =>#krate::option::Option::Some(#krate::cmp::Ordering::Equal));
|
||||
for f in fields.into_iter().rev() {
|
||||
let t1 = tt::Ident::new(format!("{}_self", f.text), f.span);
|
||||
let t2 = tt::Ident::new(format!("{}_other", f.text), f.span);
|
||||
let t1 = tt::Ident::new(&format!("{}_self", f.sym), f.span);
|
||||
let t2 = tt::Ident::new(&format!("{}_other", f.sym), f.span);
|
||||
body = compare(krate, quote!(span =>#t1), quote!(span =>#t2), body, span);
|
||||
}
|
||||
let fat_arrow = fat_arrow(span);
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
//! Builtin macro
|
||||
|
||||
use ::tt::SmolStr;
|
||||
use base_db::{AnchoredPath, FileId};
|
||||
use cfg::CfgExpr;
|
||||
use either::Either;
|
||||
use intern::sym;
|
||||
use intern::{sym, Symbol};
|
||||
use mbe::{parse_exprs_with_sep, parse_to_token_tree};
|
||||
use span::{Edition, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
|
||||
use stdx::format_to;
|
||||
|
@ -181,10 +180,10 @@ fn line_expand(
|
|||
ExpandResult::ok(tt::Subtree {
|
||||
delimiter: tt::Delimiter::invisible_spanned(span),
|
||||
token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||
text: "0".into(),
|
||||
symbol: sym::INTEGER_0.clone(),
|
||||
span,
|
||||
kind: tt::LitKind::Integer,
|
||||
suffix: Some(Box::new("u32".into())),
|
||||
suffix: Some(sym::u32.clone()),
|
||||
}))]),
|
||||
})
|
||||
}
|
||||
|
@ -301,12 +300,12 @@ fn format_args_nl_expand(
|
|||
let mut tt = tt.clone();
|
||||
tt.delimiter.kind = tt::DelimiterKind::Parenthesis;
|
||||
if let Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||
text,
|
||||
symbol: text,
|
||||
kind: tt::LitKind::Str,
|
||||
..
|
||||
}))) = tt.token_trees.first_mut()
|
||||
{
|
||||
*text = format_smolstr!("{text}\\n");
|
||||
*text = Symbol::intern(&format_smolstr!("{}\\n", text.as_str()));
|
||||
}
|
||||
ExpandResult::ok(quote! {span =>
|
||||
builtin #pound format_args #tt
|
||||
|
@ -460,14 +459,14 @@ fn compile_error_expand(
|
|||
) -> ExpandResult<tt::Subtree> {
|
||||
let err = match &*tt.token_trees {
|
||||
[tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||
text,
|
||||
symbol: text,
|
||||
span: _,
|
||||
kind: tt::LitKind::Str | tt::LitKind::StrRaw(_),
|
||||
suffix: _,
|
||||
}))] =>
|
||||
// FIXME: Use the span here!
|
||||
{
|
||||
ExpandError::other(Box::from(&*unescape_str(text)))
|
||||
ExpandError::other(Box::from(unescape_str(text).as_str()))
|
||||
}
|
||||
_ => ExpandError::other("`compile_error!` argument must be a string"),
|
||||
};
|
||||
|
@ -507,18 +506,20 @@ fn concat_expand(
|
|||
// as-is.
|
||||
match it.kind {
|
||||
tt::LitKind::Char => {
|
||||
if let Ok(c) = unescape_char(&it.text) {
|
||||
if let Ok(c) = unescape_char(it.symbol.as_str()) {
|
||||
text.extend(c.escape_default());
|
||||
}
|
||||
record_span(it.span);
|
||||
}
|
||||
tt::LitKind::Integer | tt::LitKind::Float => format_to!(text, "{}", it.text),
|
||||
tt::LitKind::Integer | tt::LitKind::Float => {
|
||||
format_to!(text, "{}", it.symbol.as_str())
|
||||
}
|
||||
tt::LitKind::Str => {
|
||||
text.push_str(&it.text);
|
||||
text.push_str(it.symbol.as_str());
|
||||
record_span(it.span);
|
||||
}
|
||||
tt::LitKind::StrRaw(_) => {
|
||||
format_to!(text, "{}", it.text.escape_debug());
|
||||
format_to!(text, "{}", it.symbol.as_str().escape_debug());
|
||||
record_span(it.span);
|
||||
}
|
||||
tt::LitKind::Byte
|
||||
|
@ -531,9 +532,9 @@ fn concat_expand(
|
|||
}
|
||||
// handle boolean literals
|
||||
tt::TokenTree::Leaf(tt::Leaf::Ident(id))
|
||||
if i % 2 == 0 && (id.text == "true" || id.text == "false") =>
|
||||
if i % 2 == 0 && (id.sym == sym::true_ || id.sym == sym::false_) =>
|
||||
{
|
||||
text.push_str(id.text.as_str());
|
||||
text.push_str(id.sym.as_str());
|
||||
record_span(id.span);
|
||||
}
|
||||
tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
|
||||
|
@ -562,21 +563,21 @@ fn concat_bytes_expand(
|
|||
};
|
||||
for (i, t) in tt.token_trees.iter().enumerate() {
|
||||
match t {
|
||||
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { text, span, kind, suffix: _ })) => {
|
||||
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { symbol: text, span, kind, suffix: _ })) => {
|
||||
record_span(*span);
|
||||
match kind {
|
||||
tt::LitKind::Byte => {
|
||||
if let Ok(b) = unescape_byte(text) {
|
||||
if let Ok(b) = unescape_byte(text.as_str()) {
|
||||
bytes.extend(
|
||||
b.escape_ascii().filter_map(|it| char::from_u32(it as u32)),
|
||||
);
|
||||
}
|
||||
}
|
||||
tt::LitKind::ByteStr => {
|
||||
bytes.push_str(text);
|
||||
bytes.push_str(text.as_str());
|
||||
}
|
||||
tt::LitKind::ByteStrRaw(_) => {
|
||||
bytes.extend(text.escape_debug());
|
||||
bytes.extend(text.as_str().escape_debug());
|
||||
}
|
||||
_ => {
|
||||
err.get_or_insert(mbe::ExpandError::UnexpectedToken.into());
|
||||
|
@ -602,7 +603,7 @@ fn concat_bytes_expand(
|
|||
value: tt::Subtree {
|
||||
delimiter: tt::Delimiter::invisible_spanned(span),
|
||||
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||
text: bytes.into(),
|
||||
symbol: Symbol::intern(&bytes),
|
||||
span,
|
||||
kind: tt::LitKind::ByteStr,
|
||||
suffix: None,
|
||||
|
@ -621,24 +622,24 @@ fn concat_bytes_expand_subtree(
|
|||
for (ti, tt) in tree.token_trees.iter().enumerate() {
|
||||
match tt {
|
||||
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||
text,
|
||||
symbol: text,
|
||||
span,
|
||||
kind: tt::LitKind::Byte,
|
||||
suffix: _,
|
||||
})) => {
|
||||
if let Ok(b) = unescape_byte(text) {
|
||||
if let Ok(b) = unescape_byte(text.as_str()) {
|
||||
bytes.extend(b.escape_ascii().filter_map(|it| char::from_u32(it as u32)));
|
||||
}
|
||||
record_span(*span);
|
||||
}
|
||||
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||
text,
|
||||
symbol: text,
|
||||
span,
|
||||
kind: tt::LitKind::Integer,
|
||||
suffix: _,
|
||||
})) => {
|
||||
record_span(*span);
|
||||
if let Ok(b) = text.parse::<u8>() {
|
||||
if let Ok(b) = text.as_str().parse::<u8>() {
|
||||
bytes.extend(b.escape_ascii().filter_map(|it| char::from_u32(it as u32)));
|
||||
}
|
||||
}
|
||||
|
@ -662,7 +663,7 @@ fn concat_idents_expand(
|
|||
for (i, t) in tt.token_trees.iter().enumerate() {
|
||||
match t {
|
||||
tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => {
|
||||
ident.push_str(id.text.as_str());
|
||||
ident.push_str(id.sym.as_str());
|
||||
}
|
||||
tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
|
||||
_ => {
|
||||
|
@ -671,7 +672,7 @@ fn concat_idents_expand(
|
|||
}
|
||||
}
|
||||
// FIXME merge spans
|
||||
let ident = tt::Ident { text: ident.into(), span, is_raw: tt::IdentIsRaw::No };
|
||||
let ident = tt::Ident { sym: Symbol::intern(&ident), span, is_raw: tt::IdentIsRaw::No };
|
||||
ExpandResult { value: quote!(span =>#ident), err }
|
||||
}
|
||||
|
||||
|
@ -694,12 +695,12 @@ fn relative_file(
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_string(tt: &tt::Subtree) -> Result<(SmolStr, Span), ExpandError> {
|
||||
fn parse_string(tt: &tt::Subtree) -> Result<(Symbol, Span), ExpandError> {
|
||||
tt.token_trees
|
||||
.first()
|
||||
.and_then(|tt| match tt {
|
||||
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||
text,
|
||||
symbol: text,
|
||||
span,
|
||||
kind: tt::LitKind::Str,
|
||||
suffix: _,
|
||||
|
@ -739,7 +740,7 @@ pub fn include_input_to_file_id(
|
|||
arg_id: MacroCallId,
|
||||
arg: &tt::Subtree,
|
||||
) -> Result<FileId, ExpandError> {
|
||||
relative_file(db, arg_id, &parse_string(arg)?.0, false)
|
||||
relative_file(db, arg_id, parse_string(arg)?.0.as_str(), false)
|
||||
}
|
||||
|
||||
fn include_bytes_expand(
|
||||
|
@ -752,7 +753,7 @@ fn include_bytes_expand(
|
|||
let res = tt::Subtree {
|
||||
delimiter: tt::Delimiter::invisible_spanned(span),
|
||||
token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||
text: r#"b"""#.into(),
|
||||
symbol: Symbol::empty(),
|
||||
span,
|
||||
kind: tt::LitKind::ByteStrRaw(1),
|
||||
suffix: None,
|
||||
|
@ -778,7 +779,7 @@ fn include_str_expand(
|
|||
// it's unusual to `include_str!` a Rust file), but we can return an empty string.
|
||||
// Ideally, we'd be able to offer a precise expansion if the user asks for macro
|
||||
// expansion.
|
||||
let file_id = match relative_file(db, arg_id, &path, true) {
|
||||
let file_id = match relative_file(db, arg_id, path.as_str(), true) {
|
||||
Ok(file_id) => file_id,
|
||||
Err(_) => {
|
||||
return ExpandResult::ok(quote!(span =>""));
|
||||
|
@ -791,9 +792,9 @@ fn include_str_expand(
|
|||
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: &Symbol) -> Option<String> {
|
||||
let krate = db.lookup_intern_macro_call(arg_id).krate;
|
||||
db.crate_graph()[krate].env.get(key).map(|it| it.escape_debug().to_string())
|
||||
db.crate_graph()[krate].env.get(key.as_str()).map(|it| it.escape_debug().to_string())
|
||||
}
|
||||
|
||||
fn env_expand(
|
||||
|
@ -813,7 +814,7 @@ fn env_expand(
|
|||
let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| {
|
||||
// The only variable rust-analyzer ever sets is `OUT_DIR`, so only diagnose that to avoid
|
||||
// unnecessary diagnostics for eg. `CARGO_PKG_NAME`.
|
||||
if key == "OUT_DIR" {
|
||||
if key.as_str() == "OUT_DIR" {
|
||||
err = Some(ExpandError::other(r#"`OUT_DIR` not set, enable "build scripts" to fix"#));
|
||||
}
|
||||
|
||||
|
@ -867,15 +868,16 @@ fn quote_expand(
|
|||
)
|
||||
}
|
||||
|
||||
fn unescape_str(s: &SmolStr) -> SmolStr {
|
||||
if s.contains('\\') {
|
||||
fn unescape_str(s: &Symbol) -> Symbol {
|
||||
if s.as_str().contains('\\') {
|
||||
let s = s.as_str();
|
||||
let mut buf = String::with_capacity(s.len());
|
||||
unescape_unicode(s, Mode::Str, &mut |_, c| {
|
||||
if let Ok(c) = c {
|
||||
buf.push(c)
|
||||
}
|
||||
});
|
||||
buf.into()
|
||||
Symbol::intern(&buf)
|
||||
} else {
|
||||
s.clone()
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ use syntax::{
|
|||
AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, T,
|
||||
};
|
||||
use tracing::{debug, warn};
|
||||
use tt::SmolStr;
|
||||
|
||||
use crate::{db::ExpandDatabase, proc_macro::ProcMacroKind, MacroCallLoc, MacroDefKind};
|
||||
|
||||
|
@ -263,7 +262,7 @@ where
|
|||
let name = match iter.next() {
|
||||
None => return None,
|
||||
Some(NodeOrToken::Token(element)) => match element.kind() {
|
||||
syntax::T![ident] => SmolStr::new(element.text()),
|
||||
syntax::T![ident] => element.text().to_owned(),
|
||||
_ => return Some(CfgExpr::Invalid),
|
||||
},
|
||||
Some(_) => return Some(CfgExpr::Invalid),
|
||||
|
@ -302,13 +301,13 @@ where
|
|||
if (value_token.kind() == syntax::SyntaxKind::STRING) =>
|
||||
{
|
||||
let value = value_token.text();
|
||||
let value = SmolStr::new(value.trim_matches('"'));
|
||||
Some(CfgExpr::Atom(CfgAtom::KeyValue { key: name, value }))
|
||||
let value = value.trim_matches('"').into();
|
||||
Some(CfgExpr::Atom(CfgAtom::KeyValue { key: name.into(), value }))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => Some(CfgExpr::Atom(CfgAtom::Flag(name))),
|
||||
_ => Some(CfgExpr::Atom(CfgAtom::Flag(name.into()))),
|
||||
},
|
||||
};
|
||||
if let Some(NodeOrToken::Token(element)) = iter.peek() {
|
||||
|
|
|
@ -120,10 +120,10 @@ impl DeclarativeMacroExpander {
|
|||
.token_tree_value()?
|
||||
.token_trees
|
||||
{
|
||||
[tt::TokenTree::Leaf(tt::Leaf::Ident(i)), ..] => match &*i.text {
|
||||
"transparent" => Some(Transparency::Transparent),
|
||||
"semitransparent" => Some(Transparency::SemiTransparent),
|
||||
"opaque" => Some(Transparency::Opaque),
|
||||
[tt::TokenTree::Leaf(tt::Leaf::Ident(i)), ..] => match &i.sym {
|
||||
s if *s == sym::transparent => Some(Transparency::Transparent),
|
||||
s if *s == sym::semitransparent => Some(Transparency::SemiTransparent),
|
||||
s if *s == sym::opaque => Some(Transparency::Opaque),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! To make attribute macros work reliably when typing, we need to take care to
|
||||
//! fix up syntax errors in the code we're passing to them.
|
||||
|
||||
use intern::sym;
|
||||
use mbe::DocCommentDesugarMode;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use smallvec::SmallVec;
|
||||
|
@ -80,7 +81,7 @@ pub(crate) fn fixup_syntax(
|
|||
original.push(original_tree);
|
||||
let span = span_map.span_for_range(node_range);
|
||||
let replacement = Leaf::Ident(Ident {
|
||||
text: "__ra_fixup".into(),
|
||||
sym: sym::__ra_fixup.clone(),
|
||||
span: Span {
|
||||
range: TextRange::new(TextSize::new(idx), FIXUP_DUMMY_RANGE_END),
|
||||
anchor: SpanAnchor { ast_id: FIXUP_DUMMY_AST_ID, ..span.anchor },
|
||||
|
@ -100,7 +101,7 @@ pub(crate) fn fixup_syntax(
|
|||
// incomplete field access: some_expr.|
|
||||
append.insert(node.clone().into(), vec![
|
||||
Leaf::Ident(Ident {
|
||||
text: "__ra_fixup".into(),
|
||||
sym: sym::__ra_fixup.clone(),
|
||||
span: fake_span(node_range),
|
||||
is_raw: tt::IdentIsRaw::No
|
||||
}),
|
||||
|
@ -138,7 +139,7 @@ pub(crate) fn fixup_syntax(
|
|||
};
|
||||
append.insert(if_token.into(), vec![
|
||||
Leaf::Ident(Ident {
|
||||
text: "__ra_fixup".into(),
|
||||
sym: sym::__ra_fixup.clone(),
|
||||
span: fake_span(node_range),
|
||||
is_raw: tt::IdentIsRaw::No
|
||||
}),
|
||||
|
@ -169,7 +170,7 @@ pub(crate) fn fixup_syntax(
|
|||
};
|
||||
append.insert(while_token.into(), vec![
|
||||
Leaf::Ident(Ident {
|
||||
text: "__ra_fixup".into(),
|
||||
sym: sym::__ra_fixup.clone(),
|
||||
span: fake_span(node_range),
|
||||
is_raw: tt::IdentIsRaw::No
|
||||
}),
|
||||
|
@ -217,7 +218,7 @@ pub(crate) fn fixup_syntax(
|
|||
};
|
||||
append.insert(match_token.into(), vec![
|
||||
Leaf::Ident(Ident {
|
||||
text: "__ra_fixup".into(),
|
||||
sym: sym::__ra_fixup.clone(),
|
||||
span: fake_span(node_range),
|
||||
is_raw: tt::IdentIsRaw::No
|
||||
}),
|
||||
|
@ -247,12 +248,12 @@ pub(crate) fn fixup_syntax(
|
|||
};
|
||||
|
||||
let [pat, in_token, iter] = [
|
||||
"_",
|
||||
"in",
|
||||
"__ra_fixup"
|
||||
].map(|text|
|
||||
sym::underscore.clone(),
|
||||
sym::in_.clone(),
|
||||
sym::__ra_fixup.clone(),
|
||||
].map(|sym|
|
||||
Leaf::Ident(Ident {
|
||||
text: text.into(),
|
||||
sym,
|
||||
span: fake_span(node_range),
|
||||
is_raw: tt::IdentIsRaw::No
|
||||
}),
|
||||
|
@ -286,7 +287,7 @@ pub(crate) fn fixup_syntax(
|
|||
if it.name_ref().is_some() && it.expr().is_none() {
|
||||
append.insert(colon.into(), vec![
|
||||
Leaf::Ident(Ident {
|
||||
text: "__ra_fixup".into(),
|
||||
sym: sym::__ra_fixup.clone(),
|
||||
span: fake_span(node_range),
|
||||
is_raw: tt::IdentIsRaw::No
|
||||
})
|
||||
|
@ -299,7 +300,7 @@ pub(crate) fn fixup_syntax(
|
|||
if it.segment().is_none() {
|
||||
append.insert(colon.into(), vec![
|
||||
Leaf::Ident(Ident {
|
||||
text: "__ra_fixup".into(),
|
||||
sym: sym::__ra_fixup.clone(),
|
||||
span: fake_span(node_range),
|
||||
is_raw: tt::IdentIsRaw::No
|
||||
})
|
||||
|
@ -333,7 +334,7 @@ pub(crate) fn fixup_syntax(
|
|||
if it.body().is_none() {
|
||||
append.insert(node.into(), vec![
|
||||
Leaf::Ident(Ident {
|
||||
text: "__ra_fixup".into(),
|
||||
sym: sym::__ra_fixup.clone(),
|
||||
span: fake_span(node_range),
|
||||
is_raw: tt::IdentIsRaw::No
|
||||
})
|
||||
|
@ -448,9 +449,9 @@ mod tests {
|
|||
// `TokenTree`s, see the last assertion in `check()`.
|
||||
fn check_leaf_eq(a: &tt::Leaf, b: &tt::Leaf) -> bool {
|
||||
match (a, b) {
|
||||
(tt::Leaf::Literal(a), tt::Leaf::Literal(b)) => a.text == b.text,
|
||||
(tt::Leaf::Literal(a), tt::Leaf::Literal(b)) => a.symbol == b.symbol,
|
||||
(tt::Leaf::Punct(a), tt::Leaf::Punct(b)) => a.char == b.char,
|
||||
(tt::Leaf::Ident(a), tt::Leaf::Ident(b)) => a.text == b.text,
|
||||
(tt::Leaf::Ident(a), tt::Leaf::Ident(b)) => a.sym == b.sym,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use intern::Symbol;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
pub struct BuiltinAttribute {
|
||||
|
@ -26,11 +27,16 @@ pub struct AttributeTemplate {
|
|||
pub name_value_str: Option<&'static str>,
|
||||
}
|
||||
|
||||
pub fn find_builtin_attr_idx(name: &str) -> Option<usize> {
|
||||
static BUILTIN_LOOKUP_TABLE: OnceLock<FxHashMap<&'static str, usize>> = OnceLock::new();
|
||||
pub fn find_builtin_attr_idx(name: &Symbol) -> Option<usize> {
|
||||
static BUILTIN_LOOKUP_TABLE: OnceLock<FxHashMap<Symbol, usize>> = OnceLock::new();
|
||||
BUILTIN_LOOKUP_TABLE
|
||||
.get_or_init(|| {
|
||||
INERT_ATTRIBUTES.iter().map(|attr| attr.name).enumerate().map(|(a, b)| (b, a)).collect()
|
||||
INERT_ATTRIBUTES
|
||||
.iter()
|
||||
.map(|attr| attr.name)
|
||||
.enumerate()
|
||||
.map(|(a, b)| (Symbol::intern(b), a))
|
||||
.collect()
|
||||
})
|
||||
.get(name)
|
||||
.copied()
|
||||
|
|
|
@ -316,30 +316,36 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModP
|
|||
tt::Leaf::Punct(tt::Punct { char: ':', .. }) => PathKind::Abs,
|
||||
_ => return None,
|
||||
},
|
||||
tt::Leaf::Ident(tt::Ident { text, span, .. }) if text == "$crate" => {
|
||||
tt::Leaf::Ident(tt::Ident { sym: text, span, .. }) if *text == sym::dollar_crate => {
|
||||
resolve_crate_root(db, span.ctx).map(PathKind::DollarCrate).unwrap_or(PathKind::Crate)
|
||||
}
|
||||
tt::Leaf::Ident(tt::Ident { text, .. }) if text == "self" => PathKind::SELF,
|
||||
tt::Leaf::Ident(tt::Ident { text, .. }) if text == "super" => {
|
||||
tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::self_ => PathKind::SELF,
|
||||
tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::super_ => {
|
||||
let mut deg = 1;
|
||||
while let Some(tt::Leaf::Ident(tt::Ident { text, span, is_raw })) = leaves.next() {
|
||||
if text != "super" {
|
||||
segments.push(Name::new(text, *is_raw, span.ctx));
|
||||
while let Some(tt::Leaf::Ident(tt::Ident { sym: text, span, is_raw })) = leaves.next() {
|
||||
if *text != sym::super_ {
|
||||
segments.push(Name::new_symbol_maybe_raw(text.clone(), *is_raw, span.ctx));
|
||||
break;
|
||||
}
|
||||
deg += 1;
|
||||
}
|
||||
PathKind::Super(deg)
|
||||
}
|
||||
tt::Leaf::Ident(tt::Ident { text, .. }) if text == "crate" => PathKind::Crate,
|
||||
tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::crate_ => PathKind::Crate,
|
||||
tt::Leaf::Ident(ident) => {
|
||||
segments.push(Name::new(&ident.text, ident.is_raw, ident.span.ctx));
|
||||
segments.push(Name::new_symbol_maybe_raw(
|
||||
ident.sym.clone(),
|
||||
ident.is_raw,
|
||||
ident.span.ctx,
|
||||
));
|
||||
PathKind::Plain
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
segments.extend(leaves.filter_map(|leaf| match leaf {
|
||||
::tt::Leaf::Ident(ident) => Some(Name::new(&ident.text, ident.is_raw, ident.span.ctx)),
|
||||
::tt::Leaf::Ident(ident) => {
|
||||
Some(Name::new_symbol_maybe_raw(ident.sym.clone(), ident.is_raw, ident.span.ctx))
|
||||
}
|
||||
_ => None,
|
||||
}));
|
||||
Some(ModPath { kind, segments })
|
||||
|
|
|
@ -17,6 +17,8 @@ use syntax::{ast, format_smolstr, utils::is_raw_identifier, SmolStr};
|
|||
pub struct Name {
|
||||
symbol: Symbol,
|
||||
ctx: (),
|
||||
// FIXME: We should probably encode rawness as a property here instead, once we have hygiene
|
||||
// in here we've got 4 bytes of padding to fill anyways
|
||||
}
|
||||
|
||||
impl fmt::Debug for Name {
|
||||
|
@ -187,14 +189,22 @@ impl Name {
|
|||
&self.symbol
|
||||
}
|
||||
|
||||
pub const fn new_symbol(doc: Symbol, ctx: SyntaxContextId) -> Self {
|
||||
pub const fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
|
||||
_ = ctx;
|
||||
Self { symbol: doc, ctx: () }
|
||||
Self { symbol, ctx: () }
|
||||
}
|
||||
|
||||
pub fn new_symbol_maybe_raw(sym: Symbol, raw: tt::IdentIsRaw, ctx: SyntaxContextId) -> Self {
|
||||
if raw.no() {
|
||||
Self { symbol: sym, ctx: () }
|
||||
} else {
|
||||
Name::new(sym.as_str(), raw, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This needs to go once we have hygiene
|
||||
pub const fn new_symbol_root(doc: Symbol) -> Self {
|
||||
Self { symbol: doc, ctx: () }
|
||||
pub const fn new_symbol_root(sym: Symbol) -> Self {
|
||||
Self { symbol: sym, ctx: () }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,7 +260,7 @@ impl AsName for ast::NameOrNameRef {
|
|||
|
||||
impl<Span> AsName for tt::Ident<Span> {
|
||||
fn as_name(&self) -> Name {
|
||||
Name::resolve(&self.text)
|
||||
Name::resolve(self.sym.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
//! A simplified version of quote-crate like quasi quote macro
|
||||
#![allow(clippy::crate_in_macro_def)]
|
||||
|
||||
use intern::Symbol;
|
||||
use intern::{sym, Symbol};
|
||||
use span::Span;
|
||||
use tt::IdentIsRaw;
|
||||
|
||||
use crate::name::Name;
|
||||
|
||||
pub(crate) const fn dollar_crate(span: Span) -> tt::Ident<Span> {
|
||||
tt::Ident { text: syntax::SmolStr::new_static("$crate"), span, is_raw: tt::IdentIsRaw::No }
|
||||
pub(crate) fn dollar_crate(span: Span) -> tt::Ident<Span> {
|
||||
tt::Ident { sym: sym::dollar_crate.clone(), span, is_raw: tt::IdentIsRaw::No }
|
||||
}
|
||||
|
||||
// A helper macro quote macro
|
||||
|
@ -99,7 +99,7 @@ macro_rules! __quote {
|
|||
($span:ident $tt:ident ) => {
|
||||
vec![ {
|
||||
crate::tt::Leaf::Ident(crate::tt::Ident {
|
||||
text: stringify!($tt).into(),
|
||||
sym: intern::Symbol::intern(stringify!($tt)),
|
||||
span: $span,
|
||||
is_raw: tt::IdentIsRaw::No,
|
||||
}).into()
|
||||
|
@ -177,12 +177,6 @@ impl ToTokenTree for crate::tt::TokenTree {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToTokenTree for &crate::tt::TokenTree {
|
||||
fn to_token(self, _: Span) -> crate::tt::TokenTree {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokenTree for crate::tt::Subtree {
|
||||
fn to_token(self, _: Span) -> crate::tt::TokenTree {
|
||||
self.into()
|
||||
|
@ -198,35 +192,34 @@ macro_rules! impl_to_to_tokentrees {
|
|||
leaf.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokenTree for &$ty {
|
||||
fn to_token($this, $span: Span) -> crate::tt::TokenTree {
|
||||
let leaf: crate::tt::Leaf = $im.clone().into();
|
||||
leaf.into()
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToTokenTree + Clone> ToTokenTree for &T {
|
||||
fn to_token(self, span: Span) -> crate::tt::TokenTree {
|
||||
self.clone().to_token(span)
|
||||
}
|
||||
}
|
||||
|
||||
impl_to_to_tokentrees! {
|
||||
span: u32 => self { crate::tt::Literal{text: self.to_string().into(), span, kind: tt::LitKind::Integer, suffix: None } };
|
||||
span: usize => self { crate::tt::Literal{text: self.to_string().into(), span, kind: tt::LitKind::Integer, suffix: None } };
|
||||
span: i32 => self { crate::tt::Literal{text: self.to_string().into(), span, kind: tt::LitKind::Integer, suffix: None } };
|
||||
span: bool => self { crate::tt::Ident{text: self.to_string().into(), span, is_raw: tt::IdentIsRaw::No } };
|
||||
span: u32 => self { crate::tt::Literal{symbol: Symbol::integer(self as _), span, kind: tt::LitKind::Integer, suffix: None } };
|
||||
span: usize => self { crate::tt::Literal{symbol: Symbol::integer(self as _), span, kind: tt::LitKind::Integer, suffix: None } };
|
||||
span: i32 => self { crate::tt::Literal{symbol: Symbol::integer(self as _), span, kind: tt::LitKind::Integer, suffix: None } };
|
||||
span: bool => self { crate::tt::Ident{sym: if self { sym::true_.clone() } else { sym::false_.clone() }, span, is_raw: tt::IdentIsRaw::No } };
|
||||
_span: crate::tt::Leaf => self { self };
|
||||
_span: crate::tt::Literal => self { self };
|
||||
_span: crate::tt::Ident => self { self };
|
||||
_span: crate::tt::Punct => self { self };
|
||||
span: &str => self { crate::tt::Literal{text: (*self).into(), span, kind: tt::LitKind::Str, suffix: None }};
|
||||
span: String => self { crate::tt::Literal{text: self.into(), span, kind: tt::LitKind::Str, suffix: None }};
|
||||
span: &str => self { crate::tt::Literal{symbol: Symbol::intern(self), span, kind: tt::LitKind::Str, suffix: None }};
|
||||
span: String => self { crate::tt::Literal{symbol: Symbol::intern(&self), span, kind: tt::LitKind::Str, suffix: None }};
|
||||
span: Name => self {
|
||||
let (is_raw, s) = IdentIsRaw::split_from_symbol(self.as_str());
|
||||
crate::tt::Ident{text: s.into(), span, is_raw }
|
||||
crate::tt::Ident{sym: Symbol::intern(s), span, is_raw }
|
||||
};
|
||||
span: Symbol => self {
|
||||
let (is_raw, s) = IdentIsRaw::split_from_symbol(self.as_str());
|
||||
crate::tt::Ident{text: s.into(), span, is_raw }
|
||||
crate::tt::Ident{sym: Symbol::intern(s), span, is_raw }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -236,6 +229,7 @@ mod tests {
|
|||
use ::tt::IdentIsRaw;
|
||||
use base_db::FileId;
|
||||
use expect_test::expect;
|
||||
use intern::Symbol;
|
||||
use span::{SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
|
||||
use syntax::{TextRange, TextSize};
|
||||
|
||||
|
@ -268,7 +262,7 @@ mod tests {
|
|||
|
||||
fn mk_ident(name: &str) -> crate::tt::Ident {
|
||||
let (is_raw, s) = IdentIsRaw::split_from_symbol(name);
|
||||
crate::tt::Ident { text: s.into(), span: DUMMY, is_raw }
|
||||
crate::tt::Ident { sym: Symbol::intern(s), span: DUMMY, is_raw }
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue