mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 13:25:09 +00:00
Use Symbol in Name
This commit is contained in:
parent
843806b79f
commit
3fe815b0f3
75 changed files with 750 additions and 755 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),)*
|
||||
])
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue