From 1bafedbfe97e7b9d527a1eb6434f4b1fb4db2dd5 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 12 Jul 2024 12:26:23 +0200 Subject: [PATCH 001/147] Implement rough symbol interning infra --- src/tools/rust-analyzer/.typos.toml | 2 + src/tools/rust-analyzer/Cargo.lock | 7 + .../rust-analyzer/crates/intern/Cargo.toml | 3 +- .../rust-analyzer/crates/intern/src/lib.rs | 3 + .../rust-analyzer/crates/intern/src/symbol.rs | 293 ++++++++++++++++++ .../crates/intern/src/symbol/symbols.rs | 236 ++++++++++++++ 6 files changed, 543 insertions(+), 1 deletion(-) create mode 100644 src/tools/rust-analyzer/crates/intern/src/symbol.rs create mode 100644 src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs diff --git a/src/tools/rust-analyzer/.typos.toml b/src/tools/rust-analyzer/.typos.toml index c2e8b265218fb..e7e764ce03517 100644 --- a/src/tools/rust-analyzer/.typos.toml +++ b/src/tools/rust-analyzer/.typos.toml @@ -14,6 +14,8 @@ extend-ignore-re = [ "\\w*\\.{3,4}\\w*", '"flate2"', "raison d'ĂȘtre", + "inout", + "optin" ] [default.extend-words] diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index e9ebe26f42c2c..b165697724e05 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -835,6 +835,7 @@ dependencies = [ "dashmap", "hashbrown", "rustc-hash", + "sptr", "triomphe", ] @@ -1885,6 +1886,12 @@ dependencies = [ "vfs", ] +[[package]] +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" + [[package]] name = "stable_deref_trait" version = "1.2.0" diff --git a/src/tools/rust-analyzer/crates/intern/Cargo.toml b/src/tools/rust-analyzer/crates/intern/Cargo.toml index 67b4164ce1fe0..c08ecb5c307b1 100644 --- a/src/tools/rust-analyzer/crates/intern/Cargo.toml +++ b/src/tools/rust-analyzer/crates/intern/Cargo.toml @@ -18,6 +18,7 @@ dashmap.workspace = true hashbrown.workspace = true rustc-hash.workspace = true triomphe.workspace = true +sptr = "0.3.2" [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/intern/src/lib.rs b/src/tools/rust-analyzer/crates/intern/src/lib.rs index 40d18b1cf8677..868d03caff557 100644 --- a/src/tools/rust-analyzer/crates/intern/src/lib.rs +++ b/src/tools/rust-analyzer/crates/intern/src/lib.rs @@ -20,6 +20,9 @@ type Guard = dashmap::RwLockWriteGuard< HashMap, SharedValue<()>, BuildHasherDefault>, >; +mod symbol; +pub use self::symbol::{symbols, Symbol}; + pub struct Interned { arc: Arc, } diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs new file mode 100644 index 0000000000000..a1cffd0662f8e --- /dev/null +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -0,0 +1,293 @@ +//! Attempt at flexible symbol interning, allowing to intern and free strings at runtime while also +//! supporting + +use std::{ + borrow::Borrow, + fmt, + hash::{BuildHasherDefault, Hash, Hasher}, + mem, + ptr::NonNull, + sync::OnceLock, +}; + +use dashmap::{DashMap, SharedValue}; +use hashbrown::{hash_map::RawEntryMut, HashMap}; +use rustc_hash::FxHasher; +use sptr::Strict; +use triomphe::Arc; + +pub mod symbols; + +// some asserts for layout compatibility +const _: () = assert!(std::mem::size_of::>() == std::mem::size_of::<&str>()); +const _: () = assert!(std::mem::align_of::>() == std::mem::align_of::<&str>()); + +const _: () = assert!(std::mem::size_of::>>() == std::mem::size_of::<&&str>()); +const _: () = assert!(std::mem::align_of::>>() == std::mem::align_of::<&&str>()); + +/// A pointer that points to a pointer to a `str`, it may be backed as a `&'static &'static str` or +/// `Arc>` but its size is that of a thin pointer. The active variant is encoded as a tag +/// in the LSB of the alignment niche. +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] +struct TaggedArcPtr { + packed: NonNull<*const str>, +} + +unsafe impl Send for TaggedArcPtr {} +unsafe impl Sync for TaggedArcPtr {} + +impl TaggedArcPtr { + const BOOL_BITS: usize = true as usize; + + const fn non_arc(r: &&str) -> Self { + Self { + // SAFETY: The pointer is non-null as it is derived from a reference + // Ideally we would call out to `pack_arc` but for a `false` tag, unfortunately the + // packing stuff requires reading out the pointer to an integer which is not supported + // in const contexts, so here we make use of the fact that for the non-arc version the + // tag is false (0) and thus does not need touching the actual pointer value.ext) + packed: unsafe { + NonNull::new_unchecked((r as *const &str).cast::<*const str>().cast_mut()) + }, + } + } + + fn arc(arc: Arc>) -> Self { + Self { + packed: Self::pack_arc( + // Safety: `Arc::into_raw` always returns a non null pointer + unsafe { NonNull::new_unchecked(Arc::into_raw(arc).cast_mut().cast()) }, + ), + } + } + + /// Retrieves the tag. + #[inline] + pub(crate) fn try_as_arc_owned(self) -> Option>> { + // Unpack the tag from the alignment niche + let tag = Strict::addr(self.packed.as_ptr()) & Self::BOOL_BITS; + if tag != 0 { + // Safety: We checked that the tag is non-zero -> true, so we are pointing to the data offset of an `Arc` + Some(unsafe { Arc::from_raw(self.pointer().as_ptr().cast::>()) }) + } else { + None + } + } + + #[inline] + const fn pack_arc(ptr: NonNull<*const str>) -> NonNull<*const str> { + let packed_tag = true as usize; + + // can't use this strict provenance stuff here due to trait methods not being const + // unsafe { + // // Safety: The pointer is derived from a non-null + // NonNull::new_unchecked(Strict::map_addr(ptr.as_ptr(), |addr| { + // // Safety: + // // - The pointer is `NonNull` => it's address is `NonZero` + // // - `P::BITS` least significant bits are always zero (`Pointer` contract) + // // - `T::BITS <= P::BITS` (from `Self::ASSERTION`) + // // + // // Thus `addr >> T::BITS` is guaranteed to be non-zero. + // // + // // `{non_zero} | packed_tag` can't make the value zero. + + // (addr >> Self::BOOL_BITS) | packed_tag + // })) + // } + // so what follows is roughly what the above looks like but inlined + + let self_addr = unsafe { core::mem::transmute::<*const _, usize>(ptr.as_ptr()) }; + let addr = self_addr | packed_tag; + let dest_addr = addr as isize; + let offset = dest_addr.wrapping_sub(self_addr as isize); + + // SAFETY: The resulting pointer is guaranteed to be NonNull as we only modify the niche bytes + unsafe { NonNull::new_unchecked(ptr.as_ptr().cast::().wrapping_offset(offset).cast()) } + } + + #[inline] + pub(crate) fn pointer(self) -> NonNull<*const str> { + // SAFETY: The resulting pointer is guaranteed to be NonNull as we only modify the niche bytes + unsafe { + NonNull::new_unchecked(Strict::map_addr(self.packed.as_ptr(), |addr| { + addr & !Self::BOOL_BITS + })) + } + } + + #[inline] + pub(crate) fn as_str(&self) -> &str { + // SAFETY: We always point to a pointer to a str no matter what variant is active + unsafe { *self.pointer().as_ptr().cast::<&str>() } + } +} + +#[derive(PartialEq, Eq, Hash, Clone, Debug)] +pub struct Symbol { + repr: TaggedArcPtr, +} +const _: () = assert!(std::mem::size_of::() == std::mem::size_of::>()); +const _: () = assert!(std::mem::align_of::() == std::mem::align_of::>()); + +static MAP: OnceLock>> = OnceLock::new(); + +impl Symbol { + pub fn intern(s: &str) -> Self { + let (mut shard, hash) = Self::select_shard(s); + // Atomically, + // - check if `obj` is already in the map + // - if so, copy out its entry, conditionally bumping the backing Arc and return it + // - if not, put it into a box and then into an Arc, insert it, bump the ref-count and return the copy + // This needs to be atomic (locking the shard) to avoid races with other thread, which could + // insert the same object between us looking it up and inserting it. + match shard.raw_entry_mut().from_key_hashed_nocheck(hash, s) { + RawEntryMut::Occupied(occ) => Self { repr: increase_arc_refcount(occ.key().0) }, + RawEntryMut::Vacant(vac) => Self { + repr: increase_arc_refcount( + vac.insert_hashed_nocheck( + hash, + SymbolProxy(TaggedArcPtr::arc(Arc::new(Box::::from(s)))), + SharedValue::new(()), + ) + .0 + .0, + ), + }, + } + } + + pub fn as_str(&self) -> &str { + self.repr.as_str() + } + + #[inline] + fn select_shard( + s: &str, + ) -> ( + dashmap::RwLockWriteGuard< + 'static, + HashMap, BuildHasherDefault>, + >, + u64, + ) { + let storage = MAP.get_or_init(symbols::prefill); + let hash = { + let mut hasher = std::hash::BuildHasher::build_hasher(storage.hasher()); + s.hash(&mut hasher); + hasher.finish() + }; + let shard_idx = storage.determine_shard(hash as usize); + let shard = &storage.shards()[shard_idx]; + (shard.write(), hash) + } + + #[cold] + fn drop_slow(arc: &Arc>) { + let (mut shard, hash) = Self::select_shard(arc); + + if Arc::count(arc) != 2 { + // Another thread has interned another copy + return; + } + + match shard.raw_entry_mut().from_key_hashed_nocheck::(hash, arc.as_ref()) { + RawEntryMut::Occupied(occ) => occ.remove_entry(), + RawEntryMut::Vacant(_) => unreachable!(), + } + .0 + .0 + .try_as_arc_owned() + .unwrap(); + + // Shrink the backing storage if the shard is less than 50% occupied. + if shard.len() * 2 < shard.capacity() { + shard.shrink_to_fit(); + } + } +} + +impl Drop for Symbol { + #[inline] + fn drop(&mut self) { + let Some(arc) = self.repr.try_as_arc_owned() else { + return; + }; + // When the last `Ref` is dropped, remove the object from the global map. + if Arc::count(&arc) == 2 { + // Only `self` and the global map point to the object. + + Self::drop_slow(&arc); + } + // decrement the ref count + drop(arc); + } +} + +fn increase_arc_refcount(repr: TaggedArcPtr) -> TaggedArcPtr { + let Some(arc) = repr.try_as_arc_owned() else { + return repr; + }; + // increase the ref count + mem::forget(arc.clone()); + mem::forget(arc); + repr +} + +impl fmt::Display for Symbol { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_str().fmt(f) + } +} + +// only exists so we can use `from_key_hashed_nocheck` with a &str +#[derive(Debug, PartialEq, Eq)] +struct SymbolProxy(TaggedArcPtr); + +impl Hash for SymbolProxy { + fn hash(&self, state: &mut H) { + self.0.as_str().hash(state); + } +} + +impl Borrow for SymbolProxy { + fn borrow(&self) -> &str { + self.0.as_str() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn smoke_test() { + Symbol::intern("isize"); + let base_len = MAP.get().unwrap().len(); + let hello = Symbol::intern("hello"); + let world = Symbol::intern("world"); + let bang = Symbol::intern("!"); + let q = Symbol::intern("?"); + assert_eq!(MAP.get().unwrap().len(), base_len + 4); + let bang2 = Symbol::intern("!"); + assert_eq!(MAP.get().unwrap().len(), base_len + 4); + drop(bang2); + assert_eq!(MAP.get().unwrap().len(), base_len + 4); + drop(q); + assert_eq!(MAP.get().unwrap().len(), base_len + 3); + let default = Symbol::intern("default"); + assert_eq!(MAP.get().unwrap().len(), base_len + 3); + assert_eq!( + "hello default world!", + format!("{} {} {}{}", hello.as_str(), default.as_str(), world.as_str(), bang.as_str()) + ); + drop(default); + assert_eq!( + "hello world!", + format!("{} {}{}", hello.as_str(), world.as_str(), bang.as_str()) + ); + drop(hello); + drop(world); + drop(bang); + assert_eq!(MAP.get().unwrap().len(), base_len); + } +} diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs new file mode 100644 index 0000000000000..d2ca4401b66e9 --- /dev/null +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -0,0 +1,236 @@ +#![allow(non_upper_case_globals)] + +use std::hash::{BuildHasherDefault, Hash as _, Hasher as _}; + +use dashmap::{DashMap, SharedValue}; +use rustc_hash::FxHasher; + +use crate::{ + symbol::{SymbolProxy, TaggedArcPtr}, + Symbol, +}; +macro_rules! define_symbols { + ($($name:ident),* $(,)?) => { + $( + pub const $name: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&stringify!($name)) }; + )* + + + pub(super) fn prefill() -> DashMap> { + let mut dashmap_ = >>::with_hasher(BuildHasherDefault::default()); + + let hash_thing_ = |hasher_: &BuildHasherDefault, it_: &SymbolProxy| { + let mut hasher_ = std::hash::BuildHasher::build_hasher(hasher_); + it_.hash(&mut hasher_); + hasher_.finish() + }; + { + $( + + let proxy_ = SymbolProxy($name.repr); + let hash_ = hash_thing_(dashmap_.hasher(), &proxy_); + let shard_idx_ = dashmap_.determine_shard(hash_ as usize); + dashmap_.shards_mut()[shard_idx_].get_mut().raw_entry_mut().from_hash(hash_, |k| k == &proxy_).insert(proxy_, SharedValue::new(())); + )* + } + dashmap_ + } + }; +} +define_symbols! { + add_assign, + add, + alloc, + as_str, + asm, + assert, + bench, + bitand_assign, + bitand, + bitor_assign, + bitor, + bitxor_assign, + bitxor, + bool, + Box, + boxed, + branch, + call_mut, + call_once, + call, + Center, + cfg_accessible, + cfg_attr, + cfg_eval, + cfg, + char, + Clone, + column, + compile_error, + concat_bytes, + concat_idents, + concat, + const_format_args, + Copy, + core_panic, + core, + crate_type, + Debug, + default, + Default, + deref_mut, + deref, + derive_const, + derive, + div_assign, + div, + doc, + drop, + env, + eq, + Eq, + f128, + f16, + f32, + f64, + feature, + file, + filter_map, + fmt, + fn_mut, + fn_once, + format_args_nl, + format_args, + format, + from_usize, + future_trait, + future, + Future, + ge, + global_allocator, + global_asm, + gt, + Hash, + i128, + i16, + i32, + i64, + i8, + Implied, + include_bytes, + include_str, + include, + index_mut, + index, + Index, + into_future, + IntoFuture, + IntoIter, + IntoIterator, + is_empty, + Is, + isize, + Item, + iter_mut, + iter, + Iterator, + le, + Left, + len, + line, + llvm_asm, + log_syntax, + lt, + macro_rules, + module_path, + mul_assign, + mul, + ne, + neg, + Neg, + new_binary, + new_debug, + new_display, + new_lower_exp, + new_lower_hex, + new_octal, + new_pointer, + new_upper_exp, + new_upper_hex, + new_v1_formatted, + new, + next, + no_core, + no_std, + none, + None, + not, + Not, + Ok, + ops, + option_env, + option, + Option, + Ord, + Output, + owned_box, + panic_2015, + panic_2021, + Param, + partial_ord, + PartialEq, + PartialOrd, + pieces, + poll, + prelude, + quote, + r#fn, + Range, + RangeFrom, + RangeFull, + RangeInclusive, + RangeTo, + RangeToInclusive, + recursion_limit, + register_attr, + register_tool, + rem_assign, + rem, + result, + Result, + Right, + rust_2015, + rust_2018, + rust_2021, + rust_2024, + shl_assign, + shl, + shr_assign, + shr, + std_panic, + std, + str, + string, + String, + stringify, + sub_assign, + sub, + Target, + test_case, + test, + trace_macros, + Try, + u128, + u16, + u32, + u64, + u8, + Unknown, + unreachable_2015, + unreachable_2021, + unreachable, + unsafe_cell, + usize, + v1, + va_list +} From e805055b0ea7595fd7400b7583fa0b6ff11264bf Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 12 Jul 2024 14:11:28 +0200 Subject: [PATCH 002/147] Add missing docs --- src/tools/rust-analyzer/crates/intern/src/symbol.rs | 2 +- src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs index a1cffd0662f8e..290657a3d3627 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -39,7 +39,7 @@ unsafe impl Sync for TaggedArcPtr {} impl TaggedArcPtr { const BOOL_BITS: usize = true as usize; - const fn non_arc(r: &&str) -> Self { + const fn non_arc(r: &'static &'static str) -> Self { Self { // SAFETY: The pointer is non-null as it is derived from a reference // Ideally we would call out to `pack_arc` but for a `false` tag, unfortunately the diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index d2ca4401b66e9..a1cf6e0941466 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -1,3 +1,4 @@ +//! Module defining all known symbols required by the rest of rust-analyzer. #![allow(non_upper_case_globals)] use std::hash::{BuildHasherDefault, Hash as _, Hasher as _}; From 602da3fadd919c41378b4b1b694ae1c391ace6d8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 12 Jul 2024 15:57:54 +0200 Subject: [PATCH 003/147] Use Symbol in Name --- .../rust-analyzer/crates/hir-def/src/attr.rs | 9 +- .../crates/hir-def/src/body/lower.rs | 114 ++--- .../crates/hir-def/src/builtin_type.rs | 85 ++-- .../rust-analyzer/crates/hir-def/src/data.rs | 4 +- .../rust-analyzer/crates/hir-def/src/db.rs | 8 +- .../crates/hir-def/src/expander.rs | 6 + .../crates/hir-def/src/find_path.rs | 25 +- .../crates/hir-def/src/hir/format_args.rs | 6 +- .../crates/hir-def/src/item_tree/lower.rs | 11 +- .../crates/hir-def/src/lang_item.rs | 13 +- .../rust-analyzer/crates/hir-def/src/lib.rs | 2 +- .../crates/hir-def/src/nameres/collector.rs | 90 ++-- .../crates/hir-def/src/path/lower.rs | 10 +- .../crates/hir-def/src/resolver.rs | 25 +- .../crates/hir-expand/src/attrs.rs | 91 ++-- .../hir-expand/src/builtin_attr_macro.rs | 3 +- .../hir-expand/src/builtin_derive_macro.rs | 3 +- .../crates/hir-expand/src/builtin_fn_macro.rs | 15 +- .../rust-analyzer/crates/hir-expand/src/db.rs | 9 + .../crates/hir-expand/src/declarative.rs | 7 +- .../crates/hir-expand/src/mod_path.rs | 30 +- .../crates/hir-expand/src/name.rs | 391 ++++-------------- .../crates/hir-expand/src/quote.rs | 2 + .../crates/hir-ty/src/autoderef.rs | 6 +- .../crates/hir-ty/src/chalk_db.rs | 9 +- .../hir-ty/src/diagnostics/decl_check.rs | 2 +- .../crates/hir-ty/src/diagnostics/expr.rs | 4 +- .../crates/hir-ty/src/display.rs | 5 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 5 +- .../crates/hir-ty/src/infer/closure.rs | 13 +- .../crates/hir-ty/src/infer/expr.rs | 15 +- .../crates/hir-ty/src/infer/mutability.rs | 15 +- .../crates/hir-ty/src/infer/path.rs | 3 +- .../crates/hir-ty/src/infer/unify.rs | 6 +- .../crates/hir-ty/src/lang_items.rs | 54 +-- .../rust-analyzer/crates/hir-ty/src/lib.rs | 7 +- .../crates/hir-ty/src/mir/eval.rs | 37 +- .../crates/hir-ty/src/mir/eval/shim.rs | 23 +- .../crates/hir-ty/src/mir/lower.rs | 6 +- .../crates/hir-ty/src/mir/lower/as_place.rs | 13 +- .../rust-analyzer/crates/hir-ty/src/traits.rs | 9 +- .../rust-analyzer/crates/hir/src/attrs.rs | 3 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 15 +- .../crates/hir/src/source_analyzer.rs | 35 +- .../rust-analyzer/crates/hir/src/symbols.rs | 2 +- .../ide-assists/src/handlers/bool_to_enum.rs | 2 +- .../src/handlers/convert_bool_then.rs | 4 +- .../handlers/convert_iter_for_each_to_for.rs | 8 +- .../handlers/destructure_struct_binding.rs | 4 +- .../handlers/generate_is_empty_from_len.rs | 6 +- .../ide-assists/src/handlers/inline_call.rs | 7 +- .../src/handlers/replace_method_eager_lazy.rs | 4 +- .../crates/ide-assists/src/utils.rs | 4 +- .../crates/ide-completion/src/completions.rs | 4 +- .../src/completions/attribute/macro_use.rs | 2 +- .../ide-completion/src/completions/dot.rs | 9 +- .../ide-completion/src/completions/expr.rs | 11 +- .../src/completions/lifetime.rs | 4 +- .../ide-completion/src/completions/use_.rs | 5 +- .../ide-completion/src/context/analysis.rs | 6 +- .../crates/ide-completion/src/render.rs | 6 +- .../ide-completion/src/render/function.rs | 10 +- .../rust-analyzer/crates/ide-db/src/defs.rs | 2 +- .../ide-db/src/imports/import_assets.rs | 6 +- .../crates/ide-db/src/path_transform.rs | 2 +- .../src/handlers/missing_fields.rs | 4 +- .../src/handlers/unresolved_field.rs | 2 +- .../crates/ide/src/goto_definition.rs | 2 +- .../crates/ide/src/inlay_hints.rs | 4 +- .../ide/src/inlay_hints/generic_param.rs | 2 +- .../crates/ide/src/test_explorer.rs | 11 +- .../crates/ide/src/view_memory_layout.rs | 15 +- .../rust-analyzer/crates/intern/src/lib.rs | 2 +- .../rust-analyzer/crates/intern/src/symbol.rs | 2 +- .../crates/intern/src/symbol/symbols.rs | 121 +++++- 75 files changed, 756 insertions(+), 761 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index 184dab8367c16..a1ffb8c0a7596 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -9,6 +9,7 @@ use hir_expand::{ attrs::{collect_attrs, Attr, AttrId, RawAttrs}, HirFileId, InFile, }; +use intern::sym; use la_arena::{ArenaMap, Idx, RawIdx}; use mbe::DelimiterKind; use syntax::{ @@ -199,8 +200,8 @@ impl Attrs { .segments() .iter() .rev() - .zip(["core", "prelude", "v1", "test"].iter().rev()) - .all(|it| it.0.as_str() == Some(it.1)) + .zip([sym::core, sym::prelude, sym::v1, sym::test].iter().rev()) + .all(|it| it.0 == it.1) }) } @@ -568,6 +569,10 @@ impl<'attr> AttrQuery<'attr> { self.attrs().find_map(|attr| attr.string_value()) } + pub fn string_value_with_span(self) -> Option<(&'attr str, span::Span)> { + self.attrs().find_map(|attr| attr.string_value_with_span()) + } + pub fn string_value_unescape(self) -> Option> { self.attrs().find_map(|attr| attr.string_value_unescape()) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index be7068c807a5f..83ba8f41931e2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -5,10 +5,10 @@ use std::mem; use base_db::CrateId; use hir_expand::{ - name::{name, AsName, Name}, + name::{AsName, Name}, ExpandError, InFile, }; -use intern::Interned; +use intern::{sym, Interned}; use rustc_hash::FxHashMap; use smallvec::SmallVec; use span::AstIdMap; @@ -187,8 +187,10 @@ impl ExprCollector<'_> { { let is_mutable = self_param.mut_token().is_some() && self_param.amp_token().is_none(); - let binding_id: la_arena::Idx = - self.alloc_binding(name![self], BindingAnnotation::new(is_mutable, false)); + let binding_id: la_arena::Idx = self.alloc_binding( + Name::new_symbol_root(sym::self_), + BindingAnnotation::new(is_mutable, false), + ); self.body.self_param = Some(binding_id); self.source_map.self_param = Some(self.expander.in_file(AstPtr::new(&self_param))); } @@ -1588,18 +1590,22 @@ impl ExprCollector<'_> { }); let mut mappings = vec![]; let fmt = match template.and_then(|it| self.expand_macros_to_string(it)) { - Some((s, is_direct_literal)) => format_args::parse( - &s, - fmt_snippet, - args, - is_direct_literal, - |name| self.alloc_expr_desugared(Expr::Path(Path::from(name))), - |name, span| { - if let Some(span) = span { - mappings.push((span, name)) - } - }, - ), + Some((s, is_direct_literal)) => { + let call_ctx = self.expander.syntax_context(); + format_args::parse( + &s, + fmt_snippet, + args, + is_direct_literal, + |name| self.alloc_expr_desugared(Expr::Path(Path::from(name))), + |name, span| { + if let Some(span) = span { + mappings.push((span, name)) + } + }, + call_ctx, + ) + } None => FormatArgs { template: Default::default(), arguments: args.finish(), @@ -1723,14 +1729,18 @@ impl ExprCollector<'_> { // unsafe { ::core::fmt::UnsafeArg::new() } // ) - let Some(new_v1_formatted) = - LangItem::FormatArguments.ty_rel_path(self.db, self.krate, name![new_v1_formatted]) - else { + let Some(new_v1_formatted) = LangItem::FormatArguments.ty_rel_path( + self.db, + self.krate, + Name::new_symbol_root(sym::new_v1_formatted), + ) else { return self.missing_expr(); }; - let Some(unsafe_arg_new) = - LangItem::FormatUnsafeArg.ty_rel_path(self.db, self.krate, name![new]) - else { + let Some(unsafe_arg_new) = LangItem::FormatUnsafeArg.ty_rel_path( + self.db, + self.krate, + Name::new_symbol_root(sym::new), + ) else { return self.missing_expr(); }; let new_v1_formatted = self.alloc_expr_desugared(Expr::Path(new_v1_formatted)); @@ -1812,10 +1822,10 @@ impl ExprCollector<'_> { self.db, self.krate, match alignment { - Some(FormatAlignment::Left) => name![Left], - Some(FormatAlignment::Right) => name![Right], - Some(FormatAlignment::Center) => name![Center], - None => name![Unknown], + Some(FormatAlignment::Left) => Name::new_symbol_root(sym::Left), + Some(FormatAlignment::Right) => Name::new_symbol_root(sym::Right), + Some(FormatAlignment::Center) => Name::new_symbol_root(sym::Center), + None => Name::new_symbol_root(sym::Unknown), }, ); match align { @@ -1838,8 +1848,11 @@ impl ExprCollector<'_> { let width = self.make_count(width, argmap); let format_placeholder_new = { - let format_placeholder_new = - LangItem::FormatPlaceholder.ty_rel_path(self.db, self.krate, name![new]); + let format_placeholder_new = LangItem::FormatPlaceholder.ty_rel_path( + self.db, + self.krate, + Name::new_symbol_root(sym::new), + ); match format_placeholder_new { Some(path) => self.alloc_expr_desugared(Expr::Path(path)), None => self.missing_expr(), @@ -1883,11 +1896,14 @@ impl ExprCollector<'_> { *n as u128, Some(BuiltinUint::Usize), ))); - let count_is = - match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) { - Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)), - None => self.missing_expr(), - }; + let count_is = match LangItem::FormatCount.ty_rel_path( + self.db, + self.krate, + Name::new_symbol_root(sym::Is), + ) { + Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)), + None => self.missing_expr(), + }; self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]), @@ -1905,7 +1921,7 @@ impl ExprCollector<'_> { let count_param = match LangItem::FormatCount.ty_rel_path( self.db, self.krate, - name![Param], + Name::new_symbol_root(sym::Param), ) { Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)), None => self.missing_expr(), @@ -1921,7 +1937,11 @@ impl ExprCollector<'_> { self.missing_expr() } } - None => match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Implied]) { + None => match LangItem::FormatCount.ty_rel_path( + self.db, + self.krate, + Name::new_symbol_root(sym::Implied), + ) { Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)), None => self.missing_expr(), }, @@ -1942,18 +1962,18 @@ impl ExprCollector<'_> { let new_fn = match LangItem::FormatArgument.ty_rel_path( self.db, self.krate, - match ty { - Format(Display) => name![new_display], - Format(Debug) => name![new_debug], - Format(LowerExp) => name![new_lower_exp], - Format(UpperExp) => name![new_upper_exp], - Format(Octal) => name![new_octal], - Format(Pointer) => name![new_pointer], - Format(Binary) => name![new_binary], - Format(LowerHex) => name![new_lower_hex], - Format(UpperHex) => name![new_upper_hex], - Usize => name![from_usize], - }, + Name::new_symbol_root(match ty { + Format(Display) => sym::new_display, + Format(Debug) => sym::new_debug, + Format(LowerExp) => sym::new_lower_exp, + Format(UpperExp) => sym::new_upper_exp, + Format(Octal) => sym::new_octal, + Format(Pointer) => sym::new_pointer, + Format(Binary) => sym::new_binary, + Format(LowerHex) => sym::new_lower_hex, + Format(UpperHex) => sym::new_upper_hex, + Usize => sym::from_usize, + }), ) { Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)), None => self.missing_expr(), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs index f9e55559dab43..2243f514fe102 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs @@ -5,7 +5,8 @@ use std::fmt; -use hir_expand::name::{name, AsName, Name}; +use hir_expand::name::{AsName, Name}; +use intern::sym; /// Different signed int types. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum BuiltinInt { @@ -49,28 +50,28 @@ pub enum BuiltinType { impl BuiltinType { #[rustfmt::skip] pub const ALL: &'static [(Name, BuiltinType)] = &[ - (name![char], BuiltinType::Char), - (name![bool], BuiltinType::Bool), - (name![str], BuiltinType::Str), - - (name![isize], BuiltinType::Int(BuiltinInt::Isize)), - (name![i8], BuiltinType::Int(BuiltinInt::I8)), - (name![i16], BuiltinType::Int(BuiltinInt::I16)), - (name![i32], BuiltinType::Int(BuiltinInt::I32)), - (name![i64], BuiltinType::Int(BuiltinInt::I64)), - (name![i128], BuiltinType::Int(BuiltinInt::I128)), - - (name![usize], BuiltinType::Uint(BuiltinUint::Usize)), - (name![u8], BuiltinType::Uint(BuiltinUint::U8)), - (name![u16], BuiltinType::Uint(BuiltinUint::U16)), - (name![u32], BuiltinType::Uint(BuiltinUint::U32)), - (name![u64], BuiltinType::Uint(BuiltinUint::U64)), - (name![u128], BuiltinType::Uint(BuiltinUint::U128)), - - (name![f16], BuiltinType::Float(BuiltinFloat::F16)), - (name![f32], BuiltinType::Float(BuiltinFloat::F32)), - (name![f64], BuiltinType::Float(BuiltinFloat::F64)), - (name![f128], BuiltinType::Float(BuiltinFloat::F128)), + (Name::new_symbol_root(sym::char), BuiltinType::Char), + (Name::new_symbol_root(sym::bool), BuiltinType::Bool), + (Name::new_symbol_root(sym::str), BuiltinType::Str), + + (Name::new_symbol_root(sym::isize), BuiltinType::Int(BuiltinInt::Isize)), + (Name::new_symbol_root(sym::i8), BuiltinType::Int(BuiltinInt::I8)), + (Name::new_symbol_root(sym::i16), BuiltinType::Int(BuiltinInt::I16)), + (Name::new_symbol_root(sym::i32), BuiltinType::Int(BuiltinInt::I32)), + (Name::new_symbol_root(sym::i64), BuiltinType::Int(BuiltinInt::I64)), + (Name::new_symbol_root(sym::i128), BuiltinType::Int(BuiltinInt::I128)), + + (Name::new_symbol_root(sym::usize), BuiltinType::Uint(BuiltinUint::Usize)), + (Name::new_symbol_root(sym::u8), BuiltinType::Uint(BuiltinUint::U8)), + (Name::new_symbol_root(sym::u16), BuiltinType::Uint(BuiltinUint::U16)), + (Name::new_symbol_root(sym::u32), BuiltinType::Uint(BuiltinUint::U32)), + (Name::new_symbol_root(sym::u64), BuiltinType::Uint(BuiltinUint::U64)), + (Name::new_symbol_root(sym::u128), BuiltinType::Uint(BuiltinUint::U128)), + + (Name::new_symbol_root(sym::f16), BuiltinType::Float(BuiltinFloat::F16)), + (Name::new_symbol_root(sym::f32), BuiltinType::Float(BuiltinFloat::F32)), + (Name::new_symbol_root(sym::f64), BuiltinType::Float(BuiltinFloat::F64)), + (Name::new_symbol_root(sym::f128), BuiltinType::Float(BuiltinFloat::F128)), ]; pub fn by_name(name: &Name) -> Option { @@ -81,30 +82,30 @@ impl BuiltinType { impl AsName for BuiltinType { fn as_name(&self) -> Name { match self { - BuiltinType::Char => name![char], - BuiltinType::Bool => name![bool], - BuiltinType::Str => name![str], + BuiltinType::Char => Name::new_symbol_root(sym::char), + BuiltinType::Bool => Name::new_symbol_root(sym::bool), + BuiltinType::Str => Name::new_symbol_root(sym::str), BuiltinType::Int(it) => match it { - BuiltinInt::Isize => name![isize], - BuiltinInt::I8 => name![i8], - BuiltinInt::I16 => name![i16], - BuiltinInt::I32 => name![i32], - BuiltinInt::I64 => name![i64], - BuiltinInt::I128 => name![i128], + BuiltinInt::Isize => Name::new_symbol_root(sym::isize), + BuiltinInt::I8 => Name::new_symbol_root(sym::i8), + BuiltinInt::I16 => Name::new_symbol_root(sym::i16), + BuiltinInt::I32 => Name::new_symbol_root(sym::i32), + BuiltinInt::I64 => Name::new_symbol_root(sym::i64), + BuiltinInt::I128 => Name::new_symbol_root(sym::i128), }, BuiltinType::Uint(it) => match it { - BuiltinUint::Usize => name![usize], - BuiltinUint::U8 => name![u8], - BuiltinUint::U16 => name![u16], - BuiltinUint::U32 => name![u32], - BuiltinUint::U64 => name![u64], - BuiltinUint::U128 => name![u128], + BuiltinUint::Usize => Name::new_symbol_root(sym::usize), + BuiltinUint::U8 => Name::new_symbol_root(sym::u8), + BuiltinUint::U16 => Name::new_symbol_root(sym::u16), + BuiltinUint::U32 => Name::new_symbol_root(sym::u32), + BuiltinUint::U64 => Name::new_symbol_root(sym::u64), + BuiltinUint::U128 => Name::new_symbol_root(sym::u128), }, BuiltinType::Float(it) => match it { - BuiltinFloat::F16 => name![f16], - BuiltinFloat::F32 => name![f32], - BuiltinFloat::F64 => name![f64], - BuiltinFloat::F128 => name![f128], + BuiltinFloat::F16 => Name::new_symbol_root(sym::f16), + BuiltinFloat::F32 => Name::new_symbol_root(sym::f32), + BuiltinFloat::F64 => Name::new_symbol_root(sym::f64), + BuiltinFloat::F128 => Name::new_symbol_root(sym::f128), }, } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 55043fdc4b054..f60a433c4dafe 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -6,7 +6,7 @@ use base_db::CrateId; use hir_expand::{ name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind, }; -use intern::Interned; +use intern::{sym, Interned}; use smallvec::SmallVec; use syntax::{ast, Parse}; use triomphe::Arc; @@ -485,7 +485,7 @@ impl ExternCrateDeclData { let name = extern_crate.name.clone(); let krate = loc.container.krate(); - let crate_id = if name == hir_expand::name![self] { + let crate_id = if name == sym::self_ { Some(krate) } else { db.crate_def_map(krate) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 0eb9e7d30b251..0a14904f0bceb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -2,7 +2,7 @@ use base_db::{salsa, CrateId, FileId, SourceDatabase, Upcast}; use either::Either; use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId}; -use intern::Interned; +use intern::{sym, Interned}; use la_arena::ArenaMap; use span::MacroCallId; use syntax::{ast, AstPtr}; @@ -261,9 +261,9 @@ fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: CrateId) -> bool { let item_tree = db.file_item_tree(file.into()); let attrs = item_tree.raw_attrs(AttrOwner::TopLevel); for attr in &**attrs { - match attr.path().as_ident().and_then(|id| id.as_text()) { - Some(ident) if ident == "no_std" => return true, - Some(ident) if ident == "cfg_attr" => {} + match attr.path().as_ident() { + Some(ident) if *ident == sym::no_std => return true, + Some(ident) if *ident == sym::cfg_attr => {} _ => continue, } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs index dbf8e6b225c2a..d1640ad7e5b7b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs @@ -10,6 +10,7 @@ use hir_expand::{ InFile, MacroCallId, }; use limit::Limit; +use span::SyntaxContextId; use syntax::{ast, Parse}; use triomphe::Arc; @@ -52,6 +53,11 @@ impl Expander { self.module.krate } + pub fn syntax_context(&self) -> SyntaxContextId { + // FIXME: + SyntaxContextId::ROOT + } + pub fn enter_expand( &mut self, db: &dyn DefDatabase, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index 9a3c0495414ca..e32add93c5526 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -3,9 +3,10 @@ use std::{cell::Cell, cmp::Ordering, iter}; use hir_expand::{ - name::{known, AsName, Name}, + name::{AsName, Name}, Lookup, }; +use intern::{sym, Symbol}; use rustc_hash::FxHashSet; use crate::{ @@ -414,13 +415,13 @@ fn select_best_path( (Unstable, Stable) => return new_path, _ => {} } - const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc]; + const STD_CRATES: [Symbol; 3] = [sym::std, sym::core, sym::alloc]; let choose = |new: (ModPath, _), old: (ModPath, _)| { let (new_path, _) = &new; let (old_path, _) = &old; - let new_has_prelude = new_path.segments().iter().any(|seg| seg == &known::prelude); - let old_has_prelude = old_path.segments().iter().any(|seg| seg == &known::prelude); + let new_has_prelude = new_path.segments().iter().any(|seg| *seg == sym::prelude); + let old_has_prelude = old_path.segments().iter().any(|seg| *seg == sym::prelude); match (new_has_prelude, old_has_prelude, cfg.prefer_prelude) { (true, false, true) | (false, true, false) => new, (true, false, false) | (false, true, true) => old, @@ -441,18 +442,20 @@ fn select_best_path( }; match (old_path.0.segments().first(), new_path.0.segments().first()) { - (Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => { + (Some(old), Some(new)) + if STD_CRATES.contains(old.symbol()) && STD_CRATES.contains(new.symbol()) => + { let rank = match cfg.prefer_no_std { false => |name: &Name| match name { - name if name == &known::core => 0, - name if name == &known::alloc => 1, - name if name == &known::std => 2, + name if *name == sym::core => 0, + name if *name == sym::alloc => 1, + name if *name == sym::std => 2, _ => unreachable!(), }, true => |name: &Name| match name { - name if name == &known::core => 2, - name if name == &known::alloc => 1, - name if name == &known::std => 0, + name if *name == sym::core => 2, + name if *name == sym::alloc => 1, + name if *name == sym::std => 0, _ => unreachable!(), }, }; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs index de0fa982c86a2..d6dd5df37366a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs @@ -3,10 +3,11 @@ use std::mem; use hir_expand::name::Name; use rustc_parse_format as parse; +use span::SyntaxContextId; use stdx::TupleExt; use syntax::{ ast::{self, IsString}, - SmolStr, TextRange, TextSize, + TextRange, TextSize, }; use crate::hir::ExprId; @@ -174,6 +175,7 @@ pub(crate) fn parse( is_direct_literal: bool, mut synth: impl FnMut(Name) -> ExprId, mut record_usage: impl FnMut(Name, Option), + call_ctx: SyntaxContextId, ) -> FormatArgs { let Ok(text) = s.value() else { return FormatArgs { @@ -248,7 +250,7 @@ pub(crate) fn parse( } } ArgRef::Name(name, span) => { - let name = Name::new_text_dont_use(SmolStr::new(name)); + let name = Name::new(name, call_ctx); if let Some((index, _)) = args.by_name(&name) { record_usage(name, span); // Name found in `args`, so we resolve it to its index. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 199b8daa37efe..496686b4f943c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -2,7 +2,8 @@ use std::collections::hash_map::Entry; -use hir_expand::{mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId}; +use hir_expand::{mod_path::path, name::AsName, span_map::SpanMapRef, HirFileId}; +use intern::sym; use la_arena::Arena; use rustc_hash::FxHashMap; use span::{AstIdMap, SyntaxContextId}; @@ -323,7 +324,7 @@ impl<'a> Ctx<'a> { let self_type = match self_param.ty() { Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), None => { - let self_type = TypeRef::Path(name![Self].into()); + let self_type = TypeRef::Path(Name::new_symbol_root(sym::Self_).into()); match self_param.kind() { ast::SelfParamKind::Owned => self_type, ast::SelfParamKind::Ref => TypeRef::Reference( @@ -669,7 +670,7 @@ impl<'a> Ctx<'a> { // Traits and trait aliases get the Self type as an implicit first type parameter. generics.type_or_consts.alloc( TypeParamData { - name: Some(name![Self]), + name: Some(Name::new_symbol_root(sym::Self_)), default: None, provenance: TypeParamProvenance::TraitSelf, } @@ -680,7 +681,7 @@ impl<'a> Ctx<'a> { generics.fill_bounds( &self.body_ctx, bounds, - Either::Left(TypeRef::Path(name![Self].into())), + Either::Left(TypeRef::Path(Name::new_symbol_root(sym::Self_).into())), ); } @@ -745,7 +746,7 @@ fn desugar_future_path(orig: TypeRef) -> Path { let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments().len() - 1).collect(); let binding = AssociatedTypeBinding { - name: name![Output], + name: Name::new_symbol_root(sym::Output), args: None, type_ref: Some(orig), bounds: Box::default(), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 6d7836d5ae899..4d17650285f40 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -3,6 +3,7 @@ //! This attribute to tell the compiler about semi built-in std library //! features, such as Fn family of traits. use hir_expand::name::Name; +use intern::{sym, Symbol}; use rustc_hash::FxHashMap; use syntax::SmolStr; use triomphe::Arc; @@ -267,6 +268,14 @@ macro_rules! language_item_table { _ => None, } } + + /// Opposite of [`LangItem::name`] + pub fn from_symbol(sym: Symbol) -> Option { + match sym { + $(sym if sym == $module::$name => Some(LangItem::$variant), )* + _ => None, + } + } } } } @@ -274,7 +283,7 @@ macro_rules! language_item_table { impl LangItem { /// Opposite of [`LangItem::name`] pub fn from_name(name: &hir_expand::name::Name) -> Option { - Self::from_str(name.as_str()?) + Self::from_str(name.as_str()) } pub fn path(&self, db: &dyn DefDatabase, start_crate: CrateId) -> Option { @@ -360,7 +369,7 @@ language_item_table! { DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None; Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None; - Fn, kw::fn, fn_trait, Target::Trait, GenericRequirement::Exact(1); + Fn, sym::fn_, fn_trait, Target::Trait, GenericRequirement::Exact(1); FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index fc026a14d442f..a33e681cb5a76 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -862,7 +862,7 @@ impl GeneralConstId { .const_data(const_id) .name .as_ref() - .and_then(|it| it.as_str()) + .map(|it| it.as_str()) .unwrap_or("_") .to_owned(), GeneralConstId::ConstBlockId(id) => format!("{{anonymous const {id:?}}}"), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index b5045efb62157..30d4a79a808d9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -13,11 +13,11 @@ use hir_expand::{ builtin_attr_macro::find_builtin_attr, builtin_derive_macro::find_builtin_derive, builtin_fn_macro::find_builtin_macro, - name::{name, AsName, Name}, + name::{AsName, Name}, proc_macro::CustomProcMacroExpander, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, }; -use intern::Interned; +use intern::{sym, Interned}; use itertools::{izip, Itertools}; use la_arena::Idx; use limit::Limit; @@ -76,25 +76,28 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI let proc_macros = if krate.is_proc_macro { match db.proc_macros().get(&def_map.krate) { - Some(Ok(proc_macros)) => Ok(proc_macros - .iter() - .enumerate() - .map(|(idx, it)| { - let name = Name::new_text_dont_use(it.name.clone()); - ( - name, - if !db.expand_proc_attr_macros() { - CustomProcMacroExpander::dummy() - } else if it.disabled { - CustomProcMacroExpander::disabled() - } else { - CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId::new( - idx as u32, - )) - }, - ) - }) - .collect()), + Some(Ok(proc_macros)) => Ok({ + let ctx = db.syntax_context(tree_id.file_id()); + proc_macros + .iter() + .enumerate() + .map(|(idx, it)| { + let name = Name::new(&it.name, ctx); + ( + name, + if !db.expand_proc_attr_macros() { + CustomProcMacroExpander::dummy() + } else if it.disabled { + CustomProcMacroExpander::disabled() + } else { + CustomProcMacroExpander::new( + hir_expand::proc_macro::ProcMacroId::new(idx as u32), + ) + }, + ) + }) + .collect() + }), Some(Err(e)) => Err(e.clone().into_boxed_str()), None => Err("No proc-macros present for crate".to_owned().into_boxed_str()), } @@ -291,24 +294,24 @@ impl DefCollector<'_> { let Some(attr_name) = attr.path.as_ident() else { continue }; match () { - () if *attr_name == hir_expand::name![recursion_limit] => { + () if *attr_name == sym::recursion_limit => { if let Some(limit) = attr.string_value() { if let Ok(limit) = limit.parse() { crate_data.recursion_limit = Some(limit); } } } - () if *attr_name == hir_expand::name![crate_type] => { + () if *attr_name == sym::crate_type => { if let Some("proc-macro") = attr.string_value() { self.is_proc_macro = true; } } - () if *attr_name == hir_expand::name![no_core] => crate_data.no_core = true, - () if *attr_name == hir_expand::name![no_std] => crate_data.no_std = true, - () if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") => { + () if *attr_name == sym::no_core => crate_data.no_core = true, + () if *attr_name == sym::no_std => crate_data.no_std = true, + () if *attr_name == sym::rustc_coherence_is_core => { crate_data.rustc_coherence_is_core = true; } - () if *attr_name == hir_expand::name![feature] => { + () if *attr_name == sym::feature => { let features = attr .parse_path_comma_token_tree(self.db.upcast()) .into_iter() @@ -319,13 +322,13 @@ impl DefCollector<'_> { }); crate_data.unstable_features.extend(features); } - () if *attr_name == hir_expand::name![register_attr] => { + () if *attr_name == sym::register_attr => { if let Some(ident) = attr.single_ident_value() { crate_data.registered_attrs.push(ident.text.clone()); cov_mark::hit!(register_attr); } } - () if *attr_name == hir_expand::name![register_tool] => { + () if *attr_name == sym::register_tool => { if let Some(ident) = attr.single_ident_value() { crate_data.registered_tools.push(ident.text.clone()); cov_mark::hit!(register_tool); @@ -535,27 +538,30 @@ impl DefCollector<'_> { } let krate = if self.def_map.data.no_std { - name![core] - } else if self.def_map.extern_prelude().any(|(name, _)| *name == name![std]) { - name![std] + Name::new_symbol_root(sym::core) + } else if self.def_map.extern_prelude().any(|(name, _)| *name == sym::std) { + Name::new_symbol_root(sym::std) } else { // If `std` does not exist for some reason, fall back to core. This mostly helps // keep r-a's own tests minimal. - name![core] + Name::new_symbol_root(sym::core) }; let edition = match self.def_map.data.edition { - Edition::Edition2015 => name![rust_2015], - Edition::Edition2018 => name![rust_2018], - Edition::Edition2021 => name![rust_2021], - Edition::Edition2024 => name![rust_2024], + Edition::Edition2015 => Name::new_symbol_root(sym::rust_2015), + Edition::Edition2018 => Name::new_symbol_root(sym::rust_2018), + Edition::Edition2021 => Name::new_symbol_root(sym::rust_2021), + Edition::Edition2024 => Name::new_symbol_root(sym::rust_2024), }; let path_kind = match self.def_map.data.edition { Edition::Edition2015 => PathKind::Plain, _ => PathKind::Abs, }; - let path = ModPath::from_segments(path_kind, [krate, name![prelude], edition]); + let path = ModPath::from_segments( + path_kind, + [krate, Name::new_symbol_root(sym::prelude), edition], + ); let (per_ns, _) = self.def_map.resolve_path(self.db, DefMap::ROOT, &path, BuiltinShadowMode::Other, None); @@ -838,7 +844,7 @@ impl DefCollector<'_> { } fn resolve_extern_crate(&self, name: &Name) -> Option { - if *name == name![self] { + if *name == sym::self_ { cov_mark::hit!(extern_crate_self_as); Some(self.def_map.crate_root()) } else { @@ -2136,9 +2142,9 @@ impl ModCollector<'_, '_> { let expander = if attrs.by_key("rustc_builtin_macro").exists() { // `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name. let name; - let name = match attrs.by_key("rustc_builtin_macro").string_value() { - Some(it) => { - name = Name::new_text_dont_use(it.into()); + let name = match attrs.by_key("rustc_builtin_macro").string_value_with_span() { + Some((it, span)) => { + name = Name::new(it, span.ctx); &name } None => { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index cee9e055459f5..22397df961066 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -6,9 +6,9 @@ use crate::{lower::LowerCtx, type_ref::ConstRef}; use hir_expand::{ mod_path::resolve_crate_root, - name::{name, AsName}, + name::{AsName, Name}, }; -use intern::Interned; +use intern::{sym, Interned}; use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds}; use crate::{ @@ -60,7 +60,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option { - segments.push(name![Self]); + segments.push(Name::new_symbol_root(sym::Self_)); } ast::PathSegmentKind::Type { type_ref, trait_ref } => { assert!(path.qualifier().is_none()); // this can only occur at the first segment @@ -268,7 +268,7 @@ fn lower_generic_args_from_fn_path( let bindings = if let Some(ret_type) = ret_type { let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty()); Box::new([AssociatedTypeBinding { - name: name![Output], + name: Name::new_symbol_root(sym::Output), args: None, type_ref: Some(type_ref), bounds: Box::default(), @@ -277,7 +277,7 @@ fn lower_generic_args_from_fn_path( // -> () let type_ref = TypeRef::Tuple(Vec::new()); Box::new([AssociatedTypeBinding { - name: name![Output], + name: Name::new_symbol_root(sym::Output), args: None, type_ref: Some(type_ref), bounds: Box::default(), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index e5c1f93bbde65..4931418546603 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -2,11 +2,8 @@ use std::{fmt, iter, mem}; use base_db::CrateId; -use hir_expand::{ - name::{name, Name}, - MacroDefId, -}; -use intern::Interned; +use hir_expand::{name::Name, MacroDefId}; +use intern::{sym, Interned}; use rustc_hash::FxHashSet; use smallvec::{smallvec, SmallVec}; use triomphe::Arc; @@ -197,12 +194,12 @@ impl Resolver { } } &Scope::ImplDefScope(impl_) => { - if first_name == &name![Self] { + if *first_name == sym::Self_ { return Some((TypeNs::SelfType(impl_), remaining_idx(), None)); } } &Scope::AdtScope(adt) => { - if first_name == &name![Self] { + if *first_name == sym::Self_ { return Some((TypeNs::AdtSelfType(adt), remaining_idx(), None)); } } @@ -294,7 +291,7 @@ impl Resolver { } }; let n_segments = path.segments().len(); - let tmp = name![self]; + let tmp = Name::new_symbol_root(sym::Self_); let first_name = if path.is_self() { &tmp } else { path.segments().first()? }; let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); if skip_to_mod { @@ -325,7 +322,7 @@ impl Resolver { } } &Scope::ImplDefScope(impl_) => { - if first_name == &name![Self] { + if *first_name == sym::Self_ { return Some(ResolveValueResult::ValueNs( ValueNs::ImplSelf(impl_), None, @@ -352,7 +349,7 @@ impl Resolver { } } &Scope::ImplDefScope(impl_) => { - if first_name == &name![Self] { + if *first_name == sym::Self_ { return Some(ResolveValueResult::Partial( TypeNs::SelfType(impl_), 1, @@ -361,7 +358,7 @@ impl Resolver { } } Scope::AdtScope(adt) => { - if first_name == &name![Self] { + if *first_name == sym::Self_ { let ty = TypeNs::AdtSelfType(*adt); return Some(ResolveValueResult::Partial(ty, 1, None)); } @@ -425,7 +422,7 @@ impl Resolver { } pub fn resolve_lifetime(&self, lifetime: &LifetimeRef) -> Option { - if lifetime.name == name::known::STATIC_LIFETIME { + if lifetime.name == sym::tick_static { return Some(LifetimeNs::Static); } @@ -781,10 +778,10 @@ impl Scope { } } Scope::ImplDefScope(i) => { - acc.add(&name![Self], ScopeDef::ImplSelfType(*i)); + acc.add(&Name::new_symbol_root(sym::Self_), ScopeDef::ImplSelfType(*i)); } Scope::AdtScope(i) => { - acc.add(&name![Self], ScopeDef::AdtSelfType(*i)); + acc.add(&Name::new_symbol_root(sym::Self_), ScopeDef::AdtSelfType(*i)); } Scope::ExprScope(scope) => { if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index db0feb055e198..6afa7a40f123f 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -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 (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); - - attrs.collect() - } - }) - .collect::>(); + 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_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::>(); 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> { 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 { - if *self.path.as_ident()? == crate::name![cfg] { + if *self.path.as_ident()? == sym::cfg { self.token_tree_value().map(CfgExpr::parse) } else { None diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs index 2e115f479327e..b9afc666f7528 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs @@ -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 { match name { - $( id if id == &name::name![$name] => Some(BuiltinAttrExpander::$variant), )* + $( id if id == &sym::$name => Some(BuiltinAttrExpander::$variant), )* _ => None, } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs index c7cdc5e92200f..269e9f308c2f6 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs @@ -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 { match name { - $( id if id == &name::name![$trait] => Some(BuiltinDeriveExpander::$trait), )* + $( id if id == &sym::$trait => Some(BuiltinDeriveExpander::$trait), )* _ => None, } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index 02fd431e4e7ec..e5de5975a2d8b 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -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> { 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}` diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index ad25a1168c4d5..e1fb3953f4d2b 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -133,6 +133,15 @@ pub trait ExpandDatabase: SourceDatabase { &self, macro_call: MacroCallId, ) -> Option>>>; + #[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 diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs index 29408902f16f8..b920d2127abe8 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs @@ -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 diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 12fdf88a2a873..7ff8b797fa4a6 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -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 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 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),)* ]) }); } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index fe754bc82494a..da0adbef16342 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -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: (), +} -/// 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 Ord for Name { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.symbol.as_str().cmp(other.symbol.as_str()) + } +} -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -enum Repr { - Text(SmolStr), - TupleField(usize), +impl PartialOrd for Name { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } } +impl PartialEq for Name { + fn eq(&self, sym: &Symbol) -> bool { + self.symbol == *sym + } +} + +impl PartialEq 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<'_> { /// 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!("{idx}")) + Name::new_text(&format_smolstr!("{idx}")) } /// Returns the tuple index this name represents if it is a tuple field. pub fn as_tuple_index(&self) -> Option { - 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 { - 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; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs index 8f1e32321e147..f4fc3b7b3e2da 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs @@ -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)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index b706cef0b3a28..736379a3d8730 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -5,7 +5,8 @@ use chalk_ir::cast::Cast; use hir_def::lang_item::LangItem; -use hir_expand::name::name; +use hir_expand::name::Name; +use intern::sym; use limit::Limit; use triomphe::Arc; @@ -151,7 +152,8 @@ pub(crate) fn deref_by_trait( let deref_trait = db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?; - let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?; + let target = + db.trait_data(deref_trait).associated_type_by_name(&Name::new_symbol_root(sym::Target))?; let projection = { let b = TyBuilder::subst_for_def(db, deref_trait, None); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 3ac8cbaaf8b70..868827b2b6603 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -3,6 +3,8 @@ use core::ops; use std::{iter, ops::ControlFlow, sync::Arc}; +use hir_expand::name::Name; +use intern::sym; use tracing::debug; use chalk_ir::{cast::Caster, fold::shift::Shift, CanonicalVarKinds}; @@ -16,7 +18,6 @@ use hir_def::{ AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, VariantId, }; -use hir_expand::name::name; use crate::{ db::{HirDatabase, InternedCoroutine}, @@ -293,8 +294,10 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { .lang_item(self.krate, LangItem::Future) .and_then(|item| item.as_trait()) .and_then(|trait_| { - let alias = - self.db.trait_data(trait_).associated_type_by_name(&name![Output])?; + let alias = self + .db + .trait_data(trait_) + .associated_type_by_name(&Name::new_symbol_root(sym::Output))?; Some((trait_, alias)) }) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index 15ecf9aafcfc9..1df801f3a4fd5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -247,7 +247,7 @@ impl<'a> DeclValidator<'a> { // Check the module name. let Some(module_name) = module_id.name(self.db.upcast()) else { return }; let Some(module_name_replacement) = - module_name.as_str().and_then(to_lower_snake_case).map(|new_name| Replacement { + to_lower_snake_case(module_name.as_str()).map(|new_name| Replacement { current_name: module_name, suggested_text: new_name, expected_case: CaseType::LowerSnakeCase, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index c28ab2e98afb1..048bdd2c38bce 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -8,7 +8,7 @@ use either::Either; use hir_def::lang_item::LangItem; use hir_def::{resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId, HasModule}; use hir_def::{ItemContainerId, Lookup}; -use hir_expand::name; +use intern::sym; use itertools::Itertools; use rustc_hash::FxHashSet; use rustc_pattern_analysis::constructor::Constructor; @@ -423,7 +423,7 @@ impl FilterMapNextChecker { ItemContainerId::TraitId(iterator_trait_id) => { let iterator_trait_items = &db.trait_data(iterator_trait_id).items; iterator_trait_items.iter().find_map(|(name, it)| match it { - &AssocItemId::FunctionId(id) if *name == name![filter_map] => Some(id), + &AssocItemId::FunctionId(id) if *name == sym::filter_map => Some(id), _ => None, }) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index a9a5d829f5f91..2a644de1fbecc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -25,7 +25,7 @@ use hir_def::{ ModuleId, TraitId, }; use hir_expand::name::Name; -use intern::{Internable, Interned}; +use intern::{sym, Internable, Interned}; use itertools::Itertools; use la_arena::ArenaMap; use rustc_apfloat::{ @@ -1171,7 +1171,8 @@ impl HirDisplay for Ty { .lang_item(body.module(db.upcast()).krate(), LangItem::Future) .and_then(LangItemTarget::as_trait); let output = future_trait.and_then(|t| { - db.trait_data(t).associated_type_by_name(&hir_expand::name!(Output)) + db.trait_data(t) + .associated_type_by_name(&Name::new_symbol_root(sym::Output)) }); write!(f, "impl ")?; if let Some(t) = future_trait { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 66ee02d74d9a0..928a3f5e493c7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -46,8 +46,9 @@ use hir_def::{ AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId, }; -use hir_expand::name::{name, Name}; +use hir_expand::name::Name; use indexmap::IndexSet; +use intern::sym; use la_arena::{ArenaMap, Entry}; use once_cell::unsync::OnceCell; use rustc_hash::{FxHashMap, FxHashSet}; @@ -1424,7 +1425,7 @@ impl<'a> InferenceContext<'a> { } fn resolve_output_on(&self, trait_: TraitId) -> Option { - self.db.trait_data(trait_).associated_type_by_name(&name![Output]) + self.db.trait_data(trait_).associated_type_by_name(&Name::new_symbol_root(sym::Output)) } fn resolve_lang_trait(&self, lang: LangItem) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index b7c7b6654536a..f54081a276c8d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -15,7 +15,8 @@ use hir_def::{ resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId, }; -use hir_expand::name; +use hir_expand::name::Name; +use intern::sym; use rustc_hash::FxHashMap; use smallvec::SmallVec; use stdx::never; @@ -268,9 +269,7 @@ impl CapturedItem { } let variant_data = f.parent.variant_data(db.upcast()); let field = match &*variant_data { - VariantData::Record(fields) => { - fields[f.local_id].name.as_str().unwrap_or("[missing field]").to_owned() - } + VariantData::Record(fields) => fields[f.local_id].name.as_str().to_owned(), VariantData::Tuple(fields) => fields .iter() .position(|it| it.0 == f.local_id) @@ -621,8 +620,10 @@ impl InferenceContext<'_> { if let Some(deref_trait) = self.resolve_lang_item(LangItem::DerefMut).and_then(|it| it.as_trait()) { - if let Some(deref_fn) = - self.db.trait_data(deref_trait).method_by_name(&name![deref_mut]) + if let Some(deref_fn) = self + .db + .trait_data(deref_trait) + .method_by_name(&Name::new_symbol_root(sym::deref_mut)) { break 'b deref_fn == f; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 7a0f7872a649d..a0c3f48642e3b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -15,7 +15,8 @@ use hir_def::{ path::{GenericArgs, Path}, BlockId, FieldId, GenericDefId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId, }; -use hir_expand::name::{name, Name}; +use hir_expand::name::Name; +use intern::sym; use stdx::always; use syntax::ast::RangeOp; @@ -646,8 +647,10 @@ impl InferenceContext<'_> { match op { UnaryOp::Deref => { if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) { - if let Some(deref_fn) = - self.db.trait_data(deref_trait).method_by_name(&name![deref]) + if let Some(deref_fn) = self + .db + .trait_data(deref_trait) + .method_by_name(&Name::new_symbol_root(sym::deref)) { // FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that // the mutability is not wrong, and will be fixed in `self.infer_mut`). @@ -785,8 +788,10 @@ impl InferenceContext<'_> { // mutability will be fixed up in `InferenceContext::infer_mut`; adj.push(Adjustment::borrow(Mutability::Not, self_ty.clone())); self.write_expr_adj(*base, adj); - if let Some(func) = - self.db.trait_data(index_trait).method_by_name(&name!(index)) + if let Some(func) = self + .db + .trait_data(index_trait) + .method_by_name(&Name::new_symbol_root(sym::index)) { let substs = TyBuilder::subst_for_def(self.db, index_trait, None) .push(self_ty.clone()) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index 00e5eac229fb6..ca8996fb89e77 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -6,7 +6,8 @@ use hir_def::{ hir::{Array, BinaryOp, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp}, lang_item::LangItem, }; -use hir_expand::name; +use hir_expand::name::Name; +use intern::sym; use crate::{lower::lower_to_chalk_mutability, Adjust, Adjustment, AutoBorrow, OverloadedDeref}; @@ -108,8 +109,10 @@ impl InferenceContext<'_> { .lang_item(self.table.trait_env.krate, LangItem::IndexMut) .and_then(|l| l.as_trait()) { - if let Some(index_fn) = - self.db.trait_data(index_trait).method_by_name(&name![index_mut]) + if let Some(index_fn) = self + .db + .trait_data(index_trait) + .method_by_name(&Name::new_symbol_root(sym::index_mut)) { *f = index_fn; let base_adjustments = self @@ -139,8 +142,10 @@ impl InferenceContext<'_> { .lang_item(self.table.trait_env.krate, LangItem::DerefMut) .and_then(|l| l.as_trait()) { - if let Some(deref_fn) = - self.db.trait_data(deref_trait).method_by_name(&name![deref_mut]) + if let Some(deref_fn) = self + .db + .trait_data(deref_trait) + .method_by_name(&Name::new_symbol_root(sym::deref_mut)) { *f = deref_fn; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 490ecfd7fa3c3..67a0ec60f19d6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -7,6 +7,7 @@ use hir_def::{ AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup, }; use hir_expand::name::Name; +use intern::sym; use stdx::never; use crate::{ @@ -227,7 +228,7 @@ impl InferenceContext<'_> { Path::LangItem(..) => ( PathSegment { name: { - _d = hir_expand::name::known::Unknown; + _d = Name::new_symbol_root(sym::Unknown); &_d }, args_and_bindings: None, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index ed4d55d203773..800b06afbd0b2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -9,7 +9,8 @@ use chalk_ir::{ use chalk_solve::infer::ParameterEnaVariableExt; use either::Either; use ena::unify::UnifyKey; -use hir_expand::name; +use hir_expand::name::Name; +use intern::sym; use rustc_hash::FxHashMap; use smallvec::SmallVec; use triomphe::Arc; @@ -781,7 +782,8 @@ impl<'a> InferenceTable<'a> { let krate = self.trait_env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; let trait_data = self.db.trait_data(fn_once_trait); - let output_assoc_type = trait_data.associated_type_by_name(&name![Output])?; + let output_assoc_type = + trait_data.associated_type_by_name(&Name::new_symbol_root(sym::Output))?; let mut arg_tys = Vec::with_capacity(num_args); let arg_ty = TyBuilder::tuple(num_args) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs index 85ed46b96321a..69ff03eb49ece 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs @@ -2,6 +2,7 @@ use hir_def::{data::adt::StructFlags, lang_item::LangItem, AdtId}; use hir_expand::name::Name; +use intern::sym; use crate::db::HirDatabase; @@ -16,48 +17,47 @@ pub fn is_unsafe_cell(db: &dyn HirDatabase, adt: AdtId) -> bool { } pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> { - use hir_expand::name; use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering}; Some(match op { BinaryOp::LogicOp(_) => return None, BinaryOp::ArithOp(aop) => match aop { - ArithOp::Add => (name![add], LangItem::Add), - ArithOp::Mul => (name![mul], LangItem::Mul), - ArithOp::Sub => (name![sub], LangItem::Sub), - ArithOp::Div => (name![div], LangItem::Div), - ArithOp::Rem => (name![rem], LangItem::Rem), - ArithOp::Shl => (name![shl], LangItem::Shl), - ArithOp::Shr => (name![shr], LangItem::Shr), - ArithOp::BitXor => (name![bitxor], LangItem::BitXor), - ArithOp::BitOr => (name![bitor], LangItem::BitOr), - ArithOp::BitAnd => (name![bitand], LangItem::BitAnd), + ArithOp::Add => (Name::new_symbol_root(sym::add), LangItem::Add), + ArithOp::Mul => (Name::new_symbol_root(sym::mul), LangItem::Mul), + ArithOp::Sub => (Name::new_symbol_root(sym::sub), LangItem::Sub), + ArithOp::Div => (Name::new_symbol_root(sym::div), LangItem::Div), + ArithOp::Rem => (Name::new_symbol_root(sym::rem), LangItem::Rem), + ArithOp::Shl => (Name::new_symbol_root(sym::shl), LangItem::Shl), + ArithOp::Shr => (Name::new_symbol_root(sym::shr), LangItem::Shr), + ArithOp::BitXor => (Name::new_symbol_root(sym::bitxor), LangItem::BitXor), + ArithOp::BitOr => (Name::new_symbol_root(sym::bitor), LangItem::BitOr), + ArithOp::BitAnd => (Name::new_symbol_root(sym::bitand), LangItem::BitAnd), }, BinaryOp::Assignment { op: Some(aop) } => match aop { - ArithOp::Add => (name![add_assign], LangItem::AddAssign), - ArithOp::Mul => (name![mul_assign], LangItem::MulAssign), - ArithOp::Sub => (name![sub_assign], LangItem::SubAssign), - ArithOp::Div => (name![div_assign], LangItem::DivAssign), - ArithOp::Rem => (name![rem_assign], LangItem::RemAssign), - ArithOp::Shl => (name![shl_assign], LangItem::ShlAssign), - ArithOp::Shr => (name![shr_assign], LangItem::ShrAssign), - ArithOp::BitXor => (name![bitxor_assign], LangItem::BitXorAssign), - ArithOp::BitOr => (name![bitor_assign], LangItem::BitOrAssign), - ArithOp::BitAnd => (name![bitand_assign], LangItem::BitAndAssign), + ArithOp::Add => (Name::new_symbol_root(sym::add_assign), LangItem::AddAssign), + ArithOp::Mul => (Name::new_symbol_root(sym::mul_assign), LangItem::MulAssign), + ArithOp::Sub => (Name::new_symbol_root(sym::sub_assign), LangItem::SubAssign), + ArithOp::Div => (Name::new_symbol_root(sym::div_assign), LangItem::DivAssign), + ArithOp::Rem => (Name::new_symbol_root(sym::rem_assign), LangItem::RemAssign), + ArithOp::Shl => (Name::new_symbol_root(sym::shl_assign), LangItem::ShlAssign), + ArithOp::Shr => (Name::new_symbol_root(sym::shr_assign), LangItem::ShrAssign), + ArithOp::BitXor => (Name::new_symbol_root(sym::bitxor_assign), LangItem::BitXorAssign), + ArithOp::BitOr => (Name::new_symbol_root(sym::bitor_assign), LangItem::BitOrAssign), + ArithOp::BitAnd => (Name::new_symbol_root(sym::bitand_assign), LangItem::BitAndAssign), }, BinaryOp::CmpOp(cop) => match cop { - CmpOp::Eq { negated: false } => (name![eq], LangItem::PartialEq), - CmpOp::Eq { negated: true } => (name![ne], LangItem::PartialEq), + CmpOp::Eq { negated: false } => (Name::new_symbol_root(sym::eq), LangItem::PartialEq), + CmpOp::Eq { negated: true } => (Name::new_symbol_root(sym::ne), LangItem::PartialEq), CmpOp::Ord { ordering: Ordering::Less, strict: false } => { - (name![le], LangItem::PartialOrd) + (Name::new_symbol_root(sym::le), LangItem::PartialOrd) } CmpOp::Ord { ordering: Ordering::Less, strict: true } => { - (name![lt], LangItem::PartialOrd) + (Name::new_symbol_root(sym::lt), LangItem::PartialOrd) } CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { - (name![ge], LangItem::PartialOrd) + (Name::new_symbol_root(sym::ge), LangItem::PartialOrd) } CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { - (name![gt], LangItem::PartialOrd) + (Name::new_symbol_root(sym::gt), LangItem::PartialOrd) } }, BinaryOp::Assignment { op: None } => return None, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index bd650869bb386..60447ac582030 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -61,7 +61,8 @@ use chalk_ir::{ }; use either::Either; use hir_def::{hir::ExprId, type_ref::Rawness, CallableDefId, GeneralConstId, TypeOrConstParamId}; -use hir_expand::name; +use hir_expand::name::Name; +use intern::sym; use la_arena::{Arena, Idx}; use mir::{MirEvalError, VTableMap}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -894,7 +895,9 @@ pub fn callable_sig_from_fn_trait( ) -> Option<(FnTrait, CallableSig)> { let krate = trait_env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; - let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; + let output_assoc_type = db + .trait_data(fn_once_trait) + .associated_type_by_name(&Name::new_symbol_root(sym::Output))?; let mut table = InferenceTable::new(db, trait_env.clone()); let b = TyBuilder::trait_ref(db, fn_once_trait); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 2d9c221b732b0..982080c5ff5fe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -14,8 +14,8 @@ use hir_def::{ AdtId, ConstId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId, VariantId, }; -use hir_expand::{mod_path::ModPath, HirFileIdExt, InFile}; -use intern::Interned; +use hir_expand::{mod_path::path, name::Name, HirFileIdExt, InFile}; +use intern::{sym, Interned}; use la_arena::ArenaMap; use rustc_abi::TargetDataLayout; use rustc_apfloat::{ @@ -35,7 +35,7 @@ use crate::{ layout::{Layout, LayoutError, RustcEnumVariantIdx}, mapping::from_chalk, method_resolution::{is_dyn_method, lookup_impl_const}, - name, static_lifetime, + static_lifetime, traits::FnTrait, utils::{detect_variant_from_bytes, ClosureSubst}, CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstScalar, FnDefId, Interner, MemoryMap, @@ -631,15 +631,19 @@ impl Evaluator<'_> { cached_fn_trait_func: db .lang_item(crate_id, LangItem::Fn) .and_then(|x| x.as_trait()) - .and_then(|x| db.trait_data(x).method_by_name(&name![call])), + .and_then(|x| db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call))), cached_fn_mut_trait_func: db .lang_item(crate_id, LangItem::FnMut) .and_then(|x| x.as_trait()) - .and_then(|x| db.trait_data(x).method_by_name(&name![call_mut])), + .and_then(|x| { + db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call_mut)) + }), cached_fn_once_trait_func: db .lang_item(crate_id, LangItem::FnOnce) .and_then(|x| x.as_trait()) - .and_then(|x| db.trait_data(x).method_by_name(&name![call_once])), + .and_then(|x| { + db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call_once)) + }), }) } @@ -2633,10 +2637,7 @@ impl Evaluator<'_> { let static_data = self.db.static_data(st); let result = if !static_data.is_extern { let konst = self.db.const_eval_static(st).map_err(|e| { - MirEvalError::ConstEvalError( - static_data.name.as_str().unwrap_or("_").to_owned(), - Box::new(e), - ) + MirEvalError::ConstEvalError(static_data.name.as_str().to_owned(), Box::new(e)) })?; self.allocate_const_in_heap(locals, &konst)? } else { @@ -2693,7 +2694,7 @@ impl Evaluator<'_> { ) -> Result<()> { let Some(drop_fn) = (|| { let drop_trait = self.db.lang_item(self.crate_id, LangItem::Drop)?.as_trait()?; - self.db.trait_data(drop_trait).method_by_name(&name![drop]) + self.db.trait_data(drop_trait).method_by_name(&Name::new_symbol_root(sym::drop)) })() else { // in some tests we don't have drop trait in minicore, and // we can ignore drop in them. @@ -2797,14 +2798,13 @@ pub fn render_const_using_debug_impl( let resolver = owner.resolver(db.upcast()); let Some(TypeNs::TraitId(debug_trait)) = resolver.resolve_path_in_type_ns_fully( db.upcast(), - &hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments( - hir_expand::mod_path::PathKind::Abs, - [name![core], name![fmt], name![Debug]], - )), + &hir_def::path::Path::from_known_path_with_no_generic(path![core::fmt::Debug]), ) else { not_supported!("core::fmt::Debug not found"); }; - let Some(debug_fmt_fn) = db.trait_data(debug_trait).method_by_name(&name![fmt]) else { + let Some(debug_fmt_fn) = + db.trait_data(debug_trait).method_by_name(&Name::new_symbol_root(sym::fmt)) + else { not_supported!("core::fmt::Debug::fmt not found"); }; // a1 = &[""] @@ -2829,10 +2829,7 @@ pub fn render_const_using_debug_impl( evaluator.write_memory(a3.offset(5 * evaluator.ptr_size()), &[1])?; let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully( db.upcast(), - &hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments( - hir_expand::mod_path::PathKind::Abs, - [name![std], name![fmt], name![format]], - )), + &hir_def::path::Path::from_known_path_with_no_generic(path![std::fmt::format]), ) else { not_supported!("std::fmt::format not found"); }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index ce22e9d2c2cb8..67e102b1ed183 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -8,12 +8,14 @@ use hir_def::{ builtin_type::{BuiltinInt, BuiltinUint}, resolver::HasResolver, }; +use hir_expand::name::Name; +use intern::sym; use crate::{ error_lifetime, mir::eval::{ - name, pad16, Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId, HasModule, - HirDisplay, Interned, InternedClosure, Interner, Interval, IntervalAndTy, IntervalOrOwned, + pad16, Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId, HasModule, HirDisplay, + Interned, InternedClosure, Interner, Interval, IntervalAndTy, IntervalOrOwned, ItemContainerId, LangItem, Layout, Locals, Lookup, MirEvalError, MirSpan, Mutability, Result, Substitution, Ty, TyBuilder, TyExt, }, @@ -64,7 +66,7 @@ impl Evaluator<'_> { }; if is_intrinsic { self.exec_intrinsic( - function_data.name.as_text().unwrap_or_default().as_str(), + function_data.name.as_str(), args, generic_args, destination, @@ -86,7 +88,7 @@ impl Evaluator<'_> { }; if is_platform_intrinsic { self.exec_platform_intrinsic( - function_data.name.as_text().unwrap_or_default().as_str(), + function_data.name.as_str(), args, generic_args, destination, @@ -104,7 +106,7 @@ impl Evaluator<'_> { }; if is_extern_c { self.exec_extern_c( - function_data.name.as_text().unwrap_or_default().as_str(), + function_data.name.as_str(), args, generic_args, destination, @@ -117,7 +119,7 @@ impl Evaluator<'_> { .attrs .iter() .filter_map(|it| it.path().as_ident()) - .filter_map(|it| it.as_str()) + .map(|it| it.as_str()) .find(|it| { [ "rustc_allocator", @@ -1274,10 +1276,11 @@ impl Evaluator<'_> { args.push(IntervalAndTy::new(addr, field, self, locals)?); } if let Some(target) = self.db.lang_item(self.crate_id, LangItem::FnOnce) { - if let Some(def) = target - .as_trait() - .and_then(|it| self.db.trait_data(it).method_by_name(&name![call_once])) - { + if let Some(def) = target.as_trait().and_then(|it| { + self.db + .trait_data(it) + .method_by_name(&Name::new_symbol_root(sym::call_once)) + }) { self.exec_fn_trait( def, &args, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 1a0a1b780a16e..1b8c772d80e32 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -1113,9 +1113,9 @@ impl<'ctx> MirLowerCtx<'ctx> { .iter() .map(|it| { let o = match it.1.name.as_str() { - Some("start") => lp.take(), - Some("end") => rp.take(), - Some("exhausted") => { + "start" => lp.take(), + "end" => rp.take(), + "exhausted" => { Some(Operand::from_bytes(Box::new([0]), TyBuilder::bool())) } _ => None, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs index 4ad00909e4127..5e8a2dfb735f6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs @@ -4,7 +4,7 @@ use crate::mir::MutBorrowKind; use super::*; use hir_def::FunctionId; -use hir_expand::name; +use intern::sym; macro_rules! not_supported { ($it: expr) => { @@ -192,7 +192,7 @@ impl MirLowerCtx<'_> { if let Some(deref_fn) = self .db .trait_data(deref_trait) - .method_by_name(&name![deref_mut]) + .method_by_name(&Name::new_symbol_root(sym::deref_mut)) { break 'b deref_fn == f; } @@ -324,12 +324,17 @@ impl MirLowerCtx<'_> { mutability: bool, ) -> Result> { let (chalk_mut, trait_lang_item, trait_method_name, borrow_kind) = if !mutability { - (Mutability::Not, LangItem::Deref, name![deref], BorrowKind::Shared) + ( + Mutability::Not, + LangItem::Deref, + Name::new_symbol_root(sym::deref), + BorrowKind::Shared, + ) } else { ( Mutability::Mut, LangItem::DerefMut, - name![deref_mut], + Name::new_symbol_root(sym::deref_mut), BorrowKind::Mut { kind: MutBorrowKind::Default }, ) }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 4283a94657b9f..ce9ffa284c904 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -12,7 +12,8 @@ use hir_def::{ lang_item::{LangItem, LangItemTarget}, BlockId, TraitId, }; -use hir_expand::name::{name, Name}; +use hir_expand::name::Name; +use intern::sym; use stdx::panic_context; use triomphe::Arc; @@ -256,9 +257,9 @@ impl FnTrait { pub fn method_name(self) -> Name { match self { - FnTrait::FnOnce => name!(call_once), - FnTrait::FnMut => name!(call_mut), - FnTrait::Fn => name!(call), + FnTrait::FnOnce => Name::new_symbol_root(sym::call_once), + FnTrait::FnMut => Name::new_symbol_root(sym::call_mut), + FnTrait::Fn => Name::new_symbol_root(sym::call), } } diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index 7b3ff7b06458b..af60c233e5519 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -12,6 +12,7 @@ use hir_def::{ }; use hir_expand::{mod_path::PathKind, name::Name}; use hir_ty::{db::HirDatabase, method_resolution}; +use span::SyntaxContextId; use crate::{ Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, @@ -328,7 +329,7 @@ fn doc_modpath_from_str(link: &str) -> Option { let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() { Ok(idx) => Name::new_tuple_field(idx), Err(_) => { - Name::new_text_dont_use(segment.split_once('<').map_or(segment, |it| it.0).into()) + Name::new(segment.split_once('<').map_or(segment, |it| it.0), SyntaxContextId::ROOT) } }); Some(ModPath::from_segments(kind, parts)) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 016f3418517f9..f90656c75f590 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -58,7 +58,7 @@ use hir_def::{ TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{ - attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult, + attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult, }; use hir_ty::{ all_super_traits, autoderef, check_orphan_rules, @@ -131,7 +131,7 @@ pub use { change::ChangeWithProcMacros, hygiene::{marks_rev, SyntaxContextExt}, inert_attr_macro::AttributeTemplate, - name::{known, Name}, + name::Name, proc_macro::ProcMacros, tt, ExpandResult, HirFileId, HirFileIdExt, InFile, InMacroFile, InRealFile, MacroFileId, MacroFileIdExt, @@ -145,6 +145,7 @@ pub use { }, // FIXME: Properly encapsulate mir hir_ty::{mir, Interner as ChalkTyInterner}, + intern::{sym, Symbol}, }; // These are negative re-exports: pub using these names is forbidden, they @@ -1826,7 +1827,7 @@ impl DefWithBody { continue; } let mut need_mut = &mol[local]; - if body[binding_id].name.as_str() == Some("self") + if body[binding_id].name == sym::self_ && need_mut == &mir::MutabilityReason::Unused { need_mut = &mir::MutabilityReason::Not; @@ -1836,7 +1837,7 @@ impl DefWithBody { match (need_mut, is_mut) { (mir::MutabilityReason::Unused, _) => { - let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with('_')); + let should_ignore = body[binding_id].name.as_str().starts_with('_'); if !should_ignore { acc.push(UnusedVariable { local }.into()) } @@ -1866,7 +1867,7 @@ impl DefWithBody { } (mir::MutabilityReason::Not, true) => { if !infer.mutated_bindings_in_closure.contains(&binding_id) { - let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with('_')); + let should_ignore = body[binding_id].name.as_str().starts_with('_'); if !should_ignore { acc.push(UnusedMut { local }.into()) } @@ -2588,7 +2589,7 @@ pub struct StaticLifetime; impl StaticLifetime { pub fn name(self) -> Name { - known::STATIC_LIFETIME + Name::new_symbol_root(sym::tick_static) } } @@ -3248,7 +3249,7 @@ impl Local { } pub fn is_self(self, db: &dyn HirDatabase) -> bool { - self.name(db) == name![self] + self.name(db) == sym::self_ } pub fn is_mut(self, db: &dyn HirDatabase) -> bool { diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 81c57f6caeb63..45401702e9f00 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -25,11 +25,8 @@ use hir_def::{ }; use hir_expand::{ mod_path::path, + name::{AsName, Name}, HirFileId, InFile, InMacroFile, MacroFileId, MacroFileIdExt, - { - name, - name::{AsName, Name}, - }, }; use hir_ty::{ diagnostics::{ @@ -40,6 +37,7 @@ use hir_ty::{ method_resolution, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext, }; +use intern::sym; use itertools::Itertools; use smallvec::SmallVec; use syntax::{ @@ -368,7 +366,7 @@ impl SourceAnalyzer { let items = into_future_trait.items(db); let into_future_type = items.into_iter().find_map(|item| match item { AssocItem::TypeAlias(alias) - if alias.name(db) == hir_expand::name![IntoFuture] => + if alias.name(db) == Name::new_symbol_root(sym::IntoFuture) => { Some(alias) } @@ -398,14 +396,17 @@ impl SourceAnalyzer { // Since deref kind is inferenced and stored in `InferenceResult.method_resolution`, // use that result to find out which one it is. let (deref_trait, deref) = - self.lang_trait_fn(db, LangItem::Deref, &name![deref])?; + self.lang_trait_fn(db, LangItem::Deref, &Name::new_symbol_root(sym::deref))?; self.infer .as_ref() .and_then(|infer| { let expr = self.expr_id(db, &prefix_expr.clone().into())?; let (func, _) = infer.method_resolution(expr)?; - let (deref_mut_trait, deref_mut) = - self.lang_trait_fn(db, LangItem::DerefMut, &name![deref_mut])?; + let (deref_mut_trait, deref_mut) = self.lang_trait_fn( + db, + LangItem::DerefMut, + &Name::new_symbol_root(sym::deref_mut), + )?; if func == deref_mut { Some((deref_mut_trait, deref_mut)) } else { @@ -414,8 +415,12 @@ impl SourceAnalyzer { }) .unwrap_or((deref_trait, deref)) } - ast::UnaryOp::Not => self.lang_trait_fn(db, LangItem::Not, &name![not])?, - ast::UnaryOp::Neg => self.lang_trait_fn(db, LangItem::Neg, &name![neg])?, + ast::UnaryOp::Not => { + self.lang_trait_fn(db, LangItem::Not, &Name::new_symbol_root(sym::not))? + } + ast::UnaryOp::Neg => { + self.lang_trait_fn(db, LangItem::Neg, &Name::new_symbol_root(sym::neg))? + } }; let ty = self.ty_of_expr(db, &prefix_expr.expr()?)?; @@ -435,15 +440,19 @@ impl SourceAnalyzer { let base_ty = self.ty_of_expr(db, &index_expr.base()?)?; let index_ty = self.ty_of_expr(db, &index_expr.index()?)?; - let (index_trait, index_fn) = self.lang_trait_fn(db, LangItem::Index, &name![index])?; + let (index_trait, index_fn) = + self.lang_trait_fn(db, LangItem::Index, &Name::new_symbol_root(sym::index))?; let (op_trait, op_fn) = self .infer .as_ref() .and_then(|infer| { let expr = self.expr_id(db, &index_expr.clone().into())?; let (func, _) = infer.method_resolution(expr)?; - let (index_mut_trait, index_mut_fn) = - self.lang_trait_fn(db, LangItem::IndexMut, &name![index_mut])?; + let (index_mut_trait, index_mut_fn) = self.lang_trait_fn( + db, + LangItem::IndexMut, + &Name::new_symbol_root(sym::index_mut), + )?; if func == index_mut_fn { Some((index_mut_trait, index_mut_fn)) } else { diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index 02905ca2ce44d..a6e69d7992b23 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -239,7 +239,7 @@ impl<'a> SymbolCollector<'a> { fn collect_from_trait(&mut self, trait_id: TraitId) { let trait_data = self.db.trait_data(trait_id); - self.with_container_name(trait_data.name.as_text(), |s| { + self.with_container_name(Some(trait_data.name.as_str().into()), |s| { for &(_, assoc_item_id) in &trait_data.items { s.push_assoc_item(assoc_item_id); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs index ab25e0167bfe7..c1fcb8e44db84 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs @@ -470,7 +470,7 @@ fn add_enum_def( .module() .scope(ctx.db(), Some(*target_module)) .iter() - .any(|(name, _)| name.as_str() == Some("Bool")) + .any(|(name, _)| name.as_str() == "Bool") { return None; } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs index 61b7b41217760..27e39f6f8ab26 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -1,4 +1,4 @@ -use hir::{known, AsAssocItem, Semantics}; +use hir::{sym, AsAssocItem, Semantics}; use ide_db::{ famous_defs::FamousDefs, syntax_helpers::node_ext::{ @@ -223,7 +223,7 @@ fn option_variants( let fam = FamousDefs(sema, sema.scope(expr)?.krate()); let option_variants = fam.core_option_Option()?.variants(sema.db); match &*option_variants { - &[variant0, variant1] => Some(if variant0.name(sema.db) == known::None { + &[variant0, variant1] => Some(if variant0.name(sema.db) == sym::None { (variant0, variant1) } else { (variant1, variant0) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs index db96c8fe40aa5..d85147e84b20c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs @@ -1,4 +1,4 @@ -use hir::known; +use hir::{sym, Name}; use ide_db::famous_defs::FamousDefs; use stdx::format_to; use syntax::{ @@ -149,7 +149,11 @@ fn is_ref_and_impls_iter_method( ast::Expr::RefExpr(r) => r, _ => return None, }; - let wanted_method = if ref_expr.mut_token().is_some() { known::iter_mut } else { known::iter }; + let wanted_method = Name::new_symbol_root(if ref_expr.mut_token().is_some() { + sym::iter_mut + } else { + sym::iter + }); let expr_behind_ref = ref_expr.expr()?; let ty = sema.type_of_expr(&expr_behind_ref)?.adjusted(); let scope = sema.scope(iterable.syntax())?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index 666e1a1496e03..62bb6dff21e52 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -169,8 +169,8 @@ fn get_names_in_scope( let mut names = FxHashSet::default(); scope.process_all_names(&mut |name, scope| { - if let (Some(name), hir::ScopeDef::Local(_)) = (name.as_text(), scope) { - names.insert(name); + if let hir::ScopeDef::Local(_) = scope { + names.insert(name.as_str().into()); } }); Some(names) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs index 4d369e705e88e..05210e66ac24d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs @@ -1,4 +1,4 @@ -use hir::{known, HasSource, Name}; +use hir::{sym, HasSource, Name}; use syntax::{ ast::{self, HasName}, AstNode, @@ -54,13 +54,13 @@ pub(crate) fn generate_is_empty_from_len(acc: &mut Assists, ctx: &AssistContext< } let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?; - let len_fn = get_impl_method(ctx, &impl_, &known::len)?; + let len_fn = get_impl_method(ctx, &impl_, &Name::new_symbol_root(sym::len))?; if !len_fn.ret_type(ctx.sema.db).is_usize() { cov_mark::hit!(len_fn_different_return_type); return None; } - if get_impl_method(ctx, &impl_, &known::is_empty).is_some() { + if get_impl_method(ctx, &impl_, &Name::new_symbol_root(sym::is_empty)).is_some() { cov_mark::hit!(is_empty_already_implemented); return None; } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 8c9fe23bb0bdd..137b8d13171fe 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -2,7 +2,7 @@ use std::collections::BTreeSet; use ast::make; use either::Either; -use hir::{db::HirDatabase, PathResolution, Semantics, TypeInfo}; +use hir::{db::HirDatabase, sym, PathResolution, Semantics, TypeInfo}; use ide_db::{ base_db::{FileId, FileRange}, defs::Definition, @@ -430,10 +430,7 @@ fn inline( let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty); - let is_self = param - .name(sema.db) - .and_then(|name| name.as_text()) - .is_some_and(|name| name == "self"); + let is_self = param.name(sema.db).is_some_and(|name| name == sym::self_); if is_self { let mut this_pat = make::ident_pat(false, false, make::name("this")); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs index 37ea5123a71e6..12d025f07594e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs @@ -47,7 +47,7 @@ pub(crate) fn replace_with_lazy_method(acc: &mut Assists, ctx: &AssistContext<'_ None, None, |func| { - let valid = func.name(ctx.sema.db).as_str() == Some(&*method_name_lazy) + let valid = func.name(ctx.sema.db).as_str() == &*method_name_lazy && func.num_params(ctx.sema.db) == n_params && { let params = func.params_without_self(ctx.sema.db); @@ -133,7 +133,7 @@ pub(crate) fn replace_with_eager_method(acc: &mut Assists, ctx: &AssistContext<' None, None, |func| { - let valid = func.name(ctx.sema.db).as_str() == Some(method_name_eager) + let valid = func.name(ctx.sema.db).as_str() == method_name_eager && func.num_params(ctx.sema.db) == n_params; valid.then_some(func) }, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index ba6ef1921ac63..c67693ea2bb89 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -88,8 +88,8 @@ pub fn has_test_related_attribute(attrs: &hir::AttrsWithOwner) -> bool { let path = attr.path(); (|| { Some( - path.segments().first()?.as_text()?.starts_with("test") - || path.segments().last()?.as_text()?.ends_with("test"), + path.segments().first()?.as_str().starts_with("test") + || path.segments().last()?.as_str().ends_with("test"), ) })() .unwrap_or_default() diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index 995a4443edff5..4a8ea171805e2 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -24,7 +24,7 @@ pub(crate) mod vis; use std::iter; -use hir::{known, HasAttrs, ImportPathConfig, ScopeDef, Variant}; +use hir::{sym, HasAttrs, ImportPathConfig, Name, ScopeDef, Variant}; use ide_db::{imports::import_assets::LocatedImport, RootDatabase, SymbolKind}; use syntax::{ast, SmolStr}; @@ -618,7 +618,7 @@ fn enum_variants_with_paths( let mut process_variant = |variant: Variant| { let self_path = hir::ModPath::from_segments( hir::PathKind::Plain, - iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))), + iter::once(Name::new_symbol_root(sym::Self_)).chain(iter::once(variant.name(ctx.db))), ); cb(acc, ctx, variant, self_path); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs index f45f9cba258de..7e3a62405a78c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs @@ -18,7 +18,7 @@ pub(super) fn complete_macro_use( for mod_def in krate.root_module().declarations(ctx.db) { if let ModuleDef::Macro(mac) = mod_def { let mac_name = mac.name(ctx.db); - let Some(mac_name) = mac_name.as_str() else { continue }; + let mac_name = mac_name.as_str(); let existing_import = existing_imports .iter() diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index a4f092cc498ef..d3290db4ef82b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -1,5 +1,6 @@ //! Completes references after dot (fields and method calls). +use hir::{sym, Name}; use ide_db::FxHashSet; use syntax::SmolStr; @@ -90,12 +91,14 @@ pub(crate) fn complete_undotted_self( in_breakable: expr_ctx.in_breakable, }, }, - Some(hir::known::SELF_PARAM), + Some(Name::new_symbol_root(sym::self_)), field, &ty, ) }, - |acc, field, ty| acc.add_tuple_field(ctx, Some(hir::known::SELF_PARAM), field, &ty), + |acc, field, ty| { + acc.add_tuple_field(ctx, Some(Name::new_symbol_root(sym::self_)), field, &ty) + }, true, false, ); @@ -112,7 +115,7 @@ pub(crate) fn complete_undotted_self( }, }, func, - Some(hir::known::SELF_PARAM), + Some(Name::new_symbol_root(sym::self_)), None, ) }); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index 01f9368aa4ebf..72b36922da0bd 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -1,6 +1,6 @@ //! Completion of names from the current scope in expression position. -use hir::{ImportPathConfig, ScopeDef}; +use hir::{sym, ImportPathConfig, Name, ScopeDef}; use syntax::ast; use crate::{ @@ -190,7 +190,7 @@ pub(crate) fn complete_expr_path( path_ctx, strukt, None, - Some(hir::known::SELF_TYPE), + Some(Name::new_symbol_root(sym::Self_)), ); } } @@ -210,7 +210,12 @@ pub(crate) fn complete_expr_path( acc.add_union_literal(ctx, un, path, None); if complete_self { - acc.add_union_literal(ctx, un, None, Some(hir::known::SELF_TYPE)); + acc.add_union_literal( + ctx, + un, + None, + Some(Name::new_symbol_root(sym::Self_)), + ); } } hir::Adt::Enum(e) => { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs index 2c6cbf6146a95..541ccf2d198e3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs @@ -7,7 +7,7 @@ //! there is no value in lifting these out into the outline module test since they will either not //! show up for normal completions, or they won't show completions other than lifetimes depending //! on the fixture input. -use hir::{known, ScopeDef}; +use hir::{sym, Name, ScopeDef}; use syntax::{ast, TokenText}; use crate::{ @@ -47,7 +47,7 @@ pub(crate) fn complete_lifetime( } }); if param_lifetime.is_none() { - acc.add_lifetime(ctx, known::STATIC_LIFETIME); + acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static)); } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs index 27e9d1d6cfe0c..5fe6cd0e90743 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs @@ -55,9 +55,8 @@ pub(crate) fn complete_use_path( if !ctx.check_stability(def.attrs(ctx.db).as_deref()) { continue; } - let is_name_already_imported = name - .as_text() - .map_or(false, |text| already_imported_names.contains(text.as_str())); + let is_name_already_imported = + already_imported_names.contains(name.as_str()); let add_resolution = match def { ScopeDef::Unknown if unknown_is_current(&name) => { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index a14fe24fa75d7..1e972b9b4ce06 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -823,13 +823,13 @@ fn classify_name_ref( for item in trait_.items_with_supertraits(sema.db) { match item { hir::AssocItem::TypeAlias(assoc_ty) => { - if assoc_ty.name(sema.db).as_str()? == arg_name { + if assoc_ty.name(sema.db).as_str() == arg_name { override_location = Some(TypeLocation::AssocTypeEq); return None; } }, hir::AssocItem::Const(const_) => { - if const_.name(sema.db)?.as_str()? == arg_name { + if const_.name(sema.db)?.as_str() == arg_name { override_location = Some(TypeLocation::AssocConstEq); return None; } @@ -867,7 +867,7 @@ fn classify_name_ref( let trait_items = trait_.items_with_supertraits(sema.db); let assoc_ty = trait_items.iter().find_map(|item| match item { hir::AssocItem::TypeAlias(assoc_ty) => { - (assoc_ty.name(sema.db).as_str()? == arg_name) + (assoc_ty.name(sema.db).as_str() == arg_name) .then_some(assoc_ty) }, _ => None, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index fe9e2e5268a99..15c20f11863b6 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -280,8 +280,7 @@ pub(crate) fn render_expr( let mut snippet_formatter = |ty: &hir::Type| { let arg_name = ty .as_adt() - .and_then(|adt| adt.name(ctx.db).as_text()) - .map(|s| stdx::to_lower_snake_case(s.as_str())) + .map(|adt| stdx::to_lower_snake_case(adt.name(ctx.db).as_str())) .unwrap_or_else(|| String::from("_")); let res = format!("${{{i}:{arg_name}}}"); i += 1; @@ -290,8 +289,7 @@ pub(crate) fn render_expr( let mut label_formatter = |ty: &hir::Type| { ty.as_adt() - .and_then(|adt| adt.name(ctx.db).as_text()) - .map(|s| stdx::to_lower_snake_case(s.as_str())) + .map(|adt| stdx::to_lower_snake_case(adt.name(ctx.db).as_str())) .unwrap_or_else(|| String::from("...")) }; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs index 48c9d624f63ac..c15e91c404839 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs @@ -188,7 +188,7 @@ fn compute_return_type_match( CompletionRelevanceReturnType::Constructor } else if ret_type .as_adt() - .and_then(|adt| adt.name(db).as_str().map(|name| name.ends_with("Builder"))) + .map(|adt| adt.name(db).as_str().ends_with("Builder")) .unwrap_or(false) { // fn([..]) -> [..]Builder @@ -227,11 +227,7 @@ pub(super) fn add_call_parens<'b>( None => { let name = match param.ty().as_adt() { None => "_".to_owned(), - Some(adt) => adt - .name(ctx.db) - .as_text() - .map(|s| to_lower_snake_case(s.as_str())) - .unwrap_or_else(|| "_".to_owned()), + Some(adt) => to_lower_snake_case(adt.name(ctx.db).as_str()), }; f(&format_args!("${{{}:{name}}}", index + offset)) } @@ -264,7 +260,7 @@ pub(super) fn add_call_parens<'b>( fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'static str { if let Some(derefed_ty) = ty.remove_ref() { for (name, local) in ctx.locals.iter() { - if name.as_text().as_deref() == Some(arg) { + if name.as_str() == arg { return if local.ty(ctx.db) == derefed_ty { if ty.is_mutable_reference() { "&mut " diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index a75a708d95692..dbb2adcd301f5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -144,7 +144,7 @@ impl Definition { Definition::Local(it) => it.name(db), Definition::GenericParam(it) => it.name(db), Definition::Label(it) => it.name(db), - Definition::BuiltinLifetime(StaticLifetime) => hir::known::STATIC_LIFETIME, + Definition::BuiltinLifetime(it) => it.name(), Definition::BuiltinAttr(_) => return None, // FIXME Definition::ToolModule(_) => return None, // FIXME Definition::DeriveHelper(it) => it.name(db), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs index 088717a66e590..4814394de6b29 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs @@ -389,16 +389,16 @@ fn import_for_item( let mut import_path_candidate_segments = import_path_candidate.segments().iter().rev(); let predicate = |it: EitherOrBoth<&SmolStr, &Name>| match it { // segments match, check next one - EitherOrBoth::Both(a, b) if b.as_str() == Some(&**a) => None, + EitherOrBoth::Both(a, b) if b.as_str() == &**a => None, // segments mismatch / qualifier is longer than the path, bail out EitherOrBoth::Both(..) | EitherOrBoth::Left(_) => Some(false), // all segments match and we have exhausted the qualifier, proceed EitherOrBoth::Right(_) => Some(true), }; if item_as_assoc.is_none() { - let item_name = item_name(db, original_item)?.as_text()?; + let item_name = item_name(db, original_item)?; let last_segment = import_path_candidate_segments.next()?; - if last_segment.as_str() != Some(&*item_name) { + if *last_segment != item_name { return None; } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index e21d54ccd0e5b..84a388a460b82 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -472,7 +472,7 @@ fn find_trait_for_assoc_item( }); for name in names { - if assoc_item_name.as_str() == name.as_text()?.as_str() { + if assoc_item_name.as_str() == name.as_str() { // It is fine to return the first match because in case of // multiple possibilities, the exact trait must be disambiguated // in the definition of trait being implemented, so this search diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 6a809cb0cefa8..4cdb279a21ca6 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -1,7 +1,7 @@ use either::Either; use hir::{ db::{ExpandDatabase, HirDatabase}, - known, AssocItem, HirDisplay, HirFileIdExt, ImportPathConfig, InFile, Type, + sym, AssocItem, HirDisplay, HirFileIdExt, ImportPathConfig, InFile, Type, }; use ide_db::{ assists::Assist, famous_defs::FamousDefs, imports::import_assets::item_for_path_search, @@ -210,7 +210,7 @@ fn get_default_constructor( let has_new_func = ty .iterate_assoc_items(ctx.sema.db, krate, |assoc_item| { if let AssocItem::Function(func) = assoc_item { - if func.name(ctx.sema.db) == known::new + if func.name(ctx.sema.db) == sym::new && func.assoc_fn_params(ctx.sema.db).is_empty() { return Some(()); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 41357b59622bf..46c373d8df081 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -76,7 +76,7 @@ fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option Some(alias), + hir::AssocItem::TypeAlias(alias) if alias.name(db) == sym::Item => Some(alias), _ => None, })?; if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs index 51855eeae232e..b60a80a8ac6b5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs @@ -46,7 +46,7 @@ pub(crate) fn hints( } let name = param.name(sema.db); - let param_name = name.as_str()?; + let param_name = name.as_str(); let should_hide = { let argument = get_string_representation(&arg)?; diff --git a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs index 99e2430860794..b27dc60ffafc7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs +++ b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs @@ -66,8 +66,11 @@ fn discover_tests_in_module( let mut r = vec![]; for c in module.children(db) { - let module_name = - c.name(db).as_ref().and_then(|n| n.as_str()).unwrap_or("[mod without name]").to_owned(); + let module_name = c + .name(db) + .as_ref() + .map(|n| n.as_str().to_owned()) + .unwrap_or_else(|| "[mod without name]".to_owned()); let module_id = format!("{prefix_id}::{module_name}"); let module_children = discover_tests_in_module(db, c, module_id.clone(), only_in_this_file); if !module_children.is_empty() { @@ -94,7 +97,7 @@ fn discover_tests_in_module( continue; } let nav = f.try_to_nav(db).map(|r| r.call_site); - let fn_name = f.name(db).as_str().unwrap_or("[function without name]").to_owned(); + let fn_name = f.name(db).as_str().to_owned(); r.push(TestItem { id: format!("{prefix_id}::{fn_name}"), kind: TestItemKind::Function, @@ -153,7 +156,7 @@ fn find_module_id_and_test_parents( let parent = Some(id.clone()); id += "::"; let module_name = &module.name(sema.db); - let module_name = module_name.as_ref().and_then(|n| n.as_str()).unwrap_or("[mod without name]"); + let module_name = module_name.as_ref().map(|n| n.as_str()).unwrap_or("[mod without name]"); id += module_name; let nav = NavigationTarget::from_module_to_decl(sema.db, module).call_site; r.push(TestItem { diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs index 826447d058dff..ad99c2162cd62 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs @@ -64,11 +64,7 @@ enum FieldOrTupleIdx { impl FieldOrTupleIdx { fn name(&self, db: &RootDatabase) -> String { match *self { - FieldOrTupleIdx::Field(f) => f - .name(db) - .as_str() - .map(|s| s.to_owned()) - .unwrap_or_else(|| format!(".{}", f.name(db).as_tuple_index().unwrap())), + FieldOrTupleIdx::Field(f) => f.name(db).as_str().to_owned(), FieldOrTupleIdx::TupleIdx(i) => format!(".{i}"), } } @@ -189,14 +185,7 @@ pub(crate) fn view_memory_layout( | Definition::SelfType(_) => "[ROOT]".to_owned(), // def is an item - def => def - .name(db) - .map(|n| { - n.as_str() - .map(|s| s.to_owned()) - .unwrap_or_else(|| format!(".{}", n.as_tuple_index().unwrap())) - }) - .unwrap_or("[ROOT]".to_owned()), + def => def.name(db).map(|n| n.as_str().to_owned()).unwrap_or("[ROOT]".to_owned()), }; let typename = ty.display(db).to_string(); diff --git a/src/tools/rust-analyzer/crates/intern/src/lib.rs b/src/tools/rust-analyzer/crates/intern/src/lib.rs index 868d03caff557..58327419f6314 100644 --- a/src/tools/rust-analyzer/crates/intern/src/lib.rs +++ b/src/tools/rust-analyzer/crates/intern/src/lib.rs @@ -21,7 +21,7 @@ type Guard = dashmap::RwLockWriteGuard< >; mod symbol; -pub use self::symbol::{symbols, Symbol}; +pub use self::symbol::{symbols as sym, Symbol}; pub struct Interned { arc: Arc, diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs index 290657a3d3627..1517f516fc15d 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -1,5 +1,5 @@ //! Attempt at flexible symbol interning, allowing to intern and free strings at runtime while also -//! supporting +//! supporting compile time declaration of symbols that will never be freed. use std::{ borrow::Borrow, diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index a1cf6e0941466..04bf4dff50c3e 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -11,10 +11,13 @@ use crate::{ Symbol, }; macro_rules! define_symbols { - ($($name:ident),* $(,)?) => { + (@WITH_NAME: $($alias:ident = $value:literal),* $(,)? @PLAIN: $($name:ident),* $(,)?) => { $( pub const $name: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&stringify!($name)) }; )* + $( + pub const $alias: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&$value) }; + )* pub(super) fn prefill() -> DashMap> { @@ -33,12 +36,45 @@ macro_rules! define_symbols { let shard_idx_ = dashmap_.determine_shard(hash_ as usize); dashmap_.shards_mut()[shard_idx_].get_mut().raw_entry_mut().from_hash(hash_, |k| k == &proxy_).insert(proxy_, SharedValue::new(())); )* + $( + + let proxy_ = SymbolProxy($alias.repr); + let hash_ = hash_thing_(dashmap_.hasher(), &proxy_); + let shard_idx_ = dashmap_.determine_shard(hash_ as usize); + dashmap_.shards_mut()[shard_idx_].get_mut().raw_entry_mut().from_hash(hash_, |k| k == &proxy_).insert(proxy_, SharedValue::new(())); + )* } dashmap_ } }; } define_symbols! { + @WITH_NAME: + + self_ = "self", + Self_ = "Self", + tick_static = "'static", + dollar_crate = "$crate", + MISSING_NAME = "[missing name]", + INTEGER_0 = "0", + INTEGER_1 = "1", + INTEGER_2 = "2", + INTEGER_3 = "3", + INTEGER_4 = "4", + INTEGER_5 = "5", + INTEGER_6 = "6", + INTEGER_7 = "7", + INTEGER_8 = "8", + INTEGER_9 = "9", + INTEGER_10 = "10", + INTEGER_11 = "11", + INTEGER_12 = "12", + INTEGER_13 = "13", + INTEGER_14 = "14", + INTEGER_15 = "15", + fn_ = "fn", + + @PLAIN: add_assign, add, alloc, @@ -52,10 +88,88 @@ define_symbols! { bitor, bitxor_assign, bitxor, + transmute_opts, + transmute_trait, + coerce_unsized, + dispatch_from_dyn,destruct, bool, + panic, + begin_panic, + panic_nounwind, + panic_fmt, + panic_misaligned_pointer_dereference, + panic_display, + const_panic_fmt, + panic_bounds_check, + panic_info, + panic_location, + panic_impl, + panic_cannot_unwind, + sized, + unsize, + format_alignment, + start, + format_argument, + format_arguments, + format_count, + format_placeholder, + format_unsafe_arg, + exchange_malloc, + box_free, + drop_in_place, + alloc_layout, + eh_personality, + eh_catch_typeinfo, + phantom_data, + manually_drop, + maybe_uninit, + align_offset, + termination, + tuple_trait, + slice_len_fn, + from_residual, + from_output, + from_yeet, + pointer_like, + const_param_ty, + Poll, + Ready, + Pending, + ResumeTy, + get_context, + Context, + Some, + Err, + Continue, + Break, + into_iter, + new_unchecked, + range_inclusive_new, + CStr, + fn_ptr_trait, + freeze, + coroutine_state, + c_void, + coroutine, + unpin, + pin, + fn_ptr_addr, + structural_teq, + fn_once_output, + copy, + clone, + sync, + discriminant_kind, Box, + structural_peq, boxed, branch, + discriminant_type, + pointee_trait, + metadata_type, + dyn_metadata, + deref_target, + receiver, call_mut, call_once, call, @@ -168,6 +282,7 @@ define_symbols! { not, Not, Ok, + opaque, ops, option_env, option, @@ -204,6 +319,9 @@ define_symbols! { rust_2018, rust_2021, rust_2024, + rustc_coherence_is_core, + rustc_macro_transparency, + semitransparent, shl_assign, shl, shr_assign, @@ -220,6 +338,7 @@ define_symbols! { test_case, test, trace_macros, + transparent, Try, u128, u16, From 292b9de2beaa5d9ccb0ef2beac1da2968f9f1b55 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 12 Jul 2024 17:11:12 +0200 Subject: [PATCH 004/147] Fix cloning Symbols not increasing their ref count --- .../rust-analyzer/crates/intern/src/symbol.rs | 90 +++++++++++++------ .../crates/intern/src/symbol/symbols.rs | 1 + 2 files changed, 63 insertions(+), 28 deletions(-) diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs index 1517f516fc15d..9f7a788d006c8 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -5,7 +5,7 @@ use std::{ borrow::Borrow, fmt, hash::{BuildHasherDefault, Hash, Hasher}, - mem, + mem::{self, ManuallyDrop}, ptr::NonNull, sync::OnceLock, }; @@ -25,6 +25,15 @@ const _: () = assert!(std::mem::align_of::>() == std::mem::align_of::<& const _: () = assert!(std::mem::size_of::>>() == std::mem::size_of::<&&str>()); const _: () = assert!(std::mem::align_of::>>() == std::mem::align_of::<&&str>()); +const _: () = + assert!(std::mem::size_of::<*const *const str>() == std::mem::size_of::()); +const _: () = + assert!(std::mem::align_of::<*const *const str>() == std::mem::align_of::()); + +const _: () = assert!(std::mem::size_of::>>() == std::mem::size_of::()); +const _: () = + assert!(std::mem::align_of::>>() == std::mem::align_of::()); + /// A pointer that points to a pointer to a `str`, it may be backed as a `&'static &'static str` or /// `Arc>` but its size is that of a thin pointer. The active variant is encoded as a tag /// in the LSB of the alignment niche. @@ -40,19 +49,24 @@ impl TaggedArcPtr { const BOOL_BITS: usize = true as usize; const fn non_arc(r: &'static &'static str) -> Self { - Self { - // SAFETY: The pointer is non-null as it is derived from a reference - // Ideally we would call out to `pack_arc` but for a `false` tag, unfortunately the - // packing stuff requires reading out the pointer to an integer which is not supported - // in const contexts, so here we make use of the fact that for the non-arc version the - // tag is false (0) and thus does not need touching the actual pointer value.ext) - packed: unsafe { - NonNull::new_unchecked((r as *const &str).cast::<*const str>().cast_mut()) - }, - } + assert!( + mem::align_of::<&'static &'static str>().trailing_zeros() as usize > Self::BOOL_BITS + ); + // SAFETY: The pointer is non-null as it is derived from a reference + // Ideally we would call out to `pack_arc` but for a `false` tag, unfortunately the + // packing stuff requires reading out the pointer to an integer which is not supported + // in const contexts, so here we make use of the fact that for the non-arc version the + // tag is false (0) and thus does not need touching the actual pointer value.ext) + + let packed = + unsafe { NonNull::new_unchecked((r as *const &str).cast::<*const str>().cast_mut()) }; + Self { packed } } fn arc(arc: Arc>) -> Self { + assert!( + mem::align_of::<&'static &'static str>().trailing_zeros() as usize > Self::BOOL_BITS + ); Self { packed: Self::pack_arc( // Safety: `Arc::into_raw` always returns a non null pointer @@ -63,12 +77,14 @@ impl TaggedArcPtr { /// Retrieves the tag. #[inline] - pub(crate) fn try_as_arc_owned(self) -> Option>> { + pub(crate) fn try_as_arc_owned(self) -> Option>>> { // Unpack the tag from the alignment niche let tag = Strict::addr(self.packed.as_ptr()) & Self::BOOL_BITS; if tag != 0 { // Safety: We checked that the tag is non-zero -> true, so we are pointing to the data offset of an `Arc` - Some(unsafe { Arc::from_raw(self.pointer().as_ptr().cast::>()) }) + Some(ManuallyDrop::new(unsafe { + Arc::from_raw(self.pointer().as_ptr().cast::>()) + })) } else { None } @@ -122,10 +138,11 @@ impl TaggedArcPtr { } } -#[derive(PartialEq, Eq, Hash, Clone, Debug)] +#[derive(PartialEq, Eq, Hash, Debug)] pub struct Symbol { repr: TaggedArcPtr, } + const _: () = assert!(std::mem::size_of::() == std::mem::size_of::>()); const _: () = assert!(std::mem::align_of::() == std::mem::align_of::>()); @@ -185,19 +202,27 @@ impl Symbol { fn drop_slow(arc: &Arc>) { let (mut shard, hash) = Self::select_shard(arc); - if Arc::count(arc) != 2 { - // Another thread has interned another copy - return; + match Arc::count(arc) { + 0 => unreachable!(), + 1 => unreachable!(), + 2 => (), + _ => { + // Another thread has interned another copy + return; + } } - match shard.raw_entry_mut().from_key_hashed_nocheck::(hash, arc.as_ref()) { - RawEntryMut::Occupied(occ) => occ.remove_entry(), - RawEntryMut::Vacant(_) => unreachable!(), - } - .0 - .0 - .try_as_arc_owned() - .unwrap(); + ManuallyDrop::into_inner( + match shard.raw_entry_mut().from_key_hashed_nocheck::(hash, arc.as_ref()) { + RawEntryMut::Occupied(occ) => occ.remove_entry(), + RawEntryMut::Vacant(_) => unreachable!(), + } + .0 + .0 + .try_as_arc_owned() + .unwrap(), + ); + debug_assert_eq!(Arc::count(&arc), 1); // Shrink the backing storage if the shard is less than 50% occupied. if shard.len() * 2 < shard.capacity() { @@ -219,7 +244,13 @@ impl Drop for Symbol { Self::drop_slow(&arc); } // decrement the ref count - drop(arc); + ManuallyDrop::into_inner(arc); + } +} + +impl Clone for Symbol { + fn clone(&self) -> Self { + Self { repr: increase_arc_refcount(self.repr) } } } @@ -228,8 +259,7 @@ fn increase_arc_refcount(repr: TaggedArcPtr) -> TaggedArcPtr { return repr; }; // increase the ref count - mem::forget(arc.clone()); - mem::forget(arc); + mem::forget(Arc::clone(&arc)); repr } @@ -265,6 +295,7 @@ mod tests { let base_len = MAP.get().unwrap().len(); let hello = Symbol::intern("hello"); let world = Symbol::intern("world"); + let more_worlds = world.clone(); let bang = Symbol::intern("!"); let q = Symbol::intern("?"); assert_eq!(MAP.get().unwrap().len(), base_len + 4); @@ -275,6 +306,7 @@ mod tests { drop(q); assert_eq!(MAP.get().unwrap().len(), base_len + 3); let default = Symbol::intern("default"); + let many_worlds = world.clone(); assert_eq!(MAP.get().unwrap().len(), base_len + 3); assert_eq!( "hello default world!", @@ -285,6 +317,8 @@ mod tests { "hello world!", format!("{} {}{}", hello.as_str(), world.as_str(), bang.as_str()) ); + drop(many_worlds); + drop(more_worlds); drop(hello); drop(world); drop(bang); diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 04bf4dff50c3e..af1af0536c2e5 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -10,6 +10,7 @@ use crate::{ symbol::{SymbolProxy, TaggedArcPtr}, Symbol, }; + macro_rules! define_symbols { (@WITH_NAME: $($alias:ident = $value:literal),* $(,)? @PLAIN: $($name:ident),* $(,)?) => { $( From 5a292c954195678125a20aa219c2d2b3b718c56f Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Sat, 13 Jul 2024 07:09:17 +0900 Subject: [PATCH 005/147] Allow macro expansions into `RestPat` in tuple args work as ellipsis like plain `RestPat` --- .../crates/hir-def/src/body/lower.rs | 44 ++++++++++-- .../src/handlers/mismatched_arg_count.rs | 69 +++++++++++++++++++ 2 files changed, 108 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index be7068c807a5f..08490470eb142 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -4,6 +4,7 @@ use std::mem; use base_db::CrateId; +use either::Either; use hir_expand::{ name::{name, AsName, Name}, ExpandError, InFile, @@ -1432,14 +1433,12 @@ impl ExprCollector<'_> { has_leading_comma: bool, binding_list: &mut BindingList, ) -> (Box<[PatId]>, Option) { + let args: Vec<_> = args.map(|p| self.collect_pat_possibly_rest(p, binding_list)).collect(); // Find the location of the `..`, if there is one. Note that we do not // consider the possibility of there being multiple `..` here. - let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_))); + let ellipsis = args.iter().position(|p| p.is_right()); // We want to skip the `..` pattern here, since we account for it above. - let mut args: Vec<_> = args - .filter(|p| !matches!(p, ast::Pat::RestPat(_))) - .map(|p| self.collect_pat(p, binding_list)) - .collect(); + let mut args: Vec<_> = args.into_iter().filter_map(Either::left).collect(); // if there is a leading comma, the user is most likely to type out a leading pattern // so we insert a missing pattern at the beginning for IDE features if has_leading_comma { @@ -1449,6 +1448,41 @@ impl ExprCollector<'_> { (args.into_boxed_slice(), ellipsis) } + // `collect_pat` rejects `ast::Pat::RestPat`, but it should be handled in some cases that + // it is the macro expansion result of an arg sub-pattern in a slice or tuple pattern. + fn collect_pat_possibly_rest( + &mut self, + pat: ast::Pat, + binding_list: &mut BindingList, + ) -> Either { + match &pat { + ast::Pat::RestPat(_) => Either::Right(()), + ast::Pat::MacroPat(mac) => match mac.macro_call() { + Some(call) => { + let macro_ptr = AstPtr::new(&call); + let src = self.expander.in_file(AstPtr::new(&pat)); + let pat = + self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| { + if let Some(expanded_pat) = expanded_pat { + this.collect_pat_possibly_rest(expanded_pat, binding_list) + } else { + Either::Left(this.missing_pat()) + } + }); + if let Some(pat) = pat.left() { + self.source_map.pat_map.insert(src, pat); + } + pat + } + None => { + let ptr = AstPtr::new(&pat); + Either::Left(self.alloc_pat(Pat::Missing, ptr)) + } + }, + _ => Either::Left(self.collect_pat(pat, binding_list)), + } + } + // endregion: patterns /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs index 41c762c85b2cd..4242422663796 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs @@ -256,6 +256,75 @@ impl Foo { ); } + #[test] + fn rest_pat_in_macro_expansion() { + check_diagnostics( + r#" +// issue #17292 +#![allow(dead_code)] + +macro_rules! replace_with_2_dots { + ( $( $input:tt )* ) => { + .. + }; +} + +macro_rules! enum_str { + ( + $( + $variant:ident ( + $( $tfield:ty ),* + ) + ) + , + * + ) => { + enum Foo { + $( + $variant ( $( $tfield ),* ), + )* + } + + impl Foo { + fn variant_name_as_str(&self) -> &str { + match self { + $( + Self::$variant ( replace_with_2_dots!( $( $tfield ),* ) ) + => "", + )* + } + } + } + }; +} + +enum_str! { + TupleVariant1(i32), + TupleVariant2(), + TupleVariant3(i8,u8,i128) +} +"#, + ); + + check_diagnostics( + r#" +#![allow(dead_code)] +macro_rules! two_dots1 { + () => { .. }; +} + +macro_rules! two_dots2 { + () => { two_dots1!() }; +} + +fn test() { + let (_, _, two_dots1!()) = ((), 42); + let (_, two_dots2!(), _) = (1, true, 2, false, (), (), 3); +} +"#, + ); + } + #[test] fn varargs() { check_diagnostics( From 377a0a7696bbd33c38ac418e8c75428a147eb688 Mon Sep 17 00:00:00 2001 From: bors Date: Thu, 11 Jul 2024 08:55:34 +0000 Subject: [PATCH 006/147] Trigger VSCode to rename after extract variable assist is applied When the user applies the "Extract Variable" assist, the cursor is positioned at the newly inserted variable. This commit adds a command to the assist that triggers the rename action in VSCode. This way, the user can quickly rename the variable after applying the assist. Fixes part of: #17579 --- .../crates/ide-assists/src/assist_context.rs | 6 +++--- .../src/handlers/extract_variable.rs | 3 +++ .../crates/ide-assists/src/tests.rs | 20 +++++++++++-------- .../crates/ide-db/src/assists.rs | 11 +++++++++- .../crates/ide-db/src/source_change.rs | 15 ++++++++++---- .../trait_impl_redundant_assoc_item.rs | 2 +- .../src/handlers/typed_hole.rs | 2 +- .../src/handlers/unresolved_field.rs | 8 ++++---- .../src/handlers/unresolved_method.rs | 4 ++-- .../src/handlers/unused_variables.rs | 2 +- .../crates/ide-diagnostics/src/lib.rs | 2 +- src/tools/rust-analyzer/crates/ide/src/ssr.rs | 10 +++++----- .../crates/rust-analyzer/src/config.rs | 2 ++ .../crates/rust-analyzer/src/lsp/to_proto.rs | 18 +++++++++++++++-- .../rust-analyzer/editors/code/src/client.ts | 1 + .../editors/code/src/commands.ts | 6 ++++++ .../rust-analyzer/editors/code/src/main.ts | 1 + 17 files changed, 80 insertions(+), 33 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs index 8c7670e0cb71a..c459cdb735af0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs @@ -185,11 +185,11 @@ impl Assists { return None; } - let mut trigger_signature_help = false; + let mut command = None; let source_change = if self.resolve.should_resolve(&id) { let mut builder = SourceChangeBuilder::new(self.file); f(&mut builder); - trigger_signature_help = builder.trigger_signature_help; + command = builder.command.take(); Some(builder.finish()) } else { None @@ -197,7 +197,7 @@ impl Assists { let label = Label::new(label); let group = group.cloned(); - self.buf.push(Assist { id, label, group, target, source_change, trigger_signature_help }); + self.buf.push(Assist { id, label, group, target, source_change, command }); Some(()) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index 36d3122651207..af21a839727a0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -135,6 +135,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op } } } + edit.rename(); } Anchor::Replace(stmt) => { cov_mark::hit!(test_extract_var_expr_stmt); @@ -149,6 +150,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op } } } + edit.rename(); } Anchor::WrapInBlock(to_wrap) => { let indent_to = to_wrap.indent_level(); @@ -192,6 +194,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op } } } + edit.rename(); // fixup indentation of block block.indent(indent_to); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs index 2dcfda334b806..29dac4c550002 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs @@ -454,7 +454,7 @@ pub fn test_some_range(a: int) -> bool { group: None, target: 59..60, source_change: None, - trigger_signature_help: false, + command: None, } "#]] .assert_debug_eq(&extract_into_variable_assist); @@ -470,7 +470,7 @@ pub fn test_some_range(a: int) -> bool { group: None, target: 59..60, source_change: None, - trigger_signature_help: false, + command: None, } "#]] .assert_debug_eq(&extract_into_function_assist); @@ -500,7 +500,7 @@ pub fn test_some_range(a: int) -> bool { group: None, target: 59..60, source_change: None, - trigger_signature_help: false, + command: None, } "#]] .assert_debug_eq(&extract_into_variable_assist); @@ -516,7 +516,7 @@ pub fn test_some_range(a: int) -> bool { group: None, target: 59..60, source_change: None, - trigger_signature_help: false, + command: None, } "#]] .assert_debug_eq(&extract_into_function_assist); @@ -587,7 +587,9 @@ pub fn test_some_range(a: int) -> bool { is_snippet: true, }, ), - trigger_signature_help: false, + command: Some( + Rename, + ), } "#]] .assert_debug_eq(&extract_into_variable_assist); @@ -603,7 +605,7 @@ pub fn test_some_range(a: int) -> bool { group: None, target: 59..60, source_change: None, - trigger_signature_help: false, + command: None, } "#]] .assert_debug_eq(&extract_into_function_assist); @@ -666,7 +668,9 @@ pub fn test_some_range(a: int) -> bool { is_snippet: true, }, ), - trigger_signature_help: false, + command: Some( + Rename, + ), } "#]] .assert_debug_eq(&extract_into_variable_assist); @@ -715,7 +719,7 @@ pub fn test_some_range(a: int) -> bool { is_snippet: true, }, ), - trigger_signature_help: false, + command: None, } "#]] .assert_debug_eq(&extract_into_function_assist); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs index 7a7328f312d20..0ddbde49abc4f 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs @@ -29,7 +29,16 @@ pub struct Assist { /// cumbersome, especially if you want to embed an assist into another data /// structure, such as a diagnostic. pub source_change: Option, - pub trigger_signature_help: bool, + /// The command to execute after the assist is applied. + pub command: Option, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Command { + /// Show the parameter hints popup. + TriggerSignatureHelp, + /// Rename the just inserted item. + Rename, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs index 7ef7b7ae1d0f8..fba377417e30a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs @@ -5,7 +5,7 @@ use std::{collections::hash_map::Entry, iter, mem}; -use crate::SnippetCap; +use crate::{assists::Command, SnippetCap}; use base_db::{AnchoredPathBuf, FileId}; use itertools::Itertools; use nohash_hasher::IntMap; @@ -194,7 +194,7 @@ pub struct SourceChangeBuilder { pub edit: TextEditBuilder, pub file_id: FileId, pub source_change: SourceChange, - pub trigger_signature_help: bool, + pub command: Option, /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin. pub mutated_tree: Option, @@ -236,7 +236,7 @@ impl SourceChangeBuilder { edit: TextEdit::builder(), file_id, source_change: SourceChange::default(), - trigger_signature_help: false, + command: None, mutated_tree: None, snippet_builder: None, } @@ -304,8 +304,15 @@ impl SourceChangeBuilder { let file_system_edit = FileSystemEdit::MoveFile { src, dst }; self.source_change.push_file_system_edit(file_system_edit); } + + /// Triggers the parameter hint popup after the assist is applied pub fn trigger_signature_help(&mut self) { - self.trigger_signature_help = true; + self.command = Some(Command::TriggerSignatureHelp); + } + + /// Renames the item at the cursor position after the assist is applied + pub fn rename(&mut self) { + self.command = Some(Command::Rename); } /// Adds a tabstop snippet to place the cursor before `node` diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs index a470ce72fc3e0..8c50960684dac 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs @@ -98,7 +98,7 @@ fn quickfix_for_redundant_assoc_item( group: None, target: range, source_change: Some(source_change_builder.finish()), - trigger_signature_help: false, + command: None, }]) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index 4f04267adb1ea..3fa38ed9eeeec 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -82,7 +82,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option original_range.file_id, TextEdit::replace(original_range.range, code), )), - trigger_signature_help: false, + command: None, }) .collect(); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 41357b59622bf..66733223e2734 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -130,7 +130,7 @@ fn add_variant_to_union( group: None, target: error_range.range, source_change: Some(src_change_builder.finish()), - trigger_signature_help: false, + command: None, }) } @@ -173,7 +173,7 @@ fn add_field_to_struct_fix( group: None, target: error_range.range, source_change: Some(src_change_builder.finish()), - trigger_signature_help: false, + command: None, }) } None => { @@ -204,7 +204,7 @@ fn add_field_to_struct_fix( group: None, target: error_range.range, source_change: Some(src_change_builder.finish()), - trigger_signature_help: false, + command: None, }) } Some(FieldList::TupleFieldList(_tuple)) => { @@ -266,7 +266,7 @@ fn method_fix( file_id, TextEdit::insert(range.end(), "()".to_owned()), )), - trigger_signature_help: false, + command: None, }) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 42211cdbe5d46..46722f43d4fbb 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -108,7 +108,7 @@ fn field_fix( (file_id, TextEdit::insert(range.start(), "(".to_owned())), (file_id, TextEdit::insert(range.end(), ")".to_owned())), ])), - trigger_signature_help: false, + command: None, }) } @@ -191,7 +191,7 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) - file_id, TextEdit::replace(range, assoc_func_call_expr_string), )), - trigger_signature_help: false, + command: None, }) } else { None diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs index fdd4e862cafcd..f3ce306885733 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs @@ -73,7 +73,7 @@ fn fixes( diagnostic_range.file_id, TextEdit::replace(name_range, format!("_{}", var_name.display(db))), )), - trigger_signature_help: false, + command: None, }]) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 6d1226d65c5cf..d30ee1a1b966f 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -613,7 +613,7 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { group: None, target, source_change: None, - trigger_signature_help: false, + command: None, } } diff --git a/src/tools/rust-analyzer/crates/ide/src/ssr.rs b/src/tools/rust-analyzer/crates/ide/src/ssr.rs index b49fe391bf258..6133c33c71a15 100644 --- a/src/tools/rust-analyzer/crates/ide/src/ssr.rs +++ b/src/tools/rust-analyzer/crates/ide/src/ssr.rs @@ -45,7 +45,7 @@ pub(crate) fn ssr_assists( group: Some(GroupLabel("Apply SSR".into())), target: comment_range, source_change, - trigger_signature_help: false, + command: None, }; ssr_assists.push(assist); @@ -143,7 +143,7 @@ mod tests { is_snippet: false, }, ), - trigger_signature_help: false, + command: None, } "#]] .assert_debug_eq(&apply_in_file_assist); @@ -196,7 +196,7 @@ mod tests { is_snippet: false, }, ), - trigger_signature_help: false, + command: None, } "#]] .assert_debug_eq(&apply_in_workspace_assist); @@ -236,7 +236,7 @@ mod tests { ), target: 10..21, source_change: None, - trigger_signature_help: false, + command: None, } "#]] .assert_debug_eq(&apply_in_file_assist); @@ -256,7 +256,7 @@ mod tests { ), target: 10..21, source_change: None, - trigger_signature_help: false, + command: None, } "#]] .assert_debug_eq(&apply_in_workspace_assist); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 3594cdda2e962..990ef77642c1b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -1135,6 +1135,7 @@ pub struct ClientCommandsConfig { pub show_reference: bool, pub goto_location: bool, pub trigger_parameter_hints: bool, + pub rename: bool, } #[derive(Debug)] @@ -1901,6 +1902,7 @@ impl Config { show_reference: get("rust-analyzer.showReferences"), goto_location: get("rust-analyzer.gotoLocation"), trigger_parameter_hints: get("editor.action.triggerParameterHints"), + rename: get("editor.action.rename"), } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index de394d3d11879..b0003fa89e3f2 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -13,7 +13,7 @@ use ide::{ NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp, SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize, }; -use ide_db::{rust_doc::format_docs, FxHasher}; +use ide_db::{assists, rust_doc::format_docs, FxHasher}; use itertools::Itertools; use paths::{Utf8Component, Utf8Prefix}; use semver::VersionReq; @@ -1336,8 +1336,14 @@ pub(crate) fn code_action( command: None, }; - if assist.trigger_signature_help && snap.config.client_commands().trigger_parameter_hints { + if assist.command == Some(assists::Command::TriggerSignatureHelp) + && snap.config.client_commands().trigger_parameter_hints + { res.command = Some(command::trigger_parameter_hints()); + } else if assist.command == Some(assists::Command::Rename) + && snap.config.client_commands().rename + { + res.command = Some(command::rename()); } match (assist.source_change, resolve_data) { @@ -1715,6 +1721,14 @@ pub(crate) mod command { arguments: None, } } + + pub(crate) fn rename() -> lsp_types::Command { + lsp_types::Command { + title: "rename".into(), + command: "rust-analyzer.rename".into(), + arguments: None, + } + } } pub(crate) fn implementation_title(count: usize) -> String { diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index 542233e7b9187..1599f4b13aea9 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -348,6 +348,7 @@ class ExperimentalFeatures implements lc.StaticFeature { "rust-analyzer.showReferences", "rust-analyzer.gotoLocation", "editor.action.triggerParameterHints", + "editor.action.rename", ], }, ...capabilities.experimental, diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts index 2b0b300106228..72ca2923dda1a 100644 --- a/src/tools/rust-analyzer/editors/code/src/commands.ts +++ b/src/tools/rust-analyzer/editors/code/src/commands.ts @@ -118,6 +118,12 @@ export function triggerParameterHints(_: CtxInit): Cmd { }; } +export function rename(_: CtxInit): Cmd { + return async () => { + await vscode.commands.executeCommand("editor.action.rename"); + }; +} + export function openLogs(ctx: CtxInit): Cmd { return async () => { if (ctx.client.outputChannel) { diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts index c96f2ae869e0c..a23f3656e3bff 100644 --- a/src/tools/rust-analyzer/editors/code/src/main.ts +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -190,6 +190,7 @@ function createCommands(): Record { runSingle: { enabled: commands.runSingle }, showReferences: { enabled: commands.showReferences }, triggerParameterHints: { enabled: commands.triggerParameterHints }, + rename: { enabled: commands.rename }, openLogs: { enabled: commands.openLogs }, revealDependency: { enabled: commands.revealDependency }, }; From 6351a2064261a8e1ec57d7dc8e1b1a1e6bf4e3fe Mon Sep 17 00:00:00 2001 From: Campbell Date: Sat, 13 Jul 2024 21:54:22 +1200 Subject: [PATCH 007/147] feat: Add incorrect case diagnostics for enum variant fields and all variables --- .../hir-ty/src/diagnostics/decl_check.rs | 93 +++++++++++-- .../src/handlers/incorrect_case.rs | 128 +++++++++++++++--- .../src/handlers/missing_match_arms.rs | 4 +- 3 files changed, 194 insertions(+), 31 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index 15ecf9aafcfc9..1e6cb85d3b0ca 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -17,8 +17,8 @@ use std::fmt; use hir_def::{ data::adt::VariantData, db::DefDatabase, hir::Pat, src::HasSource, AdtId, AttrDefId, ConstId, - EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, - TraitId, TypeAliasId, + EnumId, EnumVariantId, FunctionId, ItemContainerId, Lookup, ModuleDefId, ModuleId, StaticId, + StructId, TraitId, TypeAliasId, }; use hir_expand::{ name::{AsName, Name}, @@ -353,17 +353,16 @@ impl<'a> DeclValidator<'a> { continue; }; - let is_param = ast::Param::can_cast(parent.kind()); - // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement, - // because e.g. match arms are patterns as well. - // In other words, we check that it's a named variable binding. - let is_binding = ast::LetStmt::can_cast(parent.kind()) - || (ast::MatchArm::can_cast(parent.kind()) && ident_pat.at_token().is_some()); - if !(is_param || is_binding) { - // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm. + let is_shorthand = ast::RecordPatField::cast(parent.clone()) + .map(|parent| parent.name_ref().is_none()) + .unwrap_or_default(); + if is_shorthand { + // We don't check shorthand field patterns, such as 'field' in `Thing { field }`, + // since the shorthand isn't the declaration. continue; } + let is_param = ast::Param::can_cast(parent.kind()); let ident_type = if is_param { IdentType::Parameter } else { IdentType::Variable }; self.create_incorrect_case_diagnostic_for_ast_node( @@ -489,6 +488,11 @@ impl<'a> DeclValidator<'a> { /// Check incorrect names for enum variants. fn validate_enum_variants(&mut self, enum_id: EnumId) { let data = self.db.enum_data(enum_id); + + for (variant_id, _) in data.variants.iter() { + self.validate_enum_variant_fields(*variant_id); + } + let mut enum_variants_replacements = data .variants .iter() @@ -551,6 +555,75 @@ impl<'a> DeclValidator<'a> { } } + /// Check incorrect names for fields of enum variant. + fn validate_enum_variant_fields(&mut self, variant_id: EnumVariantId) { + let variant_data = self.db.enum_variant_data(variant_id); + let VariantData::Record(fields) = variant_data.variant_data.as_ref() else { + return; + }; + let mut variant_field_replacements = fields + .iter() + .filter_map(|(_, field)| { + to_lower_snake_case(&field.name.to_smol_str()).map(|new_name| Replacement { + current_name: field.name.clone(), + suggested_text: new_name, + expected_case: CaseType::LowerSnakeCase, + }) + }) + .peekable(); + + // XXX: only look at sources if we do have incorrect names + if variant_field_replacements.peek().is_none() { + return; + } + + let variant_loc = variant_id.lookup(self.db.upcast()); + let variant_src = variant_loc.source(self.db.upcast()); + + let Some(ast::FieldList::RecordFieldList(variant_fields_list)) = + variant_src.value.field_list() + else { + always!( + variant_field_replacements.peek().is_none(), + "Replacements ({:?}) were generated for an enum variant \ + which had no fields list: {:?}", + variant_field_replacements.collect::>(), + variant_src + ); + return; + }; + let mut variant_variants_iter = variant_fields_list.fields(); + for field_replacement in variant_field_replacements { + // We assume that parameters in replacement are in the same order as in the + // actual params list, but just some of them (ones that named correctly) are skipped. + let field = loop { + if let Some(field) = variant_variants_iter.next() { + let Some(field_name) = field.name() else { + continue; + }; + if field_name.as_name() == field_replacement.current_name { + break field; + } + } else { + never!( + "Replacement ({:?}) was generated for an enum variant field \ + which was not found: {:?}", + field_replacement, + variant_src + ); + return; + } + }; + + self.create_incorrect_case_diagnostic_for_ast_node( + field_replacement, + variant_src.file_id, + &field, + IdentType::Field, + ); + } + } + fn validate_const(&mut self, const_id: ConstId) { let container = const_id.lookup(self.db.upcast()).container; if self.is_trait_impl_container(container) { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs index a0fad7c850c6b..18a95f0963ddb 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -332,6 +332,7 @@ impl someStruct { check_diagnostics( r#" enum Option { Some, None } +use Option::{Some, None}; #[allow(unused)] fn main() { @@ -344,24 +345,6 @@ fn main() { ); } - #[test] - fn non_let_bind() { - check_diagnostics( - r#" -enum Option { Some, None } - -#[allow(unused)] -fn main() { - match Option::None { - SOME_VAR @ None => (), - // ^^^^^^^^ 💡 warn: Variable `SOME_VAR` should have snake_case name, e.g. `some_var` - Some => (), - } -} -"#, - ); - } - #[test] fn allow_attributes_crate_attr() { check_diagnostics( @@ -427,7 +410,12 @@ fn qualify() { #[test] // Issue #8809. fn parenthesized_parameter() { - check_diagnostics(r#"fn f((O): _) { _ = O; }"#) + check_diagnostics( + r#" +fn f((_O): u8) {} + // ^^ 💡 warn: Variable `_O` should have snake_case name, e.g. `_o` +"#, + ) } #[test] @@ -766,4 +754,106 @@ mod Foo; "#, ) } + + #[test] + fn test_field_shorthand() { + check_diagnostics( + r#" +struct Foo { _nonSnake: u8 } + // ^^^^^^^^^ 💡 warn: Field `_nonSnake` should have snake_case name, e.g. `_non_snake` +fn func(Foo { _nonSnake }: Foo) {} +"#, + ); + } + + #[test] + fn test_match() { + check_diagnostics( + r#" +enum Foo { Variant { nonSnake1: u8 } } + // ^^^^^^^^^ 💡 warn: Field `nonSnake1` should have snake_case name, e.g. `non_snake1` +fn func() { + match (Foo::Variant { nonSnake1: 1 }) { + Foo::Variant { nonSnake1: _nonSnake2 } => {}, + // ^^^^^^^^^^ 💡 warn: Variable `_nonSnake2` should have snake_case name, e.g. `_non_snake2` + } +} +"#, + ); + + check_diagnostics( + r#" +struct Foo(u8); + +fn func() { + match Foo(1) { + Foo(_nonSnake) => {}, + // ^^^^^^^^^ 💡 warn: Variable `_nonSnake` should have snake_case name, e.g. `_non_snake` + } +} +"#, + ); + + check_diagnostics( + r#" +fn main() { + match 1 { + _Bad1 @ _Bad2 => {} + // ^^^^^ 💡 warn: Variable `_Bad1` should have snake_case name, e.g. `_bad1` + // ^^^^^ 💡 warn: Variable `_Bad2` should have snake_case name, e.g. `_bad2` + } +} +"#, + ); + check_diagnostics( + r#" +fn main() { + match 1 { _Bad1 => () } + // ^^^^^ 💡 warn: Variable `_Bad1` should have snake_case name, e.g. `_bad1` +} +"#, + ); + + check_diagnostics( + r#" +enum Foo { V1, V2 } +use Foo::V1; + +fn main() { + match V1 { + _Bad1 @ V1 => {}, + // ^^^^^ 💡 warn: Variable `_Bad1` should have snake_case name, e.g. `_bad1` + Foo::V2 => {} + } +} +"#, + ); + } + + #[test] + fn test_for_loop() { + check_diagnostics( + r#" +//- minicore: iterators +fn func() { + for _nonSnake in [] {} + // ^^^^^^^^^ 💡 warn: Variable `_nonSnake` should have snake_case name, e.g. `_non_snake` +} +"#, + ); + + check_fix( + r#" +//- minicore: iterators +fn func() { + for nonSnake$0 in [] { nonSnake; } +} +"#, + r#" +fn func() { + for non_snake in [] { non_snake; } +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs index 6d0119fb57c6b..97296278c3a3a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs @@ -608,8 +608,8 @@ fn main() { // `Never` is deliberately not defined so that it's an uninferred type. // We ignore these to avoid triggering bugs in the analysis. match Option::::None { - None => (), - Some(never) => match never {}, + Option::None => (), + Option::Some(never) => match never {}, } match Option::::None { Option::Some(_never) => {}, From e03998bb639e8e22dd12d870d2fa059f9cb671e0 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Sat, 13 Jul 2024 19:33:35 -0700 Subject: [PATCH 008/147] Address feedback from @DropDemBits - move `edit.rename()` to the end of the function - use a match statement to set `res.command` --- .../src/handlers/extract_variable.rs | 4 +--- .../crates/rust-analyzer/src/config.rs | 2 +- .../crates/rust-analyzer/src/lsp/to_proto.rs | 17 ++++++++--------- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index af21a839727a0..cb34f8d81a33f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -135,7 +135,6 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op } } } - edit.rename(); } Anchor::Replace(stmt) => { cov_mark::hit!(test_extract_var_expr_stmt); @@ -150,7 +149,6 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op } } } - edit.rename(); } Anchor::WrapInBlock(to_wrap) => { let indent_to = to_wrap.indent_level(); @@ -194,12 +192,12 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op } } } - edit.rename(); // fixup indentation of block block.indent(indent_to); } } + edit.rename(); }, ) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 990ef77642c1b..91cde4dc0adbb 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -1128,7 +1128,7 @@ pub struct WorkspaceSymbolConfig { /// How many items are returned at most. pub search_limit: usize, } - +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ClientCommandsConfig { pub run_single: bool, pub debug_single: bool, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index b0003fa89e3f2..323926e435c9f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -1336,15 +1336,14 @@ pub(crate) fn code_action( command: None, }; - if assist.command == Some(assists::Command::TriggerSignatureHelp) - && snap.config.client_commands().trigger_parameter_hints - { - res.command = Some(command::trigger_parameter_hints()); - } else if assist.command == Some(assists::Command::Rename) - && snap.config.client_commands().rename - { - res.command = Some(command::rename()); - } + let commands = snap.config.client_commands(); + res.command = match assist.command { + Some(assists::Command::TriggerSignatureHelp) if commands.trigger_parameter_hints => { + Some(command::trigger_parameter_hints()) + } + Some(assists::Command::Rename) if commands.rename => Some(command::rename()), + _ => None, + }; match (assist.source_change, resolve_data) { (Some(it), _) => res.edit = Some(snippet_workspace_edit(snap, it)?), From b32fc1fcf6734ccbd0dab2a65b2d8969e7a178b7 Mon Sep 17 00:00:00 2001 From: Anita Hammer <166057949+anitahammer@users.noreply.github.com> Date: Sun, 14 Jul 2024 11:26:41 +0100 Subject: [PATCH 009/147] Update manual.adoc --- src/tools/rust-analyzer/docs/user/manual.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc index e1c1c54ec4185..a177720908748 100644 --- a/src/tools/rust-analyzer/docs/user/manual.adoc +++ b/src/tools/rust-analyzer/docs/user/manual.adoc @@ -623,7 +623,7 @@ https://github.com/rust-lang/rust-analyzer/tree/master/docs/dev[dev docs]! **Source:** https://github.com/rust-lang/rust-analyzer/blob/master/crates/rust-analyzer/src/config.rs[config.rs] -The <<_installation,Installation>> section contains details on configuration for some of the editors. +The <> section contains details on configuration for some of the editors. In general `rust-analyzer` is configured via LSP messages, which means that it's up to the editor to decide on the exact format and location of configuration files. Some clients, such as <> or <> provide `rust-analyzer` specific configuration UIs. Others may require you to know a bit more about the interaction with `rust-analyzer`. From 26fb6a8738f9f991078ad6eb59ee2a9f4f88c649 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 14 Jul 2024 12:19:19 +0200 Subject: [PATCH 010/147] Use statics + clone instead of const until const can access statics --- .../rust-analyzer/crates/hir-def/src/attr.rs | 10 +- .../crates/hir-def/src/body/lower.rs | 42 ++--- .../crates/hir-def/src/builtin_type.rs | 92 +++++----- .../rust-analyzer/crates/hir-def/src/data.rs | 2 +- .../rust-analyzer/crates/hir-def/src/db.rs | 4 +- .../crates/hir-def/src/find_path.rs | 20 +-- .../crates/hir-def/src/item_scope.rs | 2 +- .../crates/hir-def/src/item_tree/lower.rs | 9 +- .../crates/hir-def/src/lang_item.rs | 18 +- .../crates/hir-def/src/nameres/collector.rs | 36 ++-- .../crates/hir-def/src/path/lower.rs | 6 +- .../crates/hir-def/src/resolver.rs | 18 +- .../crates/hir-expand/src/attrs.rs | 77 +++++---- .../crates/hir-expand/src/builtin_fn_macro.rs | 12 +- .../crates/hir-expand/src/declarative.rs | 2 +- .../crates/hir-expand/src/inert_attr_macro.rs | 4 +- .../crates/hir-expand/src/mod_path.rs | 7 +- .../crates/hir-expand/src/name.rs | 17 +- .../crates/hir-ty/src/autoderef.rs | 5 +- .../crates/hir-ty/src/chalk_db.rs | 21 ++- .../crates/hir-ty/src/diagnostics/expr.rs | 4 +- .../crates/hir-ty/src/display.rs | 5 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 4 +- .../crates/hir-ty/src/infer/closure.rs | 2 +- .../crates/hir-ty/src/infer/expr.rs | 4 +- .../crates/hir-ty/src/infer/mutability.rs | 4 +- .../crates/hir-ty/src/infer/path.rs | 2 +- .../crates/hir-ty/src/infer/unify.rs | 2 +- .../crates/hir-ty/src/lang_items.rs | 62 ++++--- .../rust-analyzer/crates/hir-ty/src/lib.rs | 2 +- .../crates/hir-ty/src/mir/eval.rs | 12 +- .../crates/hir-ty/src/mir/eval/shim.rs | 4 +- .../crates/hir-ty/src/mir/lower/as_place.rs | 12 +- .../rust-analyzer/crates/hir-ty/src/traits.rs | 6 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 6 +- .../crates/hir/src/source_analyzer.rs | 19 ++- .../src/handlers/convert_bool_then.rs | 2 +- .../handlers/convert_iter_for_each_to_for.rs | 4 +- .../handlers/generate_is_empty_from_len.rs | 4 +- .../ide-assists/src/handlers/inline_call.rs | 2 +- .../crates/ide-completion/src/completions.rs | 3 +- .../ide-completion/src/completions/dot.rs | 6 +- .../ide-completion/src/completions/expr.rs | 4 +- .../src/completions/lifetime.rs | 2 +- .../src/handlers/missing_fields.rs | 2 +- .../crates/ide/src/inlay_hints.rs | 2 +- .../ide/src/syntax_highlighting/highlight.rs | 13 +- .../rust-analyzer/crates/intern/src/symbol.rs | 6 +- .../crates/intern/src/symbol/symbols.rs | 159 +++++++++--------- 49 files changed, 395 insertions(+), 368 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index a1ffb8c0a7596..aacfb07319819 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -9,7 +9,7 @@ use hir_expand::{ attrs::{collect_attrs, Attr, AttrId, RawAttrs}, HirFileId, InFile, }; -use intern::sym; +use intern::{sym, Symbol}; use la_arena::{ArenaMap, Idx, RawIdx}; use mbe::DelimiterKind; use syntax::{ @@ -153,7 +153,7 @@ impl Attrs { } pub fn lang_item(&self) -> Option { - self.by_key("lang").string_value().and_then(LangItem::from_str) + self.by_key("lang").string_value().and_then(|it| LangItem::from_symbol(&Symbol::intern(it))) } pub fn has_doc_hidden(&self) -> bool { @@ -200,7 +200,11 @@ impl Attrs { .segments() .iter() .rev() - .zip([sym::core, sym::prelude, sym::v1, sym::test].iter().rev()) + .zip( + [sym::core.clone(), sym::prelude.clone(), sym::v1.clone(), sym::test.clone()] + .iter() + .rev(), + ) .all(|it| it.0 == it.1) }) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index 83ba8f41931e2..b96745022a21a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -188,7 +188,7 @@ impl ExprCollector<'_> { let is_mutable = self_param.mut_token().is_some() && self_param.amp_token().is_none(); let binding_id: la_arena::Idx = self.alloc_binding( - Name::new_symbol_root(sym::self_), + Name::new_symbol_root(sym::self_.clone()), BindingAnnotation::new(is_mutable, false), ); self.body.self_param = Some(binding_id); @@ -1732,14 +1732,14 @@ impl ExprCollector<'_> { let Some(new_v1_formatted) = LangItem::FormatArguments.ty_rel_path( self.db, self.krate, - Name::new_symbol_root(sym::new_v1_formatted), + Name::new_symbol_root(sym::new_v1_formatted.clone()), ) else { return self.missing_expr(); }; let Some(unsafe_arg_new) = LangItem::FormatUnsafeArg.ty_rel_path( self.db, self.krate, - Name::new_symbol_root(sym::new), + Name::new_symbol_root(sym::new.clone()), ) else { return self.missing_expr(); }; @@ -1822,10 +1822,10 @@ impl ExprCollector<'_> { self.db, self.krate, match alignment { - Some(FormatAlignment::Left) => Name::new_symbol_root(sym::Left), - Some(FormatAlignment::Right) => Name::new_symbol_root(sym::Right), - Some(FormatAlignment::Center) => Name::new_symbol_root(sym::Center), - None => Name::new_symbol_root(sym::Unknown), + Some(FormatAlignment::Left) => Name::new_symbol_root(sym::Left.clone()), + Some(FormatAlignment::Right) => Name::new_symbol_root(sym::Right.clone()), + Some(FormatAlignment::Center) => Name::new_symbol_root(sym::Center.clone()), + None => Name::new_symbol_root(sym::Unknown.clone()), }, ); match align { @@ -1851,7 +1851,7 @@ impl ExprCollector<'_> { let format_placeholder_new = LangItem::FormatPlaceholder.ty_rel_path( self.db, self.krate, - Name::new_symbol_root(sym::new), + Name::new_symbol_root(sym::new.clone()), ); match format_placeholder_new { Some(path) => self.alloc_expr_desugared(Expr::Path(path)), @@ -1899,7 +1899,7 @@ impl ExprCollector<'_> { let count_is = match LangItem::FormatCount.ty_rel_path( self.db, self.krate, - Name::new_symbol_root(sym::Is), + Name::new_symbol_root(sym::Is.clone()), ) { Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)), None => self.missing_expr(), @@ -1921,7 +1921,7 @@ impl ExprCollector<'_> { let count_param = match LangItem::FormatCount.ty_rel_path( self.db, self.krate, - Name::new_symbol_root(sym::Param), + Name::new_symbol_root(sym::Param.clone()), ) { Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)), None => self.missing_expr(), @@ -1940,7 +1940,7 @@ impl ExprCollector<'_> { None => match LangItem::FormatCount.ty_rel_path( self.db, self.krate, - Name::new_symbol_root(sym::Implied), + Name::new_symbol_root(sym::Implied.clone()), ) { Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)), None => self.missing_expr(), @@ -1963,16 +1963,16 @@ impl ExprCollector<'_> { self.db, self.krate, Name::new_symbol_root(match ty { - Format(Display) => sym::new_display, - Format(Debug) => sym::new_debug, - Format(LowerExp) => sym::new_lower_exp, - Format(UpperExp) => sym::new_upper_exp, - Format(Octal) => sym::new_octal, - Format(Pointer) => sym::new_pointer, - Format(Binary) => sym::new_binary, - Format(LowerHex) => sym::new_lower_hex, - Format(UpperHex) => sym::new_upper_hex, - Usize => sym::from_usize, + Format(Display) => sym::new_display.clone(), + Format(Debug) => sym::new_debug.clone(), + Format(LowerExp) => sym::new_lower_exp.clone(), + Format(UpperExp) => sym::new_upper_exp.clone(), + Format(Octal) => sym::new_octal.clone(), + Format(Pointer) => sym::new_pointer.clone(), + Format(Binary) => sym::new_binary.clone(), + Format(LowerHex) => sym::new_lower_hex.clone(), + Format(UpperHex) => sym::new_upper_hex.clone(), + Usize => sym::from_usize.clone(), }), ) { Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs index 2243f514fe102..6dc1c4546e804 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs @@ -49,63 +49,67 @@ pub enum BuiltinType { impl BuiltinType { #[rustfmt::skip] - pub const ALL: &'static [(Name, BuiltinType)] = &[ - (Name::new_symbol_root(sym::char), BuiltinType::Char), - (Name::new_symbol_root(sym::bool), BuiltinType::Bool), - (Name::new_symbol_root(sym::str), BuiltinType::Str), - - (Name::new_symbol_root(sym::isize), BuiltinType::Int(BuiltinInt::Isize)), - (Name::new_symbol_root(sym::i8), BuiltinType::Int(BuiltinInt::I8)), - (Name::new_symbol_root(sym::i16), BuiltinType::Int(BuiltinInt::I16)), - (Name::new_symbol_root(sym::i32), BuiltinType::Int(BuiltinInt::I32)), - (Name::new_symbol_root(sym::i64), BuiltinType::Int(BuiltinInt::I64)), - (Name::new_symbol_root(sym::i128), BuiltinType::Int(BuiltinInt::I128)), - - (Name::new_symbol_root(sym::usize), BuiltinType::Uint(BuiltinUint::Usize)), - (Name::new_symbol_root(sym::u8), BuiltinType::Uint(BuiltinUint::U8)), - (Name::new_symbol_root(sym::u16), BuiltinType::Uint(BuiltinUint::U16)), - (Name::new_symbol_root(sym::u32), BuiltinType::Uint(BuiltinUint::U32)), - (Name::new_symbol_root(sym::u64), BuiltinType::Uint(BuiltinUint::U64)), - (Name::new_symbol_root(sym::u128), BuiltinType::Uint(BuiltinUint::U128)), - - (Name::new_symbol_root(sym::f16), BuiltinType::Float(BuiltinFloat::F16)), - (Name::new_symbol_root(sym::f32), BuiltinType::Float(BuiltinFloat::F32)), - (Name::new_symbol_root(sym::f64), BuiltinType::Float(BuiltinFloat::F64)), - (Name::new_symbol_root(sym::f128), BuiltinType::Float(BuiltinFloat::F128)), - ]; + pub fn all_builtin_types() -> [(Name, BuiltinType); 19] { + [ + (Name::new_symbol_root(sym::char.clone()), BuiltinType::Char), + (Name::new_symbol_root(sym::bool.clone()), BuiltinType::Bool), + (Name::new_symbol_root(sym::str.clone()), BuiltinType::Str), + + (Name::new_symbol_root(sym::isize.clone()), BuiltinType::Int(BuiltinInt::Isize)), + (Name::new_symbol_root(sym::i8.clone()), BuiltinType::Int(BuiltinInt::I8)), + (Name::new_symbol_root(sym::i16.clone()), BuiltinType::Int(BuiltinInt::I16)), + (Name::new_symbol_root(sym::i32.clone()), BuiltinType::Int(BuiltinInt::I32)), + (Name::new_symbol_root(sym::i64.clone()), BuiltinType::Int(BuiltinInt::I64)), + (Name::new_symbol_root(sym::i128.clone()), BuiltinType::Int(BuiltinInt::I128)), + + (Name::new_symbol_root(sym::usize.clone()), BuiltinType::Uint(BuiltinUint::Usize)), + (Name::new_symbol_root(sym::u8.clone()), BuiltinType::Uint(BuiltinUint::U8)), + (Name::new_symbol_root(sym::u16.clone()), BuiltinType::Uint(BuiltinUint::U16)), + (Name::new_symbol_root(sym::u32.clone()), BuiltinType::Uint(BuiltinUint::U32)), + (Name::new_symbol_root(sym::u64.clone()), BuiltinType::Uint(BuiltinUint::U64)), + (Name::new_symbol_root(sym::u128.clone()), BuiltinType::Uint(BuiltinUint::U128)), + + (Name::new_symbol_root(sym::f16.clone()), BuiltinType::Float(BuiltinFloat::F16)), + (Name::new_symbol_root(sym::f32.clone()), BuiltinType::Float(BuiltinFloat::F32)), + (Name::new_symbol_root(sym::f64.clone()), BuiltinType::Float(BuiltinFloat::F64)), + (Name::new_symbol_root(sym::f128.clone()), BuiltinType::Float(BuiltinFloat::F128)), + ] + } pub fn by_name(name: &Name) -> Option { - Self::ALL.iter().find_map(|(n, ty)| if n == name { Some(*ty) } else { None }) + Self::all_builtin_types() + .iter() + .find_map(|(n, ty)| if n == name { Some(*ty) } else { None }) } } impl AsName for BuiltinType { fn as_name(&self) -> Name { match self { - BuiltinType::Char => Name::new_symbol_root(sym::char), - BuiltinType::Bool => Name::new_symbol_root(sym::bool), - BuiltinType::Str => Name::new_symbol_root(sym::str), + BuiltinType::Char => Name::new_symbol_root(sym::char.clone()), + BuiltinType::Bool => Name::new_symbol_root(sym::bool.clone()), + BuiltinType::Str => Name::new_symbol_root(sym::str.clone()), BuiltinType::Int(it) => match it { - BuiltinInt::Isize => Name::new_symbol_root(sym::isize), - BuiltinInt::I8 => Name::new_symbol_root(sym::i8), - BuiltinInt::I16 => Name::new_symbol_root(sym::i16), - BuiltinInt::I32 => Name::new_symbol_root(sym::i32), - BuiltinInt::I64 => Name::new_symbol_root(sym::i64), - BuiltinInt::I128 => Name::new_symbol_root(sym::i128), + BuiltinInt::Isize => Name::new_symbol_root(sym::isize.clone()), + BuiltinInt::I8 => Name::new_symbol_root(sym::i8.clone()), + BuiltinInt::I16 => Name::new_symbol_root(sym::i16.clone()), + BuiltinInt::I32 => Name::new_symbol_root(sym::i32.clone()), + BuiltinInt::I64 => Name::new_symbol_root(sym::i64.clone()), + BuiltinInt::I128 => Name::new_symbol_root(sym::i128.clone()), }, BuiltinType::Uint(it) => match it { - BuiltinUint::Usize => Name::new_symbol_root(sym::usize), - BuiltinUint::U8 => Name::new_symbol_root(sym::u8), - BuiltinUint::U16 => Name::new_symbol_root(sym::u16), - BuiltinUint::U32 => Name::new_symbol_root(sym::u32), - BuiltinUint::U64 => Name::new_symbol_root(sym::u64), - BuiltinUint::U128 => Name::new_symbol_root(sym::u128), + BuiltinUint::Usize => Name::new_symbol_root(sym::usize.clone()), + BuiltinUint::U8 => Name::new_symbol_root(sym::u8.clone()), + BuiltinUint::U16 => Name::new_symbol_root(sym::u16.clone()), + BuiltinUint::U32 => Name::new_symbol_root(sym::u32.clone()), + BuiltinUint::U64 => Name::new_symbol_root(sym::u64.clone()), + BuiltinUint::U128 => Name::new_symbol_root(sym::u128.clone()), }, BuiltinType::Float(it) => match it { - BuiltinFloat::F16 => Name::new_symbol_root(sym::f16), - BuiltinFloat::F32 => Name::new_symbol_root(sym::f32), - BuiltinFloat::F64 => Name::new_symbol_root(sym::f64), - BuiltinFloat::F128 => Name::new_symbol_root(sym::f128), + BuiltinFloat::F16 => Name::new_symbol_root(sym::f16.clone()), + BuiltinFloat::F32 => Name::new_symbol_root(sym::f32.clone()), + BuiltinFloat::F64 => Name::new_symbol_root(sym::f64.clone()), + BuiltinFloat::F128 => Name::new_symbol_root(sym::f128.clone()), }, } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index f60a433c4dafe..964a5f04bfd22 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -485,7 +485,7 @@ impl ExternCrateDeclData { let name = extern_crate.name.clone(); let krate = loc.container.krate(); - let crate_id = if name == sym::self_ { + let crate_id = if name == sym::self_.clone() { Some(krate) } else { db.crate_def_map(krate) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 0a14904f0bceb..eac8f0dd74ac8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -262,8 +262,8 @@ fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: CrateId) -> bool { let attrs = item_tree.raw_attrs(AttrOwner::TopLevel); for attr in &**attrs { match attr.path().as_ident() { - Some(ident) if *ident == sym::no_std => return true, - Some(ident) if *ident == sym::cfg_attr => {} + Some(ident) if *ident == sym::no_std.clone() => return true, + Some(ident) if *ident == sym::cfg_attr.clone() => {} _ => continue, } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index e32add93c5526..a3a602c2c117b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -415,13 +415,13 @@ fn select_best_path( (Unstable, Stable) => return new_path, _ => {} } - const STD_CRATES: [Symbol; 3] = [sym::std, sym::core, sym::alloc]; + let std_crates: [Symbol; 3] = [sym::std.clone(), sym::core.clone(), sym::alloc.clone()]; let choose = |new: (ModPath, _), old: (ModPath, _)| { let (new_path, _) = &new; let (old_path, _) = &old; - let new_has_prelude = new_path.segments().iter().any(|seg| *seg == sym::prelude); - let old_has_prelude = old_path.segments().iter().any(|seg| *seg == sym::prelude); + let new_has_prelude = new_path.segments().iter().any(|seg| *seg == sym::prelude.clone()); + let old_has_prelude = old_path.segments().iter().any(|seg| *seg == sym::prelude.clone()); match (new_has_prelude, old_has_prelude, cfg.prefer_prelude) { (true, false, true) | (false, true, false) => new, (true, false, false) | (false, true, true) => old, @@ -443,19 +443,19 @@ fn select_best_path( match (old_path.0.segments().first(), new_path.0.segments().first()) { (Some(old), Some(new)) - if STD_CRATES.contains(old.symbol()) && STD_CRATES.contains(new.symbol()) => + if std_crates.contains(old.symbol()) && std_crates.contains(new.symbol()) => { let rank = match cfg.prefer_no_std { false => |name: &Name| match name { - name if *name == sym::core => 0, - name if *name == sym::alloc => 1, - name if *name == sym::std => 2, + name if *name == sym::core.clone() => 0, + name if *name == sym::alloc.clone() => 1, + name if *name == sym::std.clone() => 2, _ => unreachable!(), }, true => |name: &Name| match name { - name if *name == sym::core => 2, - name if *name == sym::alloc => 1, - name if *name == sym::std => 0, + name if *name == sym::core.clone() => 2, + name if *name == sym::alloc.clone() => 1, + name if *name == sym::std.clone() => 0, _ => unreachable!(), }, }; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index d86c0667a0bb7..092c0a1dfdf81 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -119,7 +119,7 @@ struct DeriveMacroInvocation { } pub(crate) static BUILTIN_SCOPE: Lazy> = Lazy::new(|| { - BuiltinType::ALL + BuiltinType::all_builtin_types() .iter() .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public, None))) .collect() diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 496686b4f943c..5c80da93048c7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -324,7 +324,8 @@ impl<'a> Ctx<'a> { let self_type = match self_param.ty() { Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), None => { - let self_type = TypeRef::Path(Name::new_symbol_root(sym::Self_).into()); + let self_type = + TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into()); match self_param.kind() { ast::SelfParamKind::Owned => self_type, ast::SelfParamKind::Ref => TypeRef::Reference( @@ -670,7 +671,7 @@ impl<'a> Ctx<'a> { // Traits and trait aliases get the Self type as an implicit first type parameter. generics.type_or_consts.alloc( TypeParamData { - name: Some(Name::new_symbol_root(sym::Self_)), + name: Some(Name::new_symbol_root(sym::Self_.clone())), default: None, provenance: TypeParamProvenance::TraitSelf, } @@ -681,7 +682,7 @@ impl<'a> Ctx<'a> { generics.fill_bounds( &self.body_ctx, bounds, - Either::Left(TypeRef::Path(Name::new_symbol_root(sym::Self_).into())), + Either::Left(TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into())), ); } @@ -746,7 +747,7 @@ fn desugar_future_path(orig: TypeRef) -> Path { let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments().len() - 1).collect(); let binding = AssociatedTypeBinding { - name: Name::new_symbol_root(sym::Output), + name: Name::new_symbol_root(sym::Output.clone()), args: None, type_ref: Some(orig), bounds: Box::default(), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 4d17650285f40..07b27659ab3dd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -192,8 +192,7 @@ impl LangItems { } pub(crate) fn lang_attr(db: &dyn DefDatabase, item: AttrDefId) -> Option { - let attrs = db.attrs(item); - attrs.by_key("lang").string_value().and_then(LangItem::from_str) + db.attrs(item).lang_item() } pub(crate) fn notable_traits_in_deps( @@ -261,18 +260,9 @@ macro_rules! language_item_table { } /// Opposite of [`LangItem::name`] - #[allow(clippy::should_implement_trait)] - pub fn from_str(name: &str) -> Option { - match name { - $( stringify!($name) => Some(LangItem::$variant), )* - _ => None, - } - } - - /// Opposite of [`LangItem::name`] - pub fn from_symbol(sym: Symbol) -> Option { + pub fn from_symbol(sym: &Symbol) -> Option { match sym { - $(sym if sym == $module::$name => Some(LangItem::$variant), )* + $(sym if *sym == $module::$name => Some(LangItem::$variant), )* _ => None, } } @@ -283,7 +273,7 @@ macro_rules! language_item_table { impl LangItem { /// Opposite of [`LangItem::name`] pub fn from_name(name: &hir_expand::name::Name) -> Option { - Self::from_str(name.as_str()) + Self::from_symbol(name.symbol()) } pub fn path(&self, db: &dyn DefDatabase, start_crate: CrateId) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 30d4a79a808d9..f14679f6c2f14 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -294,24 +294,24 @@ impl DefCollector<'_> { let Some(attr_name) = attr.path.as_ident() else { continue }; match () { - () if *attr_name == sym::recursion_limit => { + () if *attr_name == sym::recursion_limit.clone() => { if let Some(limit) = attr.string_value() { if let Ok(limit) = limit.parse() { crate_data.recursion_limit = Some(limit); } } } - () if *attr_name == sym::crate_type => { + () if *attr_name == sym::crate_type.clone() => { if let Some("proc-macro") = attr.string_value() { self.is_proc_macro = true; } } - () if *attr_name == sym::no_core => crate_data.no_core = true, - () if *attr_name == sym::no_std => crate_data.no_std = true, - () if *attr_name == sym::rustc_coherence_is_core => { + () if *attr_name == sym::no_core.clone() => crate_data.no_core = true, + () if *attr_name == sym::no_std.clone() => crate_data.no_std = true, + () if *attr_name == sym::rustc_coherence_is_core.clone() => { crate_data.rustc_coherence_is_core = true; } - () if *attr_name == sym::feature => { + () if *attr_name == sym::feature.clone() => { let features = attr .parse_path_comma_token_tree(self.db.upcast()) .into_iter() @@ -322,13 +322,13 @@ impl DefCollector<'_> { }); crate_data.unstable_features.extend(features); } - () if *attr_name == sym::register_attr => { + () if *attr_name == sym::register_attr.clone() => { if let Some(ident) = attr.single_ident_value() { crate_data.registered_attrs.push(ident.text.clone()); cov_mark::hit!(register_attr); } } - () if *attr_name == sym::register_tool => { + () if *attr_name == sym::register_tool.clone() => { if let Some(ident) = attr.single_ident_value() { crate_data.registered_tools.push(ident.text.clone()); cov_mark::hit!(register_tool); @@ -538,20 +538,20 @@ impl DefCollector<'_> { } let krate = if self.def_map.data.no_std { - Name::new_symbol_root(sym::core) - } else if self.def_map.extern_prelude().any(|(name, _)| *name == sym::std) { - Name::new_symbol_root(sym::std) + Name::new_symbol_root(sym::core.clone()) + } else if self.def_map.extern_prelude().any(|(name, _)| *name == sym::std.clone()) { + Name::new_symbol_root(sym::std.clone()) } else { // If `std` does not exist for some reason, fall back to core. This mostly helps // keep r-a's own tests minimal. - Name::new_symbol_root(sym::core) + Name::new_symbol_root(sym::core.clone()) }; let edition = match self.def_map.data.edition { - Edition::Edition2015 => Name::new_symbol_root(sym::rust_2015), - Edition::Edition2018 => Name::new_symbol_root(sym::rust_2018), - Edition::Edition2021 => Name::new_symbol_root(sym::rust_2021), - Edition::Edition2024 => Name::new_symbol_root(sym::rust_2024), + Edition::Edition2015 => Name::new_symbol_root(sym::rust_2015.clone()), + Edition::Edition2018 => Name::new_symbol_root(sym::rust_2018.clone()), + Edition::Edition2021 => Name::new_symbol_root(sym::rust_2021.clone()), + Edition::Edition2024 => Name::new_symbol_root(sym::rust_2024.clone()), }; let path_kind = match self.def_map.data.edition { @@ -560,7 +560,7 @@ impl DefCollector<'_> { }; let path = ModPath::from_segments( path_kind, - [krate, Name::new_symbol_root(sym::prelude), edition], + [krate, Name::new_symbol_root(sym::prelude.clone()), edition], ); let (per_ns, _) = @@ -844,7 +844,7 @@ impl DefCollector<'_> { } fn resolve_extern_crate(&self, name: &Name) -> Option { - if *name == sym::self_ { + if *name == sym::self_.clone() { cov_mark::hit!(extern_crate_self_as); Some(self.def_map.crate_root()) } else { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index 22397df961066..7c39773aa6874 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -60,7 +60,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option { - segments.push(Name::new_symbol_root(sym::Self_)); + segments.push(Name::new_symbol_root(sym::Self_.clone())); } ast::PathSegmentKind::Type { type_ref, trait_ref } => { assert!(path.qualifier().is_none()); // this can only occur at the first segment @@ -268,7 +268,7 @@ fn lower_generic_args_from_fn_path( let bindings = if let Some(ret_type) = ret_type { let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty()); Box::new([AssociatedTypeBinding { - name: Name::new_symbol_root(sym::Output), + name: Name::new_symbol_root(sym::Output.clone()), args: None, type_ref: Some(type_ref), bounds: Box::default(), @@ -277,7 +277,7 @@ fn lower_generic_args_from_fn_path( // -> () let type_ref = TypeRef::Tuple(Vec::new()); Box::new([AssociatedTypeBinding { - name: Name::new_symbol_root(sym::Output), + name: Name::new_symbol_root(sym::Output.clone()), args: None, type_ref: Some(type_ref), bounds: Box::default(), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 4931418546603..c196f00281639 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -194,12 +194,12 @@ impl Resolver { } } &Scope::ImplDefScope(impl_) => { - if *first_name == sym::Self_ { + if *first_name == sym::Self_.clone() { return Some((TypeNs::SelfType(impl_), remaining_idx(), None)); } } &Scope::AdtScope(adt) => { - if *first_name == sym::Self_ { + if *first_name == sym::Self_.clone() { return Some((TypeNs::AdtSelfType(adt), remaining_idx(), None)); } } @@ -291,7 +291,7 @@ impl Resolver { } }; let n_segments = path.segments().len(); - let tmp = Name::new_symbol_root(sym::Self_); + let tmp = Name::new_symbol_root(sym::self_.clone()); let first_name = if path.is_self() { &tmp } else { path.segments().first()? }; let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); if skip_to_mod { @@ -322,7 +322,7 @@ impl Resolver { } } &Scope::ImplDefScope(impl_) => { - if *first_name == sym::Self_ { + if *first_name == sym::Self_.clone() { return Some(ResolveValueResult::ValueNs( ValueNs::ImplSelf(impl_), None, @@ -349,7 +349,7 @@ impl Resolver { } } &Scope::ImplDefScope(impl_) => { - if *first_name == sym::Self_ { + if *first_name == sym::Self_.clone() { return Some(ResolveValueResult::Partial( TypeNs::SelfType(impl_), 1, @@ -358,7 +358,7 @@ impl Resolver { } } Scope::AdtScope(adt) => { - if *first_name == sym::Self_ { + if *first_name == sym::Self_.clone() { let ty = TypeNs::AdtSelfType(*adt); return Some(ResolveValueResult::Partial(ty, 1, None)); } @@ -422,7 +422,7 @@ impl Resolver { } pub fn resolve_lifetime(&self, lifetime: &LifetimeRef) -> Option { - if lifetime.name == sym::tick_static { + if lifetime.name == sym::tick_static.clone() { return Some(LifetimeNs::Static); } @@ -778,10 +778,10 @@ impl Scope { } } Scope::ImplDefScope(i) => { - acc.add(&Name::new_symbol_root(sym::Self_), ScopeDef::ImplSelfType(*i)); + acc.add(&Name::new_symbol_root(sym::Self_.clone()), ScopeDef::ImplSelfType(*i)); } Scope::AdtScope(i) => { - acc.add(&Name::new_symbol_root(sym::Self_), ScopeDef::AdtSelfType(*i)); + acc.add(&Name::new_symbol_root(sym::Self_.clone()), ScopeDef::AdtSelfType(*i)); } Scope::ExprScope(scope) => { if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 6afa7a40f123f..36636a228f147 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -59,7 +59,10 @@ impl RawAttrs { text: SmolStr::new(format_smolstr!("\"{}\"", Self::escape_chars(doc))), span, }))), - path: Interned::new(ModPath::from(Name::new_symbol(sym::doc, span.ctx))), + path: Interned::new(ModPath::from(Name::new_symbol( + sym::doc.clone(), + span.ctx, + ))), ctxt: span.ctx, } }), @@ -116,47 +119,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 == sym::cfg_attr)); + .any(|attr| attr.path.as_ident().map_or(false, |name| *name == sym::cfg_attr.clone())); 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 == 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 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.clone()); + if !is_cfg_attr { + 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_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::>(); + 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_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::>(); let entries = if new_attrs.is_empty() { None } else { @@ -384,7 +387,7 @@ impl Attr { } pub fn cfg(&self) -> Option { - if *self.path.as_ident()? == sym::cfg { + if *self.path.as_ident()? == sym::cfg.clone() { self.token_tree_value().map(CfgExpr::parse) } else { None diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index e5de5975a2d8b..97867dfc66e92 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -367,7 +367,11 @@ 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) { sym::panic_2021 } else { sym::panic_2015 }; + let mac = if use_panic_2021(db, call_site_span) { + sym::panic_2021.clone() + } else { + sym::panic_2015.clone() + }; // Expand to a macro call `$crate::panic::panic_{edition}` let mut call = quote!(call_site_span =>#dollar_crate::panic::#mac!); @@ -396,9 +400,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) { - sym::unreachable_2021 + sym::unreachable_2021.clone() } else { - sym::unreachable_2015 + sym::unreachable_2015.clone() }; // Expand to a macro call `$crate::panic::panic_{edition}` @@ -431,7 +435,7 @@ fn use_panic_2021(db: &dyn ExpandDatabase, span: Span) -> bool { // FIXME: Record allow_internal_unstable in the macro def (not been done yet because it // would consume quite a bit extra memory for all call locs...) // if let Some(features) = expn.def.allow_internal_unstable { - // if features.iter().any(|&f| f == sym::edition_panic) { + // if features.iter().any(|&f| f == sym::edition_panic.clone()) { // span = expn.call_site; // continue; // } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs index b920d2127abe8..2e7865ed3bf8c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs @@ -114,7 +114,7 @@ impl DeclarativeMacroExpander { .find(|it| { it.path .as_ident() - .map(|it| *it == sym::rustc_macro_transparency) + .map(|it| *it == sym::rustc_macro_transparency.clone()) .unwrap_or(false) })? .token_tree_value()? diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs index 7ead7e9390152..0c112554e1f43 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs @@ -553,7 +553,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ ), BuiltinAttribute { - // name: sym::rustc_diagnostic_item, + // name: sym::rustc_diagnostic_item.clone(), name: "rustc_diagnostic_item", // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. // only_local: false, @@ -562,7 +562,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ // duplicates: ErrorFollowing, // gate: Gated( // Stability::Unstable, - // sym::rustc_attrs, + // sym::rustc_attrs.clone(), // "diagnostic items compiler internal support for linting", // cfg_fn!(rustc_attrs), // ), diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 7ff8b797fa4a6..ed7d551888756 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -120,7 +120,8 @@ impl ModPath { #[allow(non_snake_case)] pub fn is_Self(&self) -> bool { - self.kind == PathKind::Plain && matches!(&*self.segments, [name] if *name == sym::Self_) + self.kind == PathKind::Plain + && matches!(&*self.segments, [name] if *name == sym::Self_.clone()) } /// If this path is a single identifier, like `foo`, return its name. @@ -264,7 +265,7 @@ fn convert_path( } ast::PathSegmentKind::SelfTypeKw => ModPath::from_segments( PathKind::Plain, - Some(Name::new_symbol(sym::Self_, SyntaxContextId::ROOT)), + Some(Name::new_symbol(sym::Self_.clone(), SyntaxContextId::ROOT)), ), ast::PathSegmentKind::CrateKw => ModPath::from_segments(PathKind::Crate, iter::empty()), ast::PathSegmentKind::SelfKw => handle_super_kw(0)?, @@ -396,7 +397,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::name::Name::new_symbol_root(intern::sym::$start), $($crate::name::Name::new_symbol_root(intern::sym::$seg),)* + $crate::name::Name::new_symbol_root(intern::sym::$start.clone()), $($crate::name::Name::new_symbol_root(intern::sym::$seg.clone()),)* ]) }); } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index da0adbef16342..67e73f7fc284c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -2,7 +2,7 @@ use std::fmt; -use intern::{sym::MISSING_NAME, Symbol}; +use intern::{sym, Symbol}; use span::SyntaxContextId; use syntax::{ast, format_smolstr, utils::is_raw_identifier, SmolStr}; @@ -13,12 +13,21 @@ 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)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct Name { symbol: Symbol, ctx: (), } +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() + } +} + impl Ord for Name { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.symbol.as_str().cmp(other.symbol.as_str()) @@ -116,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 { symbol: MISSING_NAME, ctx: () } + 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 diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index 736379a3d8730..ecfc1ff99e9ea 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -152,8 +152,9 @@ pub(crate) fn deref_by_trait( let deref_trait = db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?; - let target = - db.trait_data(deref_trait).associated_type_by_name(&Name::new_symbol_root(sym::Target))?; + let target = db + .trait_data(deref_trait) + .associated_type_by_name(&Name::new_symbol_root(sym::Target.clone()))?; let projection = { let b = TyBuilder::subst_for_def(db, deref_trait, None); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 868827b2b6603..d506e00ca1239 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -289,17 +289,16 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { chalk_ir::Binders::new(binders, bound) } crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => { - if let Some((future_trait, future_output)) = self - .db - .lang_item(self.krate, LangItem::Future) - .and_then(|item| item.as_trait()) - .and_then(|trait_| { - let alias = self - .db - .trait_data(trait_) - .associated_type_by_name(&Name::new_symbol_root(sym::Output))?; - Some((trait_, alias)) - }) + if let Some((future_trait, future_output)) = + self.db + .lang_item(self.krate, LangItem::Future) + .and_then(|item| item.as_trait()) + .and_then(|trait_| { + let alias = self.db.trait_data(trait_).associated_type_by_name( + &Name::new_symbol_root(sym::Output.clone()), + )?; + Some((trait_, alias)) + }) { // Making up Symbol’s value as variable is void: AsyncBlock: // diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index 048bdd2c38bce..e52fae06d7f73 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -423,7 +423,9 @@ impl FilterMapNextChecker { ItemContainerId::TraitId(iterator_trait_id) => { let iterator_trait_items = &db.trait_data(iterator_trait_id).items; iterator_trait_items.iter().find_map(|(name, it)| match it { - &AssocItemId::FunctionId(id) if *name == sym::filter_map => Some(id), + &AssocItemId::FunctionId(id) if *name == sym::filter_map.clone() => { + Some(id) + } _ => None, }) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 2a644de1fbecc..f15f6575b7904 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -1171,8 +1171,9 @@ impl HirDisplay for Ty { .lang_item(body.module(db.upcast()).krate(), LangItem::Future) .and_then(LangItemTarget::as_trait); let output = future_trait.and_then(|t| { - db.trait_data(t) - .associated_type_by_name(&Name::new_symbol_root(sym::Output)) + db.trait_data(t).associated_type_by_name(&Name::new_symbol_root( + sym::Output.clone(), + )) }); write!(f, "impl ")?; if let Some(t) = future_trait { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 928a3f5e493c7..82f4ad01e0189 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -1425,7 +1425,9 @@ impl<'a> InferenceContext<'a> { } fn resolve_output_on(&self, trait_: TraitId) -> Option { - self.db.trait_data(trait_).associated_type_by_name(&Name::new_symbol_root(sym::Output)) + self.db + .trait_data(trait_) + .associated_type_by_name(&Name::new_symbol_root(sym::Output.clone())) } fn resolve_lang_trait(&self, lang: LangItem) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index f54081a276c8d..417fca5dcd671 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -623,7 +623,7 @@ impl InferenceContext<'_> { if let Some(deref_fn) = self .db .trait_data(deref_trait) - .method_by_name(&Name::new_symbol_root(sym::deref_mut)) + .method_by_name(&Name::new_symbol_root(sym::deref_mut.clone())) { break 'b deref_fn == f; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index a0c3f48642e3b..7857d207be7cf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -650,7 +650,7 @@ impl InferenceContext<'_> { if let Some(deref_fn) = self .db .trait_data(deref_trait) - .method_by_name(&Name::new_symbol_root(sym::deref)) + .method_by_name(&Name::new_symbol_root(sym::deref.clone())) { // FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that // the mutability is not wrong, and will be fixed in `self.infer_mut`). @@ -791,7 +791,7 @@ impl InferenceContext<'_> { if let Some(func) = self .db .trait_data(index_trait) - .method_by_name(&Name::new_symbol_root(sym::index)) + .method_by_name(&Name::new_symbol_root(sym::index.clone())) { let substs = TyBuilder::subst_for_def(self.db, index_trait, None) .push(self_ty.clone()) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index ca8996fb89e77..abb702d15002f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -112,7 +112,7 @@ impl InferenceContext<'_> { if let Some(index_fn) = self .db .trait_data(index_trait) - .method_by_name(&Name::new_symbol_root(sym::index_mut)) + .method_by_name(&Name::new_symbol_root(sym::index_mut.clone())) { *f = index_fn; let base_adjustments = self @@ -145,7 +145,7 @@ impl InferenceContext<'_> { if let Some(deref_fn) = self .db .trait_data(deref_trait) - .method_by_name(&Name::new_symbol_root(sym::deref_mut)) + .method_by_name(&Name::new_symbol_root(sym::deref_mut.clone())) { *f = deref_fn; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 67a0ec60f19d6..0b44bbec70f75 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -228,7 +228,7 @@ impl InferenceContext<'_> { Path::LangItem(..) => ( PathSegment { name: { - _d = Name::new_symbol_root(sym::Unknown); + _d = Name::new_symbol_root(sym::Unknown.clone()); &_d }, args_and_bindings: None, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 800b06afbd0b2..7ee63af1c229e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -783,7 +783,7 @@ impl<'a> InferenceTable<'a> { let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; let trait_data = self.db.trait_data(fn_once_trait); let output_assoc_type = - trait_data.associated_type_by_name(&Name::new_symbol_root(sym::Output))?; + trait_data.associated_type_by_name(&Name::new_symbol_root(sym::Output.clone()))?; let mut arg_tys = Vec::with_capacity(num_args); let arg_ty = TyBuilder::tuple(num_args) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs index 69ff03eb49ece..f704b59d303e5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs @@ -21,43 +21,53 @@ pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangIte Some(match op { BinaryOp::LogicOp(_) => return None, BinaryOp::ArithOp(aop) => match aop { - ArithOp::Add => (Name::new_symbol_root(sym::add), LangItem::Add), - ArithOp::Mul => (Name::new_symbol_root(sym::mul), LangItem::Mul), - ArithOp::Sub => (Name::new_symbol_root(sym::sub), LangItem::Sub), - ArithOp::Div => (Name::new_symbol_root(sym::div), LangItem::Div), - ArithOp::Rem => (Name::new_symbol_root(sym::rem), LangItem::Rem), - ArithOp::Shl => (Name::new_symbol_root(sym::shl), LangItem::Shl), - ArithOp::Shr => (Name::new_symbol_root(sym::shr), LangItem::Shr), - ArithOp::BitXor => (Name::new_symbol_root(sym::bitxor), LangItem::BitXor), - ArithOp::BitOr => (Name::new_symbol_root(sym::bitor), LangItem::BitOr), - ArithOp::BitAnd => (Name::new_symbol_root(sym::bitand), LangItem::BitAnd), + ArithOp::Add => (Name::new_symbol_root(sym::add.clone()), LangItem::Add), + ArithOp::Mul => (Name::new_symbol_root(sym::mul.clone()), LangItem::Mul), + ArithOp::Sub => (Name::new_symbol_root(sym::sub.clone()), LangItem::Sub), + ArithOp::Div => (Name::new_symbol_root(sym::div.clone()), LangItem::Div), + ArithOp::Rem => (Name::new_symbol_root(sym::rem.clone()), LangItem::Rem), + ArithOp::Shl => (Name::new_symbol_root(sym::shl.clone()), LangItem::Shl), + ArithOp::Shr => (Name::new_symbol_root(sym::shr.clone()), LangItem::Shr), + ArithOp::BitXor => (Name::new_symbol_root(sym::bitxor.clone()), LangItem::BitXor), + ArithOp::BitOr => (Name::new_symbol_root(sym::bitor.clone()), LangItem::BitOr), + ArithOp::BitAnd => (Name::new_symbol_root(sym::bitand.clone()), LangItem::BitAnd), }, BinaryOp::Assignment { op: Some(aop) } => match aop { - ArithOp::Add => (Name::new_symbol_root(sym::add_assign), LangItem::AddAssign), - ArithOp::Mul => (Name::new_symbol_root(sym::mul_assign), LangItem::MulAssign), - ArithOp::Sub => (Name::new_symbol_root(sym::sub_assign), LangItem::SubAssign), - ArithOp::Div => (Name::new_symbol_root(sym::div_assign), LangItem::DivAssign), - ArithOp::Rem => (Name::new_symbol_root(sym::rem_assign), LangItem::RemAssign), - ArithOp::Shl => (Name::new_symbol_root(sym::shl_assign), LangItem::ShlAssign), - ArithOp::Shr => (Name::new_symbol_root(sym::shr_assign), LangItem::ShrAssign), - ArithOp::BitXor => (Name::new_symbol_root(sym::bitxor_assign), LangItem::BitXorAssign), - ArithOp::BitOr => (Name::new_symbol_root(sym::bitor_assign), LangItem::BitOrAssign), - ArithOp::BitAnd => (Name::new_symbol_root(sym::bitand_assign), LangItem::BitAndAssign), + ArithOp::Add => (Name::new_symbol_root(sym::add_assign.clone()), LangItem::AddAssign), + ArithOp::Mul => (Name::new_symbol_root(sym::mul_assign.clone()), LangItem::MulAssign), + ArithOp::Sub => (Name::new_symbol_root(sym::sub_assign.clone()), LangItem::SubAssign), + ArithOp::Div => (Name::new_symbol_root(sym::div_assign.clone()), LangItem::DivAssign), + ArithOp::Rem => (Name::new_symbol_root(sym::rem_assign.clone()), LangItem::RemAssign), + ArithOp::Shl => (Name::new_symbol_root(sym::shl_assign.clone()), LangItem::ShlAssign), + ArithOp::Shr => (Name::new_symbol_root(sym::shr_assign.clone()), LangItem::ShrAssign), + ArithOp::BitXor => { + (Name::new_symbol_root(sym::bitxor_assign.clone()), LangItem::BitXorAssign) + } + ArithOp::BitOr => { + (Name::new_symbol_root(sym::bitor_assign.clone()), LangItem::BitOrAssign) + } + ArithOp::BitAnd => { + (Name::new_symbol_root(sym::bitand_assign.clone()), LangItem::BitAndAssign) + } }, BinaryOp::CmpOp(cop) => match cop { - CmpOp::Eq { negated: false } => (Name::new_symbol_root(sym::eq), LangItem::PartialEq), - CmpOp::Eq { negated: true } => (Name::new_symbol_root(sym::ne), LangItem::PartialEq), + CmpOp::Eq { negated: false } => { + (Name::new_symbol_root(sym::eq.clone()), LangItem::PartialEq) + } + CmpOp::Eq { negated: true } => { + (Name::new_symbol_root(sym::ne.clone()), LangItem::PartialEq) + } CmpOp::Ord { ordering: Ordering::Less, strict: false } => { - (Name::new_symbol_root(sym::le), LangItem::PartialOrd) + (Name::new_symbol_root(sym::le.clone()), LangItem::PartialOrd) } CmpOp::Ord { ordering: Ordering::Less, strict: true } => { - (Name::new_symbol_root(sym::lt), LangItem::PartialOrd) + (Name::new_symbol_root(sym::lt.clone()), LangItem::PartialOrd) } CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { - (Name::new_symbol_root(sym::ge), LangItem::PartialOrd) + (Name::new_symbol_root(sym::ge.clone()), LangItem::PartialOrd) } CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { - (Name::new_symbol_root(sym::gt), LangItem::PartialOrd) + (Name::new_symbol_root(sym::gt.clone()), LangItem::PartialOrd) } }, BinaryOp::Assignment { op: None } => return None, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 60447ac582030..aabf11f268ff8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -897,7 +897,7 @@ pub fn callable_sig_from_fn_trait( let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; let output_assoc_type = db .trait_data(fn_once_trait) - .associated_type_by_name(&Name::new_symbol_root(sym::Output))?; + .associated_type_by_name(&Name::new_symbol_root(sym::Output.clone()))?; let mut table = InferenceTable::new(db, trait_env.clone()); let b = TyBuilder::trait_ref(db, fn_once_trait); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 982080c5ff5fe..32b7d6dc1138a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -631,18 +631,20 @@ impl Evaluator<'_> { cached_fn_trait_func: db .lang_item(crate_id, LangItem::Fn) .and_then(|x| x.as_trait()) - .and_then(|x| db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call))), + .and_then(|x| { + db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call.clone())) + }), cached_fn_mut_trait_func: db .lang_item(crate_id, LangItem::FnMut) .and_then(|x| x.as_trait()) .and_then(|x| { - db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call_mut)) + db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call_mut.clone())) }), cached_fn_once_trait_func: db .lang_item(crate_id, LangItem::FnOnce) .and_then(|x| x.as_trait()) .and_then(|x| { - db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call_once)) + db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call_once.clone())) }), }) } @@ -2694,7 +2696,7 @@ impl Evaluator<'_> { ) -> Result<()> { let Some(drop_fn) = (|| { let drop_trait = self.db.lang_item(self.crate_id, LangItem::Drop)?.as_trait()?; - self.db.trait_data(drop_trait).method_by_name(&Name::new_symbol_root(sym::drop)) + self.db.trait_data(drop_trait).method_by_name(&Name::new_symbol_root(sym::drop.clone())) })() else { // in some tests we don't have drop trait in minicore, and // we can ignore drop in them. @@ -2803,7 +2805,7 @@ pub fn render_const_using_debug_impl( not_supported!("core::fmt::Debug not found"); }; let Some(debug_fmt_fn) = - db.trait_data(debug_trait).method_by_name(&Name::new_symbol_root(sym::fmt)) + db.trait_data(debug_trait).method_by_name(&Name::new_symbol_root(sym::fmt.clone())) else { not_supported!("core::fmt::Debug::fmt not found"); }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 67e102b1ed183..6818759310613 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -319,7 +319,7 @@ impl Evaluator<'_> { return Some(LangItem::BeginPanic); } - let candidate = attrs.by_key("lang").string_value().and_then(LangItem::from_str)?; + let candidate = attrs.lang_item()?; // We want to execute these functions with special logic // `PanicFmt` is not detected here as it's redirected later. if [BeginPanic, SliceLen, DropInPlace].contains(&candidate) { @@ -1279,7 +1279,7 @@ impl Evaluator<'_> { if let Some(def) = target.as_trait().and_then(|it| { self.db .trait_data(it) - .method_by_name(&Name::new_symbol_root(sym::call_once)) + .method_by_name(&Name::new_symbol_root(sym::call_once.clone())) }) { self.exec_fn_trait( def, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs index 5e8a2dfb735f6..424ee1160c820 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs @@ -189,10 +189,10 @@ impl MirLowerCtx<'_> { if let Some(deref_trait) = self.resolve_lang_item(LangItem::DerefMut)?.as_trait() { - if let Some(deref_fn) = self - .db - .trait_data(deref_trait) - .method_by_name(&Name::new_symbol_root(sym::deref_mut)) + if let Some(deref_fn) = + self.db.trait_data(deref_trait).method_by_name( + &Name::new_symbol_root(sym::deref_mut.clone()), + ) { break 'b deref_fn == f; } @@ -327,14 +327,14 @@ impl MirLowerCtx<'_> { ( Mutability::Not, LangItem::Deref, - Name::new_symbol_root(sym::deref), + Name::new_symbol_root(sym::deref.clone()), BorrowKind::Shared, ) } else { ( Mutability::Mut, LangItem::DerefMut, - Name::new_symbol_root(sym::deref_mut), + Name::new_symbol_root(sym::deref_mut.clone()), BorrowKind::Mut { kind: MutBorrowKind::Default }, ) }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index ce9ffa284c904..c46382a0ea822 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -257,9 +257,9 @@ impl FnTrait { pub fn method_name(self) -> Name { match self { - FnTrait::FnOnce => Name::new_symbol_root(sym::call_once), - FnTrait::FnMut => Name::new_symbol_root(sym::call_mut), - FnTrait::Fn => Name::new_symbol_root(sym::call), + FnTrait::FnOnce => Name::new_symbol_root(sym::call_once.clone()), + FnTrait::FnMut => Name::new_symbol_root(sym::call_mut.clone()), + FnTrait::Fn => Name::new_symbol_root(sym::call.clone()), } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index f90656c75f590..c868357ff982f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -1827,7 +1827,7 @@ impl DefWithBody { continue; } let mut need_mut = &mol[local]; - if body[binding_id].name == sym::self_ + if body[binding_id].name == sym::self_.clone() && need_mut == &mir::MutabilityReason::Unused { need_mut = &mir::MutabilityReason::Not; @@ -2589,7 +2589,7 @@ pub struct StaticLifetime; impl StaticLifetime { pub fn name(self) -> Name { - Name::new_symbol_root(sym::tick_static) + Name::new_symbol_root(sym::tick_static.clone()) } } @@ -3249,7 +3249,7 @@ impl Local { } pub fn is_self(self, db: &dyn HirDatabase) -> bool { - self.name(db) == sym::self_ + self.name(db) == sym::self_.clone() } pub fn is_mut(self, db: &dyn HirDatabase) -> bool { diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 45401702e9f00..be0116862b9cf 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -366,7 +366,7 @@ impl SourceAnalyzer { let items = into_future_trait.items(db); let into_future_type = items.into_iter().find_map(|item| match item { AssocItem::TypeAlias(alias) - if alias.name(db) == Name::new_symbol_root(sym::IntoFuture) => + if alias.name(db) == Name::new_symbol_root(sym::IntoFuture.clone()) => { Some(alias) } @@ -395,8 +395,11 @@ impl SourceAnalyzer { // This can be either `Deref::deref` or `DerefMut::deref_mut`. // Since deref kind is inferenced and stored in `InferenceResult.method_resolution`, // use that result to find out which one it is. - let (deref_trait, deref) = - self.lang_trait_fn(db, LangItem::Deref, &Name::new_symbol_root(sym::deref))?; + let (deref_trait, deref) = self.lang_trait_fn( + db, + LangItem::Deref, + &Name::new_symbol_root(sym::deref.clone()), + )?; self.infer .as_ref() .and_then(|infer| { @@ -405,7 +408,7 @@ impl SourceAnalyzer { let (deref_mut_trait, deref_mut) = self.lang_trait_fn( db, LangItem::DerefMut, - &Name::new_symbol_root(sym::deref_mut), + &Name::new_symbol_root(sym::deref_mut.clone()), )?; if func == deref_mut { Some((deref_mut_trait, deref_mut)) @@ -416,10 +419,10 @@ impl SourceAnalyzer { .unwrap_or((deref_trait, deref)) } ast::UnaryOp::Not => { - self.lang_trait_fn(db, LangItem::Not, &Name::new_symbol_root(sym::not))? + self.lang_trait_fn(db, LangItem::Not, &Name::new_symbol_root(sym::not.clone()))? } ast::UnaryOp::Neg => { - self.lang_trait_fn(db, LangItem::Neg, &Name::new_symbol_root(sym::neg))? + self.lang_trait_fn(db, LangItem::Neg, &Name::new_symbol_root(sym::neg.clone()))? } }; @@ -441,7 +444,7 @@ impl SourceAnalyzer { let index_ty = self.ty_of_expr(db, &index_expr.index()?)?; let (index_trait, index_fn) = - self.lang_trait_fn(db, LangItem::Index, &Name::new_symbol_root(sym::index))?; + self.lang_trait_fn(db, LangItem::Index, &Name::new_symbol_root(sym::index.clone()))?; let (op_trait, op_fn) = self .infer .as_ref() @@ -451,7 +454,7 @@ impl SourceAnalyzer { let (index_mut_trait, index_mut_fn) = self.lang_trait_fn( db, LangItem::IndexMut, - &Name::new_symbol_root(sym::index_mut), + &Name::new_symbol_root(sym::index_mut.clone()), )?; if func == index_mut_fn { Some((index_mut_trait, index_mut_fn)) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs index 27e39f6f8ab26..77f9c66b354ee 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -223,7 +223,7 @@ fn option_variants( let fam = FamousDefs(sema, sema.scope(expr)?.krate()); let option_variants = fam.core_option_Option()?.variants(sema.db); match &*option_variants { - &[variant0, variant1] => Some(if variant0.name(sema.db) == sym::None { + &[variant0, variant1] => Some(if variant0.name(sema.db) == sym::None.clone() { (variant0, variant1) } else { (variant1, variant0) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs index d85147e84b20c..e86ff0dbebc62 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs @@ -150,9 +150,9 @@ fn is_ref_and_impls_iter_method( _ => return None, }; let wanted_method = Name::new_symbol_root(if ref_expr.mut_token().is_some() { - sym::iter_mut + sym::iter_mut.clone() } else { - sym::iter + sym::iter.clone() }); let expr_behind_ref = ref_expr.expr()?; let ty = sema.type_of_expr(&expr_behind_ref)?.adjusted(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs index 05210e66ac24d..ad422b25c39e0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs @@ -54,13 +54,13 @@ pub(crate) fn generate_is_empty_from_len(acc: &mut Assists, ctx: &AssistContext< } let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?; - let len_fn = get_impl_method(ctx, &impl_, &Name::new_symbol_root(sym::len))?; + let len_fn = get_impl_method(ctx, &impl_, &Name::new_symbol_root(sym::len.clone()))?; if !len_fn.ret_type(ctx.sema.db).is_usize() { cov_mark::hit!(len_fn_different_return_type); return None; } - if get_impl_method(ctx, &impl_, &Name::new_symbol_root(sym::is_empty)).is_some() { + if get_impl_method(ctx, &impl_, &Name::new_symbol_root(sym::is_empty.clone())).is_some() { cov_mark::hit!(is_empty_already_implemented); return None; } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 137b8d13171fe..d0382499b996a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -430,7 +430,7 @@ fn inline( let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty); - let is_self = param.name(sema.db).is_some_and(|name| name == sym::self_); + let is_self = param.name(sema.db).is_some_and(|name| name == sym::self_.clone()); if is_self { let mut this_pat = make::ident_pat(false, false, make::name("this")); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index 4a8ea171805e2..ee27d8611eb80 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -618,7 +618,8 @@ fn enum_variants_with_paths( let mut process_variant = |variant: Variant| { let self_path = hir::ModPath::from_segments( hir::PathKind::Plain, - iter::once(Name::new_symbol_root(sym::Self_)).chain(iter::once(variant.name(ctx.db))), + iter::once(Name::new_symbol_root(sym::Self_.clone())) + .chain(iter::once(variant.name(ctx.db))), ); cb(acc, ctx, variant, self_path); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index d3290db4ef82b..a07daf4c4e49c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -91,13 +91,13 @@ pub(crate) fn complete_undotted_self( in_breakable: expr_ctx.in_breakable, }, }, - Some(Name::new_symbol_root(sym::self_)), + Some(Name::new_symbol_root(sym::self_.clone())), field, &ty, ) }, |acc, field, ty| { - acc.add_tuple_field(ctx, Some(Name::new_symbol_root(sym::self_)), field, &ty) + acc.add_tuple_field(ctx, Some(Name::new_symbol_root(sym::self_.clone())), field, &ty) }, true, false, @@ -115,7 +115,7 @@ pub(crate) fn complete_undotted_self( }, }, func, - Some(Name::new_symbol_root(sym::self_)), + Some(Name::new_symbol_root(sym::self_.clone())), None, ) }); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index 72b36922da0bd..71ff6b5aea37a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -190,7 +190,7 @@ pub(crate) fn complete_expr_path( path_ctx, strukt, None, - Some(Name::new_symbol_root(sym::Self_)), + Some(Name::new_symbol_root(sym::Self_.clone())), ); } } @@ -214,7 +214,7 @@ pub(crate) fn complete_expr_path( ctx, un, None, - Some(Name::new_symbol_root(sym::Self_)), + Some(Name::new_symbol_root(sym::Self_.clone())), ); } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs index 541ccf2d198e3..f31352f49f9de 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs @@ -47,7 +47,7 @@ pub(crate) fn complete_lifetime( } }); if param_lifetime.is_none() { - acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static)); + acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static.clone())); } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 4cdb279a21ca6..a41bf457a9032 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -210,7 +210,7 @@ fn get_default_constructor( let has_new_func = ty .iterate_assoc_items(ctx.sema.db, krate, |assoc_item| { if let AssocItem::Function(func) = assoc_item { - if func.name(ctx.sema.db) == sym::new + if func.name(ctx.sema.db) == sym::new.clone() && func.assoc_fn_params(ctx.sema.db).is_empty() { return Some(()); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 0692f0d700612..ce1a56e45062b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -633,7 +633,7 @@ fn hint_iterator( if ty.impls_trait(db, iter_trait, &[]) { let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item { - hir::AssocItem::TypeAlias(alias) if alias.name(db) == sym::Item => Some(alias), + hir::AssocItem::TypeAlias(alias) if alias.name(db) == sym::Item.clone() => Some(alias), _ => None, })?; if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index c73b6acb0d073..291073f87735c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -6,6 +6,7 @@ use ide_db::{ defs::{Definition, IdentClass, NameClass, NameRefClass}, FxHashMap, RootDatabase, SymbolKind, }; +use stdx::hash_once; use syntax::{ ast, match_ast, AstNode, AstToken, NodeOrToken, SyntaxKind::{self, *}, @@ -358,17 +359,7 @@ fn highlight_name( } fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 { - fn hash(x: T) -> u64 { - use ide_db::FxHasher; - - use std::hash::Hasher; - - let mut hasher = FxHasher::default(); - x.hash(&mut hasher); - hasher.finish() - } - - hash((name, shadow_count)) + hash_once::((name.as_str(), shadow_count)) } pub(super) fn highlight_def( diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs index 9f7a788d006c8..9e275713876c0 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -91,7 +91,7 @@ impl TaggedArcPtr { } #[inline] - const fn pack_arc(ptr: NonNull<*const str>) -> NonNull<*const str> { + fn pack_arc(ptr: NonNull<*const str>) -> NonNull<*const str> { let packed_tag = true as usize; // can't use this strict provenance stuff here due to trait methods not being const @@ -112,7 +112,7 @@ impl TaggedArcPtr { // } // so what follows is roughly what the above looks like but inlined - let self_addr = unsafe { core::mem::transmute::<*const _, usize>(ptr.as_ptr()) }; + let self_addr = ptr.as_ptr() as *const *const str as usize; let addr = self_addr | packed_tag; let dest_addr = addr as isize; let offset = dest_addr.wrapping_sub(self_addr as isize); @@ -222,7 +222,7 @@ impl Symbol { .try_as_arc_owned() .unwrap(), ); - debug_assert_eq!(Arc::count(&arc), 1); + debug_assert_eq!(Arc::count(arc), 1); // Shrink the backing storage if the shard is less than 50% occupied. if shard.len() * 2 < shard.capacity() { diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index af1af0536c2e5..6304155ed76ad 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -14,10 +14,10 @@ use crate::{ macro_rules! define_symbols { (@WITH_NAME: $($alias:ident = $value:literal),* $(,)? @PLAIN: $($name:ident),* $(,)?) => { $( - pub const $name: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&stringify!($name)) }; + pub static $name: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&stringify!($name)) }; )* $( - pub const $alias: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&$value) }; + pub static $alias: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&$value) }; )* @@ -78,10 +78,13 @@ define_symbols! { @PLAIN: add_assign, add, + align_offset, + alloc_layout, alloc, as_str, asm, assert, + begin_panic, bench, bitand_assign, bitand, @@ -89,88 +92,13 @@ define_symbols! { bitor, bitxor_assign, bitxor, - transmute_opts, - transmute_trait, - coerce_unsized, - dispatch_from_dyn,destruct, bool, - panic, - begin_panic, - panic_nounwind, - panic_fmt, - panic_misaligned_pointer_dereference, - panic_display, - const_panic_fmt, - panic_bounds_check, - panic_info, - panic_location, - panic_impl, - panic_cannot_unwind, - sized, - unsize, - format_alignment, - start, - format_argument, - format_arguments, - format_count, - format_placeholder, - format_unsafe_arg, - exchange_malloc, box_free, - drop_in_place, - alloc_layout, - eh_personality, - eh_catch_typeinfo, - phantom_data, - manually_drop, - maybe_uninit, - align_offset, - termination, - tuple_trait, - slice_len_fn, - from_residual, - from_output, - from_yeet, - pointer_like, - const_param_ty, - Poll, - Ready, - Pending, - ResumeTy, - get_context, - Context, - Some, - Err, - Continue, - Break, - into_iter, - new_unchecked, - range_inclusive_new, - CStr, - fn_ptr_trait, - freeze, - coroutine_state, - c_void, - coroutine, - unpin, - pin, - fn_ptr_addr, - structural_teq, - fn_once_output, - copy, - clone, - sync, - discriminant_kind, Box, - structural_peq, boxed, branch, - discriminant_type, - pointee_trait, - metadata_type, - dyn_metadata, - deref_target, - receiver, + Break, + c_void, call_mut, call_once, call, @@ -180,31 +108,51 @@ define_symbols! { cfg_eval, cfg, char, + clone, Clone, + coerce_unsized, column, compile_error, concat_bytes, concat_idents, concat, const_format_args, + const_panic_fmt, + const_param_ty, + Context, + Continue, + copy, Copy, core_panic, core, + coroutine_state, + coroutine, crate_type, + CStr, Debug, default, Default, deref_mut, + deref_target, deref, derive_const, derive, + discriminant_kind, + discriminant_type, + dispatch_from_dyn,destruct, div_assign, div, doc, + drop_in_place, drop, + dyn_metadata, + eh_catch_typeinfo, + eh_personality, env, eq, Eq, + Err, + exchange_malloc, f128, f16, f32, @@ -214,15 +162,29 @@ define_symbols! { filter_map, fmt, fn_mut, + fn_once_output, fn_once, + fn_ptr_addr, + fn_ptr_trait, + format_alignment, format_args_nl, format_args, + format_argument, + format_arguments, + format_count, + format_placeholder, + format_unsafe_arg, format, + freeze, + from_output, + from_residual, from_usize, + from_yeet, future_trait, future, Future, ge, + get_context, global_allocator, global_asm, gt, @@ -240,6 +202,7 @@ define_symbols! { index, Index, into_future, + into_iter, IntoFuture, IntoIter, IntoIterator, @@ -258,6 +221,9 @@ define_symbols! { log_syntax, lt, macro_rules, + manually_drop, + maybe_uninit, + metadata_type, module_path, mul_assign, mul, @@ -271,6 +237,7 @@ define_symbols! { new_lower_hex, new_octal, new_pointer, + new_unchecked, new_upper_exp, new_upper_hex, new_v1_formatted, @@ -293,21 +260,39 @@ define_symbols! { owned_box, panic_2015, panic_2021, + panic_bounds_check, + panic_cannot_unwind, + panic_display, + panic_fmt, + panic_impl, + panic_info, + panic_location, + panic_misaligned_pointer_dereference, + panic_nounwind, + panic, Param, partial_ord, PartialEq, PartialOrd, + Pending, + phantom_data, pieces, + pin, + pointee_trait, + pointer_like, poll, + Poll, prelude, quote, - r#fn, + range_inclusive_new, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, + Ready, + receiver, recursion_limit, register_attr, register_tool, @@ -315,6 +300,7 @@ define_symbols! { rem, result, Result, + ResumeTy, Right, rust_2015, rust_2018, @@ -327,30 +313,43 @@ define_symbols! { shl, shr_assign, shr, + sized, + slice_len_fn, + Some, + start, std_panic, std, str, string, String, stringify, + structural_peq, + structural_teq, sub_assign, sub, + sync, Target, + termination, test_case, test, trace_macros, + transmute_opts, + transmute_trait, transparent, Try, + tuple_trait, u128, u16, u32, u64, u8, Unknown, + unpin, unreachable_2015, unreachable_2021, unreachable, unsafe_cell, + unsize, usize, v1, va_list From d95b2f3f4bb5839b508b86a751c09cb7e0d59cda Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 15 Jul 2024 11:07:04 +0200 Subject: [PATCH 011/147] Fix stable iteration ordering for `Map` usages --- .../crates/hir-def/src/item_scope.rs | 15 +++++----- .../crates/hir-def/src/nameres.rs | 10 +++---- .../hir-def/src/nameres/tests/macros.rs | 1 + .../crates/hir-def/src/resolver.rs | 9 ++++-- .../ide-assists/src/handlers/auto_import.rs | 28 ++++++++++++++++--- .../src/completions/format_string.rs | 2 +- .../ide-completion/src/render/function.rs | 2 +- .../ide-completion/src/tests/flyimport.rs | 2 +- .../ide-db/src/imports/import_assets.rs | 10 +++---- .../rust-analyzer/crates/intern/src/symbol.rs | 1 + .../crates/intern/src/symbol/symbols.rs | 4 +++ 11 files changed, 55 insertions(+), 29 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index 092c0a1dfdf81..86c3e0f041d39 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -1,10 +1,9 @@ //! Describes items defined or visible (ie, imported) in a certain scope. //! This is shared between modules and blocks. -use std::collections::hash_map::Entry; - use base_db::CrateId; use hir_expand::{attrs::AttrId, db::ExpandDatabase, name::Name, AstId, MacroCallId}; +use indexmap::map::Entry; use itertools::Itertools; use la_arena::Idx; use once_cell::sync::Lazy; @@ -17,8 +16,8 @@ use crate::{ db::DefDatabase, per_ns::PerNs, visibility::{Visibility, VisibilityExplicitness}, - AdtId, BuiltinType, ConstId, ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId, - ModuleDefId, ModuleId, TraitId, UseId, + AdtId, BuiltinType, ConstId, ExternCrateId, FxIndexMap, HasModule, ImplId, LocalModuleId, + Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId, }; #[derive(Debug, Default)] @@ -67,9 +66,9 @@ pub struct ItemScope { /// Defs visible in this scope. This includes `declarations`, but also /// imports. The imports belong to this module and can be resolved by using them on /// the `use_imports_*` fields. - types: FxHashMap)>, - values: FxHashMap)>, - macros: FxHashMap)>, + types: FxIndexMap)>, + values: FxIndexMap)>, + macros: FxIndexMap)>, unresolved: FxHashSet, /// The defs declared in this scope. Each def has a single scope where it is @@ -118,7 +117,7 @@ struct DeriveMacroInvocation { derive_call_ids: SmallVec<[Option; 1]>, } -pub(crate) static BUILTIN_SCOPE: Lazy> = Lazy::new(|| { +pub(crate) static BUILTIN_SCOPE: Lazy> = Lazy::new(|| { BuiltinType::all_builtin_types() .iter() .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public, None))) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index 8e7ef48112f04..b0543727c27d0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -323,7 +323,7 @@ pub struct ModuleData { /// /// [`None`] for block modules because they are always its `DefMap`'s root. pub parent: Option, - pub children: FxHashMap, + pub children: FxIndexMap, pub scope: ItemScope, } @@ -593,10 +593,8 @@ impl DefMap { self.data.extern_prelude.iter().map(|(name, &def)| (name, def)) } - pub(crate) fn macro_use_prelude( - &self, - ) -> impl Iterator))> + '_ { - self.macro_use_prelude.iter().map(|(name, &def)| (name, def)) + pub(crate) fn macro_use_prelude(&self) -> &FxHashMap)> { + &self.macro_use_prelude } pub(crate) fn resolve_path( @@ -668,7 +666,7 @@ impl ModuleData { origin, visibility, parent: None, - children: FxHashMap::default(), + children: Default::default(), scope: ItemScope::default(), } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs index d278b75e8158a..14d497b3a11c7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs @@ -1348,6 +1348,7 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a } .keys() .map(|name| name.display(&db).to_string()) .sorted() + .sorted() .join("\n"); expect![[r#" diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index c196f00281639..f0f2210ec2c51 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -4,6 +4,7 @@ use std::{fmt, iter, mem}; use base_db::CrateId; use hir_expand::{name::Name, MacroDefId}; use intern::{sym, Interned}; +use itertools::Itertools as _; use rustc_hash::FxHashSet; use smallvec::{smallvec, SmallVec}; use triomphe::Arc; @@ -497,9 +498,11 @@ impl Resolver { res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac))); }) }); - def_map.macro_use_prelude().for_each(|(name, (def, _extern_crate))| { - res.add(name, ScopeDef::ModuleDef(def.into())); - }); + def_map.macro_use_prelude().iter().sorted_by_key(|&(k, _)| k.clone()).for_each( + |(name, &(def, _extern_crate))| { + res.add(name, ScopeDef::ModuleDef(def.into())); + }, + ); def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| { res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def.into()))); }); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs index f17635972b78c..37c5d7ce7efd7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs @@ -1637,8 +1637,8 @@ mod bar { #[test] fn local_inline_import_has_alias() { - // FIXME - check_assist_not_applicable( + // FIXME wrong import + check_assist( auto_import, r#" struct S(T); @@ -1647,14 +1647,24 @@ use S as IoResult; mod foo { pub fn bar() -> S$0<()> {} } +"#, + r#" +struct S(T); +use S as IoResult; + +mod foo { + use crate::S; + + pub fn bar() -> S<()> {} +} "#, ); } #[test] fn alias_local() { - // FIXME - check_assist_not_applicable( + // FIXME wrong import + check_assist( auto_import, r#" struct S(T); @@ -1663,6 +1673,16 @@ use S as IoResult; mod foo { pub fn bar() -> IoResult$0<()> {} } +"#, + r#" +struct S(T); +use S as IoResult; + +mod foo { + use crate::S; + + pub fn bar() -> IoResult<()> {} +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs index 5512ac2153460..559a9bcba2961 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs @@ -31,7 +31,7 @@ pub(crate) fn format_string( }; let source_range = TextRange::new(brace_offset, cursor); - ctx.locals.iter().for_each(|(name, _)| { + ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()).for_each(|(name, _)| { CompletionItem::new(CompletionItemKind::Binding, source_range, name.to_smol_str()) .add_to(acc, ctx.db); }); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs index c15e91c404839..cdfe23170176c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs @@ -259,7 +259,7 @@ pub(super) fn add_call_parens<'b>( fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'static str { if let Some(derefed_ty) = ty.remove_ref() { - for (name, local) in ctx.locals.iter() { + for (name, local) in ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()) { if name.as_str() == arg { return if local.ty(ctx.db) == derefed_ty { if ty.is_mutable_reference() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index 7d9c1ed98ac59..eacec018c72b9 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -767,8 +767,8 @@ fn main() { } "#, expect![[r#" - fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED + fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED me random_method(
) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED "#]], ); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs index 4814394de6b29..38cb4a162c28c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs @@ -15,7 +15,7 @@ use syntax::{ use crate::{ helpers::item_name, items_locator::{self, AssocSearchMode, DEFAULT_QUERY_SEARCH_LIMIT}, - RootDatabase, + FxIndexSet, RootDatabase, }; /// A candidate for import, derived during various IDE activities: @@ -262,7 +262,7 @@ impl ImportAssets { let scope = match sema.scope(&self.candidate_node) { Some(it) => it, - None => return >::default().into_iter(), + None => return >::default().into_iter(), }; let krate = self.module_with_candidate.krate(); @@ -319,7 +319,7 @@ fn path_applicable_imports( path_candidate: &PathImportCandidate, mod_path: impl Fn(ItemInNs) -> Option + Copy, scope_filter: impl Fn(ItemInNs) -> bool + Copy, -) -> FxHashSet { +) -> FxIndexSet { let _p = tracing::info_span!("ImportAssets::path_applicable_imports").entered(); match &path_candidate.qualifier { @@ -500,7 +500,7 @@ fn trait_applicable_items( trait_assoc_item: bool, mod_path: impl Fn(ItemInNs) -> Option, scope_filter: impl Fn(hir::Trait) -> bool, -) -> FxHashSet { +) -> FxIndexSet { let _p = tracing::info_span!("ImportAssets::trait_applicable_items").entered(); let db = sema.db; @@ -566,7 +566,7 @@ fn trait_applicable_items( definitions_exist_in_trait_crate || definitions_exist_in_receiver_crate() }); - let mut located_imports = FxHashSet::default(); + let mut located_imports = FxIndexSet::default(); let mut trait_import_paths = FxHashMap::default(); if trait_assoc_item { diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs index 9e275713876c0..a3cc5c3d6a3d6 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -37,6 +37,7 @@ const _: () = /// A pointer that points to a pointer to a `str`, it may be backed as a `&'static &'static str` or /// `Arc>` but its size is that of a thin pointer. The active variant is encoded as a tag /// in the LSB of the alignment niche. +// Note, Ideally this would encode a `ThinArc` and `ThinRef`/`ThinConstPtr` instead of the double indirection. #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] struct TaggedArcPtr { packed: NonNull<*const str>, diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 6304155ed76ad..064335471e95a 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -13,6 +13,10 @@ use crate::{ macro_rules! define_symbols { (@WITH_NAME: $($alias:ident = $value:literal),* $(,)? @PLAIN: $($name:ident),* $(,)?) => { + // Ideally we would be emitting `const` here, but then we no longer have stable addresses + // which is what we are relying on for equality! In the future if consts can refer to + // statics we should swap these for `const`s and have the the string literal being pointed + // to be statics to refer to such that their address is stable. $( pub static $name: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&stringify!($name)) }; )* From 6af77a624ea72427a6bb53dac89053fc95ee3329 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 7 Jul 2024 17:47:38 +0200 Subject: [PATCH 012/147] Encode ident rawness and literal kind separately in tt::Leaf --- src/tools/rust-analyzer/Cargo.lock | 1 + .../rust-analyzer/crates/hir-def/src/attr.rs | 2 +- .../crates/hir-def/src/hir/format_args.rs | 2 +- .../macro_expansion_tests/builtin_fn_macro.rs | 8 +- .../macro_expansion_tests/mbe/regression.rs | 4 +- .../crates/hir-def/src/nameres/collector.rs | 4 +- .../crates/hir-expand/src/attrs.rs | 44 ++-- .../hir-expand/src/builtin_derive_macro.rs | 3 +- .../crates/hir-expand/src/builtin_fn_macro.rs | 199 +++++++++-------- .../crates/hir-expand/src/fixup.rs | 23 +- .../crates/hir-expand/src/lib.rs | 2 +- .../crates/hir-expand/src/mod_path.rs | 10 +- .../crates/hir-expand/src/name.rs | 11 +- .../crates/hir-expand/src/quote.rs | 31 ++- .../rust-analyzer/crates/hir/src/attrs.rs | 8 +- .../crates/ide-db/src/documentation.rs | 17 +- .../rust-analyzer/crates/ide/src/hover.rs | 2 +- src/tools/rust-analyzer/crates/mbe/Cargo.toml | 1 + .../rust-analyzer/crates/mbe/src/benchmark.rs | 15 +- .../crates/mbe/src/expander/transcriber.rs | 24 ++- src/tools/rust-analyzer/crates/mbe/src/lib.rs | 13 +- .../rust-analyzer/crates/mbe/src/parser.rs | 12 +- .../crates/mbe/src/syntax_bridge.rs | 188 +++++++++++----- .../crates/mbe/src/to_parser_input.rs | 26 +-- .../crates/proc-macro-api/src/msg.rs | 34 ++- .../crates/proc-macro-api/src/msg/flat.rs | 124 +++++++++-- .../proc-macro-test/imp/src/lib.rs | 1 - .../crates/proc-macro-srv/src/server_impl.rs | 75 +++---- .../src/server_impl/rust_analyzer_span.rs | 39 ++-- .../src/server_impl/token_id.rs | 38 ++-- .../crates/proc-macro-srv/src/tests/mod.rs | 104 ++++----- .../crates/salsa/tests/macros.rs | 1 + src/tools/rust-analyzer/crates/tt/src/lib.rs | 202 ++++++++++++++++-- 33 files changed, 858 insertions(+), 410 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index b165697724e05..e43f712a6e230 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1046,6 +1046,7 @@ dependencies = [ "arrayvec", "cov-mark", "parser", + "ra-ap-rustc_lexer", "rustc-hash", "smallvec", "span", diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index aacfb07319819..5bd60c58e9b7e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -605,7 +605,7 @@ impl<'attr> AttrQuery<'attr> { .nth(2); match name { - Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal{ ref text, ..}))) => Some(text), + Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal{ text, kind: tt::LitKind::Str | tt::LitKind::StrRaw(_) , ..}))) => Some(text), _ => None } }) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs index d6dd5df37366a..cf176e86dbd5d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs @@ -250,7 +250,7 @@ pub(crate) fn parse( } } ArgRef::Name(name, span) => { - let name = Name::new(name, call_ctx); + let name = Name::new(name, tt::IdentIsRaw::No, call_ctx); if let Some((index, _)) = args.by_name(&name) { record_usage(name, span); // Name found in `args`, so we resolve it to its index. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 9596100b60e13..ab8bb8bd4c6fc 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -460,13 +460,13 @@ fn test_concat_expand() { #[rustc_builtin_macro] macro_rules! concat {} -fn main() { concat!("fo", "o", 0, r#"bar"#, "\n", false, '"', '\0'); } +fn main() { concat!("fo", "o", 0, r#""bar""#, "\n", false, '"', '\0'); } "##, expect![[r##" #[rustc_builtin_macro] macro_rules! concat {} -fn main() { "foo0bar\nfalse\"\u{0}"; } +fn main() { "foo0\"bar\"\nfalse\"\u{0}"; } "##]], ); } @@ -478,13 +478,13 @@ fn test_concat_bytes_expand() { #[rustc_builtin_macro] macro_rules! concat_bytes {} -fn main() { concat_bytes!(b'A', b"BC", [68, b'E', 70]); } +fn main() { concat_bytes!(b'A', b"BC\"", [68, b'E', 70], br#"G""#,b'\0'); } "##, expect![[r#" #[rustc_builtin_macro] macro_rules! concat_bytes {} -fn main() { [b'A', 66, 67, 68, b'E', 70]; } +fn main() { b"ABC\"DEFG\"\x00"; } "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs index 4aad53c3bd71c..252b0bb1b59b8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs @@ -1058,7 +1058,7 @@ macro_rules! concat {} macro_rules! line {} fn main() { - "event 0u32"; + "event 0"; } "##]], @@ -1084,7 +1084,7 @@ fn main() { macro_rules! concat_bytes {} fn main() { - let x = /* error: unexpected token in input */[]; + let x = /* error: unexpected token in input */b""; } "#]], diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index f14679f6c2f14..13abcce78ead4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -82,7 +82,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI .iter() .enumerate() .map(|(idx, it)| { - let name = Name::new(&it.name, ctx); + let name = Name::new(&it.name, tt::IdentIsRaw::No, ctx); ( name, if !db.expand_proc_attr_macros() { @@ -2144,7 +2144,7 @@ impl ModCollector<'_, '_> { let name; let name = match attrs.by_key("rustc_builtin_macro").string_value_with_span() { Some((it, span)) => { - name = Name::new(it, span.ctx); + name = Name::new(it, tt::IdentIsRaw::No, span.ctx); &name } None => { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 36636a228f147..4fce7c1fde13f 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -5,11 +5,14 @@ use base_db::CrateId; use cfg::CfgExpr; use either::Either; use intern::{sym, Interned}; -use mbe::{syntax_node_to_token_tree, DelimiterKind, DocCommentDesugarMode, Punct}; +use mbe::{ + desugar_doc_comment_text, syntax_node_to_token_tree, token_to_literal, DelimiterKind, + DocCommentDesugarMode, Punct, +}; use smallvec::{smallvec, SmallVec}; use span::{Span, SyntaxContextId}; use syntax::unescape; -use syntax::{ast, format_smolstr, match_ast, AstNode, AstToken, SmolStr, SyntaxNode}; +use syntax::{ast, match_ast, AstNode, AstToken, SyntaxNode}; use triomphe::ThinArc; use crate::name::Name; @@ -53,11 +56,15 @@ impl RawAttrs { } Either::Right(comment) => comment.doc_comment().map(|doc| { let span = span_map.span_for_range(comment.syntax().text_range()); + let (text, kind) = + desugar_doc_comment_text(doc, DocCommentDesugarMode::ProcMacro); Attr { id, input: Some(Box::new(AttrInput::Literal(tt::Literal { - text: SmolStr::new(format_smolstr!("\"{}\"", Self::escape_chars(doc))), + text, span, + kind, + suffix: None, }))), path: Interned::new(ModPath::from(Name::new_symbol( sym::doc.clone(), @@ -78,10 +85,6 @@ impl RawAttrs { RawAttrs { entries } } - fn escape_chars(s: &str) -> String { - s.replace('\\', r#"\\"#).replace('"', r#"\""#) - } - pub fn from_attrs_owner( db: &dyn ExpandDatabase, owner: InFile<&dyn ast::HasAttrs>, @@ -238,10 +241,8 @@ impl Attr { })?); let span = span_map.span_for_range(range); let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { - Some(Box::new(AttrInput::Literal(tt::Literal { - text: lit.token().text().into(), - span, - }))) + let token = lit.token(); + Some(Box::new(AttrInput::Literal(token_to_literal(token.text().into(), span)))) } else if let Some(tt) = ast.token_tree() { let tree = syntax_node_to_token_tree( tt.syntax(), @@ -310,12 +311,11 @@ impl Attr { /// #[path = "string"] pub fn string_value(&self) -> Option<&str> { 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('"'), + AttrInput::Literal(tt::Literal { + text, + kind: tt::LitKind::Str | tt::LitKind::StrRaw(_), + .. + }) => Some(text), _ => None, } } @@ -336,12 +336,10 @@ impl Attr { pub fn string_value_unescape(&self) -> Option> { match self.input.as_deref()? { - AttrInput::Literal(it) => match it.text.strip_prefix('r') { - Some(it) => { - it.trim_matches('#').strip_prefix('"')?.strip_suffix('"').map(Cow::Borrowed) - } - None => it.text.strip_prefix('"')?.strip_suffix('"').and_then(unescape), - }, + AttrInput::Literal(tt::Literal { text, kind: tt::LitKind::StrRaw(_), .. }) => { + Some(Cow::Borrowed(text)) + } + AttrInput::Literal(tt::Literal { text, kind: tt::LitKind::Str, .. }) => unescape(text), _ => None, } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs index 269e9f308c2f6..180d8f05627f4 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs @@ -370,7 +370,8 @@ fn name_to_token( ExpandError::other("missing name") })?; let span = token_map.span_at(name.syntax().text_range().start()); - let name_token = tt::Ident { span, text: name.text().into() }; + + let name_token = tt::Ident::new(name.text().as_ref(), span); Ok(name_token) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index 97867dfc66e92..32befb7a7f7df 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -1,13 +1,14 @@ //! Builtin macro +use ::tt::SmolStr; 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}; -use syntax::ast::{self, AstToken}; +use stdx::format_to; +use syntax::unescape::{unescape_byte, unescape_char, unescape_unicode, Mode}; use crate::{ db::ExpandDatabase, @@ -177,8 +178,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: "0u32".into(), + text: "0".into(), span, + kind: tt::LitKind::Integer, + suffix: Some(Box::new("u32".into())), }))]), }) } @@ -444,27 +447,6 @@ fn use_panic_2021(db: &dyn ExpandDatabase, span: Span) -> bool { } } -fn unquote_str(lit: &tt::Literal) -> Option<(String, Span)> { - let span = lit.span; - let lit = ast::make::tokens::literal(&lit.to_string()); - let token = ast::String::cast(lit)?; - token.value().ok().map(|it| (it.into_owned(), span)) -} - -fn unquote_char(lit: &tt::Literal) -> Option<(char, Span)> { - let span = lit.span; - let lit = ast::make::tokens::literal(&lit.to_string()); - let token = ast::Char::cast(lit)?; - token.value().ok().zip(Some(span)) -} - -fn unquote_byte_string(lit: &tt::Literal) -> Option<(Vec, Span)> { - let span = lit.span; - let lit = ast::make::tokens::literal(&lit.to_string()); - let token = ast::ByteString::cast(lit)?; - token.value().ok().map(|it| (it.into_owned(), span)) -} - fn compile_error_expand( _db: &dyn ExpandDatabase, _id: MacroCallId, @@ -472,10 +454,16 @@ fn compile_error_expand( span: Span, ) -> ExpandResult { let err = match &*tt.token_trees { - [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => match unquote_str(it) { - Some((unquoted, _)) => ExpandError::other(unquoted.into_boxed_str()), - None => ExpandError::other("`compile_error!` argument must be a string"), - }, + [tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { + text, + span: _, + kind: tt::LitKind::Str | tt::LitKind::StrRaw(_), + suffix: _, + }))] => + // FIXME: Use the span here! + { + ExpandError::other(Box::from(&*unescape_str(text))) + } _ => ExpandError::other("`compile_error!` argument must be a string"), }; @@ -507,20 +495,33 @@ fn concat_expand( } } } - match t { tt::TokenTree::Leaf(tt::Leaf::Literal(it)) if i % 2 == 0 => { // concat works with string and char literals, so remove any quotes. // It also works with integer, float and boolean literals, so just use the rest // as-is. - if let Some((c, span)) = unquote_char(it) { - text.push(c); - record_span(span); - } else { - let (component, span) = - unquote_str(it).unwrap_or_else(|| (it.text.to_string(), it.span)); - text.push_str(&component); - record_span(span); + match it.kind { + tt::LitKind::Char => { + if let Ok(c) = unescape_char(&it.text) { + text.extend(c.escape_default()); + } + record_span(it.span); + } + tt::LitKind::Integer | tt::LitKind::Float => format_to!(text, "{}", it.text), + tt::LitKind::Str => { + text.push_str(&it.text); + record_span(it.span); + } + tt::LitKind::StrRaw(_) => { + format_to!(text, "{}", it.text.escape_debug()); + record_span(it.span); + } + tt::LitKind::Byte + | tt::LitKind::ByteStr + | tt::LitKind::ByteStrRaw(_) + | tt::LitKind::CStr + | tt::LitKind::CStrRaw(_) + | tt::LitKind::Err(_) => err = Some(ExpandError::other("unexpected literal")), } } // handle boolean literals @@ -544,9 +545,9 @@ fn concat_bytes_expand( _db: &dyn ExpandDatabase, _arg_id: MacroCallId, tt: &tt::Subtree, - call_site: Span, + _: Span, ) -> ExpandResult { - let mut bytes = Vec::new(); + let mut bytes = String::new(); let mut err = None; let mut span: Option = None; let mut record_span = |s: Span| match &mut span { @@ -556,14 +557,21 @@ fn concat_bytes_expand( }; for (i, t) in tt.token_trees.iter().enumerate() { match t { - tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { - let token = ast::make::tokens::literal(&lit.to_string()); - record_span(lit.span); - match token.kind() { - syntax::SyntaxKind::BYTE => bytes.push(token.text().to_owned()), - syntax::SyntaxKind::BYTE_STRING => { - let components = unquote_byte_string(lit).map_or(vec![], |(it, _)| it); - components.into_iter().for_each(|it| bytes.push(it.to_string())); + tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { text, span, kind, suffix: _ })) => { + record_span(*span); + match kind { + tt::LitKind::Byte => { + if let Ok(b) = unescape_byte(text) { + bytes.extend( + b.escape_ascii().filter_map(|it| char::from_u32(it as u32)), + ); + } + } + tt::LitKind::ByteStr => { + bytes.push_str(text); + } + tt::LitKind::ByteStrRaw(_) => { + bytes.extend(text.escape_debug()); } _ => { err.get_or_insert(mbe::ExpandError::UnexpectedToken.into()); @@ -584,51 +592,49 @@ fn concat_bytes_expand( } } } - let value = tt::Subtree { - delimiter: tt::Delimiter { - open: call_site, - close: call_site, - kind: tt::DelimiterKind::Bracket, - }, - token_trees: { - Itertools::intersperse_with( - bytes.into_iter().map(|it| { - tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { - text: it.into(), - span: span.unwrap_or(call_site), - })) - }), - || { - tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { - char: ',', - spacing: tt::Spacing::Alone, - span: call_site, - })) - }, - ) - .collect() + let span = span.unwrap_or(tt.delimiter.open); + ExpandResult { + value: tt::Subtree { + delimiter: tt::Delimiter::invisible_spanned(span), + token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { + text: bytes.into(), + span, + kind: tt::LitKind::ByteStr, + suffix: None, + }))] + .into(), }, - }; - ExpandResult { value, err } + err, + } } fn concat_bytes_expand_subtree( tree: &tt::Subtree, - bytes: &mut Vec, + bytes: &mut String, mut record_span: impl FnMut(Span), ) -> Result<(), ExpandError> { for (ti, tt) in tree.token_trees.iter().enumerate() { match tt { - tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => { - let lit = ast::make::tokens::literal(&it.to_string()); - match lit.kind() { - syntax::SyntaxKind::BYTE | syntax::SyntaxKind::INT_NUMBER => { - record_span(it.span); - bytes.push(lit.text().to_owned()) - } - _ => { - return Err(mbe::ExpandError::UnexpectedToken.into()); - } + tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { + text, + span, + kind: tt::LitKind::Byte, + suffix: _, + })) => { + if let Ok(b) = unescape_byte(text) { + 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, + span, + kind: tt::LitKind::Integer, + suffix: _, + })) => { + record_span(*span); + if let Ok(b) = text.parse::() { + bytes.extend(b.escape_ascii().filter_map(|it| char::from_u32(it as u32))); } } tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if ti % 2 == 1 && punct.char == ',' => (), @@ -660,7 +666,7 @@ fn concat_idents_expand( } } // FIXME merge spans - let ident = tt::Ident { text: ident.into(), span }; + let ident = tt::Ident { text: ident.into(), span, is_raw: tt::IdentIsRaw::No }; ExpandResult { value: quote!(span =>#ident), err } } @@ -683,11 +689,16 @@ fn relative_file( } } -fn parse_string(tt: &tt::Subtree) -> Result<(String, Span), ExpandError> { +fn parse_string(tt: &tt::Subtree) -> Result<(SmolStr, Span), ExpandError> { tt.token_trees .first() .and_then(|tt| match tt { - tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => unquote_str(it), + tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { + text, + span, + kind: tt::LitKind::Str, + suffix: _, + })) => Some((unescape_str(text), *span)), _ => None, }) .ok_or(mbe::ExpandError::ConversionError.into()) @@ -738,6 +749,8 @@ fn include_bytes_expand( token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { text: r#"b"""#.into(), span, + kind: tt::LitKind::ByteStrRaw(1), + suffix: None, }))]), }; ExpandResult::ok(res) @@ -848,3 +861,17 @@ fn quote_expand( ExpandError::other("quote! is not implemented"), ) } + +fn unescape_str(s: &SmolStr) -> SmolStr { + if s.contains('\\') { + 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() + } else { + s.clone() + } +} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index 9fdf4aa4f7cc7..2896afed084fd 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -86,6 +86,7 @@ pub(crate) fn fixup_syntax( anchor: SpanAnchor { ast_id: FIXUP_DUMMY_AST_ID, ..span.anchor }, ctx: span.ctx, }, + is_raw: tt::IdentIsRaw::No, }); append.insert(node.clone().into(), vec![replacement]); preorder.skip_subtree(); @@ -101,6 +102,7 @@ pub(crate) fn fixup_syntax( Leaf::Ident(Ident { text: "__ra_fixup".into(), span: fake_span(node_range), + is_raw: tt::IdentIsRaw::No }), ]); } @@ -137,7 +139,8 @@ pub(crate) fn fixup_syntax( append.insert(if_token.into(), vec![ Leaf::Ident(Ident { text: "__ra_fixup".into(), - span: fake_span(node_range) + span: fake_span(node_range), + is_raw: tt::IdentIsRaw::No }), ]); } @@ -167,7 +170,8 @@ pub(crate) fn fixup_syntax( append.insert(while_token.into(), vec![ Leaf::Ident(Ident { text: "__ra_fixup".into(), - span: fake_span(node_range) + span: fake_span(node_range), + is_raw: tt::IdentIsRaw::No }), ]); } @@ -214,7 +218,8 @@ pub(crate) fn fixup_syntax( append.insert(match_token.into(), vec![ Leaf::Ident(Ident { text: "__ra_fixup".into(), - span: fake_span(node_range) + span: fake_span(node_range), + is_raw: tt::IdentIsRaw::No }), ]); } @@ -248,7 +253,8 @@ pub(crate) fn fixup_syntax( ].map(|text| Leaf::Ident(Ident { text: text.into(), - span: fake_span(node_range) + span: fake_span(node_range), + is_raw: tt::IdentIsRaw::No }), ); @@ -281,7 +287,8 @@ pub(crate) fn fixup_syntax( append.insert(colon.into(), vec![ Leaf::Ident(Ident { text: "__ra_fixup".into(), - span: fake_span(node_range) + span: fake_span(node_range), + is_raw: tt::IdentIsRaw::No }) ]); } @@ -293,7 +300,8 @@ pub(crate) fn fixup_syntax( append.insert(colon.into(), vec![ Leaf::Ident(Ident { text: "__ra_fixup".into(), - span: fake_span(node_range) + span: fake_span(node_range), + is_raw: tt::IdentIsRaw::No }) ]); } @@ -326,7 +334,8 @@ pub(crate) fn fixup_syntax( append.insert(node.into(), vec![ Leaf::Ident(Ident { text: "__ra_fixup".into(), - span: fake_span(node_range) + span: fake_span(node_range), + is_raw: tt::IdentIsRaw::No }) ]); } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index e7c34e51e857a..c4921da61004c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -59,7 +59,7 @@ pub use span::{HirFileId, MacroCallId, MacroFileId}; pub mod tt { pub use span::Span; - pub use tt::{DelimiterKind, Spacing}; + pub use tt::{DelimiterKind, IdentIsRaw, LitKind, Spacing}; pub type Delimiter = ::tt::Delimiter; pub type DelimSpan = ::tt::DelimSpan; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index ed7d551888756..907e939153ba7 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -316,15 +316,15 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option PathKind::Abs, _ => return None, }, - tt::Leaf::Ident(tt::Ident { text, span }) if text == "$crate" => { + tt::Leaf::Ident(tt::Ident { text, span, .. }) if text == "$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" => { let mut deg = 1; - while let Some(tt::Leaf::Ident(tt::Ident { text, span, .. })) = leaves.next() { + while let Some(tt::Leaf::Ident(tt::Ident { text, span, is_raw })) = leaves.next() { if text != "super" { - segments.push(Name::new(text, span.ctx)); + segments.push(Name::new(text, *is_raw, span.ctx)); break; } deg += 1; @@ -333,13 +333,13 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option PathKind::Crate, tt::Leaf::Ident(ident) => { - segments.push(Name::new(&ident.text, ident.span.ctx)); + segments.push(Name::new(&ident.text, 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.span.ctx)), + ::tt::Leaf::Ident(ident) => Some(Name::new(&ident.text, ident.is_raw, ident.span.ctx)), _ => None, })); Some(ModPath { kind, segments }) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index 67e73f7fc284c..fce9df6722b47 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -82,9 +82,16 @@ impl Name { Name { symbol: Symbol::intern(text), ctx: () } } - pub fn new(text: &str, ctx: SyntaxContextId) -> Name { + pub fn new(text: &str, raw: tt::IdentIsRaw, ctx: SyntaxContextId) -> Name { _ = ctx; - Name { symbol: Symbol::intern(text), ctx: () } + Name { + symbol: if raw.yes() { + Symbol::intern(&format_smolstr!("{}{text}", raw.as_str())) + } else { + Symbol::intern(text) + }, + ctx: (), + } } pub fn new_tuple_field(idx: usize) -> Name { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs index f4fc3b7b3e2da..f1d28450b31e8 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs @@ -3,12 +3,12 @@ use intern::Symbol; use span::Span; -use syntax::format_smolstr; +use tt::IdentIsRaw; use crate::name::Name; pub(crate) const fn dollar_crate(span: Span) -> tt::Ident { - tt::Ident { text: syntax::SmolStr::new_static("$crate"), span } + tt::Ident { text: syntax::SmolStr::new_static("$crate"), span, is_raw: tt::IdentIsRaw::No } } // A helper macro quote macro @@ -101,6 +101,7 @@ macro_rules! __quote { crate::tt::Leaf::Ident(crate::tt::Ident { text: stringify!($tt).into(), span: $span, + is_raw: tt::IdentIsRaw::No, }).into() }] }; @@ -209,23 +210,30 @@ macro_rules! impl_to_to_tokentrees { } impl_to_to_tokentrees! { - span: u32 => self { crate::tt::Literal{text: self.to_string().into(), span} }; - span: usize => self { crate::tt::Literal{text: self.to_string().into(), span} }; - span: i32 => self { crate::tt::Literal{text: self.to_string().into(), span} }; - span: bool => self { crate::tt::Ident{text: self.to_string().into(), span} }; + 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: 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: 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}}; + 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: Name => self { + let (is_raw, s) = IdentIsRaw::split_from_symbol(self.as_str()); + crate::tt::Ident{text: s.into(), 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 } + }; } #[cfg(test)] mod tests { use crate::tt; + use ::tt::IdentIsRaw; use base_db::FileId; use expect_test::expect; use span::{SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; @@ -259,7 +267,8 @@ mod tests { } fn mk_ident(name: &str) -> crate::tt::Ident { - crate::tt::Ident { text: name.into(), span: DUMMY } + let (is_raw, s) = IdentIsRaw::split_from_symbol(name); + crate::tt::Ident { text: s.into(), span: DUMMY, is_raw } } #[test] diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index af60c233e5519..02d92620e05b6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -328,9 +328,11 @@ fn doc_modpath_from_str(link: &str) -> Option { }; let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() { Ok(idx) => Name::new_tuple_field(idx), - Err(_) => { - Name::new(segment.split_once('<').map_or(segment, |it| it.0), SyntaxContextId::ROOT) - } + Err(_) => Name::new( + segment.split_once('<').map_or(segment, |it| it.0), + tt::IdentIsRaw::No, + SyntaxContextId::ROOT, + ), }); Some(ModPath::from_segments(kind, parts)) }; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs index 58e77b95c3292..1b9b78f69182a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs @@ -269,12 +269,13 @@ fn get_doc_string_in_attr(it: &ast::Attr) -> Option { } fn doc_indent(attrs: &hir::Attrs) -> usize { - attrs - .by_key("doc") - .attrs() - .filter_map(|attr| attr.string_value()) // no need to use unescape version here - .flat_map(|s| s.lines()) - .filter_map(|line| line.chars().position(|c| !c.is_whitespace())) - .min() - .unwrap_or(0) + let mut min = !0; + for val in attrs.by_key("doc").attrs().filter_map(|attr| attr.string_value_unescape()) { + if let Some(m) = + val.lines().filter_map(|line| line.chars().position(|c| !c.is_whitespace())).min() + { + min = min.min(m); + } + } + min } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 2006baa30a8c3..701374616ad67 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -240,7 +240,7 @@ fn hover_simple( .flatten() .unique_by(|&(def, _, _)| def) .map(|(def, macro_arm, node)| { - hover_for_definition(sema, file_id, def, &node, macro_arm, config) + dbg!(hover_for_definition(sema, file_id, def, &node, macro_arm, config)) }) .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| { acc.actions.extend(actions); diff --git a/src/tools/rust-analyzer/crates/mbe/Cargo.toml b/src/tools/rust-analyzer/crates/mbe/Cargo.toml index 18444018e1b68..7ce8aadfb3619 100644 --- a/src/tools/rust-analyzer/crates/mbe/Cargo.toml +++ b/src/tools/rust-analyzer/crates/mbe/Cargo.toml @@ -17,6 +17,7 @@ rustc-hash.workspace = true smallvec.workspace = true tracing.workspace = true arrayvec.workspace = true +ra-ap-rustc_lexer.workspace = true # local deps syntax.workspace = true diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs index 27dbc84a2b1aa..6a2f1c236869d 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs @@ -226,13 +226,24 @@ fn invocation_fixtures( *seed } fn make_ident(ident: &str) -> tt::TokenTree { - tt::Leaf::Ident(tt::Ident { span: DUMMY, text: SmolStr::new(ident) }).into() + tt::Leaf::Ident(tt::Ident { + span: DUMMY, + text: SmolStr::new(ident), + is_raw: tt::IdentIsRaw::No, + }) + .into() } fn make_punct(char: char) -> tt::TokenTree { tt::Leaf::Punct(tt::Punct { span: DUMMY, char, spacing: tt::Spacing::Alone }).into() } fn make_literal(lit: &str) -> tt::TokenTree { - tt::Leaf::Literal(tt::Literal { span: DUMMY, text: SmolStr::new(lit) }).into() + tt::Leaf::Literal(tt::Literal { + span: DUMMY, + text: SmolStr::new(lit), + kind: tt::LitKind::Str, + suffix: None, + }) + .into() } fn make_subtree( kind: tt::DelimiterKind, diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs index c09cbd1d071ea..e3359865cb276 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs @@ -2,7 +2,7 @@ //! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}` use span::Span; -use syntax::SmolStr; +use syntax::{format_smolstr, SmolStr}; use tt::Delimiter; use crate::{ @@ -99,6 +99,7 @@ impl Bindings { Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text: SmolStr::new_static("missing"), span, + is_raw: tt::IdentIsRaw::No, }))) } MetaVarKind::Lifetime => { @@ -113,6 +114,7 @@ impl Bindings { tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text: SmolStr::new_static("missing"), span, + is_raw: tt::IdentIsRaw::No, })), ]), })) @@ -121,6 +123,7 @@ impl Bindings { Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text: SmolStr::new_static("\"missing\""), span, + is_raw: tt::IdentIsRaw::No, }))) } } @@ -236,8 +239,10 @@ fn expand_subtree( ctx.nesting.get(ctx.nesting.len() - 1 - depth).map_or(0, |nest| nest.idx); arena.push( tt::Leaf::Literal(tt::Literal { - text: index.to_string().into(), + text: format_smolstr!("{index}"), span: ctx.call_site, + kind: tt::LitKind::Integer, + suffix: None, }) .into(), ); @@ -249,8 +254,10 @@ fn expand_subtree( }); arena.push( tt::Leaf::Literal(tt::Literal { - text: length.to_string().into(), + text: format_smolstr!("{length}"), span: ctx.call_site, + kind: tt::LitKind::Integer, + suffix: None, }) .into(), ); @@ -314,8 +321,10 @@ fn expand_subtree( }; arena.push( tt::Leaf::Literal(tt::Literal { - text: c.to_string().into(), + text: format_smolstr!("{c}"), span: ctx.call_site, + suffix: None, + kind: tt::LitKind::Integer, }) .into(), ); @@ -363,7 +372,12 @@ fn expand_var( token_trees: Box::new([ tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, span: id }) .into(), - tt::Leaf::from(tt::Ident { text: v.clone(), span: id }).into(), + tt::Leaf::from(tt::Ident { + text: v.clone(), + span: id, + is_raw: tt::IdentIsRaw::No, + }) + .into(), ]), } .into(); diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs index b06c6cee12dbd..8ab9269e9523a 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs @@ -6,6 +6,13 @@ //! The tests for this functionality live in another crate: //! `hir_def::macro_expansion_tests::mbe`. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_lexer as rustc_lexer; +#[cfg(feature = "in-rust-tree")] +extern crate rustc_lexer; + mod expander; mod parser; mod syntax_bridge; @@ -27,9 +34,9 @@ pub use ::parser::TopEntryPoint; pub use tt::{Delimiter, DelimiterKind, Punct}; pub use crate::syntax_bridge::{ - parse_exprs_with_sep, parse_to_token_tree, parse_to_token_tree_static_span, - syntax_node_to_token_tree, syntax_node_to_token_tree_modified, token_tree_to_syntax_node, - DocCommentDesugarMode, SpanMapper, + desugar_doc_comment_text, parse_exprs_with_sep, parse_to_token_tree, + parse_to_token_tree_static_span, syntax_node_to_token_tree, syntax_node_to_token_tree_modified, + token_to_literal, token_tree_to_syntax_node, DocCommentDesugarMode, SpanMapper, }; pub use crate::syntax_bridge::dummy_test_span_utils::*; diff --git a/src/tools/rust-analyzer/crates/mbe/src/parser.rs b/src/tools/rust-analyzer/crates/mbe/src/parser.rs index 5c499c06b1525..18af35c1e2900 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/parser.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/parser.rs @@ -205,7 +205,11 @@ fn next_op( tt::TokenTree::Leaf(leaf) => match leaf { tt::Leaf::Ident(ident) if ident.text == "crate" => { // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. - Op::Ident(tt::Ident { text: "$crate".into(), span: ident.span }) + Op::Ident(tt::Ident { + text: "$crate".into(), + span: ident.span, + is_raw: tt::IdentIsRaw::No, + }) } tt::Leaf::Ident(ident) => { let kind = eat_fragment_kind(edition, src, mode)?; @@ -380,9 +384,11 @@ fn parse_metavar_expr(new_meta_vars: bool, src: &mut TtIter<'_, Span>) -> Result fn parse_depth(src: &mut TtIter<'_, Span>) -> Result { if src.len() == 0 { Ok(0) - } else if let tt::Leaf::Literal(lit) = src.expect_literal()? { + } else if let tt::Leaf::Literal(tt::Literal { text, suffix: None, .. }) = + src.expect_literal()? + { // Suffixes are not allowed. - lit.text.parse().map_err(|_| ()) + text.parse().map_err(|_| ()) } else { Err(()) } diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs index 73a04f00d9306..3feddba21061f 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs @@ -4,11 +4,11 @@ use std::fmt; use rustc_hash::{FxHashMap, FxHashSet}; use span::{Edition, SpanAnchor, SpanData, SpanMap}; -use stdx::{never, non_empty_vec::NonEmptyVec}; +use stdx::{format_to, itertools::Itertools, never, non_empty_vec::NonEmptyVec}; use syntax::{ ast::{self, make::tokens::doc_comment}, - AstToken, Parse, PreorderWithTokens, SmolStr, SyntaxElement, SyntaxKind, - SyntaxKind::*, + format_smolstr, AstToken, Parse, PreorderWithTokens, SmolStr, SyntaxElement, + SyntaxKind::{self, *}, SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextSize, WalkEvent, T, }; use tt::{ @@ -317,18 +317,29 @@ where .into() } kind => { - macro_rules! make_leaf { - ($i:ident) => { - tt::$i { span: conv.span_for(abs_range), text: token.to_text(conv) } - .into() + macro_rules! make_ident { + () => { + tt::Ident { + span: conv.span_for(abs_range), + text: token.to_text(conv), + is_raw: tt::IdentIsRaw::No, + } + .into() }; } let leaf: tt::Leaf<_> = match kind { - T![true] | T![false] => make_leaf!(Ident), - IDENT => make_leaf!(Ident), - UNDERSCORE => make_leaf!(Ident), - k if k.is_keyword() => make_leaf!(Ident), - k if k.is_literal() => make_leaf!(Literal), + T![true] | T![false] => make_ident!(), + IDENT => { + let text = token.to_text(conv); + tt::Ident::new(text, conv.span_for(abs_range)).into() + } + UNDERSCORE => make_ident!(), + k if k.is_keyword() => make_ident!(), + k if k.is_literal() => { + let text = token.to_text(conv); + let span = conv.span_for(abs_range); + token_to_literal(text, span).into() + } LIFETIME_IDENT => { let apostrophe = tt::Leaf::from(tt::Punct { char: '\'', @@ -344,6 +355,7 @@ where abs_range.start() + TextSize::of('\''), abs_range.end(), )), + is_raw: tt::IdentIsRaw::No, }); token_trees.push(ident.into()); continue; @@ -388,6 +400,56 @@ where } } +pub fn token_to_literal(text: SmolStr, span: S) -> tt::Literal +where + S: Copy, +{ + use rustc_lexer::LiteralKind; + + let token = rustc_lexer::tokenize(&text).next_tuple(); + let Some((rustc_lexer::Token { + kind: rustc_lexer::TokenKind::Literal { kind, suffix_start }, + .. + },)) = token + else { + return tt::Literal { span, text, kind: tt::LitKind::Err(()), suffix: None }; + }; + + let (kind, start_offset, end_offset) = match kind { + LiteralKind::Int { .. } => (tt::LitKind::Integer, 0, 0), + LiteralKind::Float { .. } => (tt::LitKind::Float, 0, 0), + LiteralKind::Char { terminated } => (tt::LitKind::Char, 1, terminated as usize), + LiteralKind::Byte { terminated } => (tt::LitKind::Byte, 2, terminated as usize), + LiteralKind::Str { terminated } => (tt::LitKind::Str, 1, terminated as usize), + LiteralKind::ByteStr { terminated } => (tt::LitKind::ByteStr, 2, terminated as usize), + LiteralKind::CStr { terminated } => (tt::LitKind::CStr, 2, terminated as usize), + LiteralKind::RawStr { n_hashes } => ( + tt::LitKind::StrRaw(n_hashes.unwrap_or_default()), + 2 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + LiteralKind::RawByteStr { n_hashes } => ( + tt::LitKind::ByteStrRaw(n_hashes.unwrap_or_default()), + 3 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + LiteralKind::RawCStr { n_hashes } => ( + tt::LitKind::CStrRaw(n_hashes.unwrap_or_default()), + 3 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + }; + + let (lit, suffix) = text.split_at(suffix_start as usize); + let lit = &lit[start_offset..lit.len() - end_offset]; + let suffix = match suffix { + "" | "_" => None, + suffix => Some(Box::new(suffix.into())), + }; + + tt::Literal { span, text: lit.into(), kind, suffix } +} + fn is_single_token_op(kind: SyntaxKind) -> bool { matches!( kind, @@ -421,16 +483,10 @@ fn is_single_token_op(kind: SyntaxKind) -> bool { /// That is, strips leading `///` (or `/**`, etc) /// and strips the ending `*/` /// And then quote the string, which is needed to convert to `tt::Literal` -fn doc_comment_text(comment: &ast::Comment, mode: DocCommentDesugarMode) -> SmolStr { - let prefix_len = comment.prefix().len(); - let mut text = &comment.text()[prefix_len..]; - - // Remove ending "*/" - if comment.kind().shape == ast::CommentShape::Block { - text = &text[0..text.len() - 2]; - } - - let text = match mode { +/// +/// Note that proc-macros desugar with string literals where as macro_rules macros desugar with raw string literals. +pub fn desugar_doc_comment_text(text: &str, mode: DocCommentDesugarMode) -> (SmolStr, tt::LitKind) { + match mode { DocCommentDesugarMode::Mbe => { let mut num_of_hashes = 0; let mut count = 0; @@ -444,14 +500,13 @@ fn doc_comment_text(comment: &ast::Comment, mode: DocCommentDesugarMode) -> Smol } // Quote raw string with delimiters - // Note that `tt::Literal` expect an escaped string - format!(r#"r{delim}"{text}"{delim}"#, delim = "#".repeat(num_of_hashes)) + (text.into(), tt::LitKind::StrRaw(num_of_hashes)) } // Quote string with delimiters - // Note that `tt::Literal` expect an escaped string - DocCommentDesugarMode::ProcMacro => format!(r#""{}""#, text.escape_debug()), - }; - text.into() + DocCommentDesugarMode::ProcMacro => { + (format_smolstr!("{}", text.escape_debug()), tt::LitKind::Str) + } + } } fn convert_doc_comment( @@ -463,8 +518,13 @@ fn convert_doc_comment( let comment = ast::Comment::cast(token.clone())?; let doc = comment.kind().doc?; - let mk_ident = - |s: &str| tt::TokenTree::from(tt::Leaf::from(tt::Ident { text: s.into(), span })); + let mk_ident = |s: &str| { + tt::TokenTree::from(tt::Leaf::from(tt::Ident { + text: s.into(), + span, + is_raw: tt::IdentIsRaw::No, + })) + }; let mk_punct = |c: char| { tt::TokenTree::from(tt::Leaf::from(tt::Punct { @@ -475,7 +535,15 @@ fn convert_doc_comment( }; let mk_doc_literal = |comment: &ast::Comment| { - let lit = tt::Literal { text: doc_comment_text(comment, mode), span }; + let prefix_len = comment.prefix().len(); + let mut text = &comment.text()[prefix_len..]; + + // Remove ending "*/" + if comment.kind().shape == ast::CommentShape::Block { + text = &text[0..text.len() - 2]; + } + let (text, kind) = desugar_doc_comment_text(text, mode); + let lit = tt::Literal { text, span, kind, suffix: None }; tt::TokenTree::from(tt::Leaf::from(lit)) }; @@ -902,16 +970,17 @@ fn delim_to_str(d: tt::DelimiterKind, closing: bool) -> Option<&'static str> { impl TtTreeSink<'_, Ctx> where - SpanData: Copy, + SpanData: Copy + fmt::Debug, { /// Parses a float literal as if it was a one to two name ref nodes with a dot inbetween. /// This occurs when a float literal is used as a field access. fn float_split(&mut self, has_pseudo_dot: bool) { let (text, span) = match self.cursor.token_tree() { - Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Literal(lit), _)) => { - (lit.text.as_str(), lit.span) - } - _ => unreachable!(), + Some(tt::buffer::TokenTreeRef::Leaf( + tt::Leaf::Literal(tt::Literal { text, span, kind: tt::LitKind::Float, suffix: _ }), + _, + )) => (text.as_str(), *span), + tt => unreachable!("{tt:?}"), }; // FIXME: Span splitting match text.split_once('.') { @@ -954,7 +1023,7 @@ where } let mut last = self.cursor; - for _ in 0..n_tokens { + 'tokens: for _ in 0..n_tokens { let tmp: u8; if self.cursor.eof() { break; @@ -962,23 +1031,36 @@ where last = self.cursor; let (text, span) = loop { break match self.cursor.token_tree() { - Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => { - // Mark the range if needed - let (text, span) = match leaf { - tt::Leaf::Ident(ident) => (ident.text.as_str(), ident.span), - tt::Leaf::Punct(punct) => { - assert!(punct.char.is_ascii()); - tmp = punct.char as u8; - ( - std::str::from_utf8(std::slice::from_ref(&tmp)).unwrap(), - punct.span, - ) + Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => match leaf { + tt::Leaf::Ident(ident) => { + if ident.is_raw.yes() { + self.buf.push_str("r#"); + self.text_pos += TextSize::of("r#"); } - tt::Leaf::Literal(lit) => (lit.text.as_str(), lit.span), - }; - self.cursor = self.cursor.bump(); - (text, span) - } + let r = (ident.text.as_str(), ident.span); + self.cursor = self.cursor.bump(); + r + } + tt::Leaf::Punct(punct) => { + assert!(punct.char.is_ascii()); + tmp = punct.char as u8; + let r = ( + std::str::from_utf8(std::slice::from_ref(&tmp)).unwrap(), + punct.span, + ); + self.cursor = self.cursor.bump(); + r + } + tt::Leaf::Literal(lit) => { + let buf_l = self.buf.len(); + format_to!(self.buf, "{lit}"); + debug_assert_ne!(self.buf.len() - buf_l, 0); + self.text_pos += TextSize::new((self.buf.len() - buf_l) as u32); + self.token_map.push(self.text_pos, lit.span); + self.cursor = self.cursor.bump(); + continue 'tokens; + } + }, Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => { self.cursor = self.cursor.subtree().unwrap(); match delim_to_str(subtree.delimiter.kind, false) { diff --git a/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs b/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs index 3f70149aa5eae..bf5494d37149b 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs @@ -35,20 +35,21 @@ pub(crate) fn to_parser_input(buffer: &TokenBuffer<'_, S>) Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => { match leaf { tt::Leaf::Literal(lit) => { - let is_negated = lit.text.starts_with('-'); - let inner_text = &lit.text[if is_negated { 1 } else { 0 }..]; - - let kind = parser::LexedStr::single_token(inner_text) - .map(|(kind, _error)| kind) - .filter(|kind| { - kind.is_literal() - && (!is_negated || matches!(kind, FLOAT_NUMBER | INT_NUMBER)) - }) - .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &lit)); - + let kind = match lit.kind { + tt::LitKind::Byte => SyntaxKind::BYTE, + tt::LitKind::Char => SyntaxKind::CHAR, + tt::LitKind::Integer => SyntaxKind::INT_NUMBER, + tt::LitKind::Float => SyntaxKind::FLOAT_NUMBER, + tt::LitKind::Str | tt::LitKind::StrRaw(_) => SyntaxKind::STRING, + tt::LitKind::ByteStr | tt::LitKind::ByteStrRaw(_) => { + SyntaxKind::BYTE_STRING + } + tt::LitKind::CStr | tt::LitKind::CStrRaw(_) => SyntaxKind::C_STRING, + tt::LitKind::Err(_) => SyntaxKind::ERROR, + }; res.push(kind); - if kind == FLOAT_NUMBER && !inner_text.ends_with('.') { + if kind == FLOAT_NUMBER && !lit.text.ends_with('.') { // Tag the token as joint if it is float with a fractional part // we use this jointness to inform the parser about what token split // event to emit when we encounter a float literal in a field access @@ -58,6 +59,7 @@ pub(crate) fn to_parser_input(buffer: &TokenBuffer<'_, S>) tt::Leaf::Ident(ident) => match ident.text.as_ref() { "_" => res.push(T![_]), i if i.starts_with('\'') => res.push(LIFETIME_IDENT), + _ if ident.is_raw.yes() => res.push(IDENT), _ => match SyntaxKind::from_keyword(&ident.text) { Some(kind) => res.push(kind), None => { diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs index fa3ba9bbfcd73..b5f3d0c3aacd5 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs @@ -19,8 +19,10 @@ pub const VERSION_CHECK_VERSION: u32 = 1; pub const ENCODE_CLOSE_SPAN_VERSION: u32 = 2; pub const HAS_GLOBAL_SPANS: u32 = 3; pub const RUST_ANALYZER_SPAN_SUPPORT: u32 = 4; +/// Whether literals encode their kind as an additional u32 field and idents their rawness as a u32 field +pub const EXTENDED_LEAF_DATA: u32 = 5; -pub const CURRENT_API_VERSION: u32 = RUST_ANALYZER_SPAN_SUPPORT; +pub const CURRENT_API_VERSION: u32 = EXTENDED_LEAF_DATA; #[derive(Debug, Serialize, Deserialize)] pub enum Request { @@ -178,6 +180,7 @@ mod tests { anchor, ctx: SyntaxContextId::ROOT, }, + is_raw: tt::IdentIsRaw::No, } .into(), ), @@ -185,26 +188,28 @@ mod tests { Ident { text: "Foo".into(), span: Span { - range: TextRange::at(TextSize::new(5), TextSize::of("Foo")), + range: TextRange::at(TextSize::new(5), TextSize::of("r#Foo")), anchor, ctx: SyntaxContextId::ROOT, }, + is_raw: tt::IdentIsRaw::Yes, } .into(), ), TokenTree::Leaf(Leaf::Literal(Literal { - text: "Foo".into(), - + text: "\"Foo\"".into(), span: Span { - range: TextRange::at(TextSize::new(8), TextSize::of("Foo")), + range: TextRange::at(TextSize::new(10), TextSize::of("\"Foo\"")), anchor, ctx: SyntaxContextId::ROOT, }, + kind: tt::LitKind::Str, + suffix: None, })), TokenTree::Leaf(Leaf::Punct(Punct { char: '@', span: Span { - range: TextRange::at(TextSize::new(11), TextSize::of('@')), + range: TextRange::at(TextSize::new(13), TextSize::of('@')), anchor, ctx: SyntaxContextId::ROOT, }, @@ -213,18 +218,27 @@ mod tests { TokenTree::Subtree(Subtree { delimiter: Delimiter { open: Span { - range: TextRange::at(TextSize::new(12), TextSize::of('{')), + range: TextRange::at(TextSize::new(14), TextSize::of('{')), anchor, ctx: SyntaxContextId::ROOT, }, close: Span { - range: TextRange::at(TextSize::new(13), TextSize::of('}')), + range: TextRange::at(TextSize::new(19), TextSize::of('}')), anchor, ctx: SyntaxContextId::ROOT, }, kind: DelimiterKind::Brace, }, - token_trees: Box::new([]), + token_trees: Box::new([TokenTree::Leaf(Leaf::Literal(Literal { + text: "0".into(), + span: Span { + range: TextRange::at(TextSize::new(15), TextSize::of("0u32")), + anchor, + ctx: SyntaxContextId::ROOT, + }, + kind: tt::LitKind::Integer, + suffix: Some(Box::new("u32".into())), + }))]), }), ]); @@ -236,7 +250,7 @@ mod tests { ctx: SyntaxContextId::ROOT, }, close: Span { - range: TextRange::empty(TextSize::new(13)), + range: TextRange::empty(TextSize::new(19)), anchor, ctx: SyntaxContextId::ROOT, }, diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs index 11fd7596f2b52..7f5afdb7270fe 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs @@ -43,7 +43,7 @@ use serde::{Deserialize, Serialize}; use span::{ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContextId}; use text_size::TextRange; -use crate::msg::ENCODE_CLOSE_SPAN_VERSION; +use crate::msg::{ENCODE_CLOSE_SPAN_VERSION, EXTENDED_LEAF_DATA}; pub type SpanDataIndexMap = indexmap::IndexSet>; @@ -108,6 +108,8 @@ struct SubtreeRepr { struct LiteralRepr { id: TokenId, text: u32, + suffix: u32, + kind: u16, } struct PunctRepr { @@ -119,6 +121,7 @@ struct PunctRepr { struct IdentRepr { id: TokenId, text: u32, + is_raw: bool, } impl FlatTree { @@ -147,9 +150,17 @@ impl FlatTree { } else { write_vec(w.subtree, SubtreeRepr::write) }, - literal: write_vec(w.literal, LiteralRepr::write), + literal: if version >= EXTENDED_LEAF_DATA { + write_vec(w.literal, LiteralRepr::write_with_kind) + } else { + write_vec(w.literal, LiteralRepr::write) + }, punct: write_vec(w.punct, PunctRepr::write), - ident: write_vec(w.ident, IdentRepr::write), + ident: if version >= EXTENDED_LEAF_DATA { + write_vec(w.ident, IdentRepr::write_with_rawness) + } else { + write_vec(w.ident, IdentRepr::write) + }, token_tree: w.token_tree, text: w.text, } @@ -176,9 +187,17 @@ impl FlatTree { } else { write_vec(w.subtree, SubtreeRepr::write) }, - literal: write_vec(w.literal, LiteralRepr::write), + literal: if version >= EXTENDED_LEAF_DATA { + write_vec(w.literal, LiteralRepr::write_with_kind) + } else { + write_vec(w.literal, LiteralRepr::write) + }, punct: write_vec(w.punct, PunctRepr::write), - ident: write_vec(w.ident, IdentRepr::write), + ident: if version >= EXTENDED_LEAF_DATA { + write_vec(w.ident, IdentRepr::write_with_rawness) + } else { + write_vec(w.ident, IdentRepr::write) + }, token_tree: w.token_tree, text: w.text, } @@ -195,9 +214,17 @@ impl FlatTree { } else { read_vec(self.subtree, SubtreeRepr::read) }, - literal: read_vec(self.literal, LiteralRepr::read), + literal: if version >= EXTENDED_LEAF_DATA { + read_vec(self.literal, LiteralRepr::read_with_kind) + } else { + read_vec(self.literal, LiteralRepr::read) + }, punct: read_vec(self.punct, PunctRepr::read), - ident: read_vec(self.ident, IdentRepr::read), + ident: if version >= EXTENDED_LEAF_DATA { + read_vec(self.ident, IdentRepr::read_with_rawness) + } else { + read_vec(self.ident, IdentRepr::read) + }, token_tree: self.token_tree, text: self.text, span_data_table, @@ -212,9 +239,17 @@ impl FlatTree { } else { read_vec(self.subtree, SubtreeRepr::read) }, - literal: read_vec(self.literal, LiteralRepr::read), + literal: if version >= EXTENDED_LEAF_DATA { + read_vec(self.literal, LiteralRepr::read_with_kind) + } else { + read_vec(self.literal, LiteralRepr::read) + }, punct: read_vec(self.punct, PunctRepr::read), - ident: read_vec(self.ident, IdentRepr::read), + ident: if version >= EXTENDED_LEAF_DATA { + read_vec(self.ident, IdentRepr::read_with_rawness) + } else { + read_vec(self.ident, IdentRepr::read) + }, token_tree: self.token_tree, text: self.text, span_data_table: &(), @@ -280,14 +315,20 @@ impl LiteralRepr { [self.id.0, self.text] } fn read([id, text]: [u32; 2]) -> LiteralRepr { - LiteralRepr { id: TokenId(id), text } + LiteralRepr { id: TokenId(id), text, kind: 0, suffix: !0 } + } + fn write_with_kind(self) -> [u32; 4] { + [self.id.0, self.text, self.kind as u32, self.suffix] + } + fn read_with_kind([id, text, kind, suffix]: [u32; 4]) -> LiteralRepr { + LiteralRepr { id: TokenId(id), text, kind: kind as u16, suffix } } } impl PunctRepr { fn write(self) -> [u32; 3] { let spacing = match self.spacing { - tt::Spacing::Alone => 0, + tt::Spacing::Alone | tt::Spacing::JointHidden => 0, tt::Spacing::Joint => 1, }; [self.id.0, self.char as u32, spacing] @@ -307,7 +348,13 @@ impl IdentRepr { [self.id.0, self.text] } fn read(data: [u32; 2]) -> IdentRepr { - IdentRepr { id: TokenId(data[0]), text: data[1] } + IdentRepr { id: TokenId(data[0]), text: data[1], is_raw: false } + } + fn write_with_rawness(self) -> [u32; 3] { + [self.id.0, self.text, self.is_raw as u32] + } + fn read_with_rawness([id, text, is_raw]: [u32; 3]) -> IdentRepr { + IdentRepr { id: TokenId(id), text, is_raw: is_raw == 1 } } } @@ -380,7 +427,25 @@ impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> { let idx = self.literal.len() as u32; let text = self.intern(&lit.text); let id = self.token_id_of(lit.span); - self.literal.push(LiteralRepr { id, text }); + let suffix = lit.suffix.as_ref().map(|s| self.intern(s)).unwrap_or(!0); + self.literal.push(LiteralRepr { + id, + text, + kind: u16::from_le_bytes(match lit.kind { + tt::LitKind::Err(_) => [0, 0], + tt::LitKind::Byte => [1, 0], + tt::LitKind::Char => [2, 0], + tt::LitKind::Integer => [3, 0], + tt::LitKind::Float => [4, 0], + tt::LitKind::Str => [5, 0], + tt::LitKind::StrRaw(r) => [6, r], + tt::LitKind::ByteStr => [7, 0], + tt::LitKind::ByteStrRaw(r) => [8, r], + tt::LitKind::CStr => [9, 0], + tt::LitKind::CStrRaw(r) => [10, r], + }), + suffix, + }); idx << 2 | 0b01 } tt::Leaf::Punct(punct) => { @@ -393,7 +458,11 @@ impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> { let idx = self.ident.len() as u32; let text = self.intern(&ident.text); let id = self.token_id_of(ident.span); - self.ident.push(IdentRepr { id, text }); + self.ident.push(IdentRepr { + id, + text, + is_raw: ident.is_raw == tt::IdentIsRaw::Yes, + }); idx << 2 | 0b11 } }, @@ -457,10 +526,32 @@ impl<'span, S: InternableSpan> Reader<'span, S> { // that this unwrap doesn't fire. 0b00 => res[idx].take().unwrap().into(), 0b01 => { + use tt::LitKind::*; let repr = &self.literal[idx]; tt::Leaf::Literal(tt::Literal { text: self.text[repr.text as usize].as_str().into(), span: read_span(repr.id), + kind: match u16::to_le_bytes(repr.kind) { + [0, _] => Err(()), + [1, _] => Byte, + [2, _] => Char, + [3, _] => Integer, + [4, _] => Float, + [5, _] => Str, + [6, r] => StrRaw(r), + [7, _] => ByteStr, + [8, r] => ByteStrRaw(r), + [9, _] => CStr, + [10, r] => CStrRaw(r), + _ => unreachable!(), + }, + suffix: if repr.suffix != !0 { + Some(Box::new( + self.text[repr.suffix as usize].as_str().into(), + )) + } else { + None + }, }) .into() } @@ -478,6 +569,11 @@ impl<'span, S: InternableSpan> Reader<'span, S> { tt::Leaf::Ident(tt::Ident { text: self.text[repr.text as usize].as_str().into(), span: read_span(repr.id), + is_raw: if repr.is_raw { + tt::IdentIsRaw::Yes + } else { + tt::IdentIsRaw::No + }, }) .into() } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs index a1707364f3c21..749a7760592b5 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs @@ -1,6 +1,5 @@ //! Exports a few trivial procedural macros for testing. - #![feature(proc_macro_span, proc_macro_def_site)] #![allow(clippy::all)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs index e8b340a43d305..68e0f85978e0c 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs @@ -49,58 +49,39 @@ fn spacing_to_internal(spacing: proc_macro::Spacing) -> Spacing { #[allow(unused)] fn spacing_to_external(spacing: Spacing) -> proc_macro::Spacing { match spacing { - Spacing::Alone => proc_macro::Spacing::Alone, + Spacing::Alone | Spacing::JointHidden => proc_macro::Spacing::Alone, Spacing::Joint => proc_macro::Spacing::Joint, } } -/// Invokes the callback with a `&[&str]` consisting of each part of the -/// literal's representation. This is done to allow the `ToString` and -/// `Display` implementations to borrow references to symbol values, and -/// both be optimized to reduce overhead. -fn literal_with_stringify_parts( - literal: &bridge::Literal, - interner: SymbolInternerRef, - f: impl FnOnce(&[&str]) -> R, -) -> R { - /// Returns a string containing exactly `num` '#' characters. - /// Uses a 256-character source string literal which is always safe to - /// index with a `u8` index. - fn get_hashes_str(num: u8) -> &'static str { - const HASHES: &str = "\ - ################################################################\ - ################################################################\ - ################################################################\ - ################################################################\ - "; - const _: () = assert!(HASHES.len() == 256); - &HASHES[..num as usize] +fn literal_kind_to_external(kind: tt::LitKind) -> bridge::LitKind { + match kind { + tt::LitKind::Byte => bridge::LitKind::Byte, + tt::LitKind::Char => bridge::LitKind::Char, + tt::LitKind::Integer => bridge::LitKind::Integer, + tt::LitKind::Float => bridge::LitKind::Float, + tt::LitKind::Str => bridge::LitKind::Str, + tt::LitKind::StrRaw(r) => bridge::LitKind::StrRaw(r), + tt::LitKind::ByteStr => bridge::LitKind::ByteStr, + tt::LitKind::ByteStrRaw(r) => bridge::LitKind::ByteStrRaw(r), + tt::LitKind::CStr => bridge::LitKind::CStr, + tt::LitKind::CStrRaw(r) => bridge::LitKind::CStrRaw(r), + tt::LitKind::Err(_) => bridge::LitKind::ErrWithGuar, } +} - { - let symbol = &*literal.symbol.text(interner); - let suffix = &*literal.suffix.map(|s| s.text(interner)).unwrap_or_default(); - match literal.kind { - bridge::LitKind::Byte => f(&["b'", symbol, "'", suffix]), - bridge::LitKind::Char => f(&["'", symbol, "'", suffix]), - bridge::LitKind::Str => f(&["\"", symbol, "\"", suffix]), - bridge::LitKind::StrRaw(n) => { - let hashes = get_hashes_str(n); - f(&["r", hashes, "\"", symbol, "\"", hashes, suffix]) - } - bridge::LitKind::ByteStr => f(&["b\"", symbol, "\"", suffix]), - bridge::LitKind::ByteStrRaw(n) => { - let hashes = get_hashes_str(n); - f(&["br", hashes, "\"", symbol, "\"", hashes, suffix]) - } - bridge::LitKind::CStr => f(&["c\"", symbol, "\"", suffix]), - bridge::LitKind::CStrRaw(n) => { - let hashes = get_hashes_str(n); - f(&["cr", hashes, "\"", symbol, "\"", hashes, suffix]) - } - bridge::LitKind::Integer | bridge::LitKind::Float | bridge::LitKind::ErrWithGuar => { - f(&[symbol, suffix]) - } - } +fn literal_kind_to_internal(kind: bridge::LitKind) -> tt::LitKind { + match kind { + bridge::LitKind::Byte => tt::LitKind::Byte, + bridge::LitKind::Char => tt::LitKind::Char, + bridge::LitKind::Str => tt::LitKind::Str, + bridge::LitKind::StrRaw(r) => tt::LitKind::StrRaw(r), + bridge::LitKind::ByteStr => tt::LitKind::ByteStr, + bridge::LitKind::ByteStrRaw(r) => tt::LitKind::ByteStrRaw(r), + bridge::LitKind::CStr => tt::LitKind::CStr, + bridge::LitKind::CStrRaw(r) => tt::LitKind::CStrRaw(r), + bridge::LitKind::Integer => tt::LitKind::Integer, + bridge::LitKind::Float => tt::LitKind::Float, + bridge::LitKind::ErrWithGuar => tt::LitKind::Err(()), } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index bb174ba1b2243..1a71f39612d3b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -15,7 +15,7 @@ use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER}; use tt::{TextRange, TextSize}; use crate::server_impl::{ - delim_to_external, delim_to_internal, literal_with_stringify_parts, + delim_to_external, delim_to_internal, literal_kind_to_external, literal_kind_to_internal, token_stream::TokenStreamBuilder, Symbol, SymbolInternerRef, SYMBOL_INTERNER, }; mod tt { @@ -171,20 +171,24 @@ impl server::TokenStream for RaSpanServer { bridge::TokenTree::Ident(ident) => { let text = ident.sym.text(self.interner); - let text = - if ident.is_raw { ::tt::SmolStr::from_iter(["r#", &text]) } else { text }; - let ident: tt::Ident = tt::Ident { text, span: ident.span }; + let ident: tt::Ident = tt::Ident { + text, + span: ident.span, + is_raw: if ident.is_raw { tt::IdentIsRaw::Yes } else { tt::IdentIsRaw::No }, + }; let leaf = tt::Leaf::from(ident); let tree = tt::TokenTree::from(leaf); Self::TokenStream::from_iter(iter::once(tree)) } bridge::TokenTree::Literal(literal) => { - let text = literal_with_stringify_parts(&literal, self.interner, |parts| { - ::tt::SmolStr::from_iter(parts.iter().copied()) - }); + let literal = tt::Literal { + text: literal.symbol.text(self.interner), + suffix: literal.suffix.map(|it| Box::new(it.text(self.interner))), + span: literal.span, + kind: literal_kind_to_internal(literal.kind), + }; - let literal = tt::Literal { text, span: literal.span }; let leaf: tt::Leaf = tt::Leaf::from(literal); let tree = tt::TokenTree::from(leaf); Self::TokenStream::from_iter(iter::once(tree)) @@ -250,23 +254,18 @@ impl server::TokenStream for RaSpanServer { .into_iter() .map(|tree| match tree { tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { - bridge::TokenTree::Ident(match ident.text.strip_prefix("r#") { - Some(text) => bridge::Ident { - sym: Symbol::intern(self.interner, text), - is_raw: true, - span: ident.span, - }, - None => bridge::Ident { - sym: Symbol::intern(self.interner, &ident.text), - is_raw: false, - span: ident.span, - }, + bridge::TokenTree::Ident(bridge::Ident { + sym: Symbol::intern(self.interner, &ident.text), + is_raw: ident.is_raw.yes(), + span: ident.span, }) } tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { bridge::TokenTree::Literal(bridge::Literal { span: lit.span, - ..server::FreeFunctions::literal_from_str(self, &lit.text).unwrap() + kind: literal_kind_to_external(lit.kind), + symbol: Symbol::intern(self.interner, &lit.text), + suffix: lit.suffix.map(|it| Symbol::intern(self.interner, &it)), }) } tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs index 12edacbe39dc6..94d5748b0870f 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -8,7 +8,7 @@ use std::{ use proc_macro::bridge::{self, server}; use crate::server_impl::{ - delim_to_external, delim_to_internal, literal_with_stringify_parts, + delim_to_external, delim_to_internal, literal_kind_to_external, literal_kind_to_internal, token_stream::TokenStreamBuilder, Symbol, SymbolInternerRef, SYMBOL_INTERNER, }; mod tt { @@ -25,10 +25,8 @@ mod tt { } type Group = tt::Subtree; type TokenTree = tt::TokenTree; -#[allow(unused)] type Punct = tt::Punct; type Spacing = tt::Spacing; -#[allow(unused)] type Literal = tt::Literal; type Span = tt::TokenId; type TokenStream = crate::server_impl::TokenStream; @@ -162,20 +160,23 @@ impl server::TokenStream for TokenIdServer { bridge::TokenTree::Ident(ident) => { let text = ident.sym.text(self.interner); - let text = - if ident.is_raw { ::tt::SmolStr::from_iter(["r#", &text]) } else { text }; - let ident: tt::Ident = tt::Ident { text, span: ident.span }; + let ident: tt::Ident = tt::Ident { + text, + span: ident.span, + is_raw: if ident.is_raw { tt::IdentIsRaw::Yes } else { tt::IdentIsRaw::No }, + }; let leaf = tt::Leaf::from(ident); let tree = TokenTree::from(leaf); Self::TokenStream::from_iter(iter::once(tree)) } bridge::TokenTree::Literal(literal) => { - let text = literal_with_stringify_parts(&literal, self.interner, |parts| { - ::tt::SmolStr::from_iter(parts.iter().copied()) - }); - - let literal = tt::Literal { text, span: literal.span }; + let literal = Literal { + text: literal.symbol.text(self.interner), + suffix: literal.suffix.map(|it| Box::new(it.text(self.interner))), + span: literal.span, + kind: literal_kind_to_internal(literal.kind), + }; let leaf = tt::Leaf::from(literal); let tree = TokenTree::from(leaf); @@ -183,7 +184,7 @@ impl server::TokenStream for TokenIdServer { } bridge::TokenTree::Punct(p) => { - let punct = tt::Punct { + let punct = Punct { char: p.ch as char, spacing: if p.joint { Spacing::Joint } else { Spacing::Alone }, span: p.span, @@ -238,16 +239,17 @@ impl server::TokenStream for TokenIdServer { .map(|tree| match tree { tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { bridge::TokenTree::Ident(bridge::Ident { - sym: Symbol::intern(self.interner, ident.text.trim_start_matches("r#")), - is_raw: ident.text.starts_with("r#"), + sym: Symbol::intern(self.interner, &ident.text), + is_raw: ident.is_raw.yes(), span: ident.span, }) } tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { bridge::TokenTree::Literal(bridge::Literal { span: lit.span, - ..server::FreeFunctions::literal_from_str(self, &lit.text) - .unwrap_or_else(|_| panic!("`{}`", lit.text)) + kind: literal_kind_to_external(lit.kind), + symbol: Symbol::intern(self.interner, &lit.text), + suffix: lit.suffix.map(|it| Symbol::intern(self.interner, &it)), }) } tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => { @@ -383,10 +385,12 @@ mod tests { tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text: "struct".into(), span: tt::TokenId(0), + is_raw: tt::IdentIsRaw::No, })), tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text: "T".into(), span: tt::TokenId(0), + is_raw: tt::IdentIsRaw::No, })), tt::TokenTree::Subtree(tt::Subtree { delimiter: tt::Delimiter { @@ -411,6 +415,7 @@ mod tests { kind: tt::DelimiterKind::Parenthesis, }, token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { + is_raw: tt::IdentIsRaw::No, text: "a".into(), span: tt::TokenId(0), }))]), @@ -430,6 +435,7 @@ mod tests { tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text: "_".into(), span: tt::TokenId(0), + is_raw: tt::IdentIsRaw::No, })) ); } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs index 6334282538089..dc6e71163b2f2 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs @@ -21,20 +21,20 @@ fn test_derive_error() { assert_expand( "DeriveError", r#"struct S;"#, - expect![[r##" + expect![[r#" SUBTREE $$ 1 1 IDENT compile_error 1 PUNCH ! [alone] 1 SUBTREE () 1 1 - LITERAL "#[derive(DeriveError)] struct S ;"1 - PUNCH ; [alone] 1"##]], - expect![[r##" + LITERAL Str #[derive(DeriveError)] struct S ; 1 + PUNCH ; [alone] 1"#]], + expect![[r#" SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 IDENT compile_error 42:2@0..100#0 PUNCH ! [alone] 42:2@0..100#0 SUBTREE () 42:2@0..100#0 42:2@0..100#0 - LITERAL "#[derive(DeriveError)] struct S ;"42:2@0..100#0 - PUNCH ; [alone] 42:2@0..100#0"##]], + LITERAL Str #[derive(DeriveError)] struct S ; 42:2@0..100#0 + PUNCH ; [alone] 42:2@0..100#0"#]], ); } @@ -47,18 +47,18 @@ fn test_fn_like_macro_noop() { SUBTREE $$ 1 1 IDENT ident 1 PUNCH , [alone] 1 - LITERAL 01 + LITERAL Integer 0 1 PUNCH , [alone] 1 - LITERAL 11 + LITERAL Integer 1 1 PUNCH , [alone] 1 SUBTREE [] 1 1"#]], expect![[r#" SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 IDENT ident 42:2@0..5#0 PUNCH , [alone] 42:2@5..6#0 - LITERAL 042:2@7..8#0 + LITERAL Integer 0 42:2@7..8#0 PUNCH , [alone] 42:2@8..9#0 - LITERAL 142:2@10..11#0 + LITERAL Integer 1 42:2@10..11#0 PUNCH , [alone] 42:2@11..12#0 SUBTREE [] 42:2@13..14#0 42:2@14..15#0"#]], ); @@ -135,22 +135,22 @@ fn test_fn_like_mk_literals() { r#""#, expect![[r#" SUBTREE $$ 1 1 - LITERAL b"byte_string"1 - LITERAL 'c'1 - LITERAL "string"1 - LITERAL 3.14f641 - LITERAL 3.141 - LITERAL 123i641 - LITERAL 1231"#]], + LITERAL ByteStr byte_string 1 + LITERAL Char c 1 + LITERAL Str string 1 + LITERAL Float 3.14f64 1 + LITERAL Float 3.14 1 + LITERAL Integer 123i64 1 + LITERAL Integer 123 1"#]], expect![[r#" SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - LITERAL b"byte_string"42:2@0..100#0 - LITERAL 'c'42:2@0..100#0 - LITERAL "string"42:2@0..100#0 - LITERAL 3.14f6442:2@0..100#0 - LITERAL 3.1442:2@0..100#0 - LITERAL 123i6442:2@0..100#0 - LITERAL 12342:2@0..100#0"#]], + LITERAL ByteStr byte_string 42:2@0..100#0 + LITERAL Char c 42:2@0..100#0 + LITERAL Str string 42:2@0..100#0 + LITERAL Float 3.14f64 42:2@0..100#0 + LITERAL Float 3.14 42:2@0..100#0 + LITERAL Integer 123i64 42:2@0..100#0 + LITERAL Integer 123 42:2@0..100#0"#]], ); } @@ -175,50 +175,50 @@ fn test_fn_like_macro_clone_literals() { assert_expand( "fn_like_clone_tokens", r###"1u16, 2_u32, -4i64, 3.14f32, "hello bridge", "suffixed"suffix, r##"raw"##, 'a', b'b', c"null""###, - expect![[r###" + expect![[r#" SUBTREE $$ 1 1 - LITERAL 1u161 + LITERAL Integer 1u16 1 PUNCH , [alone] 1 - LITERAL 2_u321 + LITERAL Integer 2_u32 1 PUNCH , [alone] 1 PUNCH - [alone] 1 - LITERAL 4i641 + LITERAL Integer 4i64 1 PUNCH , [alone] 1 - LITERAL 3.14f321 + LITERAL Float 3.14f32 1 PUNCH , [alone] 1 - LITERAL "hello bridge"1 + LITERAL Str hello bridge 1 PUNCH , [alone] 1 - LITERAL "suffixed"suffix1 + LITERAL Str suffixedsuffix 1 PUNCH , [alone] 1 - LITERAL r##"raw"##1 + LITERAL StrRaw(2) raw 1 PUNCH , [alone] 1 - LITERAL 'a'1 + LITERAL Char a 1 PUNCH , [alone] 1 - LITERAL b'b'1 + LITERAL Byte b 1 PUNCH , [alone] 1 - LITERAL c"null"1"###]], - expect![[r###" + LITERAL CStr null 1"#]], + expect![[r#" SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - LITERAL 1u1642:2@0..4#0 + LITERAL Integer 1u16 42:2@0..4#0 PUNCH , [alone] 42:2@4..5#0 - LITERAL 2_u3242:2@6..11#0 + LITERAL Integer 2_u32 42:2@6..11#0 PUNCH , [alone] 42:2@11..12#0 PUNCH - [alone] 42:2@13..14#0 - LITERAL 4i6442:2@14..18#0 + LITERAL Integer 4i64 42:2@14..18#0 PUNCH , [alone] 42:2@18..19#0 - LITERAL 3.14f3242:2@20..27#0 + LITERAL Float 3.14f32 42:2@20..27#0 PUNCH , [alone] 42:2@27..28#0 - LITERAL "hello bridge"42:2@29..43#0 + LITERAL Str hello bridge 42:2@29..43#0 PUNCH , [alone] 42:2@43..44#0 - LITERAL "suffixed"suffix42:2@45..61#0 + LITERAL Str suffixedsuffix 42:2@45..61#0 PUNCH , [alone] 42:2@61..62#0 - LITERAL r##"raw"##42:2@63..73#0 + LITERAL StrRaw(2) raw 42:2@63..73#0 PUNCH , [alone] 42:2@73..74#0 - LITERAL 'a'42:2@75..78#0 + LITERAL Char a 42:2@75..78#0 PUNCH , [alone] 42:2@78..79#0 - LITERAL b'b'42:2@80..84#0 + LITERAL Byte b 42:2@80..84#0 PUNCH , [alone] 42:2@84..85#0 - LITERAL c"null"42:2@86..93#0"###]], + LITERAL CStr null 42:2@86..93#0"#]], ); } @@ -231,20 +231,20 @@ fn test_attr_macro() { "attr_error", r#"mod m {}"#, r#"some arguments"#, - expect![[r##" + expect![[r#" SUBTREE $$ 1 1 IDENT compile_error 1 PUNCH ! [alone] 1 SUBTREE () 1 1 - LITERAL "#[attr_error(some arguments)] mod m {}"1 - PUNCH ; [alone] 1"##]], - expect![[r##" + LITERAL Str #[attr_error(some arguments)] mod m {} 1 + PUNCH ; [alone] 1"#]], + expect![[r#" SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 IDENT compile_error 42:2@0..100#0 PUNCH ! [alone] 42:2@0..100#0 SUBTREE () 42:2@0..100#0 42:2@0..100#0 - LITERAL "#[attr_error(some arguments)] mod m {}"42:2@0..100#0 - PUNCH ; [alone] 42:2@0..100#0"##]], + LITERAL Str #[attr_error(some arguments)] mod m {} 42:2@0..100#0 + PUNCH ; [alone] 42:2@0..100#0"#]], ); } diff --git a/src/tools/rust-analyzer/crates/salsa/tests/macros.rs b/src/tools/rust-analyzer/crates/salsa/tests/macros.rs index 3d818e53c8e93..9b07740e7de3d 100644 --- a/src/tools/rust-analyzer/crates/salsa/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/salsa/tests/macros.rs @@ -5,6 +5,7 @@ trait MyDatabase: salsa::Database { } mod another_module { + #[allow(dead_code)] pub(crate) fn another_name(_: &dyn crate::MyDatabase, (): ()) {} } diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs index 369744d0e96c7..24fd0abada5f2 100644 --- a/src/tools/rust-analyzer/crates/tt/src/lib.rs +++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs @@ -12,8 +12,54 @@ use stdx::impl_from; pub use smol_str::SmolStr; pub use text_size::{TextRange, TextSize}; +#[derive(Clone, PartialEq, Debug)] +pub struct Lit { + pub kind: LitKind, + pub symbol: SmolStr, + pub suffix: Option, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum IdentIsRaw { + No, + Yes, +} +impl IdentIsRaw { + pub fn yes(self) -> bool { + matches!(self, IdentIsRaw::Yes) + } + pub fn as_str(self) -> &'static str { + match self { + IdentIsRaw::No => "", + IdentIsRaw::Yes => "r#", + } + } + pub fn split_from_symbol(sym: &str) -> (Self, &str) { + if let Some(sym) = sym.strip_prefix("r#") { + (IdentIsRaw::Yes, sym) + } else { + (IdentIsRaw::No, sym) + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub enum LitKind { + Byte, + Char, + Integer, // e.g. `1`, `1u8`, `1f32` + Float, // e.g. `1.`, `1.0`, `1e3f32` + Str, + StrRaw(u8), // raw string delimited by `n` hash symbols + ByteStr, + ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols + CStr, + CStrRaw(u8), + Err(()), +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum TokenTree { +pub enum TokenTree { Leaf(Leaf), Subtree(Subtree), } @@ -103,6 +149,15 @@ pub struct DelimSpan { pub close: S, } +impl DelimSpan { + pub fn from_single(sp: Span) -> Self { + DelimSpan { open: sp, close: sp } + } + + pub fn from_pair(open: Span, close: Span) -> Self { + DelimSpan { open, close } + } +} #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Delimiter { pub open: S, @@ -134,8 +189,11 @@ pub enum DelimiterKind { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Literal { + // escaped pub text: SmolStr, pub span: S, + pub kind: LitKind, + pub suffix: Option>, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -145,23 +203,85 @@ pub struct Punct { pub span: S, } +/// Indicates whether a token can join with the following token to form a +/// compound token. Used for conversions to `proc_macro::Spacing`. Also used to +/// guide pretty-printing, which is where the `JointHidden` value (which isn't +/// part of `proc_macro::Spacing`) comes in useful. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Spacing { + /// The token cannot join with the following token to form a compound + /// token. + /// + /// In token streams parsed from source code, the compiler will use `Alone` + /// for any token immediately followed by whitespace, a non-doc comment, or + /// EOF. + /// + /// When constructing token streams within the compiler, use this for each + /// token that (a) should be pretty-printed with a space after it, or (b) + /// is the last token in the stream. (In the latter case the choice of + /// spacing doesn't matter because it is never used for the last token. We + /// arbitrarily use `Alone`.) + /// + /// Converts to `proc_macro::Spacing::Alone`, and + /// `proc_macro::Spacing::Alone` converts back to this. Alone, - /// Whether the following token is joint to this one. + + /// The token can join with the following token to form a compound token. + /// + /// In token streams parsed from source code, the compiler will use `Joint` + /// for any token immediately followed by punctuation (as determined by + /// `Token::is_punct`). + /// + /// When constructing token streams within the compiler, use this for each + /// token that (a) should be pretty-printed without a space after it, and + /// (b) is followed by a punctuation token. + /// + /// Converts to `proc_macro::Spacing::Joint`, and + /// `proc_macro::Spacing::Joint` converts back to this. Joint, + + /// The token can join with the following token to form a compound token, + /// but this will not be visible at the proc macro level. (This is what the + /// `Hidden` means; see below.) + /// + /// In token streams parsed from source code, the compiler will use + /// `JointHidden` for any token immediately followed by anything not + /// covered by the `Alone` and `Joint` cases: an identifier, lifetime, + /// literal, delimiter, doc comment. + /// + /// When constructing token streams, use this for each token that (a) + /// should be pretty-printed without a space after it, and (b) is followed + /// by a non-punctuation token. + /// + /// Converts to `proc_macro::Spacing::Alone`, but + /// `proc_macro::Spacing::Alone` converts back to `token::Spacing::Alone`. + /// Because of that, pretty-printing of `TokenStream`s produced by proc + /// macros is unavoidably uglier (with more whitespace between tokens) than + /// pretty-printing of `TokenStream`'s produced by other means (i.e. parsed + /// source code, internally constructed token streams, and token streams + /// produced by declarative macros). + JointHidden, } +/// Identifier or keyword. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -/// Identifier or keyword. Unlike rustc, we keep "r#" prefix when it represents a raw identifier. pub struct Ident { pub text: SmolStr, pub span: S, + pub is_raw: IdentIsRaw, } impl Ident { - pub fn new(text: impl Into, span: S) -> Self { - Ident { text: text.into(), span } + pub fn new(text: impl Into + AsRef, span: S) -> Self { + let t = text.as_ref(); + // let raw_stripped = IdentIsRaw::split_from_symbol(text.as_ref()); + let raw_stripped = t.strip_prefix("r#"); + let is_raw = if raw_stripped.is_none() { IdentIsRaw::No } else { IdentIsRaw::Yes }; + let text = match raw_stripped { + Some(derawed) => derawed.into(), + None => text.into(), + }; + Ident { text, span, is_raw } } } @@ -207,22 +327,35 @@ fn print_debug_token( match tkn { TokenTree::Leaf(leaf) => match leaf { Leaf::Literal(lit) => { - write!(f, "{}LITERAL {}", align, lit.text)?; - fmt::Debug::fmt(&lit.span, f)?; + write!( + f, + "{}LITERAL {:?} {}{} {:#?}", + align, + lit.kind, + lit.text, + lit.suffix.as_ref().map(|it| &***it).unwrap_or(""), + lit.span + )?; } Leaf::Punct(punct) => { write!( f, - "{}PUNCH {} [{}] ", + "{}PUNCH {} [{}] {:#?}", align, punct.char, if punct.spacing == Spacing::Alone { "alone" } else { "joint" }, + punct.span )?; - fmt::Debug::fmt(&punct.span, f)?; } Leaf::Ident(ident) => { - write!(f, "{}IDENT {} ", align, ident.text)?; - fmt::Debug::fmt(&ident.span, f)?; + write!( + f, + "{}IDENT {}{} {:#?}", + align, + ident.is_raw.as_str(), + ident.text, + ident.span + )?; } }, TokenTree::Subtree(subtree) => { @@ -288,13 +421,52 @@ impl fmt::Display for Leaf { impl fmt::Display for Ident { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.is_raw.as_str(), f)?; fmt::Display::fmt(&self.text, f) } } impl fmt::Display for Literal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.text, f) + match self.kind { + LitKind::Byte => write!(f, "b'{}'", self.text), + LitKind::Char => write!(f, "'{}'", self.text), + LitKind::Integer | LitKind::Float | LitKind::Err(_) => write!(f, "{}", self.text), + LitKind::Str => write!(f, "\"{}\"", self.text), + LitKind::ByteStr => write!(f, "b\"{}\"", self.text), + LitKind::CStr => write!(f, "c\"{}\"", self.text), + LitKind::StrRaw(num_of_hashes) => { + let num_of_hashes = num_of_hashes as usize; + write!( + f, + r#"r{0:# { + let num_of_hashes = num_of_hashes as usize; + write!( + f, + r#"br{0:# { + let num_of_hashes = num_of_hashes as usize; + write!( + f, + r#"cr{0:# Subtree { let s = match it { Leaf::Literal(it) => it.text.to_string(), Leaf::Punct(it) => it.char.to_string(), - Leaf::Ident(it) => it.text.to_string(), + Leaf::Ident(it) => format!("{}{}", it.is_raw.as_str(), it.text), }; match (it, last) { (Leaf::Ident(_), Some(&TokenTree::Leaf(Leaf::Ident(_)))) => { @@ -369,7 +541,9 @@ impl Subtree { pub fn pretty(tkns: &[TokenTree]) -> String { fn tokentree_to_text(tkn: &TokenTree) -> String { match tkn { - TokenTree::Leaf(Leaf::Ident(ident)) => ident.text.clone().into(), + TokenTree::Leaf(Leaf::Ident(ident)) => { + format!("{}{}", ident.is_raw.as_str(), ident.text) + } TokenTree::Leaf(Leaf::Literal(literal)) => literal.text.clone().into(), TokenTree::Leaf(Leaf::Punct(punct)) => format!("{}", punct.char), TokenTree::Subtree(subtree) => { From ed2b355872161fca4b666cf1c459210c428c57ee Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 15 Jul 2024 12:33:51 +0200 Subject: [PATCH 013/147] Add cargo xtask install proc-macro-server --- src/tools/rust-analyzer/crates/ide/src/hover.rs | 2 +- src/tools/rust-analyzer/xtask/src/flags.rs | 17 ++++++++++++++--- src/tools/rust-analyzer/xtask/src/install.rs | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 701374616ad67..2006baa30a8c3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -240,7 +240,7 @@ fn hover_simple( .flatten() .unique_by(|&(def, _, _)| def) .map(|(def, macro_arm, node)| { - dbg!(hover_for_definition(sema, file_id, def, &node, macro_arm, config)) + hover_for_definition(sema, file_id, def, &node, macro_arm, config) }) .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| { acc.actions.extend(actions); diff --git a/src/tools/rust-analyzer/xtask/src/flags.rs b/src/tools/rust-analyzer/xtask/src/flags.rs index cf4a22d476faf..fd4291de9e1b2 100644 --- a/src/tools/rust-analyzer/xtask/src/flags.rs +++ b/src/tools/rust-analyzer/xtask/src/flags.rs @@ -2,7 +2,7 @@ use std::{fmt, str::FromStr}; -use crate::install::{ClientOpt, ServerOpt}; +use crate::install::{ClientOpt, ProcMacroServerOpt, ServerOpt}; xflags::xflags! { src "./src/flags.rs" @@ -23,6 +23,10 @@ xflags::xflags! { optional --mimalloc /// Use jemalloc allocator for server. optional --jemalloc + + /// Install the proc-macro server. + optional --proc-macro-server + /// build in release with debug info set to 2. optional --dev-rel } @@ -109,6 +113,7 @@ pub struct Install { pub client: bool, pub code_bin: Option, pub server: bool, + pub proc_macro_server: bool, pub mimalloc: bool, pub jemalloc: bool, pub dev_rel: bool, @@ -284,7 +289,7 @@ impl Malloc { impl Install { pub(crate) fn server(&self) -> Option { - if self.client && !self.server { + if !self.server { return None; } let malloc = if self.mimalloc { @@ -296,8 +301,14 @@ impl Install { }; Some(ServerOpt { malloc, dev_rel: self.dev_rel }) } + pub(crate) fn proc_macro_server(&self) -> Option { + if !self.proc_macro_server { + return None; + } + Some(ProcMacroServerOpt { dev_rel: self.dev_rel }) + } pub(crate) fn client(&self) -> Option { - if !self.client && self.server { + if !self.client { return None; } Some(ClientOpt { code_bin: self.code_bin.clone() }) diff --git a/src/tools/rust-analyzer/xtask/src/install.rs b/src/tools/rust-analyzer/xtask/src/install.rs index 72e612f9e1d6b..eb33d6f9be696 100644 --- a/src/tools/rust-analyzer/xtask/src/install.rs +++ b/src/tools/rust-analyzer/xtask/src/install.rs @@ -15,6 +15,9 @@ impl flags::Install { if let Some(server) = self.server() { install_server(sh, server).context("install server")?; } + if let Some(server) = self.proc_macro_server() { + install_proc_macro_server(sh, server).context("install proc-macro server")?; + } if let Some(client) = self.client() { install_client(sh, client).context("install client")?; } @@ -34,6 +37,10 @@ pub(crate) struct ServerOpt { pub(crate) dev_rel: bool, } +pub(crate) struct ProcMacroServerOpt { + pub(crate) dev_rel: bool, +} + fn fix_path_for_mac(sh: &Shell) -> anyhow::Result<()> { let mut vscode_path: Vec = { const COMMON_APP_PATH: &str = @@ -132,3 +139,11 @@ fn install_server(sh: &Shell, opts: ServerOpt) -> anyhow::Result<()> { cmd.run()?; Ok(()) } + +fn install_proc_macro_server(sh: &Shell, opts: ProcMacroServerOpt) -> anyhow::Result<()> { + let profile = if opts.dev_rel { "dev-rel" } else { "release" }; + + let cmd = cmd!(sh, "cargo +nightly install --path crates/proc-macro-srv-cli --profile={profile} --locked --force --features sysroot-abi"); + cmd.run()?; + Ok(()) +} From 39eb8c6bc415ba222dccb22a29d8730092a06ee1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 15 Jul 2024 12:55:05 +0200 Subject: [PATCH 014/147] Escape fetched env vars in env! expansion --- .../macro_expansion_tests/builtin_fn_macro.rs | 2 +- .../crates/hir-expand/src/builtin_fn_macro.rs | 39 +++++++++++-------- .../crates/hir-ty/src/tests/macros.rs | 2 +- .../rust-analyzer/tests/slow-tests/main.rs | 2 +- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index ab8bb8bd4c6fc..487ab537cdac3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -154,7 +154,7 @@ fn main() { file!(); } #[rustc_builtin_macro] macro_rules! file {() => {}} -fn main() { ""; } +fn main() { "file"; } "##]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index 32befb7a7f7df..fb12adb87cb34 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -8,7 +8,10 @@ use intern::sym; 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; -use syntax::unescape::{unescape_byte, unescape_char, unescape_unicode, Mode}; +use syntax::{ + format_smolstr, + unescape::{unescape_byte, unescape_char, unescape_unicode, Mode}, +}; use crate::{ db::ExpandDatabase, @@ -265,7 +268,7 @@ fn file_expand( ) -> ExpandResult { // FIXME: RA purposefully lacks knowledge of absolute file names // so just return "". - let file_name = ""; + let file_name = "file"; let expanded = quote! {span => #file_name @@ -275,34 +278,36 @@ fn file_expand( } fn format_args_expand( - db: &dyn ExpandDatabase, - id: MacroCallId, + _db: &dyn ExpandDatabase, + _id: MacroCallId, tt: &tt::Subtree, span: Span, ) -> ExpandResult { - format_args_expand_general(db, id, tt, "", span) + let pound = mk_pound(span); + let mut tt = tt.clone(); + tt.delimiter.kind = tt::DelimiterKind::Parenthesis; + ExpandResult::ok(quote! {span => + builtin #pound format_args #tt + }) } fn format_args_nl_expand( - db: &dyn ExpandDatabase, - id: MacroCallId, - tt: &tt::Subtree, - span: Span, -) -> ExpandResult { - format_args_expand_general(db, id, tt, "\\n", span) -} - -fn format_args_expand_general( _db: &dyn ExpandDatabase, _id: MacroCallId, tt: &tt::Subtree, - // FIXME: Make use of this so that mir interpretation works properly - _end_string: &str, span: Span, ) -> ExpandResult { let pound = mk_pound(span); let mut tt = tt.clone(); tt.delimiter.kind = tt::DelimiterKind::Parenthesis; + if let Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { + text, + kind: tt::LitKind::Str, + .. + }))) = tt.token_trees.first_mut() + { + *text = format_smolstr!("{text}\\n"); + } ExpandResult::ok(quote! {span => builtin #pound format_args #tt }) @@ -788,7 +793,7 @@ fn include_str_expand( fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &str) -> Option { let krate = db.lookup_intern_macro_call(arg_id).krate; - db.crate_graph()[krate].env.get(key) + db.crate_graph()[krate].env.get(key).map(|it| it.escape_debug().to_string()) } fn env_expand( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs index a0899cb1d632b..5454a496ba8c1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs @@ -703,7 +703,7 @@ fn infer_builtin_macros_file() { } "#, expect![[r#" - !0..2 '""': &'static str + !0..6 '"file"': &'static str 63..87 '{ ...!(); }': () 73..74 'x': &'static str "#]], diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index 56f416a0b6e04..aa17b587e0228 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -970,7 +970,7 @@ version = \"0.0.0\" fn out_dirs_check_impl(root_contains_symlink: bool) { if skip_slow_tests() { - return; + // return; } let mut server = Project::with_fixture( From 311aaa5a792489a1f80cfa0e522e0e60b08788de Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 15 Jul 2024 14:41:35 +0200 Subject: [PATCH 015/147] Fix incorrect encoding of literals in the proc-macro-api on version 4 --- src/tools/rust-analyzer/Cargo.lock | 3 +- .../crates/hir-expand/src/attrs.rs | 7 +- .../crates/hir-expand/src/lib.rs | 2 +- src/tools/rust-analyzer/crates/mbe/Cargo.toml | 3 +- src/tools/rust-analyzer/crates/mbe/src/lib.rs | 9 +- .../crates/mbe/src/syntax_bridge.rs | 53 +------- .../crates/proc-macro-api/Cargo.toml | 2 + .../crates/proc-macro-api/src/msg.rs | 53 ++++---- .../crates/proc-macro-api/src/msg/flat.rs | 118 ++++++++++++------ .../crates/proc-macro-srv/Cargo.toml | 2 +- src/tools/rust-analyzer/crates/tt/Cargo.toml | 4 + src/tools/rust-analyzer/crates/tt/src/lib.rs | 61 ++++++++- 12 files changed, 183 insertions(+), 134 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index e43f712a6e230..500a150b57b84 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1046,7 +1046,6 @@ dependencies = [ "arrayvec", "cov-mark", "parser", - "ra-ap-rustc_lexer", "rustc-hash", "smallvec", "span", @@ -1326,6 +1325,7 @@ dependencies = [ "base-db", "indexmap", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mbe", "paths", "rustc-hash", "serde", @@ -2218,6 +2218,7 @@ name = "tt" version = "0.0.0" dependencies = [ "arrayvec", + "ra-ap-rustc_lexer", "smol_str", "stdx", "text-size", diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 4fce7c1fde13f..49a104fa118e6 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -5,9 +5,10 @@ use base_db::CrateId; use cfg::CfgExpr; use either::Either; use intern::{sym, Interned}; + use mbe::{ - desugar_doc_comment_text, syntax_node_to_token_tree, token_to_literal, DelimiterKind, - DocCommentDesugarMode, Punct, + desugar_doc_comment_text, syntax_node_to_token_tree, DelimiterKind, DocCommentDesugarMode, + Punct, }; use smallvec::{smallvec, SmallVec}; use span::{Span, SyntaxContextId}; @@ -20,7 +21,7 @@ use crate::{ db::ExpandDatabase, mod_path::ModPath, span_map::SpanMapRef, - tt::{self, Subtree}, + tt::{self, token_to_literal, Subtree}, InFile, }; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index c4921da61004c..3460d1ca3d11f 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -59,7 +59,7 @@ pub use span::{HirFileId, MacroCallId, MacroFileId}; pub mod tt { pub use span::Span; - pub use tt::{DelimiterKind, IdentIsRaw, LitKind, Spacing}; + pub use tt::{token_to_literal, DelimiterKind, IdentIsRaw, LitKind, Spacing}; pub type Delimiter = ::tt::Delimiter; pub type DelimSpan = ::tt::DelimSpan; diff --git a/src/tools/rust-analyzer/crates/mbe/Cargo.toml b/src/tools/rust-analyzer/crates/mbe/Cargo.toml index 7ce8aadfb3619..1002de2104a0c 100644 --- a/src/tools/rust-analyzer/crates/mbe/Cargo.toml +++ b/src/tools/rust-analyzer/crates/mbe/Cargo.toml @@ -17,7 +17,6 @@ rustc-hash.workspace = true smallvec.workspace = true tracing.workspace = true arrayvec.workspace = true -ra-ap-rustc_lexer.workspace = true # local deps syntax.workspace = true @@ -30,7 +29,7 @@ span.workspace = true test-utils.workspace = true [features] -in-rust-tree = ["parser/in-rust-tree", "syntax/in-rust-tree"] +in-rust-tree = ["parser/in-rust-tree", "tt/in-rust-tree", "syntax/in-rust-tree"] [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs index 8ab9269e9523a..44b056a1acf5f 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs @@ -6,13 +6,6 @@ //! The tests for this functionality live in another crate: //! `hir_def::macro_expansion_tests::mbe`. -#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] - -#[cfg(not(feature = "in-rust-tree"))] -extern crate ra_ap_rustc_lexer as rustc_lexer; -#[cfg(feature = "in-rust-tree")] -extern crate rustc_lexer; - mod expander; mod parser; mod syntax_bridge; @@ -36,7 +29,7 @@ pub use tt::{Delimiter, DelimiterKind, Punct}; pub use crate::syntax_bridge::{ desugar_doc_comment_text, parse_exprs_with_sep, parse_to_token_tree, parse_to_token_tree_static_span, syntax_node_to_token_tree, syntax_node_to_token_tree_modified, - token_to_literal, token_tree_to_syntax_node, DocCommentDesugarMode, SpanMapper, + token_tree_to_syntax_node, DocCommentDesugarMode, SpanMapper, }; pub use crate::syntax_bridge::dummy_test_span_utils::*; diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs index 3feddba21061f..4d66464932b88 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs @@ -4,7 +4,7 @@ use std::fmt; use rustc_hash::{FxHashMap, FxHashSet}; use span::{Edition, SpanAnchor, SpanData, SpanMap}; -use stdx::{format_to, itertools::Itertools, never, non_empty_vec::NonEmptyVec}; +use stdx::{format_to, never, non_empty_vec::NonEmptyVec}; use syntax::{ ast::{self, make::tokens::doc_comment}, format_smolstr, AstToken, Parse, PreorderWithTokens, SmolStr, SyntaxElement, @@ -14,6 +14,7 @@ use syntax::{ use tt::{ buffer::{Cursor, TokenBuffer}, iter::TtIter, + token_to_literal, }; use crate::to_parser_input::to_parser_input; @@ -400,56 +401,6 @@ where } } -pub fn token_to_literal(text: SmolStr, span: S) -> tt::Literal -where - S: Copy, -{ - use rustc_lexer::LiteralKind; - - let token = rustc_lexer::tokenize(&text).next_tuple(); - let Some((rustc_lexer::Token { - kind: rustc_lexer::TokenKind::Literal { kind, suffix_start }, - .. - },)) = token - else { - return tt::Literal { span, text, kind: tt::LitKind::Err(()), suffix: None }; - }; - - let (kind, start_offset, end_offset) = match kind { - LiteralKind::Int { .. } => (tt::LitKind::Integer, 0, 0), - LiteralKind::Float { .. } => (tt::LitKind::Float, 0, 0), - LiteralKind::Char { terminated } => (tt::LitKind::Char, 1, terminated as usize), - LiteralKind::Byte { terminated } => (tt::LitKind::Byte, 2, terminated as usize), - LiteralKind::Str { terminated } => (tt::LitKind::Str, 1, terminated as usize), - LiteralKind::ByteStr { terminated } => (tt::LitKind::ByteStr, 2, terminated as usize), - LiteralKind::CStr { terminated } => (tt::LitKind::CStr, 2, terminated as usize), - LiteralKind::RawStr { n_hashes } => ( - tt::LitKind::StrRaw(n_hashes.unwrap_or_default()), - 2 + n_hashes.unwrap_or_default() as usize, - 1 + n_hashes.unwrap_or_default() as usize, - ), - LiteralKind::RawByteStr { n_hashes } => ( - tt::LitKind::ByteStrRaw(n_hashes.unwrap_or_default()), - 3 + n_hashes.unwrap_or_default() as usize, - 1 + n_hashes.unwrap_or_default() as usize, - ), - LiteralKind::RawCStr { n_hashes } => ( - tt::LitKind::CStrRaw(n_hashes.unwrap_or_default()), - 3 + n_hashes.unwrap_or_default() as usize, - 1 + n_hashes.unwrap_or_default() as usize, - ), - }; - - let (lit, suffix) = text.split_at(suffix_start as usize); - let lit = &lit[start_offset..lit.len() - end_offset]; - let suffix = match suffix { - "" | "_" => None, - suffix => Some(Box::new(suffix.into())), - }; - - tt::Literal { span, text: lit.into(), kind, suffix } -} - fn is_single_token_op(kind: SyntaxKind) -> bool { matches!( kind, diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml index 7f633d91ecc8c..889eefa8b5c61 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml @@ -28,6 +28,8 @@ span.workspace = true # InternIds for the syntax context base-db.workspace = true la-arena.workspace = true +# only here to parse via token_to_literal +mbe.workspace = true [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs index b5f3d0c3aacd5..65835048173ab 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs @@ -197,7 +197,7 @@ mod tests { .into(), ), TokenTree::Leaf(Leaf::Literal(Literal { - text: "\"Foo\"".into(), + text: "Foo".into(), span: Span { range: TextRange::at(TextSize::new(10), TextSize::of("\"Foo\"")), anchor, @@ -263,32 +263,35 @@ mod tests { #[test] fn test_proc_macro_rpc_works() { let tt = fixture_token_tree(); - let mut span_data_table = Default::default(); - let task = ExpandMacro { - data: ExpandMacroData { - macro_body: FlatTree::new(&tt, CURRENT_API_VERSION, &mut span_data_table), - macro_name: Default::default(), - attributes: None, - has_global_spans: ExpnGlobals { - serialize: true, - def_site: 0, - call_site: 0, - mixed_site: 0, + for v in RUST_ANALYZER_SPAN_SUPPORT..=CURRENT_API_VERSION { + let mut span_data_table = Default::default(); + let task = ExpandMacro { + data: ExpandMacroData { + macro_body: FlatTree::new(&tt, v, &mut span_data_table), + macro_name: Default::default(), + attributes: None, + has_global_spans: ExpnGlobals { + serialize: true, + def_site: 0, + call_site: 0, + mixed_site: 0, + }, + span_data_table: Vec::new(), }, - span_data_table: Vec::new(), - }, - lib: Utf8PathBuf::from_path_buf(std::env::current_dir().unwrap()).unwrap(), - env: Default::default(), - current_dir: Default::default(), - }; + lib: Utf8PathBuf::from_path_buf(std::env::current_dir().unwrap()).unwrap(), + env: Default::default(), + current_dir: Default::default(), + }; - let json = serde_json::to_string(&task).unwrap(); - // println!("{}", json); - let back: ExpandMacro = serde_json::from_str(&json).unwrap(); + let json = serde_json::to_string(&task).unwrap(); + // println!("{}", json); + let back: ExpandMacro = serde_json::from_str(&json).unwrap(); - assert_eq!( - tt, - back.data.macro_body.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table) - ); + assert_eq!( + tt, + back.data.macro_body.to_subtree_resolved(v, &span_data_table), + "version: {v}" + ); + } } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs index 7f5afdb7270fe..3d962e99d92c2 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs @@ -141,6 +141,7 @@ impl FlatTree { ident: Vec::new(), token_tree: Vec::new(), text: Vec::new(), + version, }; w.write(subtree); @@ -178,6 +179,7 @@ impl FlatTree { ident: Vec::new(), token_tree: Vec::new(), text: Vec::new(), + version, }; w.write(subtree); @@ -228,6 +230,7 @@ impl FlatTree { token_tree: self.token_tree, text: self.text, span_data_table, + version, } .read() } @@ -253,6 +256,7 @@ impl FlatTree { token_tree: self.token_tree, text: self.text, span_data_table: &(), + version, } .read() } @@ -386,8 +390,9 @@ impl InternableSpan for Span { struct Writer<'a, 'span, S: InternableSpan> { work: VecDeque<(usize, &'a tt::Subtree)>, - string_table: FxHashMap<&'a str, u32>, + string_table: FxHashMap, u32>, span_data_table: &'span mut S::Table, + version: u32, subtree: Vec, literal: Vec, @@ -425,9 +430,15 @@ impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> { tt::TokenTree::Leaf(leaf) => match leaf { tt::Leaf::Literal(lit) => { let idx = self.literal.len() as u32; - let text = self.intern(&lit.text); let id = self.token_id_of(lit.span); - let suffix = lit.suffix.as_ref().map(|s| self.intern(s)).unwrap_or(!0); + let (text, suffix) = if self.version >= EXTENDED_LEAF_DATA { + ( + self.intern(&lit.text), + lit.suffix.as_ref().map(|s| self.intern(s)).unwrap_or(!0), + ) + } else { + (self.intern_owned(format!("{lit}")), !0) + }; self.literal.push(LiteralRepr { id, text, @@ -456,13 +467,15 @@ impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> { } tt::Leaf::Ident(ident) => { let idx = self.ident.len() as u32; - let text = self.intern(&ident.text); let id = self.token_id_of(ident.span); - self.ident.push(IdentRepr { - id, - text, - is_raw: ident.is_raw == tt::IdentIsRaw::Yes, - }); + let text = if self.version >= EXTENDED_LEAF_DATA { + self.intern(&ident.text) + } else if ident.is_raw.yes() { + self.intern_owned(format!("r#{}", ident.text,)) + } else { + self.intern(&ident.text) + }; + self.ident.push(IdentRepr { id, text, is_raw: ident.is_raw.yes() }); idx << 2 | 0b11 } }, @@ -484,15 +497,25 @@ impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> { pub(crate) fn intern(&mut self, text: &'a str) -> u32 { let table = &mut self.text; - *self.string_table.entry(text).or_insert_with(|| { + *self.string_table.entry(text.into()).or_insert_with(|| { let idx = table.len(); table.push(text.to_owned()); idx as u32 }) } + + pub(crate) fn intern_owned(&mut self, text: String) -> u32 { + let table = &mut self.text; + *self.string_table.entry(text.clone().into()).or_insert_with(|| { + let idx = table.len(); + table.push(text); + idx as u32 + }) + } } struct Reader<'span, S: InternableSpan> { + version: u32, subtree: Vec, literal: Vec, punct: Vec, @@ -528,30 +551,36 @@ impl<'span, S: InternableSpan> Reader<'span, S> { 0b01 => { use tt::LitKind::*; let repr = &self.literal[idx]; - tt::Leaf::Literal(tt::Literal { - text: self.text[repr.text as usize].as_str().into(), - span: read_span(repr.id), - kind: match u16::to_le_bytes(repr.kind) { - [0, _] => Err(()), - [1, _] => Byte, - [2, _] => Char, - [3, _] => Integer, - [4, _] => Float, - [5, _] => Str, - [6, r] => StrRaw(r), - [7, _] => ByteStr, - [8, r] => ByteStrRaw(r), - [9, _] => CStr, - [10, r] => CStrRaw(r), - _ => unreachable!(), - }, - suffix: if repr.suffix != !0 { - Some(Box::new( - self.text[repr.suffix as usize].as_str().into(), - )) - } else { - None - }, + let text = self.text[repr.text as usize].as_str(); + let span = read_span(repr.id); + tt::Leaf::Literal(if self.version >= EXTENDED_LEAF_DATA { + tt::Literal { + text: text.into(), + span, + kind: match u16::to_le_bytes(repr.kind) { + [0, _] => Err(()), + [1, _] => Byte, + [2, _] => Char, + [3, _] => Integer, + [4, _] => Float, + [5, _] => Str, + [6, r] => StrRaw(r), + [7, _] => ByteStr, + [8, r] => ByteStrRaw(r), + [9, _] => CStr, + [10, r] => CStrRaw(r), + _ => unreachable!(), + }, + suffix: if repr.suffix != !0 { + Some(Box::new( + self.text[repr.suffix as usize].as_str().into(), + )) + } else { + None + }, + } + } else { + tt::token_to_literal(text.into(), span) }) .into() } @@ -566,14 +595,23 @@ impl<'span, S: InternableSpan> Reader<'span, S> { } 0b11 => { let repr = &self.ident[idx]; + let text = self.text[repr.text as usize].as_str(); + let (is_raw, text) = if self.version >= EXTENDED_LEAF_DATA { + ( + if repr.is_raw { + tt::IdentIsRaw::Yes + } else { + tt::IdentIsRaw::No + }, + text, + ) + } else { + tt::IdentIsRaw::split_from_symbol(text) + }; tt::Leaf::Ident(tt::Ident { - text: self.text[repr.text as usize].as_str().into(), + text: text.into(), span: read_span(repr.id), - is_raw: if repr.is_raw { - tt::IdentIsRaw::Yes - } else { - tt::IdentIsRaw::No - }, + is_raw, }) .into() } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml index 735f781c43910..065701c05cc7b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml @@ -34,7 +34,7 @@ proc-macro-test.path = "./proc-macro-test" [features] sysroot-abi = [] -in-rust-tree = ["mbe/in-rust-tree", "sysroot-abi"] +in-rust-tree = ["mbe/in-rust-tree", "tt/in-rust-tree","sysroot-abi"] [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/tt/Cargo.toml b/src/tools/rust-analyzer/crates/tt/Cargo.toml index 1311e2ddf89e9..1900635b995ee 100644 --- a/src/tools/rust-analyzer/crates/tt/Cargo.toml +++ b/src/tools/rust-analyzer/crates/tt/Cargo.toml @@ -17,6 +17,10 @@ smol_str.workspace = true text-size.workspace = true stdx.workspace = true +ra-ap-rustc_lexer.workspace = true + +[features] +in-rust-tree = [] [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs index 24fd0abada5f2..c328b3f8a3cc8 100644 --- a/src/tools/rust-analyzer/crates/tt/src/lib.rs +++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs @@ -2,14 +2,21 @@ //! input and output) of macros. It closely mirrors `proc_macro` crate's //! `TokenTree`. +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(not(feature = "in-rust-tree"))] +extern crate ra_ap_rustc_lexer as rustc_lexer; +#[cfg(feature = "in-rust-tree")] +extern crate rustc_lexer; + pub mod buffer; pub mod iter; use std::fmt; -use stdx::impl_from; +use stdx::{impl_from, itertools::Itertools as _}; -pub use smol_str::SmolStr; +pub use smol_str::{format_smolstr, SmolStr}; pub use text_size::{TextRange, TextSize}; #[derive(Clone, PartialEq, Debug)] @@ -196,6 +203,56 @@ pub struct Literal { pub suffix: Option>, } +pub fn token_to_literal(text: SmolStr, span: S) -> Literal +where + S: Copy, +{ + use rustc_lexer::LiteralKind; + + let token = rustc_lexer::tokenize(&text).next_tuple(); + let Some((rustc_lexer::Token { + kind: rustc_lexer::TokenKind::Literal { kind, suffix_start }, + .. + },)) = token + else { + return Literal { span, text, kind: LitKind::Err(()), suffix: None }; + }; + + let (kind, start_offset, end_offset) = match kind { + LiteralKind::Int { .. } => (LitKind::Integer, 0, 0), + LiteralKind::Float { .. } => (LitKind::Float, 0, 0), + LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize), + LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize), + LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize), + LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize), + LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize), + LiteralKind::RawStr { n_hashes } => ( + LitKind::StrRaw(n_hashes.unwrap_or_default()), + 2 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + LiteralKind::RawByteStr { n_hashes } => ( + LitKind::ByteStrRaw(n_hashes.unwrap_or_default()), + 3 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + LiteralKind::RawCStr { n_hashes } => ( + LitKind::CStrRaw(n_hashes.unwrap_or_default()), + 3 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + }; + + let (lit, suffix) = text.split_at(suffix_start as usize); + let lit = &lit[start_offset..lit.len() - end_offset]; + let suffix = match suffix { + "" | "_" => None, + suffix => Some(Box::new(suffix.into())), + }; + + Literal { span, text: lit.into(), kind, suffix } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Punct { pub char: char, From 7f8a54bbee4fec4a6885c7554a2864a62bf40638 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 16 Jul 2024 09:59:39 +0200 Subject: [PATCH 016/147] Switch token trees to use Symbols --- src/tools/rust-analyzer/Cargo.lock | 8 +- src/tools/rust-analyzer/crates/cfg/Cargo.toml | 1 + .../rust-analyzer/crates/cfg/src/cfg_expr.rs | 13 +- src/tools/rust-analyzer/crates/cfg/src/lib.rs | 2 +- .../rust-analyzer/crates/hir-def/src/attr.rs | 34 ++--- .../crates/hir-def/src/builtin_type.rs | 27 +++- .../rust-analyzer/crates/hir-def/src/data.rs | 2 +- .../crates/hir-def/src/data/adt.rs | 22 ++-- .../rust-analyzer/crates/hir-def/src/db.rs | 2 +- .../crates/hir-def/src/nameres.rs | 15 +-- .../hir-def/src/nameres/attr_resolution.rs | 12 +- .../crates/hir-def/src/nameres/collector.rs | 10 +- .../crates/hir-def/src/nameres/proc_macro.rs | 3 +- .../crates/hir-expand/src/attrs.rs | 33 ++--- .../hir-expand/src/builtin_derive_macro.rs | 22 ++-- .../crates/hir-expand/src/builtin_fn_macro.rs | 74 +++++------ .../crates/hir-expand/src/cfg_process.rs | 9 +- .../crates/hir-expand/src/declarative.rs | 8 +- .../crates/hir-expand/src/fixup.rs | 31 ++--- .../crates/hir-expand/src/inert_attr_macro.rs | 12 +- .../crates/hir-expand/src/mod_path.rs | 24 ++-- .../crates/hir-expand/src/name.rs | 20 ++- .../crates/hir-expand/src/quote.rs | 46 +++---- .../diagnostics/match_check/pat_analysis.rs | 5 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 32 +++-- .../rust-analyzer/crates/ide-db/src/defs.rs | 10 +- .../rust-analyzer/crates/intern/src/symbol.rs | 26 ++++ .../crates/intern/src/symbol/symbols.rs | 24 ++++ src/tools/rust-analyzer/crates/mbe/Cargo.toml | 1 + .../rust-analyzer/crates/mbe/src/benchmark.rs | 7 +- .../rust-analyzer/crates/mbe/src/expander.rs | 6 +- .../crates/mbe/src/expander/matcher.rs | 48 +++---- .../crates/mbe/src/expander/transcriber.rs | 28 ++--- .../rust-analyzer/crates/mbe/src/parser.rs | 42 +++---- .../crates/mbe/src/syntax_bridge.rs | 28 +++-- .../crates/mbe/src/to_parser_input.rs | 11 +- .../crates/proc-macro-api/Cargo.toml | 3 +- .../crates/proc-macro-api/src/lib.rs | 3 +- .../crates/proc-macro-api/src/msg.rs | 11 +- .../crates/proc-macro-api/src/msg/flat.rs | 21 ++-- .../crates/proc-macro-srv/Cargo.toml | 1 + .../crates/proc-macro-srv/src/lib.rs | 3 +- .../crates/proc-macro-srv/src/server_impl.rs | 4 +- .../src/server_impl/rust_analyzer_span.rs | 118 +++++++++++++++--- .../proc-macro-srv/src/server_impl/symbol.rs | 1 - .../src/server_impl/token_id.rs | 38 +++--- .../crates/test-fixture/Cargo.toml | 3 +- .../crates/test-fixture/src/lib.rs | 5 +- src/tools/rust-analyzer/crates/tt/Cargo.toml | 2 +- src/tools/rust-analyzer/crates/tt/src/iter.rs | 5 +- src/tools/rust-analyzer/crates/tt/src/lib.rs | 76 +++++------ 51 files changed, 593 insertions(+), 399 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 500a150b57b84..241392edb1e5d 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -149,6 +149,7 @@ dependencies = [ "mbe", "oorandom", "rustc-hash", + "smol_str", "syntax", "tt", ] @@ -1045,6 +1046,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "cov-mark", + "intern", "parser", "rustc-hash", "smallvec", @@ -1324,8 +1326,8 @@ version = "0.0.0" dependencies = [ "base-db", "indexmap", + "intern", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mbe", "paths", "rustc-hash", "serde", @@ -1343,6 +1345,7 @@ version = "0.0.0" dependencies = [ "base-db", "expect-test", + "intern", "libloading", "mbe", "memmap2", @@ -1966,6 +1969,7 @@ dependencies = [ "base-db", "cfg", "hir-expand", + "intern", "rustc-hash", "span", "stdx", @@ -2218,8 +2222,8 @@ name = "tt" version = "0.0.0" dependencies = [ "arrayvec", + "intern", "ra-ap-rustc_lexer", - "smol_str", "stdx", "text-size", ] diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml index 9b3a5026ac800..784e86649d1ab 100644 --- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml +++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml @@ -16,6 +16,7 @@ rustc-hash.workspace = true # locals deps tt.workspace = true +smol_str.workspace = true [dev-dependencies] expect-test = "1.4.1" diff --git a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs index b7dbb7b5fdd79..9c95f0e4e4baa 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs @@ -4,7 +4,7 @@ use std::{fmt, slice::Iter as SliceIter}; -use tt::SmolStr; +use smol_str::SmolStr; /// A simple configuration value passed in from the outside. #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] @@ -66,7 +66,7 @@ impl CfgExpr { fn next_cfg_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option { let name = match it.next() { None => return None, - Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.text.clone(), + Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.sym.clone(), Some(_) => return Some(CfgExpr::Invalid), }; @@ -77,10 +77,9 @@ fn next_cfg_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option Some(tt::TokenTree::Leaf(tt::Leaf::Literal(literal))) => { it.next(); it.next(); - // FIXME: escape? raw string? - let value = - SmolStr::new(literal.text.trim_start_matches('"').trim_end_matches('"')); - CfgAtom::KeyValue { key: name, value }.into() + // FIXME: escape? + let value = literal.symbol.as_str().into(); + CfgAtom::KeyValue { key: name.as_str().into(), value }.into() } _ => return Some(CfgExpr::Invalid), } @@ -96,7 +95,7 @@ fn next_cfg_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option _ => CfgExpr::Invalid, } } - _ => CfgAtom::Flag(name).into(), + _ => CfgAtom::Flag(name.as_str().into()).into(), }; // Eat comma separator diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs index 8b30286a0a8a8..5ef7a104dda59 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs @@ -8,10 +8,10 @@ mod tests; use std::fmt; use rustc_hash::FxHashSet; -use tt::SmolStr; pub use cfg_expr::{CfgAtom, CfgExpr}; pub use dnf::DnfExpr; +use smol_str::SmolStr; /// Configuration options used for conditional compilation on items with `cfg` attributes. /// We have two kind of options in different namespaces: atomic options like `unix`, and diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index 5bd60c58e9b7e..1a5ac96aa29bb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -159,14 +159,14 @@ impl Attrs { pub fn has_doc_hidden(&self) -> bool { self.by_key("doc").tt_values().any(|tt| { tt.delimiter.kind == DelimiterKind::Parenthesis && - matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "hidden") + matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.sym == sym::hidden) }) } pub fn has_doc_notable_trait(&self) -> bool { self.by_key("doc").tt_values().any(|tt| { tt.delimiter.kind == DelimiterKind::Parenthesis && - matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "notable_trait") + matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.sym == sym::notable_trait) }) } @@ -267,7 +267,7 @@ impl DocExpr { fn next_doc_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option { let name = match it.next() { None => return None, - Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.text.clone(), + Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.sym.clone(), Some(_) => return Some(DocExpr::Invalid), }; @@ -275,13 +275,16 @@ fn next_doc_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option let ret = match it.as_slice().first() { Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '=' => { match it.as_slice().get(1) { - Some(tt::TokenTree::Leaf(tt::Leaf::Literal(literal))) => { + Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { + symbol: text, + kind: tt::LitKind::Str, + .. + }))) => { it.next(); it.next(); // FIXME: escape? raw string? - let value = - SmolStr::new(literal.text.trim_start_matches('"').trim_end_matches('"')); - DocAtom::KeyValue { key: name, value }.into() + let value = SmolStr::new(text.as_str()); + DocAtom::KeyValue { key: name.as_str().into(), value }.into() } _ => return Some(DocExpr::Invalid), } @@ -294,7 +297,7 @@ fn next_doc_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option _ => DocExpr::Invalid, } } - _ => DocAtom::Flag(name).into(), + _ => DocAtom::Flag(name.as_str().into()).into(), }; // Eat comma separator @@ -311,10 +314,11 @@ fn parse_comma_sep(subtree: &tt::Subtree) -> Vec { .token_trees .iter() .filter_map(|tt| match tt { - tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => { - // FIXME: escape? raw string? - Some(SmolStr::new(lit.text.trim_start_matches('"').trim_end_matches('"'))) - } + tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { + kind: tt::LitKind::Str, + symbol: text, + .. + })) => Some(SmolStr::new(text.as_str())), _ => None, }) .collect() @@ -598,14 +602,14 @@ impl<'attr> AttrQuery<'attr> { /// #[doc(html_root_url = "url")] /// ^^^^^^^^^^^^^ key /// ``` - pub fn find_string_value_in_tt(self, key: &'attr str) -> Option<&SmolStr> { + pub fn find_string_value_in_tt(self, key: &'attr str) -> Option<&str> { self.tt_values().find_map(|tt| { let name = tt.token_trees.iter() - .skip_while(|tt| !matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text, ..} )) if text == key)) + .skip_while(|tt| !matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym, ..} )) if sym.as_str() == key)) .nth(2); match name { - Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal{ text, kind: tt::LitKind::Str | tt::LitKind::StrRaw(_) , ..}))) => Some(text), + Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal{ symbol: text, kind: tt::LitKind::Str | tt::LitKind::StrRaw(_) , ..}))) => Some(text.as_str()), _ => None } }) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs index 6dc1c4546e804..14b9af84e6ffb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs @@ -6,7 +6,7 @@ use std::fmt; use hir_expand::name::{AsName, Name}; -use intern::sym; +use intern::{sym, Symbol}; /// Different signed int types. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum BuiltinInt { @@ -143,6 +143,18 @@ impl BuiltinInt { }; Some(res) } + pub fn from_suffix_sym(suffix: &Symbol) -> Option { + let res = match suffix { + s if *s == sym::isize => Self::Isize, + s if *s == sym::i8 => Self::I8, + s if *s == sym::i16 => Self::I16, + s if *s == sym::i32 => Self::I32, + s if *s == sym::i64 => Self::I64, + s if *s == sym::i128 => Self::I128, + _ => return None, + }; + Some(res) + } } #[rustfmt::skip] @@ -160,6 +172,19 @@ impl BuiltinUint { }; Some(res) } + pub fn from_suffix_sym(suffix: &Symbol) -> Option { + let res = match suffix { + s if *s == sym::usize => Self::Usize, + s if *s == sym::u8 => Self::U8, + s if *s == sym::u16 => Self::U16, + s if *s == sym::u32 => Self::U32, + s if *s == sym::u64 => Self::U64, + s if *s == sym::u128 => Self::U128, + + _ => return None, + }; + Some(res) + } } #[rustfmt::skip] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 964a5f04bfd22..e2bb02c0c13ff 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -150,7 +150,7 @@ fn parse_rustc_legacy_const_generics(tt: &crate::tt::Subtree) -> Box<[u32]> { let mut indices = Vec::new(); for args in tt.token_trees.chunks(2) { match &args[0] { - tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => match lit.text.parse() { + tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => match lit.symbol.as_str().parse() { Ok(index) => indices.push(index), Err(_) => break, }, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs index 0fe73418e51fc..3942c2a98af78 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs @@ -9,7 +9,7 @@ use hir_expand::{ name::{AsName, Name}, HirFileId, InFile, }; -use intern::Interned; +use intern::{sym, Interned}; use la_arena::Arena; use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions}; use syntax::ast::{self, HasName, HasVisibility}; @@ -112,12 +112,12 @@ fn parse_repr_tt(tt: &Subtree) -> Option { let mut tts = tt.token_trees.iter().peekable(); while let Some(tt) = tts.next() { if let TokenTree::Leaf(Leaf::Ident(ident)) = tt { - flags.insert(match &*ident.text { - "packed" => { + flags.insert(match &ident.sym { + s if *s == sym::packed => { let pack = if let Some(TokenTree::Subtree(tt)) = tts.peek() { tts.next(); if let Some(TokenTree::Leaf(Leaf::Literal(lit))) = tt.token_trees.first() { - lit.text.parse().unwrap_or_default() + lit.symbol.as_str().parse().unwrap_or_default() } else { 0 } @@ -129,11 +129,11 @@ fn parse_repr_tt(tt: &Subtree) -> Option { Some(if let Some(min_pack) = min_pack { min_pack.min(pack) } else { pack }); ReprFlags::empty() } - "align" => { + s if *s == sym::align => { if let Some(TokenTree::Subtree(tt)) = tts.peek() { tts.next(); if let Some(TokenTree::Leaf(Leaf::Literal(lit))) = tt.token_trees.first() { - if let Ok(align) = lit.text.parse() { + if let Ok(align) = lit.symbol.as_str().parse() { let align = Align::from_bytes(align).ok(); max_align = max_align.max(align); } @@ -141,13 +141,13 @@ fn parse_repr_tt(tt: &Subtree) -> Option { } ReprFlags::empty() } - "C" => ReprFlags::IS_C, - "transparent" => ReprFlags::IS_TRANSPARENT, - "simd" => ReprFlags::IS_SIMD, + s if *s == sym::C => ReprFlags::IS_C, + s if *s == sym::transparent => ReprFlags::IS_TRANSPARENT, + s if *s == sym::simd => ReprFlags::IS_SIMD, repr => { - if let Some(builtin) = BuiltinInt::from_suffix(repr) + if let Some(builtin) = BuiltinInt::from_suffix_sym(repr) .map(Either::Left) - .or_else(|| BuiltinUint::from_suffix(repr).map(Either::Right)) + .or_else(|| BuiltinUint::from_suffix_sym(repr).map(Either::Right)) { int = Some(match builtin { Either::Left(bi) => match bi { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index eac8f0dd74ac8..1f728a0b38b52 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -278,7 +278,7 @@ fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: CrateId) -> bool { tt.split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',')); for output in segments.skip(1) { match output { - [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "no_std" => { + [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.sym == sym::no_std => { return true } _ => {} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index b0543727c27d0..6861e0f2f5be5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -63,6 +63,7 @@ use base_db::{CrateId, FileId}; use hir_expand::{ name::Name, proc_macro::ProcMacroKind, ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId, }; +use intern::Symbol; use itertools::Itertools; use la_arena::Arena; use rustc_hash::{FxHashMap, FxHashSet}; @@ -148,11 +149,11 @@ struct DefMapCrateData { proc_macro_loading_error: Option>, /// Custom attributes registered with `#![register_attr]`. - registered_attrs: Vec, + registered_attrs: Vec, /// Custom tool modules registered with `#![register_tool]`. - registered_tools: Vec, + registered_tools: Vec, /// Unstable features of Rust enabled with `#![feature(A, B)]`. - unstable_features: FxHashSet, + unstable_features: FxHashSet, /// #[rustc_coherence_is_core] rustc_coherence_is_core: bool, no_core: bool, @@ -170,7 +171,7 @@ impl DefMapCrateData { fn_proc_macro_mapping: FxHashMap::default(), proc_macro_loading_error: None, registered_attrs: Vec::new(), - registered_tools: PREDEFINED_TOOLS.into(), + registered_tools: PREDEFINED_TOOLS.iter().map(|it| Symbol::intern(it)).collect(), unstable_features: FxHashSet::default(), rustc_coherence_is_core: false, no_core: false, @@ -447,15 +448,15 @@ impl DefMap { self.derive_helpers_in_scope.get(&id.map(|it| it.upcast())).map(Deref::deref) } - pub fn registered_tools(&self) -> &[SmolStr] { + pub fn registered_tools(&self) -> &[Symbol] { &self.data.registered_tools } - pub fn registered_attrs(&self) -> &[SmolStr] { + pub fn registered_attrs(&self) -> &[Symbol] { &self.data.registered_attrs } - pub fn is_unstable_feature_enabled(&self, feature: &str) -> bool { + pub fn is_unstable_feature_enabled(&self, feature: &Symbol) -> bool { self.data.unstable_features.contains(feature) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs index f842027d642a6..747860fd8e17b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs @@ -7,7 +7,7 @@ use hir_expand::{ MacroCallId, MacroCallKind, MacroDefId, }; use span::SyntaxContextId; -use syntax::{ast, SmolStr}; +use syntax::ast; use triomphe::Arc; use crate::{ @@ -79,20 +79,20 @@ impl DefMap { let segments = path.segments(); if let Some(name) = segments.first() { - let name = name.to_smol_str(); - let pred = |n: &_| *n == name; + let name = name.symbol(); + let pred = |n: &_| *n == *name; - let is_tool = self.data.registered_tools.iter().map(SmolStr::as_str).any(pred); + let is_tool = self.data.registered_tools.iter().any(pred); // FIXME: tool modules can be shadowed by actual modules if is_tool { return true; } if segments.len() == 1 { - if find_builtin_attr_idx(&name).is_some() { + if find_builtin_attr_idx(name).is_some() { return true; } - if self.data.registered_attrs.iter().map(SmolStr::as_str).any(pred) { + if self.data.registered_attrs.iter().any(pred) { return true; } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 13abcce78ead4..a614d99de6c1f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -317,20 +317,20 @@ impl DefCollector<'_> { .into_iter() .flatten() .filter_map(|(feat, _)| match feat.segments() { - [name] => Some(name.to_smol_str()), + [name] => Some(name.symbol().clone()), _ => None, }); crate_data.unstable_features.extend(features); } () if *attr_name == sym::register_attr.clone() => { if let Some(ident) = attr.single_ident_value() { - crate_data.registered_attrs.push(ident.text.clone()); + crate_data.registered_attrs.push(ident.sym.clone()); cov_mark::hit!(register_attr); } } () if *attr_name == sym::register_tool.clone() => { if let Some(ident) = attr.single_ident_value() { - crate_data.registered_tools.push(ident.text.clone()); + crate_data.registered_tools.push(ident.sym.clone()); cov_mark::hit!(register_tool); } } @@ -2129,9 +2129,7 @@ impl ModCollector<'_, '_> { let is_export = export_attr.exists(); let local_inner = if is_export { export_attr.tt_values().flat_map(|it| it.token_trees.iter()).any(|it| match it { - tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { - ident.text.contains("local_inner_macros") - } + tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.sym == sym::local_inner_macros, _ => false, }) } else { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs index 5052708dc9391..4789b1f014579 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs @@ -1,6 +1,7 @@ //! Nameres-specific procedural macro data and helpers. use hir_expand::name::{AsName, Name}; +use intern::sym; use crate::attr::Attrs; use crate::tt::{Leaf, TokenTree}; @@ -67,7 +68,7 @@ pub(crate) fn parse_macro_name_and_helper_attrs(tt: &[TokenTree]) -> Option<(Nam TokenTree::Leaf(Leaf::Punct(comma)), TokenTree::Leaf(Leaf::Ident(attributes)), TokenTree::Subtree(helpers) - ] if comma.char == ',' && attributes.text == "attributes" => + ] if comma.char == ',' && attributes.sym == sym::attributes => { let helpers = helpers .token_trees diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 49a104fa118e6..8ef7b7049ae7d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -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 { 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> { 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, } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs index 180d8f05627f4..b2924ae6736c7 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs @@ -82,7 +82,7 @@ enum VariantShape { } fn tuple_field_iterator(span: Span, n: usize) -> impl Iterator { - (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 } [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 { |(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 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); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index fb12adb87cb34..4b1a3d697280c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -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 { 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::() { + if let Ok(b) = text.as_str().parse::() { 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 { - 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 { +fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &Symbol) -> Option { 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() } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs index 55ae19068f9c6..5f038cfe6871d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs @@ -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() { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs index 2e7865ed3bf8c..3d3df83361814 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs @@ -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, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index 2896afed084fd..cf51535630f5e 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -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, } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs index 0c112554e1f43..ee15b1b5ce9d5 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs @@ -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 { - static BUILTIN_LOOKUP_TABLE: OnceLock> = OnceLock::new(); +pub fn find_builtin_attr_idx(name: &Symbol) -> Option { + static BUILTIN_LOOKUP_TABLE: OnceLock> = 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() diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 907e939153ba7..2c26fe414d91e 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -316,30 +316,36 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option 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 }) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index fce9df6722b47..64c094bd28759 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -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 AsName for tt::Ident { fn as_name(&self) -> Name { - Name::resolve(&self.text) + Name::resolve(self.sym.as_str()) } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs index f1d28450b31e8..a65d46161e583 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs @@ -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 { - tt::Ident { text: syntax::SmolStr::new_static("$crate"), span, is_raw: tt::IdentIsRaw::No } +pub(crate) fn dollar_crate(span: Span) -> tt::Ident { + 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 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] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 01e43a67e434b..1374d0c38b866 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -3,6 +3,7 @@ use std::fmt; use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId}; +use intern::sym; use once_cell::unsync::Lazy; use rustc_index::IndexVec; use rustc_pattern_analysis::{ @@ -75,9 +76,9 @@ pub(crate) struct MatchCheckCtx<'db> { impl<'db> MatchCheckCtx<'db> { pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self { let def_map = db.crate_def_map(module.krate()); - let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns"); + let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns); let min_exhaustive_patterns = - def_map.is_unstable_feature_enabled("min_exhaustive_patterns"); + def_map.is_unstable_feature_enabled(&sym::min_exhaustive_patterns); Self { module, body, db, exhaustive_patterns, min_exhaustive_patterns } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index c868357ff982f..9f33c50670857 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -3380,23 +3380,27 @@ impl BuiltinAttr { if let builtin @ Some(_) = Self::builtin(name) { return builtin; } - let idx = - db.crate_def_map(krate.id).registered_attrs().iter().position(|it| it == name)? as u32; + let idx = db + .crate_def_map(krate.id) + .registered_attrs() + .iter() + .position(|it| it.as_str() == name)? as u32; Some(BuiltinAttr { krate: Some(krate.id), idx }) } fn builtin(name: &str) -> Option { - hir_expand::inert_attr_macro::find_builtin_attr_idx(name) + hir_expand::inert_attr_macro::find_builtin_attr_idx(&Symbol::intern(name)) .map(|idx| BuiltinAttr { krate: None, idx: idx as u32 }) } - pub fn name(&self, db: &dyn HirDatabase) -> SmolStr { - // FIXME: Return a `Name` here + pub fn name(&self, db: &dyn HirDatabase) -> Name { match self.krate { - Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(), - None => { - SmolStr::new(hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].name) - } + Some(krate) => Name::new_symbol_root( + db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(), + ), + None => Name::new_symbol_root(Symbol::intern( + hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].name, + )), } } @@ -3420,13 +3424,15 @@ impl ToolModule { pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option { let krate = krate.id; let idx = - db.crate_def_map(krate).registered_tools().iter().position(|it| it == name)? as u32; + db.crate_def_map(krate).registered_tools().iter().position(|it| it.as_str() == name)? + as u32; Some(ToolModule { krate, idx }) } - pub fn name(&self, db: &dyn HirDatabase) -> SmolStr { - // FIXME: Return a `Name` here - db.crate_def_map(self.krate).registered_tools()[self.idx as usize].clone() + pub fn name(&self, db: &dyn HirDatabase) -> Name { + Name::new_symbol_root( + db.crate_def_map(self.krate).registered_tools()[self.idx as usize].clone(), + ) } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index dbb2adcd301f5..a53c156b5da62 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -192,13 +192,13 @@ impl Definition { let AttributeTemplate { word, list, name_value_str } = it.template(db)?; let mut docs = "Valid forms are:".to_owned(); if word { - format_to!(docs, "\n - #\\[{}]", name); + format_to!(docs, "\n - #\\[{}]", name.display(db)); } if let Some(list) = list { - format_to!(docs, "\n - #\\[{}({})]", name, list); + format_to!(docs, "\n - #\\[{}({})]", name.display(db), list); } if let Some(name_value_str) = name_value_str { - format_to!(docs, "\n - #\\[{} = {}]", name, name_value_str); + format_to!(docs, "\n - #\\[{} = {}]", name.display(db), name_value_str); } Some(Documentation::new(docs.replace('*', "\\*"))) } @@ -256,8 +256,8 @@ impl Definition { Definition::GenericParam(it) => it.display(db).to_string(), Definition::Label(it) => it.name(db).display(db).to_string(), Definition::ExternCrateDecl(it) => it.display(db).to_string(), - Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db)), - Definition::ToolModule(it) => it.name(db).to_string(), + Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db).display(db)), + Definition::ToolModule(it) => it.name(db).display(db).to_string(), Definition::DeriveHelper(it) => format!("derive_helper {}", it.name(db).display(db)), } } diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs index a3cc5c3d6a3d6..9e3f6d842f315 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -174,6 +174,32 @@ impl Symbol { } } + pub fn integer(i: usize) -> Self { + match i { + 0 => symbols::INTEGER_0.clone(), + 1 => symbols::INTEGER_1.clone(), + 2 => symbols::INTEGER_2.clone(), + 3 => symbols::INTEGER_3.clone(), + 4 => symbols::INTEGER_4.clone(), + 5 => symbols::INTEGER_5.clone(), + 6 => symbols::INTEGER_6.clone(), + 7 => symbols::INTEGER_7.clone(), + 8 => symbols::INTEGER_8.clone(), + 9 => symbols::INTEGER_9.clone(), + 10 => symbols::INTEGER_10.clone(), + 11 => symbols::INTEGER_11.clone(), + 12 => symbols::INTEGER_12.clone(), + 13 => symbols::INTEGER_13.clone(), + 14 => symbols::INTEGER_14.clone(), + 15 => symbols::INTEGER_15.clone(), + i => Symbol::intern(&format!("{i}")), + } + } + + pub fn empty() -> Self { + symbols::__empty.clone() + } + pub fn as_str(&self) -> &str { self.repr.as_str() } diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 064335471e95a..61b9d099e06a3 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -56,6 +56,10 @@ macro_rules! define_symbols { define_symbols! { @WITH_NAME: + __empty = "", + unsafe_ = "unsafe", + in_ = "in", + super_ = "super", self_ = "self", Self_ = "Self", tick_static = "'static", @@ -78,10 +82,18 @@ define_symbols! { INTEGER_14 = "14", INTEGER_15 = "15", fn_ = "fn", + crate_ = "crate", + underscore = "_", + true_ = "true", + false_ = "false", + let_ = "let", + const_ = "const", @PLAIN: + __ra_fixup, add_assign, add, + attributes, align_offset, alloc_layout, alloc, @@ -92,6 +104,9 @@ define_symbols! { bench, bitand_assign, bitand, + notable_trait, + hidden, + local_inner_macros, bitor_assign, bitor, bitxor_assign, @@ -225,9 +240,12 @@ define_symbols! { log_syntax, lt, macro_rules, + ignore, + count, manually_drop, maybe_uninit, metadata_type, + missing, module_path, mul_assign, mul, @@ -349,6 +367,10 @@ define_symbols! { u8, Unknown, unpin, + simd, + C, + align, + packed, unreachable_2015, unreachable_2021, unreachable, @@ -356,5 +378,7 @@ define_symbols! { unsize, usize, v1, + exhaustive_patterns, + min_exhaustive_patterns, va_list } diff --git a/src/tools/rust-analyzer/crates/mbe/Cargo.toml b/src/tools/rust-analyzer/crates/mbe/Cargo.toml index 1002de2104a0c..57834623e84fa 100644 --- a/src/tools/rust-analyzer/crates/mbe/Cargo.toml +++ b/src/tools/rust-analyzer/crates/mbe/Cargo.toml @@ -24,6 +24,7 @@ parser.workspace = true tt.workspace = true stdx.workspace = true span.workspace = true +intern.workspace = true [dev-dependencies] test-utils.workspace = true diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs index 6a2f1c236869d..04e78a0833407 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs @@ -1,10 +1,11 @@ //! This module add real world mbe example for benchmark tests +use intern::Symbol; use rustc_hash::FxHashMap; use span::{Edition, Span}; use syntax::{ ast::{self, HasName}, - AstNode, SmolStr, + AstNode, }; use test_utils::{bench, bench_fixture, skip_slow_tests}; @@ -228,7 +229,7 @@ fn invocation_fixtures( fn make_ident(ident: &str) -> tt::TokenTree { tt::Leaf::Ident(tt::Ident { span: DUMMY, - text: SmolStr::new(ident), + sym: Symbol::intern(ident), is_raw: tt::IdentIsRaw::No, }) .into() @@ -239,7 +240,7 @@ fn invocation_fixtures( fn make_literal(lit: &str) -> tt::TokenTree { tt::Leaf::Literal(tt::Literal { span: DUMMY, - text: SmolStr::new(lit), + symbol: Symbol::intern(lit), kind: tt::LitKind::Str, suffix: None, }) diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander.rs b/src/tools/rust-analyzer/crates/mbe/src/expander.rs index cfad8bcc0b454..55b89aa848d5d 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander.rs @@ -5,9 +5,9 @@ mod matcher; mod transcriber; +use intern::Symbol; use rustc_hash::FxHashMap; use span::{Edition, Span}; -use syntax::SmolStr; use crate::{parser::MetaVarKind, ExpandError, ExpandResult, MatchedArmIndex}; @@ -110,12 +110,12 @@ pub(crate) fn expand_rules( /// the `Bindings` we should take. We push to the stack when we enter a /// repetition. /// -/// In other words, `Bindings` is a *multi* mapping from `SmolStr` to +/// In other words, `Bindings` is a *multi* mapping from `Symbol` to /// `tt::TokenTree`, where the index to select a particular `TokenTree` among /// many is not a plain `usize`, but a `&[usize]`. #[derive(Debug, Default, Clone, PartialEq, Eq)] struct Bindings { - inner: FxHashMap, + inner: FxHashMap, } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs index b20d5579ca63b..3762d20bab62e 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs @@ -61,9 +61,9 @@ use std::{rc::Rc, sync::Arc}; +use intern::{sym, Symbol}; use smallvec::{smallvec, SmallVec}; use span::{Edition, Span}; -use syntax::SmolStr; use tt::{iter::TtIter, DelimSpan}; use crate::{ @@ -74,12 +74,12 @@ use crate::{ }; impl Bindings { - fn push_optional(&mut self, name: &SmolStr) { - self.inner.insert(name.clone(), Binding::Fragment(Fragment::Empty)); + fn push_optional(&mut self, name: Symbol) { + self.inner.insert(name, Binding::Fragment(Fragment::Empty)); } - fn push_empty(&mut self, name: &SmolStr) { - self.inner.insert(name.clone(), Binding::Empty); + fn push_empty(&mut self, name: Symbol) { + self.inner.insert(name, Binding::Empty); } fn bindings(&self) -> impl Iterator { @@ -127,10 +127,10 @@ pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree, edition: #[derive(Debug, Clone)] enum BindingKind { - Empty(SmolStr), - Optional(SmolStr), - Fragment(SmolStr, Fragment), - Missing(SmolStr, MetaVarKind), + Empty(Symbol), + Optional(Symbol), + Fragment(Symbol, Fragment), + Missing(Symbol, MetaVarKind), Nested(usize, usize), } @@ -178,20 +178,20 @@ impl BindingsBuilder { } } - fn push_empty(&mut self, idx: &mut BindingsIdx, var: &SmolStr) { + fn push_empty(&mut self, idx: &mut BindingsIdx, var: &Symbol) { self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Empty(var.clone())))); } - fn push_optional(&mut self, idx: &mut BindingsIdx, var: &SmolStr) { + fn push_optional(&mut self, idx: &mut BindingsIdx, var: &Symbol) { self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Optional(var.clone())))); } - fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &SmolStr, fragment: Fragment) { + fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &Symbol, fragment: Fragment) { self.nodes[idx.0] .push(LinkNode::Node(Rc::new(BindingKind::Fragment(var.clone(), fragment)))); } - fn push_missing(&mut self, idx: &mut BindingsIdx, var: &SmolStr, kind: MetaVarKind) { + fn push_missing(&mut self, idx: &mut BindingsIdx, var: &Symbol, kind: MetaVarKind) { self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Missing(var.clone(), kind)))); } @@ -219,10 +219,10 @@ impl BindingsBuilder { for cmd in nodes { match cmd { BindingKind::Empty(name) => { - bindings.push_empty(name); + bindings.push_empty(name.clone()); } BindingKind::Optional(name) => { - bindings.push_optional(name); + bindings.push_optional(name.clone()); } BindingKind::Fragment(name, fragment) => { bindings.inner.insert(name.clone(), Binding::Fragment(fragment.clone())); @@ -507,7 +507,7 @@ fn match_loop_inner<'t>( } OpDelimited::Op(Op::Literal(lhs)) => { if let Ok(rhs) = src.clone().expect_leaf() { - if matches!(rhs, tt::Leaf::Literal(it) if it.text == lhs.text) { + if matches!(rhs, tt::Leaf::Literal(it) if it.symbol == lhs.symbol) { item.dot.next(); } else { res.add_err(ExpandError::UnexpectedToken); @@ -521,7 +521,7 @@ fn match_loop_inner<'t>( } OpDelimited::Op(Op::Ident(lhs)) => { if let Ok(rhs) = src.clone().expect_leaf() { - if matches!(rhs, tt::Leaf::Ident(it) if it.text == lhs.text) { + if matches!(rhs, tt::Leaf::Ident(it) if it.sym == lhs.sym) { item.dot.next(); } else { res.add_err(ExpandError::UnexpectedToken); @@ -554,7 +554,7 @@ fn match_loop_inner<'t>( // ident, not a punct. ExpandError::UnexpectedToken } else { - let lhs: SmolStr = lhs.collect(); + let lhs = lhs.collect::(); ExpandError::binding_error(format!("expected punct: `{lhs}`")) } } else { @@ -759,7 +759,9 @@ fn match_meta_var( // [1]: https://github.com/rust-lang/rust/blob/f0c4da499/compiler/rustc_expand/src/mbe/macro_parser.rs#L576 match input.peek_n(0) { Some(tt::TokenTree::Leaf(tt::Leaf::Ident(it))) - if it.text == "_" || it.text == "let" || it.text == "const" => + if it.sym == sym::underscore + || it.sym == sym::let_ + || it.sym == sym::const_ => { return ExpandResult::only_err(ExpandError::NoMatchingRule) } @@ -824,7 +826,7 @@ fn match_meta_var( expect_fragment(input, fragment, edition).map(|it| it.map(Fragment::Tokens)) } -fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate) { +fn collect_vars(collector_fun: &mut impl FnMut(Symbol), pattern: &MetaTemplate) { for op in pattern.iter() { match op { Op::Var { name, .. } => collector_fun(name.clone()), @@ -908,13 +910,13 @@ fn expect_separator(iter: &mut TtIter<'_, S>, separator: &Separator) -> let mut fork = iter.clone(); let ok = match separator { Separator::Ident(lhs) => match fork.expect_ident_or_underscore() { - Ok(rhs) => rhs.text == lhs.text, + Ok(rhs) => rhs.sym == lhs.sym, Err(_) => false, }, Separator::Literal(lhs) => match fork.expect_literal() { Ok(rhs) => match rhs { - tt::Leaf::Literal(rhs) => rhs.text == lhs.text, - tt::Leaf::Ident(rhs) => rhs.text == lhs.text, + tt::Leaf::Literal(rhs) => rhs.symbol == lhs.symbol, + tt::Leaf::Ident(rhs) => rhs.sym == lhs.symbol, tt::Leaf::Punct(_) => false, }, Err(_) => false, diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs index e3359865cb276..4de7cccd9680e 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs @@ -1,8 +1,8 @@ //! Transcriber takes a template, like `fn $ident() {}`, a set of bindings like //! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}` +use intern::{sym, Symbol}; use span::Span; -use syntax::{format_smolstr, SmolStr}; use tt::Delimiter; use crate::{ @@ -12,16 +12,16 @@ use crate::{ }; impl Bindings { - fn get(&self, name: &str) -> Result<&Binding, ExpandError> { + fn get(&self, name: &Symbol) -> Result<&Binding, ExpandError> { match self.inner.get(name) { Some(binding) => Ok(binding), - None => Err(ExpandError::UnresolvedBinding(Box::new(Box::from(name)))), + None => Err(ExpandError::UnresolvedBinding(Box::new(Box::from(name.as_str())))), } } fn get_fragment( &self, - name: &str, + name: &Symbol, mut span: Span, nesting: &mut [NestingState], marker: impl Fn(&mut Span), @@ -97,7 +97,7 @@ impl Bindings { | MetaVarKind::Expr | MetaVarKind::Ident => { Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: SmolStr::new_static("missing"), + sym: sym::missing.clone(), span, is_raw: tt::IdentIsRaw::No, }))) @@ -112,7 +112,7 @@ impl Bindings { spacing: tt::Spacing::Joint, })), tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: SmolStr::new_static("missing"), + sym: sym::missing.clone(), span, is_raw: tt::IdentIsRaw::No, })), @@ -121,7 +121,7 @@ impl Bindings { } MetaVarKind::Literal => { Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: SmolStr::new_static("\"missing\""), + sym: sym::missing.clone(), span, is_raw: tt::IdentIsRaw::No, }))) @@ -239,7 +239,7 @@ fn expand_subtree( ctx.nesting.get(ctx.nesting.len() - 1 - depth).map_or(0, |nest| nest.idx); arena.push( tt::Leaf::Literal(tt::Literal { - text: format_smolstr!("{index}"), + symbol: Symbol::integer(index), span: ctx.call_site, kind: tt::LitKind::Integer, suffix: None, @@ -254,7 +254,7 @@ fn expand_subtree( }); arena.push( tt::Leaf::Literal(tt::Literal { - text: format_smolstr!("{length}"), + symbol: Symbol::integer(length), span: ctx.call_site, kind: tt::LitKind::Integer, suffix: None, @@ -263,7 +263,7 @@ fn expand_subtree( ); } Op::Count { name, depth } => { - let mut binding = match ctx.bindings.get(name.as_str()) { + let mut binding = match ctx.bindings.get(name) { Ok(b) => b, Err(e) => { if err.is_none() { @@ -321,7 +321,7 @@ fn expand_subtree( }; arena.push( tt::Leaf::Literal(tt::Literal { - text: format_smolstr!("{c}"), + symbol: Symbol::integer(c), span: ctx.call_site, suffix: None, kind: tt::LitKind::Integer, @@ -344,12 +344,12 @@ fn expand_subtree( fn expand_var( ctx: &mut ExpandCtx<'_>, - v: &SmolStr, + v: &Symbol, id: Span, marker: impl Fn(&mut Span), ) -> ExpandResult { // We already handle $crate case in mbe parser - debug_assert!(v != "crate"); + debug_assert!(*v != sym::crate_); match ctx.bindings.get_fragment(v, id, &mut ctx.nesting, marker) { Ok(it) => ExpandResult::ok(it), @@ -373,7 +373,7 @@ fn expand_var( tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, span: id }) .into(), tt::Leaf::from(tt::Ident { - text: v.clone(), + sym: v.clone(), span: id, is_raw: tt::IdentIsRaw::No, }) diff --git a/src/tools/rust-analyzer/crates/mbe/src/parser.rs b/src/tools/rust-analyzer/crates/mbe/src/parser.rs index 18af35c1e2900..74a2c771e2037 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/parser.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/parser.rs @@ -4,8 +4,8 @@ use std::sync::Arc; use arrayvec::ArrayVec; +use intern::{sym, Symbol}; use span::{Edition, Span, SyntaxContextId}; -use syntax::SmolStr; use tt::iter::TtIter; use crate::ParseError; @@ -67,12 +67,12 @@ impl MetaTemplate { #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) enum Op { Var { - name: SmolStr, + name: Symbol, kind: Option, id: Span, }, Ignore { - name: SmolStr, + name: Symbol, id: Span, }, Index { @@ -82,7 +82,7 @@ pub(crate) enum Op { depth: usize, }, Count { - name: SmolStr, + name: Symbol, // FIXME: `usize`` once we drop support for 1.76 depth: Option, }, @@ -138,8 +138,8 @@ impl PartialEq for Separator { use Separator::*; match (self, other) { - (Ident(a), Ident(b)) => a.text == b.text, - (Literal(a), Literal(b)) => a.text == b.text, + (Ident(a), Ident(b)) => a.sym == b.sym, + (Literal(a), Literal(b)) => a.symbol == b.symbol, (Puncts(a), Puncts(b)) if a.len() == b.len() => { let a_iter = a.iter().map(|a| a.char); let b_iter = b.iter().map(|b| b.char); @@ -203,23 +203,23 @@ fn next_op( } }, tt::TokenTree::Leaf(leaf) => match leaf { - tt::Leaf::Ident(ident) if ident.text == "crate" => { + tt::Leaf::Ident(ident) if ident.sym == sym::crate_ => { // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. Op::Ident(tt::Ident { - text: "$crate".into(), + sym: sym::dollar_crate.clone(), span: ident.span, is_raw: tt::IdentIsRaw::No, }) } tt::Leaf::Ident(ident) => { let kind = eat_fragment_kind(edition, src, mode)?; - let name = ident.text.clone(); + let name = ident.sym.clone(); let id = ident.span; Op::Var { name, kind, id } } tt::Leaf::Literal(lit) if is_boolean_literal(lit) => { let kind = eat_fragment_kind(edition, src, mode)?; - let name = lit.text.clone(); + let name = lit.symbol.clone(); let id = lit.span; Op::Var { name, kind, id } } @@ -277,7 +277,7 @@ fn eat_fragment_kind( let ident = src .expect_ident() .map_err(|()| ParseError::unexpected("missing fragment specifier"))?; - let kind = match ident.text.as_str() { + let kind = match ident.sym.as_str() { "path" => MetaVarKind::Path, "ty" => MetaVarKind::Ty, "pat" => match edition(ident.span.ctx) { @@ -303,7 +303,7 @@ fn eat_fragment_kind( } fn is_boolean_literal(lit: &tt::Literal) -> bool { - matches!(lit.text.as_str(), "true" | "false") + matches!(lit.symbol.as_str(), "true" | "false") } fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option, RepeatKind), ParseError> { @@ -353,23 +353,23 @@ fn parse_metavar_expr(new_meta_vars: bool, src: &mut TtIter<'_, Span>) -> Result let mut args = TtIter::new(args); - let op = match &*func.text { - "ignore" => { + let op = match &func.sym { + s if sym::ignore == *s => { if new_meta_vars { args.expect_dollar()?; } let ident = args.expect_ident()?; - Op::Ignore { name: ident.text.clone(), id: ident.span } + Op::Ignore { name: ident.sym.clone(), id: ident.span } } - "index" => Op::Index { depth: parse_depth(&mut args)? }, - "len" => Op::Len { depth: parse_depth(&mut args)? }, - "count" => { + s if sym::index == *s => Op::Index { depth: parse_depth(&mut args)? }, + s if sym::len == *s => Op::Len { depth: parse_depth(&mut args)? }, + s if sym::count == *s => { if new_meta_vars { args.expect_dollar()?; } let ident = args.expect_ident()?; let depth = if try_eat_comma(&mut args) { Some(parse_depth(&mut args)?) } else { None }; - Op::Count { name: ident.text.clone(), depth } + Op::Count { name: ident.sym.clone(), depth } } _ => return Err(()), }; @@ -384,11 +384,11 @@ fn parse_metavar_expr(new_meta_vars: bool, src: &mut TtIter<'_, Span>) -> Result fn parse_depth(src: &mut TtIter<'_, Span>) -> Result { if src.len() == 0 { Ok(0) - } else if let tt::Leaf::Literal(tt::Literal { text, suffix: None, .. }) = + } else if let tt::Leaf::Literal(tt::Literal { symbol: text, suffix: None, .. }) = src.expect_literal()? { // Suffixes are not allowed. - text.parse().map_err(|_| ()) + text.as_str().parse().map_err(|_| ()) } else { Err(()) } diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs index 4d66464932b88..7ff89631080e4 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs @@ -2,6 +2,7 @@ use std::fmt; +use intern::Symbol; use rustc_hash::{FxHashMap, FxHashSet}; use span::{Edition, SpanAnchor, SpanData, SpanMap}; use stdx::{format_to, never, non_empty_vec::NonEmptyVec}; @@ -322,7 +323,7 @@ where () => { tt::Ident { span: conv.span_for(abs_range), - text: token.to_text(conv), + sym: Symbol::intern(&token.to_text(conv)), is_raw: tt::IdentIsRaw::No, } .into() @@ -332,14 +333,14 @@ where T![true] | T![false] => make_ident!(), IDENT => { let text = token.to_text(conv); - tt::Ident::new(text, conv.span_for(abs_range)).into() + tt::Ident::new(&text, conv.span_for(abs_range)).into() } UNDERSCORE => make_ident!(), k if k.is_keyword() => make_ident!(), k if k.is_literal() => { let text = token.to_text(conv); let span = conv.span_for(abs_range); - token_to_literal(text, span).into() + token_to_literal(&text, span).into() } LIFETIME_IDENT => { let apostrophe = tt::Leaf::from(tt::Punct { @@ -351,7 +352,7 @@ where token_trees.push(apostrophe.into()); let ident = tt::Leaf::from(tt::Ident { - text: SmolStr::new(&token.to_text(conv)[1..]), + sym: Symbol::intern(&token.to_text(conv)[1..]), span: conv.span_for(TextRange::new( abs_range.start() + TextSize::of('\''), abs_range.end(), @@ -436,7 +437,7 @@ fn is_single_token_op(kind: SyntaxKind) -> bool { /// And then quote the string, which is needed to convert to `tt::Literal` /// /// Note that proc-macros desugar with string literals where as macro_rules macros desugar with raw string literals. -pub fn desugar_doc_comment_text(text: &str, mode: DocCommentDesugarMode) -> (SmolStr, tt::LitKind) { +pub fn desugar_doc_comment_text(text: &str, mode: DocCommentDesugarMode) -> (Symbol, tt::LitKind) { match mode { DocCommentDesugarMode::Mbe => { let mut num_of_hashes = 0; @@ -451,11 +452,11 @@ pub fn desugar_doc_comment_text(text: &str, mode: DocCommentDesugarMode) -> (Smo } // Quote raw string with delimiters - (text.into(), tt::LitKind::StrRaw(num_of_hashes)) + (Symbol::intern(text), tt::LitKind::StrRaw(num_of_hashes)) } // Quote string with delimiters DocCommentDesugarMode::ProcMacro => { - (format_smolstr!("{}", text.escape_debug()), tt::LitKind::Str) + (Symbol::intern(&format_smolstr!("{}", text.escape_debug())), tt::LitKind::Str) } } } @@ -471,7 +472,7 @@ fn convert_doc_comment( let mk_ident = |s: &str| { tt::TokenTree::from(tt::Leaf::from(tt::Ident { - text: s.into(), + sym: Symbol::intern(s), span, is_raw: tt::IdentIsRaw::No, })) @@ -494,7 +495,7 @@ fn convert_doc_comment( text = &text[0..text.len() - 2]; } let (text, kind) = desugar_doc_comment_text(text, mode); - let lit = tt::Literal { text, span, kind, suffix: None }; + let lit = tt::Literal { symbol: text, span, kind, suffix: None }; tt::TokenTree::from(tt::Leaf::from(lit)) }; @@ -928,7 +929,12 @@ where fn float_split(&mut self, has_pseudo_dot: bool) { let (text, span) = match self.cursor.token_tree() { Some(tt::buffer::TokenTreeRef::Leaf( - tt::Leaf::Literal(tt::Literal { text, span, kind: tt::LitKind::Float, suffix: _ }), + tt::Leaf::Literal(tt::Literal { + symbol: text, + span, + kind: tt::LitKind::Float, + suffix: _, + }), _, )) => (text.as_str(), *span), tt => unreachable!("{tt:?}"), @@ -988,7 +994,7 @@ where self.buf.push_str("r#"); self.text_pos += TextSize::of("r#"); } - let r = (ident.text.as_str(), ident.span); + let r = (ident.sym.as_str(), ident.span); self.cursor = self.cursor.bump(); r } diff --git a/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs b/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs index bf5494d37149b..7636359805c72 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/to_parser_input.rs @@ -49,23 +49,22 @@ pub(crate) fn to_parser_input(buffer: &TokenBuffer<'_, S>) }; res.push(kind); - if kind == FLOAT_NUMBER && !lit.text.ends_with('.') { + if kind == FLOAT_NUMBER && !lit.symbol.as_str().ends_with('.') { // Tag the token as joint if it is float with a fractional part // we use this jointness to inform the parser about what token split // event to emit when we encounter a float literal in a field access res.was_joint(); } } - tt::Leaf::Ident(ident) => match ident.text.as_ref() { + tt::Leaf::Ident(ident) => match ident.sym.as_str() { "_" => res.push(T![_]), i if i.starts_with('\'') => res.push(LIFETIME_IDENT), _ if ident.is_raw.yes() => res.push(IDENT), - _ => match SyntaxKind::from_keyword(&ident.text) { + text => match SyntaxKind::from_keyword(text) { Some(kind) => res.push(kind), None => { - let contextual_keyword = - SyntaxKind::from_contextual_keyword(&ident.text) - .unwrap_or(SyntaxKind::IDENT); + let contextual_keyword = SyntaxKind::from_contextual_keyword(text) + .unwrap_or(SyntaxKind::IDENT); res.push_ident(contextual_keyword); } }, diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml index 889eefa8b5c61..345fb9f8ae973 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml @@ -28,8 +28,7 @@ span.workspace = true # InternIds for the syntax context base-db.workspace = true la-arena.workspace = true -# only here to parse via token_to_literal -mbe.workspace = true +intern.workspace = true [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs index 3a915e668bbff..54c1475b8b1c8 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs @@ -13,7 +13,6 @@ use base_db::Env; use paths::{AbsPath, AbsPathBuf}; use span::Span; use std::{fmt, io, sync::Arc}; -use tt::SmolStr; use serde::{Deserialize, Serialize}; @@ -66,7 +65,7 @@ impl MacroDylib { pub struct ProcMacro { process: Arc, dylib_path: Arc, - name: SmolStr, + name: Box, kind: ProcMacroKind, } diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs index 65835048173ab..65f60a7c5bd28 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs @@ -158,6 +158,7 @@ type ProtocolWrite = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str) #[cfg(test)] mod tests { use base_db::FileId; + use intern::{sym, Symbol}; use la_arena::RawIdx; use span::{ErasedFileAstId, Span, SpanAnchor, SyntaxContextId}; use text_size::{TextRange, TextSize}; @@ -174,7 +175,7 @@ mod tests { let token_trees = Box::new([ TokenTree::Leaf( Ident { - text: "struct".into(), + sym: Symbol::intern("struct"), span: Span { range: TextRange::at(TextSize::new(0), TextSize::of("struct")), anchor, @@ -186,7 +187,7 @@ mod tests { ), TokenTree::Leaf( Ident { - text: "Foo".into(), + sym: Symbol::intern("Foo"), span: Span { range: TextRange::at(TextSize::new(5), TextSize::of("r#Foo")), anchor, @@ -197,7 +198,7 @@ mod tests { .into(), ), TokenTree::Leaf(Leaf::Literal(Literal { - text: "Foo".into(), + symbol: Symbol::intern("Foo"), span: Span { range: TextRange::at(TextSize::new(10), TextSize::of("\"Foo\"")), anchor, @@ -230,14 +231,14 @@ mod tests { kind: DelimiterKind::Brace, }, token_trees: Box::new([TokenTree::Leaf(Leaf::Literal(Literal { - text: "0".into(), + symbol: sym::INTEGER_0.clone(), span: Span { range: TextRange::at(TextSize::new(15), TextSize::of("0u32")), anchor, ctx: SyntaxContextId::ROOT, }, kind: tt::LitKind::Integer, - suffix: Some(Box::new("u32".into())), + suffix: Some(sym::u32.clone()), }))]), }), ]); diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs index 3d962e99d92c2..19260bc817dae 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs @@ -37,6 +37,7 @@ use std::collections::VecDeque; +use intern::Symbol; use la_arena::RawIdx; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; @@ -433,8 +434,8 @@ impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> { let id = self.token_id_of(lit.span); let (text, suffix) = if self.version >= EXTENDED_LEAF_DATA { ( - self.intern(&lit.text), - lit.suffix.as_ref().map(|s| self.intern(s)).unwrap_or(!0), + self.intern(lit.symbol.as_str()), + lit.suffix.as_ref().map(|s| self.intern(s.as_str())).unwrap_or(!0), ) } else { (self.intern_owned(format!("{lit}")), !0) @@ -469,11 +470,11 @@ impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> { let idx = self.ident.len() as u32; let id = self.token_id_of(ident.span); let text = if self.version >= EXTENDED_LEAF_DATA { - self.intern(&ident.text) + self.intern(ident.sym.as_str()) } else if ident.is_raw.yes() { - self.intern_owned(format!("r#{}", ident.text,)) + self.intern_owned(format!("r#{}", ident.sym.as_str(),)) } else { - self.intern(&ident.text) + self.intern(ident.sym.as_str()) }; self.ident.push(IdentRepr { id, text, is_raw: ident.is_raw.yes() }); idx << 2 | 0b11 @@ -555,7 +556,7 @@ impl<'span, S: InternableSpan> Reader<'span, S> { let span = read_span(repr.id); tt::Leaf::Literal(if self.version >= EXTENDED_LEAF_DATA { tt::Literal { - text: text.into(), + symbol: Symbol::intern(text), span, kind: match u16::to_le_bytes(repr.kind) { [0, _] => Err(()), @@ -572,15 +573,15 @@ impl<'span, S: InternableSpan> Reader<'span, S> { _ => unreachable!(), }, suffix: if repr.suffix != !0 { - Some(Box::new( - self.text[repr.suffix as usize].as_str().into(), + Some(Symbol::intern( + self.text[repr.suffix as usize].as_str(), )) } else { None }, } } else { - tt::token_to_literal(text.into(), span) + tt::token_to_literal(text, span) }) .into() } @@ -609,7 +610,7 @@ impl<'span, S: InternableSpan> Reader<'span, S> { tt::IdentIsRaw::split_from_symbol(text) }; tt::Leaf::Ident(tt::Ident { - text: text.into(), + sym: Symbol::intern(text), span: read_span(repr.id), is_raw, }) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml index 065701c05cc7b..673b5bd78a8e9 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml @@ -25,6 +25,7 @@ base-db.workspace = true span.workspace = true proc-macro-api.workspace = true ra-ap-rustc_lexer.workspace = true +intern.workspace = true [dev-dependencies] expect-test = "1.4.0" diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index e6281035e1a2e..f0aa6b3f93f95 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -130,14 +130,13 @@ impl ProcMacroSrvSpan for TokenId { type Server = server_impl::token_id::TokenIdServer; fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { - Self::Server { interner: &server_impl::SYMBOL_INTERNER, call_site, def_site, mixed_site } + Self::Server { call_site, def_site, mixed_site } } } impl ProcMacroSrvSpan for Span { type Server = server_impl::rust_analyzer_span::RaSpanServer; fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { Self::Server { - interner: &server_impl::SYMBOL_INTERNER, call_site, def_site, mixed_site, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs index 68e0f85978e0c..c9a8621690552 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs @@ -14,9 +14,9 @@ mod token_stream; pub use token_stream::TokenStream; pub mod rust_analyzer_span; -mod symbol; +// mod symbol; pub mod token_id; -pub use symbol::*; +// pub use symbol::*; use tt::Spacing; fn delim_to_internal(d: proc_macro::Delimiter, span: bridge::DelimSpan) -> tt::Delimiter { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 1a71f39612d3b..452ad8e083daa 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -10,13 +10,14 @@ use std::{ ops::{Bound, Range}, }; +use intern::Symbol; use proc_macro::bridge::{self, server}; use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER}; use tt::{TextRange, TextSize}; use crate::server_impl::{ delim_to_external, delim_to_internal, literal_kind_to_external, literal_kind_to_internal, - token_stream::TokenStreamBuilder, Symbol, SymbolInternerRef, SYMBOL_INTERNER, + token_stream::TokenStreamBuilder, }; mod tt { pub use tt::*; @@ -36,7 +37,6 @@ pub struct SourceFile; pub struct FreeFunctions; pub struct RaSpanServer { - pub(crate) interner: SymbolInternerRef, // FIXME: Report this back to the caller to track as dependencies pub tracked_env_vars: HashMap, Option>>, // FIXME: Report this back to the caller to track as dependencies @@ -126,15 +126,10 @@ impl server::FreeFunctions for RaSpanServer { let lit = &lit[start_offset..lit.len() - end_offset]; let suffix = match suffix { "" | "_" => None, - suffix => Some(Symbol::intern(self.interner, suffix)), + suffix => Some(Symbol::intern(suffix)), }; - Ok(bridge::Literal { - kind, - symbol: Symbol::intern(self.interner, lit), - suffix, - span: self.call_site, - }) + Ok(bridge::Literal { kind, symbol: Symbol::intern(lit), suffix, span: self.call_site }) } fn emit_diagnostic(&mut self, _: bridge::Diagnostic) { @@ -170,9 +165,9 @@ impl server::TokenStream for RaSpanServer { } bridge::TokenTree::Ident(ident) => { - let text = ident.sym.text(self.interner); + let text = ident.sym; let ident: tt::Ident = tt::Ident { - text, + sym: text, span: ident.span, is_raw: if ident.is_raw { tt::IdentIsRaw::Yes } else { tt::IdentIsRaw::No }, }; @@ -183,8 +178,8 @@ impl server::TokenStream for RaSpanServer { bridge::TokenTree::Literal(literal) => { let literal = tt::Literal { - text: literal.symbol.text(self.interner), - suffix: literal.suffix.map(|it| Box::new(it.text(self.interner))), + symbol: literal.symbol, + suffix: literal.suffix, span: literal.span, kind: literal_kind_to_internal(literal.kind), }; @@ -255,7 +250,7 @@ impl server::TokenStream for RaSpanServer { .map(|tree| match tree { tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { bridge::TokenTree::Ident(bridge::Ident { - sym: Symbol::intern(self.interner, &ident.text), + sym: ident.sym, is_raw: ident.is_raw.yes(), span: ident.span, }) @@ -264,8 +259,8 @@ impl server::TokenStream for RaSpanServer { bridge::TokenTree::Literal(bridge::Literal { span: lit.span, kind: literal_kind_to_external(lit.kind), - symbol: Symbol::intern(self.interner, &lit.text), - suffix: lit.suffix.map(|it| Symbol::intern(self.interner, &it)), + symbol: lit.symbol, + suffix: lit.suffix, }) } tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => { @@ -464,12 +459,95 @@ impl server::Server for RaSpanServer { } fn intern_symbol(ident: &str) -> Self::Symbol { - // FIXME: should be `self.interner` once the proc-macro api allows it. - Symbol::intern(&SYMBOL_INTERNER, &::tt::SmolStr::from(ident)) + Symbol::intern(ident) } fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { - // FIXME: should be `self.interner` once the proc-macro api allows it. - f(symbol.text(&SYMBOL_INTERNER).as_str()) + f(symbol.as_str()) + } +} + +#[cfg(test)] +mod tests { + use span::SyntaxContextId; + + use super::*; + + #[test] + fn test_ra_server_to_string() { + let span = Span { + range: TextRange::empty(TextSize::new(0)), + anchor: span::SpanAnchor { + file_id: span::FileId::from_raw(0), + ast_id: span::ErasedFileAstId::from_raw(0.into()), + }, + ctx: SyntaxContextId::ROOT, + }; + let s = TokenStream { + token_trees: vec![ + tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { + sym: Symbol::intern("struct"), + span, + is_raw: tt::IdentIsRaw::No, + })), + tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { + sym: Symbol::intern("T"), + span: span, + is_raw: tt::IdentIsRaw::No, + })), + tt::TokenTree::Subtree(tt::Subtree { + delimiter: tt::Delimiter { + open: span, + close: span, + kind: tt::DelimiterKind::Brace, + }, + token_trees: Box::new([]), + }), + ], + }; + + assert_eq!(s.to_string(), "struct T {}"); + } + + #[test] + fn test_ra_server_from_str() { + let span = Span { + range: TextRange::empty(TextSize::new(0)), + anchor: span::SpanAnchor { + file_id: span::FileId::from_raw(0), + ast_id: span::ErasedFileAstId::from_raw(0.into()), + }, + ctx: SyntaxContextId::ROOT, + }; + let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree { + delimiter: tt::Delimiter { + open: span, + close: span, + kind: tt::DelimiterKind::Parenthesis, + }, + token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { + is_raw: tt::IdentIsRaw::No, + sym: Symbol::intern("a"), + span, + }))]), + }); + + let t1 = TokenStream::from_str("(a)", span).unwrap(); + assert_eq!(t1.token_trees.len(), 1); + assert_eq!(t1.token_trees[0], subtree_paren_a); + + let t2 = TokenStream::from_str("(a);", span).unwrap(); + assert_eq!(t2.token_trees.len(), 2); + assert_eq!(t2.token_trees[0], subtree_paren_a); + + let underscore = TokenStream::from_str("_", span).unwrap(); + assert_eq!( + underscore.token_trees[0], + tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { + sym: Symbol::intern("_"), + span, + is_raw: tt::IdentIsRaw::No, + })) + ); } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs index 540d06457f2f3..6863ce959973e 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs @@ -1,7 +1,6 @@ //! Symbol interner for proc-macro-srv use std::{cell::RefCell, collections::HashMap, thread::LocalKey}; -use tt::SmolStr; thread_local! { pub(crate) static SYMBOL_INTERNER: RefCell = Default::default(); diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs index 94d5748b0870f..7720c6d83c38d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -5,11 +5,12 @@ use std::{ ops::{Bound, Range}, }; +use intern::Symbol; use proc_macro::bridge::{self, server}; use crate::server_impl::{ delim_to_external, delim_to_internal, literal_kind_to_external, literal_kind_to_internal, - token_stream::TokenStreamBuilder, Symbol, SymbolInternerRef, SYMBOL_INTERNER, + token_stream::TokenStreamBuilder, }; mod tt { pub use proc_macro_api::msg::TokenId; @@ -36,7 +37,6 @@ pub struct SourceFile; pub struct FreeFunctions; pub struct TokenIdServer { - pub(crate) interner: SymbolInternerRef, pub call_site: Span, pub def_site: Span, pub mixed_site: Span, @@ -117,15 +117,10 @@ impl server::FreeFunctions for TokenIdServer { let lit = &lit[start_offset..lit.len() - end_offset]; let suffix = match suffix { "" | "_" => None, - suffix => Some(Symbol::intern(self.interner, suffix)), + suffix => Some(Symbol::intern(suffix)), }; - Ok(bridge::Literal { - kind, - symbol: Symbol::intern(self.interner, lit), - suffix, - span: self.call_site, - }) + Ok(bridge::Literal { kind, symbol: Symbol::intern(lit), suffix, span: self.call_site }) } fn emit_diagnostic(&mut self, _: bridge::Diagnostic) {} @@ -159,9 +154,8 @@ impl server::TokenStream for TokenIdServer { } bridge::TokenTree::Ident(ident) => { - let text = ident.sym.text(self.interner); let ident: tt::Ident = tt::Ident { - text, + sym: ident.sym, span: ident.span, is_raw: if ident.is_raw { tt::IdentIsRaw::Yes } else { tt::IdentIsRaw::No }, }; @@ -172,8 +166,8 @@ impl server::TokenStream for TokenIdServer { bridge::TokenTree::Literal(literal) => { let literal = Literal { - text: literal.symbol.text(self.interner), - suffix: literal.suffix.map(|it| Box::new(it.text(self.interner))), + symbol: literal.symbol, + suffix: literal.suffix, span: literal.span, kind: literal_kind_to_internal(literal.kind), }; @@ -239,7 +233,7 @@ impl server::TokenStream for TokenIdServer { .map(|tree| match tree { tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { bridge::TokenTree::Ident(bridge::Ident { - sym: Symbol::intern(self.interner, &ident.text), + sym: ident.sym, is_raw: ident.is_raw.yes(), span: ident.span, }) @@ -248,8 +242,8 @@ impl server::TokenStream for TokenIdServer { bridge::TokenTree::Literal(bridge::Literal { span: lit.span, kind: literal_kind_to_external(lit.kind), - symbol: Symbol::intern(self.interner, &lit.text), - suffix: lit.suffix.map(|it| Symbol::intern(self.interner, &it)), + symbol: lit.symbol, + suffix: lit.suffix, }) } tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => { @@ -366,11 +360,11 @@ impl server::Server for TokenIdServer { } fn intern_symbol(ident: &str) -> Self::Symbol { - Symbol::intern(&SYMBOL_INTERNER, &::tt::SmolStr::from(ident)) + Symbol::intern(ident) } fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { - f(symbol.text(&SYMBOL_INTERNER).as_str()) + f(symbol.as_str()) } } @@ -383,12 +377,12 @@ mod tests { let s = TokenStream { token_trees: vec![ tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "struct".into(), + sym: Symbol::intern("struct"), span: tt::TokenId(0), is_raw: tt::IdentIsRaw::No, })), tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "T".into(), + sym: Symbol::intern("T"), span: tt::TokenId(0), is_raw: tt::IdentIsRaw::No, })), @@ -416,7 +410,7 @@ mod tests { }, token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { is_raw: tt::IdentIsRaw::No, - text: "a".into(), + sym: Symbol::intern("a"), span: tt::TokenId(0), }))]), }); @@ -433,7 +427,7 @@ mod tests { assert_eq!( underscore.token_trees[0], tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { - text: "_".into(), + sym: Symbol::intern("_"), span: tt::TokenId(0), is_raw: tt::IdentIsRaw::No, })) diff --git a/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml b/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml index 35e39229894f2..f9565721dd5f9 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml +++ b/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml @@ -16,6 +16,7 @@ base-db.workspace = true rustc-hash.workspace = true span.workspace = true stdx.workspace = true +intern.workspace = true [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index e65186d377151..7a0c474b750b6 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -13,6 +13,7 @@ use hir_expand::{ ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacros, }, }; +use intern::Symbol; use rustc_hash::FxHashMap; use span::{Edition, FileId, FilePosition, FileRange, Span}; use test_utils::{ @@ -640,11 +641,11 @@ impl ProcMacroExpander for ShortenProcMacroExpander { Leaf::Literal(it) => { // XXX Currently replaces any literals with an empty string, but supporting // "shortening" other literals would be nice. - it.text = "\"\"".into(); + it.symbol = Symbol::empty(); } Leaf::Punct(_) => {} Leaf::Ident(it) => { - it.text = it.text.chars().take(1).collect(); + it.sym = Symbol::intern(&it.sym.as_str().chars().take(1).collect::()); } } leaf diff --git a/src/tools/rust-analyzer/crates/tt/Cargo.toml b/src/tools/rust-analyzer/crates/tt/Cargo.toml index 1900635b995ee..cea1519c2dd46 100644 --- a/src/tools/rust-analyzer/crates/tt/Cargo.toml +++ b/src/tools/rust-analyzer/crates/tt/Cargo.toml @@ -13,10 +13,10 @@ doctest = false [dependencies] arrayvec.workspace = true -smol_str.workspace = true text-size.workspace = true stdx.workspace = true +intern.workspace = true ra-ap-rustc_lexer.workspace = true [features] diff --git a/src/tools/rust-analyzer/crates/tt/src/iter.rs b/src/tools/rust-analyzer/crates/tt/src/iter.rs index 175259a3e4719..c0195b835ac6c 100644 --- a/src/tools/rust-analyzer/crates/tt/src/iter.rs +++ b/src/tools/rust-analyzer/crates/tt/src/iter.rs @@ -2,6 +2,7 @@ //! macro definition into a list of patterns and templates. use arrayvec::ArrayVec; +use intern::sym; use crate::{Ident, Leaf, Punct, Spacing, Subtree, TokenTree}; @@ -58,7 +59,7 @@ impl<'a, S: Copy> TtIter<'a, S> { pub fn expect_ident(&mut self) -> Result<&'a Ident, ()> { match self.expect_leaf()? { - Leaf::Ident(it) if it.text != "_" => Ok(it), + Leaf::Ident(it) if it.sym != sym::underscore => Ok(it), _ => Err(()), } } @@ -74,7 +75,7 @@ impl<'a, S: Copy> TtIter<'a, S> { let it = self.expect_leaf()?; match it { Leaf::Literal(_) => Ok(it), - Leaf::Ident(ident) if ident.text == "true" || ident.text == "false" => Ok(it), + Leaf::Ident(ident) if ident.sym == sym::true_ || ident.sym == sym::false_ => Ok(it), _ => Err(()), } } diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs index c328b3f8a3cc8..7b72f9ff108d3 100644 --- a/src/tools/rust-analyzer/crates/tt/src/lib.rs +++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs @@ -14,16 +14,16 @@ pub mod iter; use std::fmt; +use intern::Symbol; use stdx::{impl_from, itertools::Itertools as _}; -pub use smol_str::{format_smolstr, SmolStr}; pub use text_size::{TextRange, TextSize}; #[derive(Clone, PartialEq, Debug)] pub struct Lit { pub kind: LitKind, - pub symbol: SmolStr, - pub suffix: Option, + pub symbol: Symbol, + pub suffix: Option, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -35,6 +35,9 @@ impl IdentIsRaw { pub fn yes(self) -> bool { matches!(self, IdentIsRaw::Yes) } + pub fn no(&self) -> bool { + matches!(self, IdentIsRaw::No) + } pub fn as_str(self) -> &'static str { match self { IdentIsRaw::No => "", @@ -197,25 +200,30 @@ pub enum DelimiterKind { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Literal { // escaped - pub text: SmolStr, + pub symbol: Symbol, pub span: S, pub kind: LitKind, - pub suffix: Option>, + pub suffix: Option, } -pub fn token_to_literal(text: SmolStr, span: S) -> Literal +pub fn token_to_literal(text: &str, span: S) -> Literal where S: Copy, { use rustc_lexer::LiteralKind; - let token = rustc_lexer::tokenize(&text).next_tuple(); + let token = rustc_lexer::tokenize(text).next_tuple(); let Some((rustc_lexer::Token { kind: rustc_lexer::TokenKind::Literal { kind, suffix_start }, .. },)) = token else { - return Literal { span, text, kind: LitKind::Err(()), suffix: None }; + return Literal { + span, + symbol: Symbol::intern(text), + kind: LitKind::Err(()), + suffix: None, + }; }; let (kind, start_offset, end_offset) = match kind { @@ -247,10 +255,10 @@ where let lit = &lit[start_offset..lit.len() - end_offset]; let suffix = match suffix { "" | "_" => None, - suffix => Some(Box::new(suffix.into())), + suffix => Some(Symbol::intern(suffix)), }; - Literal { span, text: lit.into(), kind, suffix } + Literal { span, symbol: Symbol::intern(lit), kind, suffix } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -323,22 +331,16 @@ pub enum Spacing { /// Identifier or keyword. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Ident { - pub text: SmolStr, + pub sym: Symbol, pub span: S, pub is_raw: IdentIsRaw, } impl Ident { - pub fn new(text: impl Into + AsRef, span: S) -> Self { - let t = text.as_ref(); + pub fn new(text: &str, span: S) -> Self { // let raw_stripped = IdentIsRaw::split_from_symbol(text.as_ref()); - let raw_stripped = t.strip_prefix("r#"); - let is_raw = if raw_stripped.is_none() { IdentIsRaw::No } else { IdentIsRaw::Yes }; - let text = match raw_stripped { - Some(derawed) => derawed.into(), - None => text.into(), - }; - Ident { text, span, is_raw } + let (is_raw, text) = IdentIsRaw::split_from_symbol(text); + Ident { sym: Symbol::intern(text), span, is_raw } } } @@ -389,8 +391,8 @@ fn print_debug_token( "{}LITERAL {:?} {}{} {:#?}", align, lit.kind, - lit.text, - lit.suffix.as_ref().map(|it| &***it).unwrap_or(""), + lit.symbol, + lit.suffix.as_ref().map(|it| it.as_str()).unwrap_or(""), lit.span )?; } @@ -410,7 +412,7 @@ fn print_debug_token( "{}IDENT {}{} {:#?}", align, ident.is_raw.as_str(), - ident.text, + ident.sym, ident.span )?; } @@ -479,26 +481,26 @@ impl fmt::Display for Leaf { impl fmt::Display for Ident { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.is_raw.as_str(), f)?; - fmt::Display::fmt(&self.text, f) + fmt::Display::fmt(&self.sym, f) } } impl fmt::Display for Literal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.kind { - LitKind::Byte => write!(f, "b'{}'", self.text), - LitKind::Char => write!(f, "'{}'", self.text), - LitKind::Integer | LitKind::Float | LitKind::Err(_) => write!(f, "{}", self.text), - LitKind::Str => write!(f, "\"{}\"", self.text), - LitKind::ByteStr => write!(f, "b\"{}\"", self.text), - LitKind::CStr => write!(f, "c\"{}\"", self.text), + LitKind::Byte => write!(f, "b'{}'", self.symbol), + LitKind::Char => write!(f, "'{}'", self.symbol), + LitKind::Integer | LitKind::Float | LitKind::Err(_) => write!(f, "{}", self.symbol), + LitKind::Str => write!(f, "\"{}\"", self.symbol), + LitKind::ByteStr => write!(f, "b\"{}\"", self.symbol), + LitKind::CStr => write!(f, "c\"{}\"", self.symbol), LitKind::StrRaw(num_of_hashes) => { let num_of_hashes = num_of_hashes as usize; write!( f, r#"r{0:# { @@ -507,7 +509,7 @@ impl fmt::Display for Literal { f, r#"br{0:# { @@ -516,7 +518,7 @@ impl fmt::Display for Literal { f, r#"cr{0:# Subtree { let s = match child { TokenTree::Leaf(it) => { let s = match it { - Leaf::Literal(it) => it.text.to_string(), + Leaf::Literal(it) => it.symbol.to_string(), Leaf::Punct(it) => it.char.to_string(), - Leaf::Ident(it) => format!("{}{}", it.is_raw.as_str(), it.text), + Leaf::Ident(it) => format!("{}{}", it.is_raw.as_str(), it.sym), }; match (it, last) { (Leaf::Ident(_), Some(&TokenTree::Leaf(Leaf::Ident(_)))) => { @@ -599,9 +601,9 @@ pub fn pretty(tkns: &[TokenTree]) -> String { fn tokentree_to_text(tkn: &TokenTree) -> String { match tkn { TokenTree::Leaf(Leaf::Ident(ident)) => { - format!("{}{}", ident.is_raw.as_str(), ident.text) + format!("{}{}", ident.is_raw.as_str(), ident.sym) } - TokenTree::Leaf(Leaf::Literal(literal)) => literal.text.clone().into(), + TokenTree::Leaf(Leaf::Literal(literal)) => literal.symbol.as_str().to_owned(), TokenTree::Leaf(Leaf::Punct(punct)) => format!("{}", punct.char), TokenTree::Subtree(subtree) => { let content = pretty(&subtree.token_trees); From 9ce066e6faa1bfcec7792a0fae4231a5bd7a5a56 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 16 Jul 2024 10:36:59 +0200 Subject: [PATCH 017/147] Use symbol in cfg --- src/tools/rust-analyzer/Cargo.lock | 4 +- src/tools/rust-analyzer/Cargo.toml | 2 +- src/tools/rust-analyzer/crates/cfg/Cargo.toml | 4 +- .../rust-analyzer/crates/cfg/src/cfg_expr.rs | 39 +++++++++++-------- src/tools/rust-analyzer/crates/cfg/src/dnf.rs | 19 +++++++-- src/tools/rust-analyzer/crates/cfg/src/lib.rs | 16 ++++---- .../rust-analyzer/crates/cfg/src/tests.rs | 26 +++++++------ .../crates/hir-expand/src/builtin_fn_macro.rs | 7 +++- .../crates/hir-expand/src/cfg_process.rs | 25 +++++++----- .../src/completions/attribute/cfg.rs | 2 + src/tools/rust-analyzer/crates/ide/src/lib.rs | 4 +- .../rust-analyzer/crates/ide/src/runnables.rs | 4 +- .../rust-analyzer/crates/intern/src/symbol.rs | 8 +++- .../crates/intern/src/symbol/symbols.rs | 29 ++++++++------ .../crates/project-model/Cargo.toml | 1 + .../crates/project-model/src/cfg.rs | 7 +++- .../crates/project-model/src/tests.rs | 5 ++- .../crates/project-model/src/workspace.rs | 21 +++++----- .../crates/rust-analyzer/Cargo.toml | 1 + .../crates/rust-analyzer/src/config.rs | 8 +++- .../crates/rust-analyzer/src/target_spec.rs | 3 +- .../crates/test-fixture/src/lib.rs | 4 +- 22 files changed, 147 insertions(+), 92 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 241392edb1e5d..c9542ead79070 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -146,10 +146,10 @@ dependencies = [ "arbitrary", "derive_arbitrary", "expect-test", + "intern", "mbe", "oorandom", "rustc-hash", - "smol_str", "syntax", "tt", ] @@ -1416,6 +1416,7 @@ dependencies = [ "cargo_metadata", "cfg", "expect-test", + "intern", "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "paths", @@ -1656,6 +1657,7 @@ dependencies = [ "ide", "ide-db", "ide-ssr", + "intern", "itertools", "load-cargo", "lsp-server 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index d4c3b7a3bfbd2..428d11ad60d48 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -50,7 +50,7 @@ debug = 2 [workspace.dependencies] # local crates base-db = { path = "./crates/base-db", version = "0.0.0" } -cfg = { path = "./crates/cfg", version = "0.0.0" } +cfg = { path = "./crates/cfg", version = "0.0.0", features = ["tt"] } flycheck = { path = "./crates/flycheck", version = "0.0.0" } hir = { path = "./crates/hir", version = "0.0.0" } hir-def = { path = "./crates/hir-def", version = "0.0.0" } diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml index 784e86649d1ab..faf93f62c6afb 100644 --- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml +++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml @@ -15,8 +15,8 @@ doctest = false rustc-hash.workspace = true # locals deps -tt.workspace = true -smol_str.workspace = true +tt = { workspace = true, optional = true } +intern.workspace = true [dev-dependencies] expect-test = "1.4.1" diff --git a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs index 9c95f0e4e4baa..e4c2a28fb0607 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs @@ -2,20 +2,20 @@ //! //! See: -use std::{fmt, slice::Iter as SliceIter}; +use std::fmt; -use smol_str::SmolStr; +use intern::Symbol; /// A simple configuration value passed in from the outside. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum CfgAtom { /// eg. `#[cfg(test)]` - Flag(SmolStr), + Flag(Symbol), /// eg. `#[cfg(target_os = "linux")]` /// /// Note that a key can have multiple values that are all considered "active" at the same time. /// For example, `#[cfg(target_feature = "sse")]` and `#[cfg(target_feature = "sse2")]`. - KeyValue { key: SmolStr, value: SmolStr }, + KeyValue { key: Symbol, value: Symbol }, } impl fmt::Display for CfgAtom { @@ -44,6 +44,7 @@ impl From for CfgExpr { } impl CfgExpr { + #[cfg(feature = "tt")] pub fn parse(tt: &tt::Subtree) -> CfgExpr { next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid) } @@ -63,7 +64,11 @@ impl CfgExpr { } } } -fn next_cfg_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option { + +#[cfg(feature = "tt")] +fn next_cfg_expr(it: &mut std::slice::Iter<'_, tt::TokenTree>) -> Option { + use intern::sym; + let name = match it.next() { None => return None, Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.sym.clone(), @@ -77,9 +82,7 @@ fn next_cfg_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option Some(tt::TokenTree::Leaf(tt::Leaf::Literal(literal))) => { it.next(); it.next(); - // FIXME: escape? - let value = literal.symbol.as_str().into(); - CfgAtom::KeyValue { key: name.as_str().into(), value }.into() + CfgAtom::KeyValue { key: name, value: literal.symbol.clone() }.into() } _ => return Some(CfgExpr::Invalid), } @@ -88,14 +91,16 @@ fn next_cfg_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option it.next(); let mut sub_it = subtree.token_trees.iter(); let mut subs = std::iter::from_fn(|| next_cfg_expr(&mut sub_it)).collect(); - match name.as_str() { - "all" => CfgExpr::All(subs), - "any" => CfgExpr::Any(subs), - "not" => CfgExpr::Not(Box::new(subs.pop().unwrap_or(CfgExpr::Invalid))), + match &name { + s if *s == sym::all => CfgExpr::All(subs), + s if *s == sym::any => CfgExpr::Any(subs), + s if *s == sym::not => { + CfgExpr::Not(Box::new(subs.pop().unwrap_or(CfgExpr::Invalid))) + } _ => CfgExpr::Invalid, } } - _ => CfgAtom::Flag(name.as_str().into()).into(), + _ => CfgAtom::Flag(name).into(), }; // Eat comma separator @@ -111,11 +116,11 @@ fn next_cfg_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option impl arbitrary::Arbitrary<'_> for CfgAtom { fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { if u.arbitrary()? { - Ok(CfgAtom::Flag(String::arbitrary(u)?.into())) + Ok(CfgAtom::Flag(Symbol::intern(<_>::arbitrary(u)?))) } else { Ok(CfgAtom::KeyValue { - key: String::arbitrary(u)?.into(), - value: String::arbitrary(u)?.into(), + key: Symbol::intern(<_>::arbitrary(u)?), + value: Symbol::intern(<_>::arbitrary(u)?), }) } } diff --git a/src/tools/rust-analyzer/crates/cfg/src/dnf.rs b/src/tools/rust-analyzer/crates/cfg/src/dnf.rs index fd80e1ebe683b..58a250829d4f1 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/dnf.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/dnf.rs @@ -66,9 +66,9 @@ impl DnfExpr { } } - res.enabled.sort_unstable(); + res.enabled.sort_unstable_by(compare); res.enabled.dedup(); - res.disabled.sort_unstable(); + res.disabled.sort_unstable_by(compare); res.disabled.dedup(); Some(res) } @@ -114,14 +114,25 @@ impl DnfExpr { }; // Undo the FxHashMap randomization for consistent output. - diff.enable.sort_unstable(); - diff.disable.sort_unstable(); + diff.enable.sort_unstable_by(compare); + diff.disable.sort_unstable_by(compare); Some(diff) }) } } +fn compare(a: &CfgAtom, b: &CfgAtom) -> std::cmp::Ordering { + match (a, b) { + (CfgAtom::Flag(a), CfgAtom::Flag(b)) => a.as_str().cmp(b.as_str()), + (CfgAtom::Flag(_), CfgAtom::KeyValue { .. }) => std::cmp::Ordering::Less, + (CfgAtom::KeyValue { .. }, CfgAtom::Flag(_)) => std::cmp::Ordering::Greater, + (CfgAtom::KeyValue { key, value }, CfgAtom::KeyValue { key: key2, value: value2 }) => { + key.as_str().cmp(key2.as_str()).then(value.as_str().cmp(value2.as_str())) + } + } +} + impl fmt::Display for DnfExpr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.conjunctions.len() != 1 { diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs index 5ef7a104dda59..6d46dfb99949b 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs @@ -9,9 +9,10 @@ use std::fmt; use rustc_hash::FxHashSet; +use intern::Symbol; + pub use cfg_expr::{CfgAtom, CfgExpr}; pub use dnf::DnfExpr; -use smol_str::SmolStr; /// Configuration options used for conditional compilation on items with `cfg` attributes. /// We have two kind of options in different namespaces: atomic options like `unix`, and @@ -48,11 +49,11 @@ impl CfgOptions { cfg.fold(&|atom| self.enabled.contains(atom)) } - pub fn insert_atom(&mut self, key: SmolStr) { + pub fn insert_atom(&mut self, key: Symbol) { self.enabled.insert(CfgAtom::Flag(key)); } - pub fn insert_key_value(&mut self, key: SmolStr, value: SmolStr) { + pub fn insert_key_value(&mut self, key: Symbol, value: Symbol) { self.enabled.insert(CfgAtom::KeyValue { key, value }); } @@ -66,19 +67,16 @@ impl CfgOptions { } } - pub fn get_cfg_keys(&self) -> impl Iterator { + pub fn get_cfg_keys(&self) -> impl Iterator { self.enabled.iter().map(|it| match it { CfgAtom::Flag(key) => key, CfgAtom::KeyValue { key, .. } => key, }) } - pub fn get_cfg_values<'a>( - &'a self, - cfg_key: &'a str, - ) -> impl Iterator + 'a { + pub fn get_cfg_values<'a>(&'a self, cfg_key: &'a str) -> impl Iterator + 'a { self.enabled.iter().filter_map(move |it| match it { - CfgAtom::KeyValue { key, value } if cfg_key == key => Some(value), + CfgAtom::KeyValue { key, value } if cfg_key == key.as_str() => Some(value), _ => None, }) } diff --git a/src/tools/rust-analyzer/crates/cfg/src/tests.rs b/src/tools/rust-analyzer/crates/cfg/src/tests.rs index dddaf2cce1823..278e5f61de251 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/tests.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/tests.rs @@ -1,5 +1,6 @@ use arbitrary::{Arbitrary, Unstructured}; use expect_test::{expect, Expect}; +use intern::Symbol; use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, DummyTestSpanMap, DUMMY}; use syntax::{ast, AstNode, Edition}; @@ -65,22 +66,25 @@ fn check_enable_hints(input: &str, opts: &CfgOptions, expected_hints: &[&str]) { #[test] fn test_cfg_expr_parser() { - assert_parse_result("#![cfg(foo)]", CfgAtom::Flag("foo".into()).into()); - assert_parse_result("#![cfg(foo,)]", CfgAtom::Flag("foo".into()).into()); + assert_parse_result("#![cfg(foo)]", CfgAtom::Flag(Symbol::intern("foo")).into()); + assert_parse_result("#![cfg(foo,)]", CfgAtom::Flag(Symbol::intern("foo")).into()); assert_parse_result( "#![cfg(not(foo))]", - CfgExpr::Not(Box::new(CfgAtom::Flag("foo".into()).into())), + CfgExpr::Not(Box::new(CfgAtom::Flag(Symbol::intern("foo")).into())), ); assert_parse_result("#![cfg(foo(bar))]", CfgExpr::Invalid); // Only take the first - assert_parse_result(r#"#![cfg(foo, bar = "baz")]"#, CfgAtom::Flag("foo".into()).into()); + assert_parse_result( + r#"#![cfg(foo, bar = "baz")]"#, + CfgAtom::Flag(Symbol::intern("foo")).into(), + ); assert_parse_result( r#"#![cfg(all(foo, bar = "baz"))]"#, CfgExpr::All(vec![ - CfgAtom::Flag("foo".into()).into(), - CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(), + CfgAtom::Flag(Symbol::intern("foo")).into(), + CfgAtom::KeyValue { key: Symbol::intern("bar"), value: Symbol::intern("baz") }.into(), ]), ); @@ -90,7 +94,7 @@ fn test_cfg_expr_parser() { CfgExpr::Not(Box::new(CfgExpr::Invalid)), CfgExpr::All(vec![]), CfgExpr::Invalid, - CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(), + CfgAtom::KeyValue { key: Symbol::intern("bar"), value: Symbol::intern("baz") }.into(), ]), ); } @@ -167,7 +171,7 @@ fn hints() { check_enable_hints("#![cfg(all(a, b))]", &opts, &["enable a and b"]); - opts.insert_atom("test".into()); + opts.insert_atom(Symbol::intern("test")); check_enable_hints("#![cfg(test)]", &opts, &[]); check_enable_hints("#![cfg(not(test))]", &opts, &["disable test"]); @@ -180,7 +184,7 @@ fn hints_impossible() { check_enable_hints("#![cfg(all(test, not(test)))]", &opts, &[]); - opts.insert_atom("test".into()); + opts.insert_atom(Symbol::intern("test")); check_enable_hints("#![cfg(all(test, not(test)))]", &opts, &[]); } @@ -188,8 +192,8 @@ fn hints_impossible() { #[test] fn why_inactive() { let mut opts = CfgOptions::default(); - opts.insert_atom("test".into()); - opts.insert_atom("test2".into()); + opts.insert_atom(Symbol::intern("test")); + opts.insert_atom(Symbol::intern("test2")); check_why_inactive("#![cfg(a)]", &opts, expect![["a is disabled"]]); check_why_inactive("#![cfg(not(test))]", &opts, expect![["test is enabled"]]); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index 4b1a3d697280c..e3290f53432b6 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -563,7 +563,12 @@ fn concat_bytes_expand( }; for (i, t) in tt.token_trees.iter().enumerate() { match t { - tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { symbol: 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 => { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs index 5f038cfe6871d..9f927184193e9 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs @@ -3,6 +3,7 @@ use std::iter::Peekable; use base_db::CrateId; use cfg::{CfgAtom, CfgExpr}; +use intern::{sym, Symbol}; use rustc_hash::FxHashSet; use syntax::{ ast::{self, Attr, HasAttrs, Meta, VariantList}, @@ -262,13 +263,13 @@ where let name = match iter.next() { None => return None, Some(NodeOrToken::Token(element)) => match element.kind() { - syntax::T![ident] => element.text().to_owned(), + syntax::T![ident] => Symbol::intern(element.text()), _ => return Some(CfgExpr::Invalid), }, Some(_) => return Some(CfgExpr::Invalid), }; - let result = match name.as_str() { - "all" | "any" | "not" => { + let result = match &name { + s if [&sym::all, &sym::any, &sym::not].contains(&s) => { let mut preds = Vec::new(); let Some(NodeOrToken::Node(tree)) = iter.next() else { return Some(CfgExpr::Invalid); @@ -285,10 +286,12 @@ where preds.push(pred); } } - let group = match name.as_str() { - "all" => CfgExpr::All(preds), - "any" => CfgExpr::Any(preds), - "not" => CfgExpr::Not(Box::new(preds.pop().unwrap_or(CfgExpr::Invalid))), + let group = match &name { + s if *s == sym::all => CfgExpr::All(preds), + s if *s == sym::any => CfgExpr::Any(preds), + s if *s == sym::not => { + CfgExpr::Not(Box::new(preds.pop().unwrap_or(CfgExpr::Invalid))) + } _ => unreachable!(), }; Some(group) @@ -301,13 +304,15 @@ where if (value_token.kind() == syntax::SyntaxKind::STRING) => { let value = value_token.text(); - let value = value.trim_matches('"').into(); - Some(CfgExpr::Atom(CfgAtom::KeyValue { key: name.into(), value })) + Some(CfgExpr::Atom(CfgAtom::KeyValue { + key: name, + value: Symbol::intern(value.trim_matches('"')), + })) } _ => None, } } - _ => Some(CfgExpr::Atom(CfgAtom::Flag(name.into()))), + _ => Some(CfgExpr::Atom(CfgAtom::Flag(name))), }, }; if let Some(NodeOrToken::Token(element)) = iter.peek() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs index 87a286778e631..6e7d50ede066e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs @@ -39,6 +39,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { "target_vendor" => KNOWN_VENDOR.iter().copied().for_each(add_completion), "target_endian" => ["little", "big"].into_iter().for_each(add_completion), name => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| { + let s = s.as_str(); let insert_text = format!(r#""{s}""#); let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s); item.insert_text(insert_text); @@ -47,6 +48,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { }), }, None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| { + let s = s.as_str(); let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s); acc.add(item.build(ctx.db)); }), diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index f0b35903f38de..a7073f7062e3e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -62,7 +62,7 @@ use std::panic::UnwindSafe; use cfg::CfgOptions; use fetch_crates::CrateInfo; -use hir::ChangeWithProcMacros; +use hir::{sym, ChangeWithProcMacros}; use ide_db::{ base_db::{ salsa::{self, ParallelDatabase}, @@ -248,7 +248,7 @@ impl Analysis { // FIXME: cfg options // Default to enable test for single file. let mut cfg_options = CfgOptions::default(); - cfg_options.insert_atom("test".into()); + cfg_options.insert_atom(sym::test.clone()); crate_graph.add_crate_root( file_id, Edition::CURRENT, diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index a68ee4f8671f1..362d3238a9aa3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -3,7 +3,7 @@ use std::fmt; use ast::HasName; use cfg::{CfgAtom, CfgExpr}; use hir::{ - db::HirDatabase, AsAssocItem, AttrsWithOwner, HasAttrs, HasSource, HirFileIdExt, Semantics, + db::HirDatabase, sym, AsAssocItem, AttrsWithOwner, HasAttrs, HasSource, HirFileIdExt, Semantics, }; use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn}; use ide_db::{ @@ -403,7 +403,7 @@ pub(crate) fn runnable_impl( } fn has_cfg_test(attrs: AttrsWithOwner) -> bool { - attrs.cfgs().any(|cfg| matches!(cfg, CfgExpr::Atom(CfgAtom::Flag(s)) if s == "test")) + attrs.cfgs().any(|cfg| matches!(&cfg, CfgExpr::Atom(CfgAtom::Flag(s)) if *s == sym::test)) } /// Creates a test mod runnable for outline modules at the top of their definition. diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs index 9e3f6d842f315..ef76192ba83ed 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -139,11 +139,17 @@ impl TaggedArcPtr { } } -#[derive(PartialEq, Eq, Hash, Debug)] +#[derive(PartialEq, Eq, Hash)] pub struct Symbol { repr: TaggedArcPtr, } +impl fmt::Debug for Symbol { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_str().fmt(f) + } +} + const _: () = assert!(std::mem::size_of::() == std::mem::size_of::>()); const _: () = assert!(std::mem::align_of::() == std::mem::align_of::>()); diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 61b9d099e06a3..04c70e4fae188 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -93,20 +93,20 @@ define_symbols! { __ra_fixup, add_assign, add, - attributes, align_offset, + align, + all, alloc_layout, alloc, + any, as_str, asm, assert, + attributes, begin_panic, bench, bitand_assign, bitand, - notable_trait, - hidden, - local_inner_macros, bitor_assign, bitor, bitxor_assign, @@ -118,6 +118,7 @@ define_symbols! { branch, Break, c_void, + C, call_mut, call_once, call, @@ -146,8 +147,10 @@ define_symbols! { core, coroutine_state, coroutine, + count, crate_type, CStr, + debug_assertions, Debug, default, Default, @@ -172,6 +175,7 @@ define_symbols! { Eq, Err, exchange_malloc, + exhaustive_patterns, f128, f16, f32, @@ -208,11 +212,13 @@ define_symbols! { global_asm, gt, Hash, + hidden, i128, i16, i32, i64, i8, + ignore, Implied, include_bytes, include_str, @@ -237,14 +243,15 @@ define_symbols! { len, line, llvm_asm, + local_inner_macros, log_syntax, lt, macro_rules, - ignore, - count, manually_drop, maybe_uninit, metadata_type, + min_exhaustive_patterns, + miri, missing, module_path, mul_assign, @@ -271,6 +278,7 @@ define_symbols! { None, not, Not, + notable_trait, Ok, opaque, ops, @@ -280,6 +288,7 @@ define_symbols! { Ord, Output, owned_box, + packed, panic_2015, panic_2021, panic_bounds_check, @@ -328,6 +337,7 @@ define_symbols! { rust_2018, rust_2021, rust_2024, + rust_analyzer, rustc_coherence_is_core, rustc_macro_transparency, semitransparent, @@ -335,6 +345,7 @@ define_symbols! { shl, shr_assign, shr, + simd, sized, slice_len_fn, Some, @@ -367,10 +378,6 @@ define_symbols! { u8, Unknown, unpin, - simd, - C, - align, - packed, unreachable_2015, unreachable_2021, unreachable, @@ -378,7 +385,5 @@ define_symbols! { unsize, usize, v1, - exhaustive_patterns, - min_exhaustive_patterns, va_list } diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml index 097ee1f75cd75..8b34bd3fad1a1 100644 --- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml +++ b/src/tools/rust-analyzer/crates/project-model/Cargo.toml @@ -25,6 +25,7 @@ itertools.workspace = true # local deps base-db.workspace = true +intern.workspace = true span.workspace = true cfg.workspace = true paths = { workspace = true, features = ["serde1"] } diff --git a/src/tools/rust-analyzer/crates/project-model/src/cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/cfg.rs index b409bc1ce7ad1..e921e3de722d1 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cfg.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cfg.rs @@ -4,6 +4,7 @@ use std::{fmt, str::FromStr}; use cfg::{CfgDiff, CfgOptions}; +use intern::Symbol; use rustc_hash::FxHashMap; use serde::Serialize; @@ -44,8 +45,10 @@ impl Extend for CfgOptions { fn extend>(&mut self, iter: T) { for cfg_flag in iter { match cfg_flag { - CfgFlag::Atom(it) => self.insert_atom(it.into()), - CfgFlag::KeyValue { key, value } => self.insert_key_value(key.into(), value.into()), + CfgFlag::Atom(it) => self.insert_atom(Symbol::intern(&it)), + CfgFlag::KeyValue { key, value } => { + self.insert_key_value(Symbol::intern(&key), Symbol::intern(&value)) + } } } } diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index 2762de5997ae9..8d50d4bdfe2c2 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -4,6 +4,7 @@ use base_db::{CrateGraph, FileId, ProcMacroPaths}; use cargo_metadata::Metadata; use cfg::{CfgAtom, CfgDiff}; use expect_test::{expect_file, ExpectFile}; +use intern::sym; use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf}; use rustc_hash::FxHashMap; use serde::de::DeserializeOwned; @@ -180,7 +181,7 @@ fn check_crate_graph(crate_graph: CrateGraph, expect: ExpectFile) { #[test] fn cargo_hello_world_project_model_with_wildcard_overrides() { let cfg_overrides = CfgOverrides { - global: CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(), + global: CfgDiff::new(Vec::new(), vec![CfgAtom::Flag(sym::test.clone())]).unwrap(), selective: Default::default(), }; let (crate_graph, _proc_macros) = @@ -199,7 +200,7 @@ fn cargo_hello_world_project_model_with_selective_overrides() { global: Default::default(), selective: std::iter::once(( "libc".to_owned(), - CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(), + CfgDiff::new(Vec::new(), vec![CfgAtom::Flag(sym::test.clone())]).unwrap(), )) .collect(), }; diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index 5e27ce298735e..e006b70362e99 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -10,6 +10,7 @@ use base_db::{ LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult, }; use cfg::{CfgAtom, CfgDiff, CfgOptions}; +use intern::{sym, Symbol}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; @@ -977,8 +978,8 @@ fn cargo_to_crate_graph( if cargo[pkg].is_local { // Add test cfg for local crates - cfg_options.insert_atom("test".into()); - cfg_options.insert_atom("rust_analyzer".into()); + cfg_options.insert_atom(sym::test.clone()); + cfg_options.insert_atom(sym::rust_analyzer.clone()); } override_cfg.apply(&mut cfg_options, &cargo[pkg].name); @@ -1144,8 +1145,8 @@ fn detached_file_to_crate_graph( sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load); let mut cfg_options = CfgOptions::from_iter(rustc_cfg); - cfg_options.insert_atom("test".into()); - cfg_options.insert_atom("rust_analyzer".into()); + cfg_options.insert_atom(sym::test.clone()); + cfg_options.insert_atom(sym::rust_analyzer.clone()); override_cfg.apply(&mut cfg_options, ""); let cfg_options = Arc::new(cfg_options); @@ -1307,7 +1308,7 @@ fn add_target_crate_root( let cfg_options = { let mut opts = cfg_options; for feature in pkg.active_features.iter() { - opts.insert_key_value("feature".into(), feature.into()); + opts.insert_key_value(sym::feature.clone(), Symbol::intern(feature)); } if let Some(cfgs) = build_data.as_ref().map(|it| &it.cfgs) { opts.extend(cfgs.iter().cloned()); @@ -1381,8 +1382,8 @@ fn sysroot_to_crate_graph( &CfgOverrides { global: CfgDiff::new( vec![ - CfgAtom::Flag("debug_assertions".into()), - CfgAtom::Flag("miri".into()), + CfgAtom::Flag(sym::debug_assertions.clone()), + CfgAtom::Flag(sym::miri.clone()), ], vec![], ) @@ -1394,7 +1395,7 @@ fn sysroot_to_crate_graph( let mut pub_deps = vec![]; let mut libproc_macro = None; - let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag("test".into())]).unwrap(); + let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag(sym::test.clone())]).unwrap(); for (cid, c) in cg.iter_mut() { // uninject `test` flag so `core` keeps working. Arc::make_mut(&mut c.cfg_options).apply_diff(diff.clone()); @@ -1449,8 +1450,8 @@ fn sysroot_to_crate_graph( let cfg_options = Arc::new({ let mut cfg_options = CfgOptions::default(); cfg_options.extend(rustc_cfg); - cfg_options.insert_atom("debug_assertions".into()); - cfg_options.insert_atom("miri".into()); + cfg_options.insert_atom(sym::debug_assertions.clone()); + cfg_options.insert_atom(sym::miri.clone()); cfg_options }); let sysroot_crates: FxHashMap = stitched diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index 93fb55ede8ea2..bc1b13a649700 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -54,6 +54,7 @@ hir-def.workspace = true hir-ty.workspace = true hir.workspace = true ide-db.workspace = true +intern.workspace = true # This should only be used in CLI ide-ssr.workspace = true ide.workspace = true diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 91cde4dc0adbb..a0ec3920e6e29 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -8,6 +8,7 @@ use std::{fmt, iter, ops::Not, sync::OnceLock}; use cfg::{CfgAtom, CfgDiff}; use dirs::config_dir; use flycheck::{CargoOptions, FlycheckConfig}; +use hir::Symbol; use ide::{ AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, GenericParameterHints, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, @@ -1691,8 +1692,11 @@ impl Config { self.cargo_cfgs() .iter() .map(|(key, val)| match val { - Some(val) => CfgAtom::KeyValue { key: key.into(), value: val.into() }, - None => CfgAtom::Flag(key.into()), + Some(val) => CfgAtom::KeyValue { + key: Symbol::intern(key), + value: Symbol::intern(val), + }, + None => CfgAtom::Flag(Symbol::intern(key)), }) .collect(), vec![], diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs index 863ff06439961..045b9e4198a64 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs @@ -3,6 +3,7 @@ use std::mem; use cfg::{CfgAtom, CfgExpr}; +use hir::sym; use ide::{Cancellable, CrateId, FileId, RunnableKind, TestId}; use project_model::project_json::Runnable; use project_model::{CargoFeatures, ManifestPath, TargetKind}; @@ -237,7 +238,7 @@ impl CargoTargetSpec { /// Fill minimal features needed fn required_features(cfg_expr: &CfgExpr, features: &mut Vec) { match cfg_expr { - CfgExpr::Atom(CfgAtom::KeyValue { key, value }) if key == "feature" => { + CfgExpr::Atom(CfgAtom::KeyValue { key, value }) if *key == sym::feature => { features.push(value.to_string()) } CfgExpr::All(preds) => { diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index 7a0c474b750b6..e910094c77232 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -481,9 +481,9 @@ impl FileMeta { let mut cfg = CfgOptions::default(); for (k, v) in f.cfgs { if let Some(v) = v { - cfg.insert_key_value(k.into(), v.into()); + cfg.insert_key_value(Symbol::intern(&k), Symbol::intern(&v)); } else { - cfg.insert_atom(k.into()); + cfg.insert_atom(Symbol::intern(&k)); } } From 1a20a0803f82446491be0fddfc142a90126bc15f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 16 Jul 2024 12:05:16 +0200 Subject: [PATCH 018/147] More symbol usage --- src/tools/rust-analyzer/Cargo.lock | 1 + .../rust-analyzer/crates/base-db/Cargo.toml | 1 + .../rust-analyzer/crates/base-db/src/input.rs | 34 +++--- .../rust-analyzer/crates/hir-def/src/attr.rs | 100 +++++++++--------- .../crates/hir-def/src/body/lower.rs | 45 ++++---- .../crates/hir-def/src/body/scope.rs | 2 +- .../rust-analyzer/crates/hir-def/src/data.rs | 24 ++--- .../crates/hir-def/src/data/adt.rs | 12 +-- .../rust-analyzer/crates/hir-def/src/hir.rs | 31 +++--- .../crates/hir-def/src/hir/format_args.rs | 11 +- .../crates/hir-def/src/hir/type_ref.rs | 14 +-- .../crates/hir-def/src/item_tree.rs | 6 +- .../crates/hir-def/src/item_tree/lower.rs | 8 +- .../crates/hir-def/src/lang_item.rs | 5 +- .../crates/hir-def/src/nameres/collector.rs | 32 +++--- .../crates/hir-def/src/nameres/proc_macro.rs | 4 +- .../crates/hir-def/src/pretty.rs | 2 +- .../crates/hir-expand/src/attrs.rs | 10 +- .../hir-ty/src/diagnostics/decl_check.rs | 5 +- .../diagnostics/match_check/pat_analysis.rs | 2 +- .../crates/hir-ty/src/display.rs | 4 +- .../crates/hir-ty/src/inhabitedness.rs | 3 +- .../crates/hir-ty/src/layout/adt.rs | 6 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 78 +++++++------- .../rust-analyzer/crates/hir-ty/src/lower.rs | 4 +- .../crates/hir-ty/src/method_resolution.rs | 3 +- .../crates/hir-ty/src/mir/eval.rs | 2 +- .../crates/hir-ty/src/mir/eval/shim.rs | 22 ++-- .../crates/hir-ty/src/mir/lower.rs | 1 + .../rust-analyzer/crates/hir-ty/src/utils.rs | 7 +- .../rust-analyzer/crates/hir/src/display.rs | 3 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 14 +-- .../rust-analyzer/crates/hir/src/symbols.rs | 4 +- .../src/handlers/add_missing_match_arms.rs | 4 +- .../handlers/destructure_struct_binding.rs | 4 +- .../src/handlers/move_module_to_file.rs | 4 +- .../crates/ide-completion/src/context.rs | 6 +- .../crates/ide-completion/src/render.rs | 4 +- .../ide-completion/src/render/variant.rs | 4 +- .../crates/ide-db/src/documentation.rs | 8 +- .../rust-analyzer/crates/ide-db/src/search.rs | 6 +- .../rust-analyzer/crates/ide/src/doc_links.rs | 15 +-- .../crates/ide/src/fetch_crates.rs | 2 +- .../rust-analyzer/crates/ide/src/moniker.rs | 2 +- .../ide/src/syntax_highlighting/inject.rs | 6 +- .../crates/intern/src/symbol/symbols.rs | 91 ++++++++++++++-- .../crates/project-model/src/project_json.rs | 1 + .../crates/project-model/src/workspace.rs | 24 ++--- .../rust-analyzer/src/cli/analysis_stats.rs | 4 +- .../crates/test-fixture/src/lib.rs | 6 +- 50 files changed, 388 insertions(+), 303 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index c9542ead79070..4ed4a45014191 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -70,6 +70,7 @@ name = "base-db" version = "0.0.0" dependencies = [ "cfg", + "intern", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lz4_flex", "rustc-hash", diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index 4ab99fc33c466..1b1ee034cac2f 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -27,6 +27,7 @@ stdx.workspace = true syntax.workspace = true vfs.workspace = true span.workspace = true +intern.workspace = true [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 1d172ab9e40e3..41b7e271b0c4b 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -9,10 +9,10 @@ use std::{fmt, mem, ops}; use cfg::CfgOptions; +use intern::Symbol; use la_arena::{Arena, Idx, RawIdx}; use rustc_hash::{FxHashMap, FxHashSet}; use span::Edition; -use syntax::SmolStr; use triomphe::Arc; use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath}; @@ -99,8 +99,8 @@ impl fmt::Debug for CrateGraph { pub type CrateId = Idx; -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct CrateName(SmolStr); +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CrateName(Symbol); impl CrateName { /// Creates a crate name, checking for dashes in the string provided. @@ -110,16 +110,16 @@ impl CrateName { if name.contains('-') { Err(name) } else { - Ok(Self(SmolStr::new(name))) + Ok(Self(Symbol::intern(name))) } } /// Creates a crate name, unconditionally replacing the dashes with underscores. pub fn normalize_dashes(name: &str) -> CrateName { - Self(SmolStr::new(name.replace('-', "_"))) + Self(Symbol::intern(&name.replace('-', "_"))) } - pub fn as_smol_str(&self) -> &SmolStr { + pub fn symbol(&self) -> &Symbol { &self.0 } } @@ -133,7 +133,7 @@ impl fmt::Display for CrateName { impl ops::Deref for CrateName { type Target = str; fn deref(&self) -> &str { - &self.0 + self.0.as_str() } } @@ -141,11 +141,11 @@ impl ops::Deref for CrateName { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum CrateOrigin { /// Crates that are from the rustc workspace. - Rustc { name: String }, + Rustc { name: Symbol }, /// Crates that are workspace members. - Local { repo: Option, name: Option }, + Local { repo: Option, name: Option }, /// Crates that are non member libraries. - Library { repo: Option, name: String }, + Library { repo: Option, name: Symbol }, /// Crates that are provided by the language, like std, core, proc-macro, ... Lang(LangCrateOrigin), } @@ -201,16 +201,16 @@ impl fmt::Display for LangCrateOrigin { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateDisplayName { // The name we use to display various paths (with `_`). crate_name: CrateName, // The name as specified in Cargo.toml (with `-`). - canonical_name: String, + canonical_name: Symbol, } impl CrateDisplayName { - pub fn canonical_name(&self) -> &str { + pub fn canonical_name(&self) -> &Symbol { &self.canonical_name } pub fn crate_name(&self) -> &CrateName { @@ -220,7 +220,7 @@ impl CrateDisplayName { impl From for CrateDisplayName { fn from(crate_name: CrateName) -> CrateDisplayName { - let canonical_name = crate_name.to_string(); + let canonical_name = crate_name.0.clone(); CrateDisplayName { crate_name, canonical_name } } } @@ -239,9 +239,9 @@ impl ops::Deref for CrateDisplayName { } impl CrateDisplayName { - pub fn from_canonical_name(canonical_name: String) -> CrateDisplayName { - let crate_name = CrateName::normalize_dashes(&canonical_name); - CrateDisplayName { crate_name, canonical_name } + pub fn from_canonical_name(canonical_name: &str) -> CrateDisplayName { + let crate_name = CrateName::normalize_dashes(canonical_name); + CrateDisplayName { crate_name, canonical_name: Symbol::intern(canonical_name) } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index 1a5ac96aa29bb..723d675347551 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -1,6 +1,6 @@ //! A higher level attributes based on TokenTree, with also some shortcuts. -use std::{borrow::Cow, hash::Hash, ops, slice::Iter as SliceIter}; +use std::{borrow::Cow, hash::Hash, ops, slice}; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; @@ -14,7 +14,7 @@ use la_arena::{ArenaMap, Idx, RawIdx}; use mbe::DelimiterKind; use syntax::{ ast::{self, HasAttrs}, - AstPtr, SmolStr, + AstPtr, }; use triomphe::Arc; @@ -121,12 +121,12 @@ impl Attrs { } impl Attrs { - pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { + pub fn by_key<'attrs>(&'attrs self, key: &'attrs Symbol) -> AttrQuery<'_> { AttrQuery { attrs: self, key } } pub fn cfg(&self) -> Option { - let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse); + let mut cfgs = self.by_key(&sym::cfg).tt_values().map(CfgExpr::parse); let first = cfgs.next()?; match cfgs.next() { Some(second) => { @@ -138,7 +138,7 @@ impl Attrs { } pub fn cfgs(&self) -> impl Iterator + '_ { - self.by_key("cfg").tt_values().map(CfgExpr::parse) + self.by_key(&sym::cfg).tt_values().map(CfgExpr::parse) } pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { @@ -148,50 +148,50 @@ impl Attrs { } } - pub fn lang(&self) -> Option<&str> { - self.by_key("lang").string_value() + pub fn lang(&self) -> Option<&Symbol> { + self.by_key(&sym::lang).string_value() } pub fn lang_item(&self) -> Option { - self.by_key("lang").string_value().and_then(|it| LangItem::from_symbol(&Symbol::intern(it))) + self.by_key(&sym::lang).string_value().and_then(LangItem::from_symbol) } pub fn has_doc_hidden(&self) -> bool { - self.by_key("doc").tt_values().any(|tt| { + self.by_key(&sym::doc).tt_values().any(|tt| { tt.delimiter.kind == DelimiterKind::Parenthesis && matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.sym == sym::hidden) }) } pub fn has_doc_notable_trait(&self) -> bool { - self.by_key("doc").tt_values().any(|tt| { + self.by_key(&sym::doc).tt_values().any(|tt| { tt.delimiter.kind == DelimiterKind::Parenthesis && matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.sym == sym::notable_trait) }) } pub fn doc_exprs(&self) -> impl Iterator + '_ { - self.by_key("doc").tt_values().map(DocExpr::parse) + self.by_key(&sym::doc).tt_values().map(DocExpr::parse) } - pub fn doc_aliases(&self) -> impl Iterator + '_ { + pub fn doc_aliases(&self) -> impl Iterator + '_ { self.doc_exprs().flat_map(|doc_expr| doc_expr.aliases().to_vec()) } - pub fn export_name(&self) -> Option<&str> { - self.by_key("export_name").string_value() + pub fn export_name(&self) -> Option<&Symbol> { + self.by_key(&sym::export_name).string_value() } pub fn is_proc_macro(&self) -> bool { - self.by_key("proc_macro").exists() + self.by_key(&sym::proc_macro).exists() } pub fn is_proc_macro_attribute(&self) -> bool { - self.by_key("proc_macro_attribute").exists() + self.by_key(&sym::proc_macro_attribute).exists() } pub fn is_proc_macro_derive(&self) -> bool { - self.by_key("proc_macro_derive").exists() + self.by_key(&sym::proc_macro_derive).exists() } pub fn is_test(&self) -> bool { @@ -210,27 +210,27 @@ impl Attrs { } pub fn is_ignore(&self) -> bool { - self.by_key("ignore").exists() + self.by_key(&sym::ignore).exists() } pub fn is_bench(&self) -> bool { - self.by_key("bench").exists() + self.by_key(&sym::bench).exists() } pub fn is_unstable(&self) -> bool { - self.by_key("unstable").exists() + self.by_key(&sym::unstable).exists() } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum DocAtom { /// eg. `#[doc(hidden)]` - Flag(SmolStr), + Flag(Symbol), /// eg. `#[doc(alias = "it")]` /// /// Note that a key can have multiple values that are all considered "active" at the same time. /// For example, `#[doc(alias = "x")]` and `#[doc(alias = "y")]`. - KeyValue { key: SmolStr, value: SmolStr }, + KeyValue { key: Symbol, value: Symbol }, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -239,7 +239,7 @@ pub enum DocExpr { /// eg. `#[doc(hidden)]`, `#[doc(alias = "x")]` Atom(DocAtom), /// eg. `#[doc(alias("x", "y"))]` - Alias(Vec), + Alias(Vec), } impl From for DocExpr { @@ -253,9 +253,9 @@ impl DocExpr { next_doc_expr(&mut tt.token_trees.iter()).unwrap_or(DocExpr::Invalid) } - pub fn aliases(&self) -> &[SmolStr] { + pub fn aliases(&self) -> &[Symbol] { match self { - DocExpr::Atom(DocAtom::KeyValue { key, value }) if key == "alias" => { + DocExpr::Atom(DocAtom::KeyValue { key, value }) if *key == sym::alias => { std::slice::from_ref(value) } DocExpr::Alias(aliases) => aliases, @@ -264,7 +264,7 @@ impl DocExpr { } } -fn next_doc_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option { +fn next_doc_expr(it: &mut slice::Iter<'_, tt::TokenTree>) -> Option { let name = match it.next() { None => return None, Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.sym.clone(), @@ -282,9 +282,7 @@ fn next_doc_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option }))) => { it.next(); it.next(); - // FIXME: escape? raw string? - let value = SmolStr::new(text.as_str()); - DocAtom::KeyValue { key: name.as_str().into(), value }.into() + DocAtom::KeyValue { key: name, value: text.clone() }.into() } _ => return Some(DocExpr::Invalid), } @@ -292,12 +290,12 @@ fn next_doc_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option Some(tt::TokenTree::Subtree(subtree)) => { it.next(); let subs = parse_comma_sep(subtree); - match name.as_str() { - "alias" => DocExpr::Alias(subs), + match &name { + s if *s == sym::alias => DocExpr::Alias(subs), _ => DocExpr::Invalid, } } - _ => DocAtom::Flag(name.as_str().into()).into(), + _ => DocAtom::Flag(name).into(), }; // Eat comma separator @@ -309,16 +307,16 @@ fn next_doc_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option Some(ret) } -fn parse_comma_sep(subtree: &tt::Subtree) -> Vec { +fn parse_comma_sep(subtree: &tt::Subtree) -> Vec { subtree .token_trees .iter() .filter_map(|tt| match tt { tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { kind: tt::LitKind::Str, - symbol: text, + symbol, .. - })) => Some(SmolStr::new(text.as_str())), + })) => Some(symbol.clone()), _ => None, }) .collect() @@ -565,7 +563,7 @@ impl AttrSourceMap { #[derive(Debug, Clone, Copy)] pub struct AttrQuery<'attr> { attrs: &'attr Attrs, - key: &'static str, + key: &'attr Symbol, } impl<'attr> AttrQuery<'attr> { @@ -573,11 +571,11 @@ impl<'attr> AttrQuery<'attr> { self.attrs().filter_map(|attr| attr.token_tree_value()) } - pub fn string_value(self) -> Option<&'attr str> { + pub fn string_value(self) -> Option<&'attr Symbol> { self.attrs().find_map(|attr| attr.string_value()) } - pub fn string_value_with_span(self) -> Option<(&'attr str, span::Span)> { + pub fn string_value_with_span(self) -> Option<(&'attr Symbol, span::Span)> { self.attrs().find_map(|attr| attr.string_value_with_span()) } @@ -591,9 +589,7 @@ impl<'attr> AttrQuery<'attr> { pub fn attrs(self) -> impl Iterator + Clone { let key = self.key; - self.attrs - .iter() - .filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_smol_str() == key)) + self.attrs.iter().filter(move |attr| attr.path.as_ident().map_or(false, |s| *s == *key)) } /// Find string value for a specific key inside token tree @@ -602,10 +598,10 @@ impl<'attr> AttrQuery<'attr> { /// #[doc(html_root_url = "url")] /// ^^^^^^^^^^^^^ key /// ``` - pub fn find_string_value_in_tt(self, key: &'attr str) -> Option<&str> { + pub fn find_string_value_in_tt(self, key: &'attr Symbol) -> Option<&str> { self.tt_values().find_map(|tt| { let name = tt.token_trees.iter() - .skip_while(|tt| !matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym, ..} )) if sym.as_str() == key)) + .skip_while(|tt| !matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym, ..} )) if *sym == *key)) .nth(2); match name { @@ -660,6 +656,7 @@ mod tests { //! This module contains tests for doc-expression parsing. //! Currently, it tests `#[doc(hidden)]` and `#[doc(alias)]`. + use intern::Symbol; use triomphe::Arc; use base_db::FileId; @@ -685,24 +682,29 @@ mod tests { #[test] fn test_doc_expr_parser() { - assert_parse_result("#![doc(hidden)]", DocAtom::Flag("hidden".into()).into()); + assert_parse_result("#![doc(hidden)]", DocAtom::Flag(Symbol::intern("hidden")).into()); assert_parse_result( r#"#![doc(alias = "foo")]"#, - DocAtom::KeyValue { key: "alias".into(), value: "foo".into() }.into(), + DocAtom::KeyValue { key: Symbol::intern("alias"), value: Symbol::intern("foo") }.into(), ); - assert_parse_result(r#"#![doc(alias("foo"))]"#, DocExpr::Alias(["foo".into()].into())); + assert_parse_result( + r#"#![doc(alias("foo"))]"#, + DocExpr::Alias([Symbol::intern("foo")].into()), + ); assert_parse_result( r#"#![doc(alias("foo", "bar", "baz"))]"#, - DocExpr::Alias(["foo".into(), "bar".into(), "baz".into()].into()), + DocExpr::Alias( + [Symbol::intern("foo"), Symbol::intern("bar"), Symbol::intern("baz")].into(), + ), ); assert_parse_result( r#" #[doc(alias("Bar", "Qux"))] struct Foo;"#, - DocExpr::Alias(["Bar".into(), "Qux".into()].into()), + DocExpr::Alias([Symbol::intern("Bar"), Symbol::intern("Qux")].into()), ); } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index b96745022a21a..b6d43af2eb04c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -8,7 +8,7 @@ use hir_expand::{ name::{AsName, Name}, ExpandError, InFile, }; -use intern::{sym, Interned}; +use intern::{sym, Interned, Symbol}; use rustc_hash::FxHashMap; use smallvec::SmallVec; use span::AstIdMap; @@ -1623,30 +1623,29 @@ impl ExprCollector<'_> { } } - let lit_pieces = - fmt.template - .iter() - .enumerate() - .filter_map(|(i, piece)| { - match piece { - FormatArgsPiece::Literal(s) => Some( - self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone()))), - ), - &FormatArgsPiece::Placeholder(_) => { - // Inject empty string before placeholders when not already preceded by a literal piece. - if i == 0 - || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) - { - Some(self.alloc_expr_desugared(Expr::Literal(Literal::String( - "".into(), - )))) - } else { - None - } + let lit_pieces = fmt + .template + .iter() + .enumerate() + .filter_map(|(i, piece)| { + match piece { + FormatArgsPiece::Literal(s) => { + Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone())))) + } + &FormatArgsPiece::Placeholder(_) => { + // Inject empty string before placeholders when not already preceded by a literal piece. + if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) + { + Some(self.alloc_expr_desugared(Expr::Literal(Literal::String( + Symbol::empty(), + )))) + } else { + None } } - }) - .collect(); + } + }) + .collect(); let lit_pieces = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces, is_assignee_expr: false, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs index fd685235e17db..3fc244a1e873b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs @@ -338,7 +338,7 @@ mod tests { let actual = scopes .scope_chain(scope) .flat_map(|scope| scopes.entries(scope)) - .map(|it| it.name().to_smol_str()) + .map(|it| it.name().as_str()) .collect::>() .join("\n"); let expected = expected.join("\n"); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index e2bb02c0c13ff..a887612707470 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -6,7 +6,7 @@ use base_db::CrateId; use hir_expand::{ name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind, }; -use intern::{sym, Interned}; +use intern::{sym, Interned, Symbol}; use smallvec::SmallVec; use syntax::{ast, Parse}; use triomphe::Arc; @@ -38,7 +38,7 @@ pub struct FunctionData { pub ret_type: Interned, pub attrs: Attrs, pub visibility: RawVisibility, - pub abi: Option>, + pub abi: Option, pub legacy_const_generics_indices: Box<[u32]>, pub rustc_allow_incoherent_impl: bool, flags: FnFlags, @@ -92,12 +92,12 @@ impl FunctionData { let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); let legacy_const_generics_indices = attrs - .by_key("rustc_legacy_const_generics") + .by_key(&sym::rustc_legacy_const_generics) .tt_values() .next() .map(parse_rustc_legacy_const_generics) .unwrap_or_default(); - let rustc_allow_incoherent_impl = attrs.by_key("rustc_allow_incoherent_impl").exists(); + let rustc_allow_incoherent_impl = attrs.by_key(&sym::rustc_allow_incoherent_impl).exists(); Arc::new(FunctionData { name: func.name.clone(), @@ -200,8 +200,8 @@ impl TypeAliasData { ModItem::from(loc.id.value).into(), ); let rustc_has_incoherent_inherent_impls = - attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); - let rustc_allow_incoherent_impl = attrs.by_key("rustc_allow_incoherent_impl").exists(); + attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists(); + let rustc_allow_incoherent_impl = attrs.by_key(&sym::rustc_allow_incoherent_impl).exists(); Arc::new(TypeAliasData { name: typ.name.clone(), @@ -251,10 +251,10 @@ impl TraitData { let visibility = item_tree[tr_def.visibility].clone(); let attrs = item_tree.attrs(db, module_id.krate(), ModItem::from(tree_id.value).into()); let skip_array_during_method_dispatch = - attrs.by_key("rustc_skip_array_during_method_dispatch").exists(); + attrs.by_key(&sym::rustc_skip_array_during_method_dispatch).exists(); let rustc_has_incoherent_inherent_impls = - attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); - let fundamental = attrs.by_key("fundamental").exists(); + attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists(); + let fundamental = attrs.by_key(&sym::fundamental).exists(); let mut collector = AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr)); collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items); @@ -393,7 +393,7 @@ impl Macro2Data { let helpers = item_tree .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into()) - .by_key("rustc_builtin_macro") + .by_key(&sym::rustc_builtin_macro) .tt_values() .next() .and_then(|attr| parse_macro_name_and_helper_attrs(&attr.token_trees)) @@ -423,7 +423,7 @@ impl MacroRulesData { let macro_export = item_tree .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into()) - .by_key("macro_export") + .by_key(&sym::macro_export) .exists(); Arc::new(MacroRulesData { name: makro.name.clone(), macro_export }) @@ -526,7 +526,7 @@ impl ConstData { let rustc_allow_incoherent_impl = item_tree .attrs(db, loc.container.module(db).krate(), ModItem::from(loc.id.value).into()) - .by_key("rustc_allow_incoherent_impl") + .by_key(&sym::rustc_allow_incoherent_impl) .exists(); Arc::new(ConstData { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs index 3942c2a98af78..cc6e408b65bac 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs @@ -95,7 +95,7 @@ fn repr_from_value( item_tree: &ItemTree, of: AttrOwner, ) -> Option { - item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt) + item_tree.attrs(db, krate, of).by_key(&sym::repr).tt_values().find_map(parse_repr_tt) } fn parse_repr_tt(tt: &Subtree) -> Option { @@ -194,10 +194,10 @@ impl StructData { let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); let mut flags = StructFlags::NO_FLAGS; - if attrs.by_key("rustc_has_incoherent_inherent_impls").exists() { + if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() { flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL; } - if attrs.by_key("fundamental").exists() { + if attrs.by_key(&sym::fundamental).exists() { flags |= StructFlags::IS_FUNDAMENTAL; } if let Some(lang) = attrs.lang_item() { @@ -248,10 +248,10 @@ impl StructData { let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); let mut flags = StructFlags::NO_FLAGS; - if attrs.by_key("rustc_has_incoherent_inherent_impls").exists() { + if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() { flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL; } - if attrs.by_key("fundamental").exists() { + if attrs.by_key(&sym::fundamental).exists() { flags |= StructFlags::IS_FUNDAMENTAL; } @@ -287,7 +287,7 @@ impl EnumData { let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); let rustc_has_incoherent_inherent_impls = item_tree .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()) - .by_key("rustc_has_incoherent_inherent_impls") + .by_key(&sym::rustc_has_incoherent_inherent_impls) .exists(); let enum_ = &item_tree[loc.id.value]; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index d306f9be657a1..d7eb80a88bfa0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -18,7 +18,7 @@ pub mod type_ref; use std::fmt; use hir_expand::name::Name; -use intern::Interned; +use intern::{Interned, Symbol}; use la_arena::{Idx, RawIdx}; use rustc_apfloat::ieee::{Half as f16, Quad as f128}; use smallvec::SmallVec; @@ -60,41 +60,41 @@ pub type LabelId = Idx