Use Symbol in Name

This commit is contained in:
Lukas Wirth 2024-07-12 15:57:54 +02:00
parent 843806b79f
commit 3fe815b0f3
75 changed files with 750 additions and 755 deletions

View file

@ -4,7 +4,7 @@ use std::{borrow::Cow, fmt, ops};
use base_db::CrateId;
use cfg::CfgExpr;
use either::Either;
use intern::Interned;
use intern::{sym, Interned};
use mbe::{syntax_node_to_token_tree, DelimiterKind, DocCommentDesugarMode, Punct};
use smallvec::{smallvec, SmallVec};
use span::{Span, SyntaxContextId};
@ -12,6 +12,7 @@ use syntax::unescape;
use syntax::{ast, format_smolstr, match_ast, AstNode, AstToken, SmolStr, SyntaxNode};
use triomphe::ThinArc;
use crate::name::Name;
use crate::{
db::ExpandDatabase,
mod_path::ModPath,
@ -58,7 +59,7 @@ impl RawAttrs {
text: SmolStr::new(format_smolstr!("\"{}\"", Self::escape_chars(doc))),
span,
}))),
path: Interned::new(ModPath::from(crate::name!(doc))),
path: Interned::new(ModPath::from(Name::new_symbol(sym::doc, span.ctx))),
ctxt: span.ctx,
}
}),
@ -115,47 +116,47 @@ impl RawAttrs {
pub fn filter(self, db: &dyn ExpandDatabase, krate: CrateId) -> RawAttrs {
let has_cfg_attrs = self
.iter()
.any(|attr| attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr]));
.any(|attr| attr.path.as_ident().map_or(false, |name| *name == sym::cfg_attr));
if !has_cfg_attrs {
return self;
}
let crate_graph = db.crate_graph();
let new_attrs =
self.iter()
.flat_map(|attr| -> SmallVec<[_; 1]> {
let is_cfg_attr =
attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr]);
if !is_cfg_attr {
return smallvec![attr.clone()];
}
let new_attrs = self
.iter()
.flat_map(|attr| -> SmallVec<[_; 1]> {
let is_cfg_attr = attr.path.as_ident().map_or(false, |name| *name == sym::cfg_attr);
if !is_cfg_attr {
return smallvec![attr.clone()];
}
let subtree = match attr.token_tree_value() {
Some(it) => it,
_ => return smallvec![attr.clone()],
};
let subtree = match attr.token_tree_value() {
Some(it) => it,
_ => return smallvec![attr.clone()],
};
let (cfg, parts) = match parse_cfg_attr_input(subtree) {
Some(it) => it,
None => return smallvec![attr.clone()],
};
let index = attr.id;
let attrs = parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map(
|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)),
);
let (cfg, parts) = match parse_cfg_attr_input(subtree) {
Some(it) => it,
None => return smallvec![attr.clone()],
};
let index = attr.id;
let attrs = parts
.enumerate()
.take(1 << AttrId::CFG_ATTR_BITS)
.filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)));
let cfg_options = &crate_graph[krate].cfg_options;
let cfg = Subtree { delimiter: subtree.delimiter, token_trees: Box::from(cfg) };
let cfg = CfgExpr::parse(&cfg);
if cfg_options.check(&cfg) == Some(false) {
smallvec![]
} else {
cov_mark::hit!(cfg_attr_active);
let cfg_options = &crate_graph[krate].cfg_options;
let cfg = Subtree { delimiter: subtree.delimiter, token_trees: Box::from(cfg) };
let cfg = CfgExpr::parse(&cfg);
if cfg_options.check(&cfg) == Some(false) {
smallvec![]
} else {
cov_mark::hit!(cfg_attr_active);
attrs.collect()
}
})
.collect::<Vec<_>>();
attrs.collect()
}
})
.collect::<Vec<_>>();
let entries = if new_attrs.is_empty() {
None
} else {
@ -316,6 +317,20 @@ 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)),
_ => None,
}
}
pub fn string_value_unescape(&self) -> Option<Cow<'_, str>> {
match self.input.as_deref()? {
AttrInput::Literal(it) => match it.text.strip_prefix('r') {
@ -369,7 +384,7 @@ impl Attr {
}
pub fn cfg(&self) -> Option<CfgExpr> {
if *self.path.as_ident()? == crate::name![cfg] {
if *self.path.as_ident()? == sym::cfg {
self.token_tree_value().map(CfgExpr::parse)
} else {
None

View file

@ -1,4 +1,5 @@
//! Builtin attributes.
use intern::sym;
use span::{MacroCallId, Span};
use crate::{db::ExpandDatabase, name, tt, ExpandResult, MacroCallKind};
@ -19,7 +20,7 @@ macro_rules! register_builtin {
fn find_by_name(name: &name::Name) -> Option<Self> {
match name {
$( id if id == &name::name![$name] => Some(BuiltinAttrExpander::$variant), )*
$( id if id == &sym::$name => Some(BuiltinAttrExpander::$variant), )*
_ => None,
}
}

View file

@ -1,5 +1,6 @@
//! Builtin derives.
use intern::sym;
use itertools::izip;
use mbe::DocCommentDesugarMode;
use rustc_hash::FxHashSet;
@ -36,7 +37,7 @@ macro_rules! register_builtin {
fn find_by_name(name: &name::Name) -> Option<Self> {
match name {
$( id if id == &name::name![$trait] => Some(BuiltinDeriveExpander::$trait), )*
$( id if id == &sym::$trait => Some(BuiltinDeriveExpander::$trait), )*
_ => None,
}
}

View file

@ -3,6 +3,7 @@
use base_db::{AnchoredPath, FileId};
use cfg::CfgExpr;
use either::Either;
use intern::sym;
use itertools::Itertools;
use mbe::{parse_exprs_with_sep, parse_to_token_tree};
use span::{Edition, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
@ -11,8 +12,7 @@ use syntax::ast::{self, AstToken};
use crate::{
db::ExpandDatabase,
hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
name::{self, known},
quote,
name, quote,
quote::dollar_crate,
tt::{self, DelimSpan},
ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroFileIdExt,
@ -48,8 +48,8 @@ macro_rules! register_builtin {
fn find_by_name(ident: &name::Name) -> Option<Either<BuiltinFnLikeExpander, EagerExpander>> {
match ident {
$( id if id == &name::name![$name] => Some(Either::Left(BuiltinFnLikeExpander::$kind)), )*
$( id if id == &name::name![$e_name] => Some(Either::Right(EagerExpander::$e_kind)), )*
$( id if id == &sym::$name => Some(Either::Left(BuiltinFnLikeExpander::$kind)), )*
$( id if id == &sym::$e_name => Some(Either::Right(EagerExpander::$e_kind)), )*
_ => return None,
}
}
@ -367,8 +367,7 @@ fn panic_expand(
let dollar_crate = dollar_crate(span);
let call_site_span = span_with_call_site_ctxt(db, span, id);
let mac =
if use_panic_2021(db, call_site_span) { known::panic_2021 } else { known::panic_2015 };
let mac = if use_panic_2021(db, call_site_span) { sym::panic_2021 } else { sym::panic_2015 };
// Expand to a macro call `$crate::panic::panic_{edition}`
let mut call = quote!(call_site_span =>#dollar_crate::panic::#mac!);
@ -397,9 +396,9 @@ fn unreachable_expand(
let call_site_span = span_with_call_site_ctxt(db, span, id);
let mac = if use_panic_2021(db, call_site_span) {
known::unreachable_2021
sym::unreachable_2021
} else {
known::unreachable_2015
sym::unreachable_2015
};
// Expand to a macro call `$crate::panic::panic_{edition}`

View file

@ -133,6 +133,15 @@ pub trait ExpandDatabase: SourceDatabase {
&self,
macro_call: MacroCallId,
) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>>;
#[salsa::transparent]
fn syntax_context(&self, file: HirFileId) -> SyntaxContextId;
}
fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId) -> SyntaxContextId {
match file.repr() {
HirFileIdRepr::FileId(_) => SyntaxContextId::ROOT,
HirFileIdRepr::MacroFile(m) => db.macro_arg(m.macro_call_id).2.ctx,
}
}
/// This expands the given macro call, but with different arguments. This is

View file

@ -2,6 +2,7 @@
use std::sync::OnceLock;
use base_db::{CrateId, VersionReq};
use intern::sym;
use mbe::DocCommentDesugarMode;
use span::{Edition, MacroCallId, Span, SyntaxContextId};
use stdx::TupleExt;
@ -111,8 +112,10 @@ impl DeclarativeMacroExpander {
match &*attrs
.iter()
.find(|it| {
it.path.as_ident().and_then(|it| it.as_str())
== Some("rustc_macro_transparency")
it.path
.as_ident()
.map(|it| *it == sym::rustc_macro_transparency)
.unwrap_or(false)
})?
.token_tree_value()?
.token_trees

View file

@ -8,10 +8,11 @@ use std::{
use crate::{
db::ExpandDatabase,
hygiene::{marks_rev, SyntaxContextExt, Transparency},
name::{known, AsName, Name},
name::{AsName, Name},
tt,
};
use base_db::CrateId;
use intern::sym;
use smallvec::SmallVec;
use span::SyntaxContextId;
use syntax::{ast, AstNode};
@ -106,10 +107,7 @@ impl ModPath {
PathKind::Abs => 0,
PathKind::DollarCrate(_) => "$crate".len(),
};
self.segments()
.iter()
.map(|segment| segment.as_str().map_or(0, str::len))
.fold(base, core::ops::Add::add)
self.segments().iter().map(|segment| segment.as_str().len()).fold(base, core::ops::Add::add)
}
pub fn is_ident(&self) -> bool {
@ -122,8 +120,7 @@ impl ModPath {
#[allow(non_snake_case)]
pub fn is_Self(&self) -> bool {
self.kind == PathKind::Plain
&& matches!(&*self.segments, [name] if *name == known::SELF_TYPE)
self.kind == PathKind::Plain && matches!(&*self.segments, [name] if *name == sym::Self_)
}
/// If this path is a single identifier, like `foo`, return its name.
@ -265,9 +262,10 @@ fn convert_path(
res
}
}
ast::PathSegmentKind::SelfTypeKw => {
ModPath::from_segments(PathKind::Plain, Some(known::SELF_TYPE))
}
ast::PathSegmentKind::SelfTypeKw => ModPath::from_segments(
PathKind::Plain,
Some(Name::new_symbol(sym::Self_, SyntaxContextId::ROOT)),
),
ast::PathSegmentKind::CrateKw => ModPath::from_segments(PathKind::Crate, iter::empty()),
ast::PathSegmentKind::SelfKw => handle_super_kw(0)?,
ast::PathSegmentKind::SuperKw => handle_super_kw(1)?,
@ -323,9 +321,9 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModP
tt::Leaf::Ident(tt::Ident { text, .. }) if text == "self" => PathKind::SELF,
tt::Leaf::Ident(tt::Ident { text, .. }) if text == "super" => {
let mut deg = 1;
while let Some(tt::Leaf::Ident(tt::Ident { text, .. })) = leaves.next() {
while let Some(tt::Leaf::Ident(tt::Ident { text, span, .. })) = leaves.next() {
if text != "super" {
segments.push(Name::new_text_dont_use(text.clone()));
segments.push(Name::new(text, span.ctx));
break;
}
deg += 1;
@ -334,13 +332,13 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModP
}
tt::Leaf::Ident(tt::Ident { text, .. }) if text == "crate" => PathKind::Crate,
tt::Leaf::Ident(ident) => {
segments.push(Name::new_text_dont_use(ident.text.clone()));
segments.push(Name::new(&ident.text, ident.span.ctx));
PathKind::Plain
}
_ => return None,
};
segments.extend(leaves.filter_map(|leaf| match leaf {
::tt::Leaf::Ident(ident) => Some(Name::new_text_dont_use(ident.text.clone())),
::tt::Leaf::Ident(ident) => Some(Name::new(&ident.text, ident.span.ctx)),
_ => None,
}));
Some(ModPath { kind, segments })
@ -385,6 +383,8 @@ macro_rules! __known_path {
(core::ops::RangeInclusive) => {};
(core::future::Future) => {};
(core::future::IntoFuture) => {};
(core::fmt::Debug) => {};
(std::fmt::format) => {};
(core::ops::Try) => {};
($path:path) => {
compile_error!("Please register your known path in the path module")
@ -396,7 +396,7 @@ macro_rules! __path {
($start:ident $(:: $seg:ident)*) => ({
$crate::__known_path!($start $(:: $seg)*);
$crate::mod_path::ModPath::from_segments($crate::mod_path::PathKind::Abs, vec![
$crate::mod_path::__name![$start], $($crate::mod_path::__name![$seg],)*
$crate::name::Name::new_symbol_root(intern::sym::$start), $($crate::name::Name::new_symbol_root(intern::sym::$seg),)*
])
});
}

View file

@ -2,6 +2,8 @@
use std::fmt;
use intern::{sym::MISSING_NAME, Symbol};
use span::SyntaxContextId;
use syntax::{ast, format_smolstr, utils::is_raw_identifier, SmolStr};
/// `Name` is a wrapper around string, which is used in hir for both references
@ -11,32 +13,49 @@ use syntax::{ast, format_smolstr, utils::is_raw_identifier, SmolStr};
/// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it
/// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the
/// name without "r#".
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Name(Repr);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Name {
symbol: Symbol,
ctx: (),
}
impl Ord for Name {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.symbol.as_str().cmp(other.symbol.as_str())
}
}
impl PartialOrd for Name {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq<Symbol> for Name {
fn eq(&self, sym: &Symbol) -> bool {
self.symbol == *sym
}
}
impl PartialEq<Name> for Symbol {
fn eq(&self, name: &Name) -> bool {
*self == name.symbol
}
}
/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UnescapedName<'a>(&'a Name);
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
enum Repr {
Text(SmolStr),
TupleField(usize),
}
impl UnescapedName<'_> {
/// Returns the textual representation of this name as a [`SmolStr`]. Prefer using this over
/// [`ToString::to_string`] if possible as this conversion is cheaper in the general case.
pub fn to_smol_str(&self) -> SmolStr {
match &self.0 .0 {
Repr::Text(it) => {
if let Some(stripped) = it.strip_prefix("r#") {
SmolStr::new(stripped)
} else {
it.clone()
}
}
Repr::TupleField(it) => SmolStr::new(it.to_string()),
let it = self.0.symbol.as_str();
if let Some(stripped) = it.strip_prefix("r#") {
SmolStr::new(stripped)
} else {
it.into()
}
}
@ -50,27 +69,26 @@ impl Name {
/// Note: this is private to make creating name from random string hard.
/// Hopefully, this should allow us to integrate hygiene cleaner in the
/// future, and to switch to interned representation of names.
const fn new_text(text: SmolStr) -> Name {
Name(Repr::Text(text))
fn new_text(text: &str) -> Name {
Name { symbol: Symbol::intern(text), ctx: () }
}
// FIXME: See above, unfortunately some places really need this right now
#[doc(hidden)]
pub const fn new_text_dont_use(text: SmolStr) -> Name {
Name(Repr::Text(text))
pub fn new(text: &str, ctx: SyntaxContextId) -> Name {
_ = ctx;
Name { symbol: Symbol::intern(text), ctx: () }
}
pub fn new_tuple_field(idx: usize) -> Name {
Name(Repr::TupleField(idx))
Name { symbol: Symbol::intern(&idx.to_string()), ctx: () }
}
pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
Self::new_text(lt.text().into())
Name { symbol: Symbol::intern(lt.text().as_str()), ctx: () }
}
/// Shortcut to create a name from a string literal.
const fn new_static(text: &'static str) -> Name {
Name::new_text(SmolStr::new_static(text))
fn new_ref(text: &str) -> Name {
Name { symbol: Symbol::intern(text), ctx: () }
}
/// Resolve a name from the text of token.
@ -78,14 +96,14 @@ impl Name {
match raw_text.strip_prefix("r#") {
// When `raw_text` starts with "r#" but the name does not coincide with any
// keyword, we never need the prefix so we strip it.
Some(text) if !is_raw_identifier(text) => Name::new_text(SmolStr::new(text)),
Some(text) if !is_raw_identifier(text) => Name::new_ref(text),
// Keywords (in the current edition) *can* be used as a name in earlier editions of
// Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their
// escaped form.
None if is_raw_identifier(raw_text) => {
Name::new_text(format_smolstr!("r#{}", raw_text))
Name::new_text(&format_smolstr!("r#{}", raw_text))
}
_ => Name::new_text(raw_text.into()),
_ => Name::new_text(raw_text),
}
}
@ -99,7 +117,7 @@ impl Name {
/// name is equal only to itself. It's not clear how to implement this in
/// salsa though, so we punt on that bit for a moment.
pub const fn missing() -> Name {
Name::new_static("[missing name]")
Name { symbol: MISSING_NAME, ctx: () }
}
/// Returns true if this is a fake name for things missing in the source code. See
@ -115,41 +133,25 @@ impl Name {
/// creating desugared locals and labels. The caller is responsible for picking an index
/// that is stable across re-executions
pub fn generate_new_name(idx: usize) -> Name {
Name::new_text(format_smolstr!("<ra@gennew>{idx}"))
Name::new_text(&format_smolstr!("<ra@gennew>{idx}"))
}
/// Returns the tuple index this name represents if it is a tuple field.
pub fn as_tuple_index(&self) -> Option<usize> {
match self.0 {
Repr::TupleField(idx) => Some(idx),
_ => None,
}
self.symbol.as_str().parse().ok()
}
/// Returns the text this name represents if it isn't a tuple field.
pub fn as_text(&self) -> Option<SmolStr> {
match &self.0 {
Repr::Text(it) => Some(it.clone()),
_ => None,
}
}
/// Returns the text this name represents if it isn't a tuple field.
pub fn as_str(&self) -> Option<&str> {
match &self.0 {
Repr::Text(it) => Some(it),
_ => None,
}
pub fn as_str(&self) -> &str {
self.symbol.as_str()
}
// FIXME: Remove this
/// Returns the textual representation of this name as a [`SmolStr`].
/// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in
/// the general case.
pub fn to_smol_str(&self) -> SmolStr {
match &self.0 {
Repr::Text(it) => it.clone(),
Repr::TupleField(it) => SmolStr::new(it.to_string()),
}
self.symbol.as_str().into()
}
pub fn unescaped(&self) -> UnescapedName<'_> {
@ -157,16 +159,27 @@ impl Name {
}
pub fn is_escaped(&self) -> bool {
match &self.0 {
Repr::Text(it) => it.starts_with("r#"),
Repr::TupleField(_) => false,
}
self.symbol.as_str().starts_with("r#")
}
pub fn display<'a>(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
_ = db;
Display { name: self }
}
pub fn symbol(&self) -> &Symbol {
&self.symbol
}
pub const fn new_symbol(doc: Symbol, ctx: SyntaxContextId) -> Self {
_ = ctx;
Self { symbol: doc, ctx: () }
}
// FIXME: This needs to go once we have hygiene
pub const fn new_symbol_root(doc: Symbol) -> Self {
Self { symbol: doc, ctx: () }
}
}
struct Display<'a> {
@ -175,10 +188,7 @@ struct Display<'a> {
impl fmt::Display for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.name.0 {
Repr::Text(text) => fmt::Display::fmt(&text, f),
Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
}
fmt::Display::fmt(self.name.symbol.as_str(), f)
}
}
@ -188,13 +198,9 @@ struct UnescapedDisplay<'a> {
impl fmt::Display for UnescapedDisplay<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.name.0 .0 {
Repr::Text(text) => {
let text = text.strip_prefix("r#").unwrap_or(text);
fmt::Display::fmt(&text, f)
}
Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
}
let symbol = &self.name.0.symbol.as_str();
let text = symbol.strip_prefix("r#").unwrap_or(symbol);
fmt::Display::fmt(&text, f)
}
}
@ -246,251 +252,6 @@ impl AsName for ast::FieldKind {
impl AsName for base_db::Dependency {
fn as_name(&self) -> Name {
Name::new_text(SmolStr::new(&*self.name))
Name::new_text(&self.name)
}
}
pub mod known {
macro_rules! known_names {
($($ident:ident),* $(,)?) => {
$(
#[allow(bad_style)]
pub const $ident: super::Name =
super::Name::new_static(stringify!($ident));
)*
};
}
known_names!(
// Primitives
isize,
i8,
i16,
i32,
i64,
i128,
usize,
u8,
u16,
u32,
u64,
u128,
f16,
f32,
f64,
f128,
bool,
char,
str,
// Special names
macro_rules,
doc,
cfg,
cfg_attr,
register_attr,
register_tool,
// Components of known path (value or mod name)
std,
core,
alloc,
iter,
ops,
fmt,
future,
result,
string,
boxed,
option,
prelude,
rust_2015,
rust_2018,
rust_2021,
rust_2024,
v1,
new_display,
new_debug,
new_lower_exp,
new_upper_exp,
new_octal,
new_pointer,
new_binary,
new_lower_hex,
new_upper_hex,
from_usize,
panic_2015,
panic_2021,
unreachable_2015,
unreachable_2021,
// Components of known path (type name)
Iterator,
IntoIterator,
Item,
IntoIter,
Try,
Ok,
Future,
IntoFuture,
Result,
Option,
Output,
Target,
Box,
RangeFrom,
RangeFull,
RangeInclusive,
RangeToInclusive,
RangeTo,
Range,
String,
Neg,
Not,
None,
Index,
Left,
Right,
Center,
Unknown,
Is,
Param,
Implied,
// Components of known path (function name)
filter_map,
next,
iter_mut,
len,
is_empty,
as_str,
new,
new_v1_formatted,
none,
// Builtin macros
asm,
assert,
column,
compile_error,
concat_idents,
concat_bytes,
concat,
const_format_args,
core_panic,
env,
file,
format,
format_args_nl,
format_args,
global_asm,
include_bytes,
include_str,
include,
line,
llvm_asm,
log_syntax,
module_path,
option_env,
quote,
std_panic,
stringify,
trace_macros,
unreachable,
// Builtin derives
Copy,
Clone,
Default,
Debug,
Hash,
Ord,
PartialOrd,
Eq,
PartialEq,
// Builtin attributes
bench,
cfg_accessible,
cfg_eval,
crate_type,
derive,
derive_const,
global_allocator,
no_core,
no_std,
test,
test_case,
recursion_limit,
feature,
// known methods of lang items
call_once,
call_mut,
call,
eq,
ne,
ge,
gt,
le,
lt,
// known fields of lang items
pieces,
// lang items
add_assign,
add,
bitand_assign,
bitand,
bitor_assign,
bitor,
bitxor_assign,
bitxor,
branch,
deref_mut,
deref,
div_assign,
div,
drop,
fn_mut,
fn_once,
future_trait,
index,
index_mut,
into_future,
mul_assign,
mul,
neg,
not,
owned_box,
partial_ord,
poll,
r#fn,
rem_assign,
rem,
shl_assign,
shl,
shr_assign,
shr,
sub_assign,
sub,
unsafe_cell,
va_list
);
// self/Self cannot be used as an identifier
pub const SELF_PARAM: super::Name = super::Name::new_static("self");
pub const SELF_TYPE: super::Name = super::Name::new_static("Self");
pub const STATIC_LIFETIME: super::Name = super::Name::new_static("'static");
pub const DOLLAR_CRATE: super::Name = super::Name::new_static("$crate");
#[macro_export]
macro_rules! name {
(self) => {
$crate::name::known::SELF_PARAM
};
(Self) => {
$crate::name::known::SELF_TYPE
};
('static) => {
$crate::name::known::STATIC_LIFETIME
};
($ident:ident) => {
$crate::name::known::$ident
};
}
}
pub use crate::name;

View file

@ -1,6 +1,7 @@
//! A simplified version of quote-crate like quasi quote macro
#![allow(clippy::crate_in_macro_def)]
use intern::Symbol;
use span::Span;
use syntax::format_smolstr;
@ -219,6 +220,7 @@ impl_to_to_tokentrees! {
span: &str => self { crate::tt::Literal{text: format_smolstr!("\"{}\"", self.escape_default()), span}};
span: String => self { crate::tt::Literal{text: format_smolstr!("\"{}\"", self.escape_default()), span}};
span: Name => self { crate::tt::Ident{text: self.to_smol_str(), span}};
span: Symbol => self { crate::tt::Ident{text: self.as_str().into(), span}};
}
#[cfg(test)]