about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-07-15 09:39:22 +0000
committerbors <bors@rust-lang.org>2024-07-15 09:39:22 +0000
commit305bd5d06604764a8c6244ccd1d4354e8b1a34f5 (patch)
tree7c25b67c41d6eb9f98504d3ff99a296fd896f474 /src
parentfcbf77fae5d34658af90b68509fc1ce032247f41 (diff)
parentd95b2f3f4bb5839b508b86a751c09cb7e0d59cda (diff)
downloadrust-305bd5d06604764a8c6244ccd1d4354e8b1a34f5.tar.gz
rust-305bd5d06604764a8c6244ccd1d4354e8b1a34f5.zip
Auto merge of #17584 - Veykril:landing-page, r=Veykril
Implement symbol interning infra

Will fix https://github.com/rust-lang/rust-analyzer/issues/15590

My unsafe-fu is not the best but it does satisfy miri.

There is still some follow up work to do, notably a lot of places using strings instead of symbols/names, most notably the token tree.
Diffstat (limited to 'src')
-rw-r--r--src/tools/rust-analyzer/.typos.toml2
-rw-r--r--src/tools/rust-analyzer/Cargo.lock7
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs114
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs95
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expander.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs90
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs29
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs402
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/quote.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs64
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs39
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/traits.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/attrs.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs40
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs28
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/test_explorer.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs15
-rw-r--r--src/tools/rust-analyzer/crates/intern/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/lib.rs3
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol.rs328
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs360
86 files changed, 1418 insertions, 792 deletions
diff --git a/src/tools/rust-analyzer/.typos.toml b/src/tools/rust-analyzer/.typos.toml
index c2e8b265218..e7e764ce035 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 e9ebe26f42c..b165697724e 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",
 ]
 
@@ -1886,6 +1887,12 @@ dependencies = [
 ]
 
 [[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"
 source = "registry+https://github.com/rust-lang/crates.io-index"
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 184dab8367c..aacfb073198 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, Symbol};
 use la_arena::{ArenaMap, Idx, RawIdx};
 use mbe::DelimiterKind;
 use syntax::{
@@ -152,7 +153,7 @@ impl Attrs {
     }
 
     pub fn lang_item(&self) -> Option<LangItem> {
-        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 {
@@ -199,8 +200,12 @@ impl Attrs {
                 .segments()
                 .iter()
                 .rev()
-                .zip(["core", "prelude", "v1", "test"].iter().rev())
-                .all(|it| it.0.as_str() == Some(it.1))
+                .zip(
+                    [sym::core.clone(), sym::prelude.clone(), sym::v1.clone(), sym::test.clone()]
+                        .iter()
+                        .rev(),
+                )
+                .all(|it| it.0 == it.1)
         })
     }
 
@@ -568,6 +573,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<Cow<'attr, str>> {
         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 be7068c807a..b96745022a2 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<Binding> =
-                    self.alloc_binding(name![self], BindingAnnotation::new(is_mutable, false));
+                let binding_id: la_arena::Idx<Binding> = self.alloc_binding(
+                    Name::new_symbol_root(sym::self_.clone()),
+                    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.clone()),
+        ) 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.clone()),
+        ) 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.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 {
@@ -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.clone()),
+            );
             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.clone()),
+                ) {
+                    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.clone()),
                     ) {
                         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.clone()),
+            ) {
                 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.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)),
             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 f9e55559dab..6dc1c4546e8 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 {
@@ -48,63 +49,67 @@ 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)),
-    ];
+    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> {
-        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![char],
-            BuiltinType::Bool => name![bool],
-            BuiltinType::Str => name![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![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.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![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.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![f16],
-                BuiltinFloat::F32 => name![f32],
-                BuiltinFloat::F64 => name![f64],
-                BuiltinFloat::F128 => name![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 55043fdc4b0..964a5f04bfd 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_.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 0eb9e7d30b2..eac8f0dd74a 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.clone() => return true,
+            Some(ident) if *ident == sym::cfg_attr.clone() => {}
             _ => 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 dbf8e6b225c..d1640ad7e5b 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<T: ast::AstNode>(
         &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 9a3c0495414..a3a602c2c11 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];
+    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 == &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.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,
@@ -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.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 == &known::core => 2,
-                    name if name == &known::alloc => 1,
-                    name if name == &known::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/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
index de0fa982c86..d6dd5df3736 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<TextRange>),
+    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_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index d86c0667a0b..86c3e0f041d 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<Name, (ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
-    values: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportId>)>,
-    macros: FxHashMap<Name, (MacroId, Visibility, Option<ImportId>)>,
+    types: FxIndexMap<Name, (ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
+    values: FxIndexMap<Name, (ModuleDefId, Visibility, Option<ImportId>)>,
+    macros: FxIndexMap<Name, (MacroId, Visibility, Option<ImportId>)>,
     unresolved: FxHashSet<Name>,
 
     /// The defs declared in this scope. Each def has a single scope where it is
@@ -118,8 +117,8 @@ struct DeriveMacroInvocation {
     derive_call_ids: SmallVec<[Option<MacroCallId>; 1]>,
 }
 
-pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
-    BuiltinType::ALL
+pub(crate) static BUILTIN_SCOPE: Lazy<FxIndexMap<Name, PerNs>> = Lazy::new(|| {
+    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 199b8daa37e..5c80da93048 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,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![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(
@@ -669,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![Self]),
+                    name: Some(Name::new_symbol_root(sym::Self_.clone())),
                     default: None,
                     provenance: TypeParamProvenance::TraitSelf,
                 }
@@ -680,7 +682,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_.clone()).into())),
             );
         }
 
@@ -745,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![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 6d7836d5ae8..07b27659ab3 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;
@@ -191,8 +192,7 @@ impl LangItems {
 }
 
 pub(crate) fn lang_attr(db: &dyn DefDatabase, item: AttrDefId) -> Option<LangItem> {
-    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(
@@ -260,10 +260,9 @@ macro_rules! language_item_table {
             }
 
             /// Opposite of [`LangItem::name`]
-            #[allow(clippy::should_implement_trait)]
-            pub fn from_str(name: &str) -> Option<Self> {
-                match name {
-                    $( stringify!($name) => Some(LangItem::$variant), )*
+            pub fn from_symbol(sym: &Symbol) -> Option<Self> {
+                match sym {
+                    $(sym if *sym == $module::$name => Some(LangItem::$variant), )*
                     _ => None,
                 }
             }
@@ -274,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> {
-        Self::from_str(name.as_str()?)
+        Self::from_symbol(name.symbol())
     }
 
     pub fn path(&self, db: &dyn DefDatabase, start_crate: CrateId) -> Option<Path> {
@@ -360,7 +359,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 fc026a14d44..a33e681cb5a 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.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index 8e7ef48112f..b0543727c27 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<LocalModuleId>,
-    pub children: FxHashMap<Name, LocalModuleId>,
+    pub children: FxIndexMap<Name, LocalModuleId>,
     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<Item = (&Name, (MacroId, Option<ExternCrateId>))> + '_ {
-        self.macro_use_prelude.iter().map(|(name, &def)| (name, def))
+    pub(crate) fn macro_use_prelude(&self) -> &FxHashMap<Name, (MacroId, Option<ExternCrateId>)> {
+        &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/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index b5045efb621..f14679f6c2f 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.clone() => {
                     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.clone() => {
                     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.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 == hir_expand::name![feature] => {
+                () if *attr_name == sym::feature.clone() => {
                     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.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 == hir_expand::name![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);
@@ -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.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![core]
+            Name::new_symbol_root(sym::core.clone())
         };
 
         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.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 {
             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.clone()), 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<CrateRootModuleId> {
-        if *name == name![self] {
+        if *name == sym::self_.clone() {
             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/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
index d278b75e815..14d497b3a11 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/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
index cee9e055459..7c39773aa68 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<Path
                 segments.push(name);
             }
             ast::PathSegmentKind::SelfTypeKw => {
-                segments.push(name![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![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![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 e5c1f93bbde..f0f2210ec2c 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,9 @@
 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 itertools::Itertools as _;
 use rustc_hash::FxHashSet;
 use smallvec::{smallvec, SmallVec};
 use triomphe::Arc;
@@ -197,12 +195,12 @@ impl Resolver {
                     }
                 }
                 &Scope::ImplDefScope(impl_) => {
-                    if first_name == &name![Self] {
+                    if *first_name == sym::Self_.clone() {
                         return Some((TypeNs::SelfType(impl_), remaining_idx(), None));
                     }
                 }
                 &Scope::AdtScope(adt) => {
-                    if first_name == &name![Self] {
+                    if *first_name == sym::Self_.clone() {
                         return Some((TypeNs::AdtSelfType(adt), remaining_idx(), None));
                     }
                 }
@@ -294,7 +292,7 @@ impl Resolver {
             }
         };
         let n_segments = path.segments().len();
-        let tmp = name![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 {
@@ -325,7 +323,7 @@ impl Resolver {
                         }
                     }
                     &Scope::ImplDefScope(impl_) => {
-                        if first_name == &name![Self] {
+                        if *first_name == sym::Self_.clone() {
                             return Some(ResolveValueResult::ValueNs(
                                 ValueNs::ImplSelf(impl_),
                                 None,
@@ -352,7 +350,7 @@ impl Resolver {
                         }
                     }
                     &Scope::ImplDefScope(impl_) => {
-                        if first_name == &name![Self] {
+                        if *first_name == sym::Self_.clone() {
                             return Some(ResolveValueResult::Partial(
                                 TypeNs::SelfType(impl_),
                                 1,
@@ -361,7 +359,7 @@ impl Resolver {
                         }
                     }
                     Scope::AdtScope(adt) => {
-                        if first_name == &name![Self] {
+                        if *first_name == sym::Self_.clone() {
                             let ty = TypeNs::AdtSelfType(*adt);
                             return Some(ResolveValueResult::Partial(ty, 1, None));
                         }
@@ -425,7 +423,7 @@ impl Resolver {
     }
 
     pub fn resolve_lifetime(&self, lifetime: &LifetimeRef) -> Option<LifetimeNs> {
-        if lifetime.name == name::known::STATIC_LIFETIME {
+        if lifetime.name == sym::tick_static.clone() {
             return Some(LifetimeNs::Static);
         }
 
@@ -500,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())));
         });
@@ -781,10 +781,10 @@ impl Scope {
                 }
             }
             Scope::ImplDefScope(i) => {
-                acc.add(&name![Self], ScopeDef::ImplSelfType(*i));
+                acc.add(&Name::new_symbol_root(sym::Self_.clone()), ScopeDef::ImplSelfType(*i));
             }
             Scope::AdtScope(i) => {
-                acc.add(&name![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 db0feb055e1..36636a228f1 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,10 @@ 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.clone(),
+                            span.ctx,
+                        ))),
                         ctxt: span.ctx,
                     }
                 }),
@@ -115,7 +119,7 @@ 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.clone()));
         if !has_cfg_attrs {
             return self;
         }
@@ -125,7 +129,7 @@ impl RawAttrs {
             self.iter()
                 .flat_map(|attr| -> SmallVec<[_; 1]> {
                     let is_cfg_attr =
-                        attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr]);
+                        attr.path.as_ident().map_or(false, |name| *name == sym::cfg_attr.clone());
                     if !is_cfg_attr {
                         return smallvec![attr.clone()];
                     }
@@ -316,6 +320,20 @@ impl Attr {
         }
     }
 
+    /// #[path = "string"]
+    pub fn string_value_with_span(&self) -> Option<(&str, span::Span)> {
+        match self.input.as_deref()? {
+            AttrInput::Literal(it) => match it.text.strip_prefix('r') {
+                Some(it) => it.trim_matches('#'),
+                None => it.text.as_str(),
+            }
+            .strip_prefix('"')?
+            .strip_suffix('"')
+            .zip(Some(it.span)),
+            _ => None,
+        }
+    }
+
     pub fn string_value_unescape(&self) -> Option<Cow<'_, str>> {
         match self.input.as_deref()? {
             AttrInput::Literal(it) => match it.text.strip_prefix('r') {
@@ -369,7 +387,7 @@ impl Attr {
     }
 
     pub fn cfg(&self) -> Option<CfgExpr> {
-        if *self.path.as_ident()? == crate::name![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_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs
index 2e115f47932..b9afc666f75 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<Self> {
                 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 c7cdc5e9220..269e9f308c2 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<Self> {
                 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 02fd431e4e7..97867dfc66e 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<Either<BuiltinFnLikeExpander, EagerExpander>> {
             match ident {
-                $( id if id == &name::name![$name] => Some(Either::Left(BuiltinFnLikeExpander::$kind)), )*
-                $( id if id == &name::name![$e_name] => Some(Either::Right(EagerExpander::$e_kind)), )*
+                $( id if id == &sym::$name => Some(Either::Left(BuiltinFnLikeExpander::$kind)), )*
+                $( id if id == &sym::$e_name => Some(Either::Right(EagerExpander::$e_kind)), )*
                 _ => return None,
             }
         }
@@ -367,8 +367,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) { known::panic_2021 } else { known::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!);
@@ -397,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) {
-        known::unreachable_2021
+        sym::unreachable_2021.clone()
     } else {
-        known::unreachable_2015
+        sym::unreachable_2015.clone()
     };
 
     // Expand to a macro call `$crate::panic::panic_{edition}`
@@ -432,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/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index ad25a1168c4..e1fb3953f4d 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<Arc<ExpandResult<Arc<[SyntaxError]>>>>;
+    #[salsa::transparent]
+    fn syntax_context(&self, file: HirFileId) -> SyntaxContextId;
+}
+
+fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId) -> SyntaxContextId {
+    match file.repr() {
+        HirFileIdRepr::FileId(_) => SyntaxContextId::ROOT,
+        HirFileIdRepr::MacroFile(m) => db.macro_arg(m.macro_call_id).2.ctx,
+    }
 }
 
 /// This expands the given macro call, but with different arguments. This is
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 29408902f16..2e7865ed3bf 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.clone())
+                        .unwrap_or(false)
                 })?
                 .token_tree_value()?
                 .token_trees
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 7ead7e93901..0c112554e1f 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 12fdf88a2a8..ed7d5518887 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 {
@@ -123,7 +121,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)
+            && matches!(&*self.segments, [name] if *name == sym::Self_.clone())
     }
 
     /// If this path is a single identifier, like `foo`, return its name.
@@ -265,9 +263,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_.clone(), 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 +322,9 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModP
         tt::Leaf::Ident(tt::Ident { text, .. }) if text == "self" => PathKind::SELF,
         tt::Leaf::Ident(tt::Ident { text, .. }) if text == "super" => {
             let mut deg = 1;
-            while let Some(tt::Leaf::Ident(tt::Ident { text, .. })) = leaves.next() {
+            while let Some(tt::Leaf::Ident(tt::Ident { text, span, .. })) = leaves.next() {
                 if text != "super" {
-                    segments.push(Name::new_text_dont_use(text.clone()));
+                    segments.push(Name::new(text, span.ctx));
                     break;
                 }
                 deg += 1;
@@ -334,13 +333,13 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModP
         }
         tt::Leaf::Ident(tt::Ident { text, .. }) if text == "crate" => PathKind::Crate,
         tt::Leaf::Ident(ident) => {
-            segments.push(Name::new_text_dont_use(ident.text.clone()));
+            segments.push(Name::new(&ident.text, ident.span.ctx));
             PathKind::Plain
         }
         _ => return None,
     };
     segments.extend(leaves.filter_map(|leaf| match leaf {
-        ::tt::Leaf::Ident(ident) => Some(Name::new_text_dont_use(ident.text.clone())),
+        ::tt::Leaf::Ident(ident) => Some(Name::new(&ident.text, ident.span.ctx)),
         _ => None,
     }));
     Some(ModPath { kind, segments })
@@ -385,6 +384,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 +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::mod_path::__name![$start], $($crate::mod_path::__name![$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 fe754bc8249..67e73f7fc28 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, 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,58 @@ use syntax::{ast, format_smolstr, utils::is_raw_identifier, SmolStr};
 /// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it
 /// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the
 /// name without "r#".
-#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct Name(Repr);
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct Name {
+    symbol: Symbol,
+    ctx: (),
+}
 
-/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
-#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct UnescapedName<'a>(&'a Name);
+impl fmt::Debug for Name {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Name")
+            .field("symbol", &self.symbol.as_str())
+            .field("ctx", &self.ctx)
+            .finish()
+    }
+}
 
-#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
-enum Repr {
-    Text(SmolStr),
-    TupleField(usize),
+impl Ord for Name {
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        self.symbol.as_str().cmp(other.symbol.as_str())
+    }
 }
 
+impl PartialOrd for Name {
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl PartialEq<Symbol> for Name {
+    fn eq(&self, sym: &Symbol) -> bool {
+        self.symbol == *sym
+    }
+}
+
+impl PartialEq<Name> for Symbol {
+    fn eq(&self, name: &Name) -> bool {
+        *self == name.symbol
+    }
+}
+
+/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct UnescapedName<'a>(&'a Name);
+
 impl UnescapedName<'_> {
     /// 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 +78,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 +105,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),
         }
     }
 
@@ -98,8 +125,8 @@ impl Name {
     /// Ideally, we want a `gensym` semantics for missing names -- each missing
     /// name is equal only to itself. It's not clear how to implement this in
     /// salsa though, so we punt on that bit for a moment.
-    pub const fn missing() -> Name {
-        Name::new_static("[missing name]")
+    pub fn missing() -> Name {
+        Name { symbol: sym::MISSING_NAME.clone(), ctx: () }
     }
 
     /// Returns true if this is a fake name for things missing in the source code. See
@@ -115,41 +142,25 @@ impl Name {
     /// creating desugared locals and labels. The caller is responsible for picking an index
     /// that is stable across re-executions
     pub fn generate_new_name(idx: usize) -> Name {
-        Name::new_text(format_smolstr!("<ra@gennew>{idx}"))
+        Name::new_text(&format_smolstr!("<ra@gennew>{idx}"))
     }
 
     /// Returns the tuple index this name represents if it is a tuple field.
     pub fn as_tuple_index(&self) -> Option<usize> {
-        match self.0 {
-            Repr::TupleField(idx) => Some(idx),
-            _ => None,
-        }
+        self.symbol.as_str().parse().ok()
     }
 
     /// Returns the text this name represents if it isn't a tuple field.
-    pub fn as_text(&self) -> Option<SmolStr> {
-        match &self.0 {
-            Repr::Text(it) => Some(it.clone()),
-            _ => None,
-        }
-    }
-
-    /// Returns the text this name represents if it isn't a tuple field.
-    pub fn as_str(&self) -> Option<&str> {
-        match &self.0 {
-            Repr::Text(it) => Some(it),
-            _ => None,
-        }
+    pub fn as_str(&self) -> &str {
+        self.symbol.as_str()
     }
 
+    // FIXME: Remove this
     /// Returns the textual representation of this name as a [`SmolStr`].
     /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in
     /// the general case.
     pub fn to_smol_str(&self) -> SmolStr {
-        match &self.0 {
-            Repr::Text(it) => it.clone(),
-            Repr::TupleField(it) => SmolStr::new(it.to_string()),
-        }
+        self.symbol.as_str().into()
     }
 
     pub fn unescaped(&self) -> UnescapedName<'_> {
@@ -157,16 +168,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 +197,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 +207,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 +261,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 8f1e32321e1..f4fc3b7b3e2 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 b706cef0b3a..ecfc1ff99e9 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,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![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 3ac8cbaaf8b..d506e00ca12 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},
@@ -288,15 +289,16 @@ impl chalk_solve::RustIrDatabase<Interner> 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![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<T>:
                     //
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 15ecf9aafcf..1df801f3a4f 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 c28ab2e98af..e52fae06d7f 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,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 == name![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 a9a5d829f5f..f15f6575b79 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,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(&hir_expand::name!(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 66ee02d74d9..82f4ad01e01 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,9 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn resolve_output_on(&self, trait_: TraitId) -> Option<TypeAliasId> {
-        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.clone()))
     }
 
     fn resolve_lang_trait(&self, lang: LangItem) -> Option<TraitId> {
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 b7c7b665453..417fca5dcd6 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.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 7a0f7872a64..7857d207be7 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.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`).
@@ -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.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 00e5eac229f..abb702d1500 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.clone()))
                             {
                                 *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.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 490ecfd7fa3..0b44bbec70f 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.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 ed4d55d2037..7ee63af1c22 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.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 85ed46b9632..f704b59d303 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,57 @@ 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.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![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.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![eq], LangItem::PartialEq),
-            CmpOp::Eq { negated: true } => (name![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![le], LangItem::PartialOrd)
+                (Name::new_symbol_root(sym::le.clone()), LangItem::PartialOrd)
             }
             CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
-                (name![lt], LangItem::PartialOrd)
+                (Name::new_symbol_root(sym::lt.clone()), LangItem::PartialOrd)
             }
             CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
-                (name![ge], LangItem::PartialOrd)
+                (Name::new_symbol_root(sym::ge.clone()), LangItem::PartialOrd)
             }
             CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
-                (name![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 bd650869bb3..aabf11f268f 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.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 2d9c221b732..32b7d6dc113 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,21 @@ 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.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![call_mut])),
+                .and_then(|x| {
+                    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![call_once])),
+                .and_then(|x| {
+                    db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call_once.clone()))
+                }),
         })
     }
 
@@ -2633,10 +2639,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 +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![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.
@@ -2797,14 +2800,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.clone()))
+    else {
         not_supported!("core::fmt::Debug::fmt not found");
     };
     // a1 = &[""]
@@ -2829,10 +2831,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 ce22e9d2c2c..68187593106 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",
@@ -317,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) {
@@ -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.clone()))
+                    }) {
                         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 1a0a1b780a1..1b8c772d80e 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 4ad00909e41..424ee1160c8 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) => {
@@ -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![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;
                                     }
@@ -324,12 +324,17 @@ impl MirLowerCtx<'_> {
         mutability: bool,
     ) -> Result<Option<(Place, BasicBlockId)>> {
         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.clone()),
+                BorrowKind::Shared,
+            )
         } else {
             (
                 Mutability::Mut,
                 LangItem::DerefMut,
-                name![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 4283a94657b..c46382a0ea8 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.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/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
index 7b3ff7b0645..af60c233e55 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<ModPath> {
         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 016f3418517..c868357ff98 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_.clone()
                         && 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.clone())
     }
 }
 
@@ -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_.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 81c57f6caeb..be0116862b9 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.clone()) =>
                     {
                         Some(alias)
                     }
@@ -397,15 +395,21 @@ 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![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| {
                         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.clone()),
+                        )?;
                         if func == deref_mut {
                             Some((deref_mut_trait, deref_mut))
                         } else {
@@ -414,8 +418,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.clone()))?
+            }
+            ast::UnaryOp::Neg => {
+                self.lang_trait_fn(db, LangItem::Neg, &Name::new_symbol_root(sym::neg.clone()))?
+            }
         };
 
         let ty = self.ty_of_expr(db, &prefix_expr.expr()?)?;
@@ -435,15 +443,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.clone()))?;
         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.clone()),
+                )?;
                 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 02905ca2ce4..a6e69d7992b 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/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
index f17635972b7..37c5d7ce7ef 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>(T);
@@ -1648,13 +1648,23 @@ mod foo {
     pub fn bar() -> S$0<()> {}
 }
 "#,
+            r#"
+struct S<T>(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>(T);
@@ -1664,6 +1674,16 @@ mod foo {
     pub fn bar() -> IoResult$0<()> {}
 }
 "#,
+            r#"
+struct S<T>(T);
+use S as IoResult;
+
+mod foo {
+    use crate::S;
+
+    pub fn bar() -> IoResult<()> {}
+}
+"#,
         );
     }
 
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 ab25e0167bf..c1fcb8e44db 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 61b7b412177..77f9c66b354 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.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 db96c8fe40a..e86ff0dbebc 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.clone()
+    } else {
+        sym::iter.clone()
+    });
     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 666e1a1496e..62bb6dff21e 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 4d369e705e8..ad422b25c39 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.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_, &known::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 8c9fe23bb0b..d0382499b99 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_.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-assists/src/handlers/replace_method_eager_lazy.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs
index 37ea5123a71..12d025f0759 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 ba6ef1921ac..c67693ea2bb 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 995a4443edf..ee27d8611eb 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,8 @@ 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_.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/attribute/macro_use.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs
index f45f9cba258..7e3a62405a7 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 a4f092cc498..a07daf4c4e4 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_.clone())),
                 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_.clone())), 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_.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 01f9368aa4e..71ff6b5aea3 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_.clone())),
                             );
                         }
                     }
@@ -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_.clone())),
+                            );
                         }
                     }
                     hir::Adt::Enum(e) => {
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 5512ac21534..559a9bcba29 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/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs
index 2c6cbf6146a..f31352f49f9 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.clone()));
     }
 }
 
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 27e9d1d6cfe..5fe6cd0e907 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 a14fe24fa75..1e972b9b4ce 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 fe9e2e5268a..15c20f11863 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 48c9d624f63..cdfe2317017 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))
                         }
@@ -263,8 +259,8 @@ 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) {
+        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() {
                         "&mut "
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 7d9c1ed98ac..eacec018c72 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/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index a75a708d956..dbb2adcd301 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 088717a66e5..38cb4a162c2 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 <FxHashSet<_>>::default().into_iter(),
+            None => return <FxIndexSet<_>>::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<ModPath> + Copy,
     scope_filter: impl Fn(ItemInNs) -> bool + Copy,
-) -> FxHashSet<LocatedImport> {
+) -> FxIndexSet<LocatedImport> {
     let _p = tracing::info_span!("ImportAssets::path_applicable_imports").entered();
 
     match &path_candidate.qualifier {
@@ -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;
         }
     }
@@ -500,7 +500,7 @@ fn trait_applicable_items(
     trait_assoc_item: bool,
     mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
     scope_filter: impl Fn(hir::Trait) -> bool,
-) -> FxHashSet<LocatedImport> {
+) -> FxIndexSet<LocatedImport> {
     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/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index e21d54ccd0e..84a388a460b 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 6a809cb0cef..a41bf457a90 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.clone()
                     && 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 41357b59622..46c373d8df0 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<A
     let expr = d.expr.value.to_node(&root);
 
     let error_range = ctx.sema.original_range_opt(expr.syntax())?;
-    let field_name = d.name.as_str()?;
+    let field_name = d.name.as_str();
     // Convert the receiver to an ADT
     let adt = d.receiver.strip_references().as_adt()?;
     let target_module = adt.module(ctx.sema.db);
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index f57cb1cb730..7fecc37c4c6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -150,7 +150,7 @@ fn try_lookup_macro_def_in_macro_use(
 
     for mod_def in krate.root_module().declarations(sema.db) {
         if let ModuleDef::Macro(mac) = mod_def {
-            if mac.name(sema.db).as_str() == Some(token.text()) {
+            if mac.name(sema.db).as_str() == token.text() {
                 if let Some(nav) = mac.try_to_nav(sema.db) {
                     return Some(nav.call_site);
                 }
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 944951f26a2..ce1a56e4506 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -5,7 +5,7 @@ use std::{
 
 use either::Either;
 use hir::{
-    known, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef,
+    sym, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef,
     ModuleDefId, Semantics,
 };
 use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase};
@@ -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) == known::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/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
index 51855eeae23..b60a80a8ac6 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/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
index c73b6acb0d0..291073f8773 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<T: std::hash::Hash + std::fmt::Debug>(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::<ide_db::FxHasher>((name.as_str(), shadow_count))
 }
 
 pub(super) fn highlight_def(
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 99e24308607..b27dc60ffaf 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 826447d058d..ad99c2162cd 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/Cargo.toml b/src/tools/rust-analyzer/crates/intern/Cargo.toml
index 67b4164ce1f..c08ecb5c307 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 40d18b1cf86..58327419f63 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<T> = dashmap::RwLockWriteGuard<
     HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>,
 >;
 
+mod symbol;
+pub use self::symbol::{symbols as sym, Symbol};
+
 pub struct Interned<T: Internable + ?Sized> {
     arc: Arc<T>,
 }
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 00000000000..a3cc5c3d6a3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs
@@ -0,0 +1,328 @@
+//! Attempt at flexible symbol interning, allowing to intern and free strings at runtime while also
+//! supporting compile time declaration of symbols that will never be freed.
+
+use std::{
+    borrow::Borrow,
+    fmt,
+    hash::{BuildHasherDefault, Hash, Hasher},
+    mem::{self, ManuallyDrop},
+    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::<Box<str>>() == std::mem::size_of::<&str>());
+const _: () = assert!(std::mem::align_of::<Box<str>>() == std::mem::align_of::<&str>());
+
+const _: () = assert!(std::mem::size_of::<Arc<Box<str>>>() == std::mem::size_of::<&&str>());
+const _: () = assert!(std::mem::align_of::<Arc<Box<str>>>() == std::mem::align_of::<&&str>());
+
+const _: () =
+    assert!(std::mem::size_of::<*const *const str>() == std::mem::size_of::<TaggedArcPtr>());
+const _: () =
+    assert!(std::mem::align_of::<*const *const str>() == std::mem::align_of::<TaggedArcPtr>());
+
+const _: () = assert!(std::mem::size_of::<Arc<Box<str>>>() == std::mem::size_of::<TaggedArcPtr>());
+const _: () =
+    assert!(std::mem::align_of::<Arc<Box<str>>>() == std::mem::align_of::<TaggedArcPtr>());
+
+/// A pointer that points to a pointer to a `str`, it may be backed as a `&'static &'static str` or
+/// `Arc<Box<str>>` 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<str>` and `ThinRef<str>`/`ThinConstPtr<str>` instead of the double indirection.
+#[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: &'static &'static str) -> Self {
+        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<Box<str>>) -> 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
+                unsafe { NonNull::new_unchecked(Arc::into_raw(arc).cast_mut().cast()) },
+            ),
+        }
+    }
+
+    /// Retrieves the tag.
+    #[inline]
+    pub(crate) fn try_as_arc_owned(self) -> Option<ManuallyDrop<Arc<Box<str>>>> {
+        // 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(ManuallyDrop::new(unsafe {
+                Arc::from_raw(self.pointer().as_ptr().cast::<Box<str>>())
+            }))
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    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<usize>`
+        //         // - `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 = 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);
+
+        // SAFETY: The resulting pointer is guaranteed to be NonNull as we only modify the niche bytes
+        unsafe { NonNull::new_unchecked(ptr.as_ptr().cast::<u8>().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, Debug)]
+pub struct Symbol {
+    repr: TaggedArcPtr,
+}
+
+const _: () = assert!(std::mem::size_of::<Symbol>() == std::mem::size_of::<NonNull<()>>());
+const _: () = assert!(std::mem::align_of::<Symbol>() == std::mem::align_of::<NonNull<()>>());
+
+static MAP: OnceLock<DashMap<SymbolProxy, (), BuildHasherDefault<FxHasher>>> = 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::<str>::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<SymbolProxy, SharedValue<()>, BuildHasherDefault<FxHasher>>,
+        >,
+        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<Box<str>>) {
+        let (mut shard, hash) = Self::select_shard(arc);
+
+        match Arc::count(arc) {
+            0 => unreachable!(),
+            1 => unreachable!(),
+            2 => (),
+            _ => {
+                // Another thread has interned another copy
+                return;
+            }
+        }
+
+        ManuallyDrop::into_inner(
+            match shard.raw_entry_mut().from_key_hashed_nocheck::<str>(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() {
+            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
+        ManuallyDrop::into_inner(arc);
+    }
+}
+
+impl Clone for Symbol {
+    fn clone(&self) -> Self {
+        Self { repr: increase_arc_refcount(self.repr) }
+    }
+}
+
+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(&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<H: Hasher>(&self, state: &mut H) {
+        self.0.as_str().hash(state);
+    }
+}
+
+impl Borrow<str> 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 more_worlds = world.clone();
+        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");
+        let many_worlds = world.clone();
+        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(many_worlds);
+        drop(more_worlds);
+        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 00000000000..064335471e9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -0,0 +1,360 @@
+//! 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 _};
+
+use dashmap::{DashMap, SharedValue};
+use rustc_hash::FxHasher;
+
+use crate::{
+    symbol::{SymbolProxy, TaggedArcPtr},
+    Symbol,
+};
+
+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)) };
+        )*
+        $(
+            pub static $alias: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&$value) };
+        )*
+
+
+        pub(super) fn prefill() -> DashMap<SymbolProxy, (), BuildHasherDefault<FxHasher>> {
+            let mut dashmap_ = <DashMap<SymbolProxy, (), BuildHasherDefault<FxHasher>>>::with_hasher(BuildHasherDefault::default());
+
+            let hash_thing_ = |hasher_: &BuildHasherDefault<FxHasher>, 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(()));
+                )*
+                $(
+
+                    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,
+    align_offset,
+    alloc_layout,
+    alloc,
+    as_str,
+    asm,
+    assert,
+    begin_panic,
+    bench,
+    bitand_assign,
+    bitand,
+    bitor_assign,
+    bitor,
+    bitxor_assign,
+    bitxor,
+    bool,
+    box_free,
+    Box,
+    boxed,
+    branch,
+    Break,
+    c_void,
+    call_mut,
+    call_once,
+    call,
+    Center,
+    cfg_accessible,
+    cfg_attr,
+    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,
+    f64,
+    feature,
+    file,
+    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,
+    Hash,
+    i128,
+    i16,
+    i32,
+    i64,
+    i8,
+    Implied,
+    include_bytes,
+    include_str,
+    include,
+    index_mut,
+    index,
+    Index,
+    into_future,
+    into_iter,
+    IntoFuture,
+    IntoIter,
+    IntoIterator,
+    is_empty,
+    Is,
+    isize,
+    Item,
+    iter_mut,
+    iter,
+    Iterator,
+    le,
+    Left,
+    len,
+    line,
+    llvm_asm,
+    log_syntax,
+    lt,
+    macro_rules,
+    manually_drop,
+    maybe_uninit,
+    metadata_type,
+    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_unchecked,
+    new_upper_exp,
+    new_upper_hex,
+    new_v1_formatted,
+    new,
+    next,
+    no_core,
+    no_std,
+    none,
+    None,
+    not,
+    Not,
+    Ok,
+    opaque,
+    ops,
+    option_env,
+    option,
+    Option,
+    Ord,
+    Output,
+    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,
+    range_inclusive_new,
+    Range,
+    RangeFrom,
+    RangeFull,
+    RangeInclusive,
+    RangeTo,
+    RangeToInclusive,
+    Ready,
+    receiver,
+    recursion_limit,
+    register_attr,
+    register_tool,
+    rem_assign,
+    rem,
+    result,
+    Result,
+    ResumeTy,
+    Right,
+    rust_2015,
+    rust_2018,
+    rust_2021,
+    rust_2024,
+    rustc_coherence_is_core,
+    rustc_macro_transparency,
+    semitransparent,
+    shl_assign,
+    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
+}