Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-expand/src/name.rs')
-rw-r--r--crates/hir-expand/src/name.rs438
1 files changed, 107 insertions, 331 deletions
diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs
index fe754bc824..d012d272d7 100644
--- a/crates/hir-expand/src/name.rs
+++ b/crates/hir-expand/src/name.rs
@@ -2,7 +2,9 @@
use std::fmt;
-use syntax::{ast, format_smolstr, utils::is_raw_identifier, SmolStr};
+use intern::{sym, Symbol};
+use span::SyntaxContextId;
+use syntax::{ast, utils::is_raw_identifier};
/// `Name` is a wrapper around string, which is used in hir for both references
/// and declarations. In theory, names should also carry hygiene info, but we are
@@ -11,66 +13,93 @@ 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(Clone, PartialEq, Eq, Hash)]
+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
+}
-/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
-#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct UnescapedName<'a>(&'a Name);
+impl fmt::Debug for Name {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Name")
+ .field("symbol", &self.symbol.as_str())
+ .field("ctx", &self.ctx)
+ .finish()
+ }
+}
-#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
-enum Repr {
- Text(SmolStr),
- TupleField(usize),
+impl Ord for Name {
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+ self.symbol.as_str().cmp(other.symbol.as_str())
+ }
}
-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()),
- }
+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)]
+pub struct UnescapedName<'a>(&'a Name);
+
+impl UnescapedName<'_> {
pub fn display(&self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + '_ {
_ = db;
UnescapedDisplay { name: self }
}
+ #[doc(hidden)]
+ pub fn display_no_db(&self) -> impl fmt::Display + '_ {
+ UnescapedDisplay { name: self }
+ }
}
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, raw: tt::IdentIsRaw, ctx: SyntaxContextId) -> Name {
+ _ = ctx;
+ Name {
+ symbol: if raw.yes() {
+ Symbol::intern(&format!("{}{text}", raw.as_str()))
+ } else {
+ 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 +107,12 @@ 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(raw_text.into()),
+ None if is_raw_identifier(raw_text) => Name::new_text(&format!("r#{}", raw_text)),
+ _ => Name::new_text(raw_text),
}
}
@@ -98,8 +125,8 @@ impl Name {
/// Ideally, we want a `gensym` semantics for missing names -- each missing
/// 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]")
+ pub fn missing() -> Name {
+ Name { symbol: sym::MISSING_NAME.clone(), ctx: () }
}
/// Returns true if this is a fake name for things missing in the source code. See
@@ -115,41 +142,17 @@ 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!("<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,
- }
- }
-
- /// 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()),
- }
+ pub fn as_str(&self) -> &str {
+ self.symbol.as_str()
}
pub fn unescaped(&self) -> UnescapedName<'_> {
@@ -157,16 +160,41 @@ 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 }
}
+
+ // FIXME: Remove this
+ #[doc(hidden)]
+ pub fn display_no_db(&self) -> impl fmt::Display + '_ {
+ Display { name: self }
+ }
+
+ pub fn symbol(&self) -> &Symbol {
+ &self.symbol
+ }
+
+ pub const fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
+ _ = 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(sym: Symbol) -> Self {
+ Self { symbol: sym, ctx: () }
+ }
}
struct Display<'a> {
@@ -175,10 +203,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 +213,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)
}
}
@@ -228,7 +249,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())
}
}
@@ -246,251 +267,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;