about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2023-01-21 17:29:07 +0100
committerLukas Wirth <lukastw97@gmail.com>2023-01-21 17:55:45 +0100
commit15358818363f66fc8b99e3711e6eb99a5e8684b9 (patch)
treee3630300168fb34f6aab485874ff9ccbdee88fb7
parent1afa032f34db45a7018ced2c1a59798139e95bfc (diff)
downloadrust-15358818363f66fc8b99e3711e6eb99a5e8684b9.tar.gz
rust-15358818363f66fc8b99e3711e6eb99a5e8684b9.zip
Replace SmolStr usage with lang item enum for lang items
-rw-r--r--crates/hir-def/src/db.rs6
-rw-r--r--crates/hir-def/src/lang_item.rs298
-rw-r--r--crates/hir-def/src/lib.rs1
-rw-r--r--crates/hir-expand/src/name.rs8
-rw-r--r--crates/hir-ty/src/autoderef.rs7
-rw-r--r--crates/hir-ty/src/chalk_db.rs81
-rw-r--r--crates/hir-ty/src/chalk_ext.rs7
-rw-r--r--crates/hir-ty/src/display.rs7
-rw-r--r--crates/hir-ty/src/infer.rs20
-rw-r--r--crates/hir-ty/src/infer/coerce.rs15
-rw-r--r--crates/hir-ty/src/infer/expr.rs4
-rw-r--r--crates/hir-ty/src/lang_items.rs11
-rw-r--r--crates/hir-ty/src/lower.rs10
-rw-r--r--crates/hir-ty/src/method_resolution.rs59
-rw-r--r--crates/hir-ty/src/traits.rs18
-rw-r--r--crates/hir-ty/src/utils.rs8
-rw-r--r--crates/hir/src/display.rs5
-rw-r--r--crates/hir/src/lib.rs13
-rw-r--r--crates/hir/src/source_analyzer.rs36
-rw-r--r--crates/project-model/src/sysroot.rs7
-rw-r--r--crates/project-model/src/workspace.rs4
21 files changed, 432 insertions, 193 deletions
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 65cdd1b69b1..b23427a73b3 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -6,7 +6,7 @@ use either::Either;
 use hir_expand::{db::AstDatabase, HirFileId};
 use intern::Interned;
 use la_arena::ArenaMap;
-use syntax::{ast, AstPtr, SmolStr};
+use syntax::{ast, AstPtr};
 
 use crate::{
     adt::{EnumData, StructData},
@@ -19,7 +19,7 @@ use crate::{
     generics::GenericParams,
     import_map::ImportMap,
     item_tree::{AttrOwner, ItemTree},
-    lang_item::{LangItemTarget, LangItems},
+    lang_item::{LangItem, LangItemTarget, LangItems},
     nameres::{diagnostics::DefDiagnostic, DefMap},
     visibility::{self, Visibility},
     AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId,
@@ -183,7 +183,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
     fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>;
 
     #[salsa::invoke(LangItems::lang_item_query)]
-    fn lang_item(&self, start_crate: CrateId, item: SmolStr) -> Option<LangItemTarget>;
+    fn lang_item(&self, start_crate: CrateId, item: LangItem) -> Option<LangItemTarget>;
 
     #[salsa::invoke(ImportMap::import_map_query)]
     fn import_map(&self, krate: CrateId) -> Arc<ImportMap>;
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index 87785018458..ab9bc615daf 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -8,19 +8,21 @@ use rustc_hash::FxHashMap;
 use syntax::SmolStr;
 
 use crate::{
-    db::DefDatabase, AdtId, AttrDefId, CrateId, EnumId, EnumVariantId, FunctionId, ImplId,
-    ModuleDefId, StaticId, StructId, TraitId,
+    db::DefDatabase, AdtId, AssocItemId, AttrDefId, CrateId, EnumId, EnumVariantId, FunctionId,
+    ImplId, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
 };
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum LangItemTarget {
     EnumId(EnumId),
-    FunctionId(FunctionId),
-    ImplDefId(ImplId),
-    StaticId(StaticId),
-    StructId(StructId),
-    TraitId(TraitId),
-    EnumVariantId(EnumVariantId),
+    Function(FunctionId),
+    ImplDef(ImplId),
+    Static(StaticId),
+    Struct(StructId),
+    Union(UnionId),
+    TypeAlias(TypeAliasId),
+    Trait(TraitId),
+    EnumVariant(EnumVariantId),
 }
 
 impl LangItemTarget {
@@ -33,42 +35,42 @@ impl LangItemTarget {
 
     pub fn as_function(self) -> Option<FunctionId> {
         match self {
-            LangItemTarget::FunctionId(id) => Some(id),
+            LangItemTarget::Function(id) => Some(id),
             _ => None,
         }
     }
 
     pub fn as_impl_def(self) -> Option<ImplId> {
         match self {
-            LangItemTarget::ImplDefId(id) => Some(id),
+            LangItemTarget::ImplDef(id) => Some(id),
             _ => None,
         }
     }
 
     pub fn as_static(self) -> Option<StaticId> {
         match self {
-            LangItemTarget::StaticId(id) => Some(id),
+            LangItemTarget::Static(id) => Some(id),
             _ => None,
         }
     }
 
     pub fn as_struct(self) -> Option<StructId> {
         match self {
-            LangItemTarget::StructId(id) => Some(id),
+            LangItemTarget::Struct(id) => Some(id),
             _ => None,
         }
     }
 
     pub fn as_trait(self) -> Option<TraitId> {
         match self {
-            LangItemTarget::TraitId(id) => Some(id),
+            LangItemTarget::Trait(id) => Some(id),
             _ => None,
         }
     }
 
     pub fn as_enum_variant(self) -> Option<EnumVariantId> {
         match self {
-            LangItemTarget::EnumVariantId(id) => Some(id),
+            LangItemTarget::EnumVariant(id) => Some(id),
             _ => None,
         }
     }
@@ -76,12 +78,12 @@ impl LangItemTarget {
 
 #[derive(Default, Debug, Clone, PartialEq, Eq)]
 pub struct LangItems {
-    items: FxHashMap<SmolStr, LangItemTarget>,
+    items: FxHashMap<LangItem, LangItemTarget>,
 }
 
 impl LangItems {
-    pub fn target(&self, item: &str) -> Option<LangItemTarget> {
-        self.items.get(item).copied()
+    pub fn target(&self, item: LangItem) -> Option<LangItemTarget> {
+        self.items.get(&item).copied()
     }
 
     /// Salsa query. This will look for lang items in a specific crate.
@@ -94,16 +96,27 @@ impl LangItems {
 
         for (_, module_data) in crate_def_map.modules() {
             for impl_def in module_data.scope.impls() {
-                lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDefId)
+                lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef);
+                for assoc in db.impl_data(impl_def).items.iter().copied() {
+                    match assoc {
+                        AssocItemId::FunctionId(f) => {
+                            lang_items.collect_lang_item(db, f, LangItemTarget::Function)
+                        }
+                        AssocItemId::TypeAliasId(t) => {
+                            lang_items.collect_lang_item(db, t, LangItemTarget::TypeAlias)
+                        }
+                        AssocItemId::ConstId(_) => (),
+                    }
+                }
             }
 
             for def in module_data.scope.declarations() {
                 match def {
                     ModuleDefId::TraitId(trait_) => {
-                        lang_items.collect_lang_item(db, trait_, LangItemTarget::TraitId);
+                        lang_items.collect_lang_item(db, trait_, LangItemTarget::Trait);
                         db.trait_data(trait_).items.iter().for_each(|&(_, assoc_id)| {
-                            if let crate::AssocItemId::FunctionId(f) = assoc_id {
-                                lang_items.collect_lang_item(db, f, LangItemTarget::FunctionId);
+                            if let AssocItemId::FunctionId(f) = assoc_id {
+                                lang_items.collect_lang_item(db, f, LangItemTarget::Function);
                             }
                         });
                     }
@@ -113,18 +126,24 @@ impl LangItems {
                             lang_items.collect_lang_item(
                                 db,
                                 EnumVariantId { parent: e, local_id },
-                                LangItemTarget::EnumVariantId,
+                                LangItemTarget::EnumVariant,
                             );
                         });
                     }
                     ModuleDefId::AdtId(AdtId::StructId(s)) => {
-                        lang_items.collect_lang_item(db, s, LangItemTarget::StructId);
+                        lang_items.collect_lang_item(db, s, LangItemTarget::Struct);
+                    }
+                    ModuleDefId::AdtId(AdtId::UnionId(u)) => {
+                        lang_items.collect_lang_item(db, u, LangItemTarget::Union);
                     }
                     ModuleDefId::FunctionId(f) => {
-                        lang_items.collect_lang_item(db, f, LangItemTarget::FunctionId);
+                        lang_items.collect_lang_item(db, f, LangItemTarget::Function);
                     }
                     ModuleDefId::StaticId(s) => {
-                        lang_items.collect_lang_item(db, s, LangItemTarget::StaticId);
+                        lang_items.collect_lang_item(db, s, LangItemTarget::Static);
+                    }
+                    ModuleDefId::TypeAliasId(t) => {
+                        lang_items.collect_lang_item(db, t, LangItemTarget::TypeAlias);
                     }
                     _ => {}
                 }
@@ -139,7 +158,7 @@ impl LangItems {
     pub(crate) fn lang_item_query(
         db: &dyn DefDatabase,
         start_crate: CrateId,
-        item: SmolStr,
+        item: LangItem,
     ) -> Option<LangItemTarget> {
         let _p = profile::span("lang_item_query");
         let lang_items = db.crate_lang_items(start_crate);
@@ -150,7 +169,7 @@ impl LangItems {
         db.crate_graph()[start_crate]
             .dependencies
             .iter()
-            .find_map(|dep| db.lang_item(dep.crate_id, item.clone()))
+            .find_map(|dep| db.lang_item(dep.crate_id, item))
     }
 
     fn collect_lang_item<T>(
@@ -162,8 +181,8 @@ impl LangItems {
         T: Into<AttrDefId> + Copy,
     {
         let _p = profile::span("collect_lang_item");
-        if let Some(lang_item_name) = lang_attr(db, item) {
-            self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
+        if let Some(lang_item) = lang_attr(db, item).and_then(|it| LangItem::from_str(&it)) {
+            self.items.entry(lang_item).or_insert_with(|| constructor(item));
         }
     }
 }
@@ -172,3 +191,224 @@ pub fn lang_attr(db: &dyn DefDatabase, item: impl Into<AttrDefId> + Copy) -> Opt
     let attrs = db.attrs(item.into());
     attrs.by_key("lang").string_value().cloned()
 }
+
+pub enum GenericRequirement {
+    None,
+    Minimum(usize),
+    Exact(usize),
+}
+
+macro_rules! language_item_table {
+    (
+        $( $(#[$attr:meta])* $variant:ident, $name:ident, $method:ident, $target:expr, $generics:expr; )*
+    ) => {
+
+        /// A representation of all the valid language items in Rust.
+        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+        pub enum LangItem {
+            $(
+                #[doc = concat!("The `", stringify!($name), "` lang item.")]
+                $(#[$attr])*
+                $variant,
+            )*
+        }
+
+        impl LangItem {
+            pub fn name(self) -> SmolStr {
+                match self {
+                    $( LangItem::$variant => SmolStr::new(stringify!($name)), )*
+                }
+            }
+
+            /// Opposite of [`LangItem::name`]
+            pub fn from_name(name: &hir_expand::name::Name) -> Option<Self> {
+                Self::from_str(name.as_str()?)
+            }
+
+            /// Opposite of [`LangItem::name`]
+            pub fn from_str(name: &str) -> Option<Self> {
+                match name {
+                    $( stringify!($name) => Some(LangItem::$variant), )*
+                    _ => None,
+                }
+            }
+        }
+    }
+}
+
+language_item_table! {
+//  Variant name,            Name,                     Getter method name,         Target                  Generic requirements;
+    Sized,                   sized,               sized_trait,                Target::Trait,          GenericRequirement::Exact(0);
+    Unsize,                  unsize,              unsize_trait,               Target::Trait,          GenericRequirement::Minimum(1);
+    /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ").
+    StructuralPeq,           structural_peq,      structural_peq_trait,       Target::Trait,          GenericRequirement::None;
+    /// Trait injected by `#[derive(Eq)]`, (i.e. "Total EQ"; no, I will not apologize).
+    StructuralTeq,           structural_teq,      structural_teq_trait,       Target::Trait,          GenericRequirement::None;
+    Copy,                    copy,                copy_trait,                 Target::Trait,          GenericRequirement::Exact(0);
+    Clone,                   clone,               clone_trait,                Target::Trait,          GenericRequirement::None;
+    Sync,                    sync,                sync_trait,                 Target::Trait,          GenericRequirement::Exact(0);
+    DiscriminantKind,        discriminant_kind,   discriminant_kind_trait,    Target::Trait,          GenericRequirement::None;
+    /// The associated item of the [`DiscriminantKind`] trait.
+    Discriminant,            discriminant_type,   discriminant_type,          Target::AssocTy,        GenericRequirement::None;
+
+    PointeeTrait,            pointee_trait,       pointee_trait,              Target::Trait,          GenericRequirement::None;
+    Metadata,                metadata_type,       metadata_type,              Target::AssocTy,        GenericRequirement::None;
+    DynMetadata,             dyn_metadata,        dyn_metadata,               Target::Struct,         GenericRequirement::None;
+
+    Freeze,                  freeze,              freeze_trait,               Target::Trait,          GenericRequirement::Exact(0);
+
+    Drop,                    drop,                drop_trait,                 Target::Trait,          GenericRequirement::None;
+    Destruct,                destruct,            destruct_trait,             Target::Trait,          GenericRequirement::None;
+
+    CoerceUnsized,           coerce_unsized,      coerce_unsized_trait,       Target::Trait,          GenericRequirement::Minimum(1);
+    DispatchFromDyn,         dispatch_from_dyn,   dispatch_from_dyn_trait,    Target::Trait,          GenericRequirement::Minimum(1);
+
+    // language items relating to transmutability
+    TransmuteOpts,           transmute_opts,      transmute_opts,             Target::Struct,         GenericRequirement::Exact(0);
+    TransmuteTrait,          transmute_trait,     transmute_trait,            Target::Trait,          GenericRequirement::Exact(3);
+
+    Add,                     add,                 add_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    Sub,                     sub,                 sub_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    Mul,                     mul,                 mul_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    Div,                     div,                 div_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    Rem,                     rem,                 rem_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    Neg,                     neg,                 neg_trait,                  Target::Trait,          GenericRequirement::Exact(0);
+    Not,                     not,                 not_trait,                  Target::Trait,          GenericRequirement::Exact(0);
+    BitXor,                  bitxor,              bitxor_trait,               Target::Trait,          GenericRequirement::Exact(1);
+    BitAnd,                  bitand,              bitand_trait,               Target::Trait,          GenericRequirement::Exact(1);
+    BitOr,                   bitor,               bitor_trait,                Target::Trait,          GenericRequirement::Exact(1);
+    Shl,                     shl,                 shl_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    Shr,                     shr,                 shr_trait,                  Target::Trait,          GenericRequirement::Exact(1);
+    AddAssign,               add_assign,          add_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    SubAssign,               sub_assign,          sub_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    MulAssign,               mul_assign,          mul_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    DivAssign,               div_assign,          div_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    RemAssign,               rem_assign,          rem_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    BitXorAssign,            bitxor_assign,       bitxor_assign_trait,        Target::Trait,          GenericRequirement::Exact(1);
+    BitAndAssign,            bitand_assign,       bitand_assign_trait,        Target::Trait,          GenericRequirement::Exact(1);
+    BitOrAssign,             bitor_assign,        bitor_assign_trait,         Target::Trait,          GenericRequirement::Exact(1);
+    ShlAssign,               shl_assign,          shl_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    ShrAssign,               shr_assign,          shr_assign_trait,           Target::Trait,          GenericRequirement::Exact(1);
+    Index,                   index,               index_trait,                Target::Trait,          GenericRequirement::Exact(1);
+    IndexMut,                index_mut,           index_mut_trait,            Target::Trait,          GenericRequirement::Exact(1);
+
+    UnsafeCell,              unsafe_cell,         unsafe_cell_type,           Target::Struct,         GenericRequirement::None;
+    VaList,                  va_list,             va_list,                    Target::Struct,         GenericRequirement::None;
+
+    Deref,                   deref,               deref_trait,                Target::Trait,          GenericRequirement::Exact(0);
+    DerefMut,                deref_mut,           deref_mut_trait,            Target::Trait,          GenericRequirement::Exact(0);
+    DerefTarget,             deref_target,        deref_target,               Target::AssocTy,        GenericRequirement::None;
+    Receiver,                receiver,            receiver_trait,             Target::Trait,          GenericRequirement::None;
+
+    Fn,                      fn,                  fn_trait,                   Target::Trait,          GenericRequirement::Exact(1);
+    FnMut,                   fn_mut,              fn_mut_trait,               Target::Trait,          GenericRequirement::Exact(1);
+    FnOnce,                  fn_once,             fn_once_trait,              Target::Trait,          GenericRequirement::Exact(1);
+
+    FnOnceOutput,            fn_once_output,      fn_once_output,             Target::AssocTy,        GenericRequirement::None;
+
+    Future,                  future_trait,        future_trait,               Target::Trait,          GenericRequirement::Exact(0);
+    GeneratorState,          generator_state,     gen_state,                  Target::Enum,           GenericRequirement::None;
+    Generator,               generator,           gen_trait,                  Target::Trait,          GenericRequirement::Minimum(1);
+    Unpin,                   unpin,               unpin_trait,                Target::Trait,          GenericRequirement::None;
+    Pin,                     pin,                 pin_type,                   Target::Struct,         GenericRequirement::None;
+
+    PartialEq,               eq,                  eq_trait,                   Target::Trait,          GenericRequirement::Exact(1);
+    PartialOrd,              partial_ord,         partial_ord_trait,          Target::Trait,          GenericRequirement::Exact(1);
+
+    // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
+    // various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.
+    //
+    // The `begin_unwind` lang item has a predefined symbol name and is sort of a "weak lang item"
+    // in the sense that a crate is not required to have it defined to use it, but a final product
+    // is required to define it somewhere. Additionally, there are restrictions on crates that use
+    // a weak lang item, but do not have it defined.
+    Panic,                   panic,               panic_fn,                   Target::Fn,             GenericRequirement::Exact(0);
+    PanicNounwind,           panic_nounwind,      panic_nounwind,             Target::Fn,             GenericRequirement::Exact(0);
+    PanicFmt,                panic_fmt,           panic_fmt,                  Target::Fn,             GenericRequirement::None;
+    PanicDisplay,            panic_display,       panic_display,              Target::Fn,             GenericRequirement::None;
+    ConstPanicFmt,           const_panic_fmt,     const_panic_fmt,            Target::Fn,             GenericRequirement::None;
+    PanicBoundsCheck,        panic_bounds_check,  panic_bounds_check_fn,      Target::Fn,             GenericRequirement::Exact(0);
+    PanicInfo,               panic_info,          panic_info,                 Target::Struct,         GenericRequirement::None;
+    PanicLocation,           panic_location,      panic_location,             Target::Struct,         GenericRequirement::None;
+    PanicImpl,               panic_impl,          panic_impl,                 Target::Fn,             GenericRequirement::None;
+    PanicCannotUnwind,       panic_cannot_unwind, panic_cannot_unwind,        Target::Fn,             GenericRequirement::Exact(0);
+    /// libstd panic entry point. Necessary for const eval to be able to catch it
+    BeginPanic,              begin_panic,         begin_panic_fn,             Target::Fn,             GenericRequirement::None;
+
+    ExchangeMalloc,          exchange_malloc,     exchange_malloc_fn,         Target::Fn,             GenericRequirement::None;
+    BoxFree,                 box_free,            box_free_fn,                Target::Fn,             GenericRequirement::Minimum(1);
+    DropInPlace,             drop_in_place,       drop_in_place_fn,           Target::Fn,             GenericRequirement::Minimum(1);
+    AllocLayout,             alloc_layout,        alloc_layout,               Target::Struct,         GenericRequirement::None;
+
+    Start,                   start,               start_fn,                   Target::Fn,             GenericRequirement::Exact(1);
+
+    EhPersonality,           eh_personality,      eh_personality,             Target::Fn,             GenericRequirement::None;
+    EhCatchTypeinfo,         eh_catch_typeinfo,   eh_catch_typeinfo,          Target::Static,         GenericRequirement::None;
+
+    OwnedBox,                owned_box,           owned_box,                  Target::Struct,         GenericRequirement::Minimum(1);
+
+    PhantomData,             phantom_data,        phantom_data,               Target::Struct,         GenericRequirement::Exact(1);
+
+    ManuallyDrop,            manually_drop,       manually_drop,              Target::Struct,         GenericRequirement::None;
+
+    MaybeUninit,             maybe_uninit,        maybe_uninit,               Target::Union,          GenericRequirement::None;
+
+    /// Align offset for stride != 1; must not panic.
+    AlignOffset,             align_offset,        align_offset_fn,            Target::Fn,             GenericRequirement::None;
+
+    Termination,             termination,         termination,                Target::Trait,          GenericRequirement::None;
+
+    Try,                     Try,                 try_trait,                  Target::Trait,          GenericRequirement::None;
+
+    Tuple,                   tuple_trait,         tuple_trait,                Target::Trait,          GenericRequirement::Exact(0);
+
+    SliceLen,                slice_len_fn,        slice_len_fn,               Target::Method(MethodKind::Inherent), GenericRequirement::None;
+
+    // Language items from AST lowering
+    TryTraitFromResidual,    from_residual,       from_residual_fn,           Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+    TryTraitFromOutput,      from_output,         from_output_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+    TryTraitBranch,          branch,              branch_fn,                  Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+    TryTraitFromYeet,        from_yeet,           from_yeet_fn,               Target::Fn,             GenericRequirement::None;
+
+    PointerSized,            pointer_sized,       pointer_sized,              Target::Trait,          GenericRequirement::Exact(0);
+
+    Poll,                    Poll,                poll,                       Target::Enum,           GenericRequirement::None;
+    PollReady,               Ready,               poll_ready_variant,         Target::Variant,        GenericRequirement::None;
+    PollPending,             Pending,             poll_pending_variant,       Target::Variant,        GenericRequirement::None;
+
+    // FIXME(swatinem): the following lang items are used for async lowering and
+    // should become obsolete eventually.
+    ResumeTy,                ResumeTy,            resume_ty,                  Target::Struct,         GenericRequirement::None;
+    IdentityFuture,          identity_future,     identity_future_fn,         Target::Fn,             GenericRequirement::None;
+    GetContext,              get_context,         get_context_fn,             Target::Fn,             GenericRequirement::None;
+
+    Context,                 Context,             context,                    Target::Struct,         GenericRequirement::None;
+    FuturePoll,              poll,                future_poll_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+
+    FromFrom,                from,                from_fn,                    Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+
+    OptionSome,              Some,                option_some_variant,        Target::Variant,        GenericRequirement::None;
+    OptionNone,              None,                option_none_variant,        Target::Variant,        GenericRequirement::None;
+
+    ResultOk,                Ok,                  result_ok_variant,          Target::Variant,        GenericRequirement::None;
+    ResultErr,               Err,                 result_err_variant,         Target::Variant,        GenericRequirement::None;
+
+    ControlFlowContinue,     Continue,            cf_continue_variant,        Target::Variant,        GenericRequirement::None;
+    ControlFlowBreak,        Break,               cf_break_variant,           Target::Variant,        GenericRequirement::None;
+
+    IntoFutureIntoFuture,    into_future,         into_future_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+    IntoIterIntoIter,        into_iter,           into_iter_fn,               Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+    IteratorNext,            next,                next_fn,                    Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None;
+
+    PinNewUnchecked,         new_unchecked,       new_unchecked_fn,           Target::Method(MethodKind::Inherent), GenericRequirement::None;
+
+    RangeFrom,               RangeFrom,           range_from_struct,          Target::Struct,         GenericRequirement::None;
+    RangeFull,               RangeFull,           range_full_struct,          Target::Struct,         GenericRequirement::None;
+    RangeInclusiveStruct,    RangeInclusive,      range_inclusive_struct,     Target::Struct,         GenericRequirement::None;
+    RangeInclusiveNew,       range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent), GenericRequirement::None;
+    Range,                   Range,               range_struct,               Target::Struct,         GenericRequirement::None;
+    RangeToInclusive,        RangeToInclusive,    range_to_inclusive_struct,  Target::Struct,         GenericRequirement::None;
+    RangeTo,                 RangeTo,             range_to_struct,            Target::Struct,         GenericRequirement::None;
+
+    String,                  String,              string,                     Target::Struct,         GenericRequirement::None;
+}
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index 8eae2e92f42..9e4e0dcc96c 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -634,7 +634,6 @@ pub trait Lookup {
 pub trait HasModule {
     fn module(&self, db: &dyn db::DefDatabase) -> ModuleId;
 }
-
 impl HasModule for ItemContainerId {
     fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
         match *self {
diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs
index e8b3e312aab..b62f4fe7701 100644
--- a/crates/hir-expand/src/name.rs
+++ b/crates/hir-expand/src/name.rs
@@ -133,6 +133,14 @@ impl Name {
         }
     }
 
+    /// Returns the text this name represents if it isn't a tuple field.
+    pub fn as_str(&self) -> Option<&str> {
+        match &self.0 {
+            Repr::Text(it) => Some(it),
+            _ => None,
+        }
+    }
+
     /// Returns the textual representation of this name as a [`SmolStr`].
     /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in
     /// the general case.
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index cbcf8f74c55..caddca6d915 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -6,9 +6,9 @@
 use std::sync::Arc;
 
 use chalk_ir::cast::Cast;
+use hir_def::lang_item::LangItem;
 use hir_expand::name::name;
 use limit::Limit;
-use syntax::SmolStr;
 
 use crate::{
     db::HirDatabase, infer::unify::InferenceTable, Canonical, Goal, Interner, ProjectionTyExt,
@@ -117,9 +117,8 @@ fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
     }
 
     let db = table.db;
-    let deref_trait = db
-        .lang_item(table.trait_env.krate, SmolStr::new_inline("deref"))
-        .and_then(|l| l.as_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 projection = {
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index 1c2b8de7f78..bbb6625855d 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -3,7 +3,6 @@
 use std::sync::Arc;
 
 use cov_mark::hit;
-use syntax::SmolStr;
 use tracing::debug;
 
 use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
@@ -12,7 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
 use base_db::CrateId;
 use hir_def::{
     expr::Movability,
-    lang_item::{lang_attr, LangItemTarget},
+    lang_item::{lang_attr, LangItem, LangItemTarget},
     AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
 };
 use hir_expand::name::name;
@@ -182,9 +181,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
         &self,
         well_known_trait: rust_ir::WellKnownTrait,
     ) -> Option<chalk_ir::TraitId<Interner>> {
-        let lang_attr = lang_attr_from_well_known_trait(well_known_trait);
+        let lang_attr = lang_item_from_well_known_trait(well_known_trait);
         let trait_ = match self.db.lang_item(self.krate, lang_attr.into()) {
-            Some(LangItemTarget::TraitId(trait_)) => trait_,
+            Some(LangItemTarget::Trait(trait_)) => trait_,
             _ => return None,
         };
         Some(to_chalk_trait_id(trait_))
@@ -216,7 +215,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
             crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
                 if let Some((future_trait, future_output)) = self
                     .db
-                    .lang_item(self.krate, SmolStr::new_inline("future_trait"))
+                    .lang_item(self.krate, LangItem::Future)
                     .and_then(|item| item.as_trait())
                     .and_then(|trait_| {
                         let alias =
@@ -246,7 +245,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
                     binder.push(crate::wrap_empty_binders(impl_bound));
                     let sized_trait = self
                         .db
-                        .lang_item(self.krate, SmolStr::new_inline("sized"))
+                        .lang_item(self.krate, LangItem::Sized)
                         .and_then(|item| item.as_trait());
                     if let Some(sized_trait_) = sized_trait {
                         let sized_bound = WhereClause::Implemented(TraitRef {
@@ -493,7 +492,7 @@ pub(crate) fn associated_ty_data_query(
 
     if !ctx.unsized_types.borrow().contains(&self_ty) {
         let sized_trait = db
-            .lang_item(resolver.krate(), SmolStr::new_inline("sized"))
+            .lang_item(resolver.krate(), LangItem::Sized)
             .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
         let sized_bound = sized_trait.into_iter().map(|sized_trait| {
             let trait_bound =
@@ -541,8 +540,8 @@ pub(crate) fn trait_datum_query(
     let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
     let associated_ty_ids = trait_data.associated_types().map(to_assoc_type_id).collect();
     let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses };
-    let well_known =
-        lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
+    let well_known = lang_attr(db.upcast(), trait_)
+        .and_then(|name| well_known_trait_from_lang_item(LangItem::from_str(&name)?));
     let trait_datum = TraitDatum {
         id: trait_id,
         binders: make_binders(db, &generic_params, trait_datum_bound),
@@ -553,42 +552,42 @@ pub(crate) fn trait_datum_query(
     Arc::new(trait_datum)
 }
 
-fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> {
-    Some(match name {
-        "clone" => WellKnownTrait::Clone,
-        "coerce_unsized" => WellKnownTrait::CoerceUnsized,
-        "copy" => WellKnownTrait::Copy,
-        "discriminant_kind" => WellKnownTrait::DiscriminantKind,
-        "dispatch_from_dyn" => WellKnownTrait::DispatchFromDyn,
-        "drop" => WellKnownTrait::Drop,
-        "fn" => WellKnownTrait::Fn,
-        "fn_mut" => WellKnownTrait::FnMut,
-        "fn_once" => WellKnownTrait::FnOnce,
-        "generator" => WellKnownTrait::Generator,
-        "sized" => WellKnownTrait::Sized,
-        "unpin" => WellKnownTrait::Unpin,
-        "unsize" => WellKnownTrait::Unsize,
-        "tuple_trait" => WellKnownTrait::Tuple,
+fn well_known_trait_from_lang_item(item: LangItem) -> Option<WellKnownTrait> {
+    Some(match item {
+        LangItem::Clone => WellKnownTrait::Clone,
+        LangItem::CoerceUnsized => WellKnownTrait::CoerceUnsized,
+        LangItem::Copy => WellKnownTrait::Copy,
+        LangItem::DiscriminantKind => WellKnownTrait::DiscriminantKind,
+        LangItem::DispatchFromDyn => WellKnownTrait::DispatchFromDyn,
+        LangItem::Drop => WellKnownTrait::Drop,
+        LangItem::Fn => WellKnownTrait::Fn,
+        LangItem::FnMut => WellKnownTrait::FnMut,
+        LangItem::FnOnce => WellKnownTrait::FnOnce,
+        LangItem::Generator => WellKnownTrait::Generator,
+        LangItem::Sized => WellKnownTrait::Sized,
+        LangItem::Unpin => WellKnownTrait::Unpin,
+        LangItem::Unsize => WellKnownTrait::Unsize,
+        LangItem::Tuple => WellKnownTrait::Tuple,
         _ => return None,
     })
 }
 
-fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str {
-    match attr {
-        WellKnownTrait::Clone => "clone",
-        WellKnownTrait::CoerceUnsized => "coerce_unsized",
-        WellKnownTrait::Copy => "copy",
-        WellKnownTrait::DiscriminantKind => "discriminant_kind",
-        WellKnownTrait::DispatchFromDyn => "dispatch_from_dyn",
-        WellKnownTrait::Drop => "drop",
-        WellKnownTrait::Fn => "fn",
-        WellKnownTrait::FnMut => "fn_mut",
-        WellKnownTrait::FnOnce => "fn_once",
-        WellKnownTrait::Generator => "generator",
-        WellKnownTrait::Sized => "sized",
-        WellKnownTrait::Tuple => "tuple_trait",
-        WellKnownTrait::Unpin => "unpin",
-        WellKnownTrait::Unsize => "unsize",
+fn lang_item_from_well_known_trait(trait_: WellKnownTrait) -> LangItem {
+    match trait_ {
+        WellKnownTrait::Clone => LangItem::Clone,
+        WellKnownTrait::CoerceUnsized => LangItem::CoerceUnsized,
+        WellKnownTrait::Copy => LangItem::Copy,
+        WellKnownTrait::DiscriminantKind => LangItem::DiscriminantKind,
+        WellKnownTrait::DispatchFromDyn => LangItem::DispatchFromDyn,
+        WellKnownTrait::Drop => LangItem::Drop,
+        WellKnownTrait::Fn => LangItem::Fn,
+        WellKnownTrait::FnMut => LangItem::FnMut,
+        WellKnownTrait::FnOnce => LangItem::FnOnce,
+        WellKnownTrait::Generator => LangItem::Generator,
+        WellKnownTrait::Sized => LangItem::Sized,
+        WellKnownTrait::Tuple => LangItem::Tuple,
+        WellKnownTrait::Unpin => LangItem::Unpin,
+        WellKnownTrait::Unsize => LangItem::Unsize,
     }
 }
 
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index 0244b6c653e..329c87c74e9 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -4,10 +4,10 @@ use chalk_ir::{FloatTy, IntTy, Mutability, Scalar, TyVariableKind, UintTy};
 use hir_def::{
     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint},
     generics::TypeOrConstParamData,
+    lang_item::LangItem,
     type_ref::Rawness,
     FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
 };
-use syntax::SmolStr;
 
 use crate::{
     db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
@@ -214,9 +214,8 @@ impl TyExt for Ty {
                 match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) {
                     ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
                         let krate = def.module(db.upcast()).krate();
-                        if let Some(future_trait) = db
-                            .lang_item(krate, SmolStr::new_inline("future_trait"))
-                            .and_then(|item| item.as_trait())
+                        if let Some(future_trait) =
+                            db.lang_item(krate, LangItem::Future).and_then(|item| item.as_trait())
                         {
                             // This is only used by type walking.
                             // Parameters will be walked outside, and projection predicate is not used.
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 3a96e53d719..ae2162dd7cd 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -12,6 +12,7 @@ use hir_def::{
     find_path,
     generics::{TypeOrConstParamData, TypeParamProvenance},
     item_scope::ItemInNs,
+    lang_item::LangItem,
     path::{Path, PathKind},
     type_ref::{ConstScalar, TraitBoundModifier, TypeBound, TypeRef},
     visibility::Visibility,
@@ -21,7 +22,6 @@ use hir_expand::{hygiene::Hygiene, name::Name};
 use intern::{Internable, Interned};
 use itertools::Itertools;
 use smallvec::SmallVec;
-use syntax::SmolStr;
 
 use crate::{
     db::HirDatabase,
@@ -925,7 +925,7 @@ impl SizedByDefault {
             Self::NotSized => false,
             Self::Sized { anchor } => {
                 let sized_trait = db
-                    .lang_item(anchor, SmolStr::new_inline("sized"))
+                    .lang_item(anchor, LangItem::Sized)
                     .and_then(|lang_item| lang_item.as_trait());
                 Some(trait_) == sized_trait
             }
@@ -1057,8 +1057,7 @@ fn write_bounds_like_dyn_trait(
     }
     if let SizedByDefault::Sized { anchor } = default_sized {
         let sized_trait =
-            f.db.lang_item(anchor, SmolStr::new_inline("sized"))
-                .and_then(|lang_item| lang_item.as_trait());
+            f.db.lang_item(anchor, LangItem::Sized).and_then(|lang_item| lang_item.as_trait());
         if !is_sized {
             if !first {
                 write!(f, " + ")?;
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 0e177db7726..d06b22fff9a 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -22,7 +22,7 @@ use hir_def::{
     builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
     data::{ConstData, StaticData},
     expr::{BindingAnnotation, ExprId, ExprOrPatId, PatId},
-    lang_item::LangItemTarget,
+    lang_item::{LangItem, LangItemTarget},
     layout::Integer,
     path::{path, Path},
     resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
@@ -30,7 +30,7 @@ use hir_def::{
     AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule,
     ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId,
 };
-use hir_expand::name::{name, Name};
+use hir_expand::name::name;
 use itertools::Either;
 use la_arena::ArenaMap;
 use rustc_hash::FxHashMap;
@@ -917,9 +917,9 @@ impl<'a> InferenceContext<'a> {
         }
     }
 
-    fn resolve_lang_item(&self, name: Name) -> Option<LangItemTarget> {
+    fn resolve_lang_item(&self, item: LangItem) -> Option<LangItemTarget> {
         let krate = self.resolver.krate();
-        self.db.lang_item(krate, name.to_smol_str())
+        self.db.lang_item(krate, item)
     }
 
     fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
@@ -946,12 +946,12 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
-        let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?;
+        let trait_ = self.resolve_lang_item(LangItem::Neg)?.as_trait()?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Output])
     }
 
     fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
-        let trait_ = self.resolve_lang_item(name![not])?.as_trait()?;
+        let trait_ = self.resolve_lang_item(LangItem::Not)?.as_trait()?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Output])
     }
 
@@ -959,12 +959,12 @@ impl<'a> InferenceContext<'a> {
         let trait_ = self
             .resolver
             .resolve_known_trait(self.db.upcast(), &path![core::future::IntoFuture])
-            .or_else(|| self.resolve_lang_item(name![future_trait])?.as_trait())?;
+            .or_else(|| self.resolve_lang_item(LangItem::Future)?.as_trait())?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Output])
     }
 
     fn resolve_boxed_box(&self) -> Option<AdtId> {
-        let struct_ = self.resolve_lang_item(name![owned_box])?.as_struct()?;
+        let struct_ = self.resolve_lang_item(LangItem::OwnedBox)?.as_struct()?;
         Some(struct_.into())
     }
 
@@ -1005,7 +1005,7 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn resolve_ops_index(&self) -> Option<TraitId> {
-        self.resolve_lang_item(name![index])?.as_trait()
+        self.resolve_lang_item(LangItem::Index)?.as_trait()
     }
 
     fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
@@ -1014,7 +1014,7 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn resolve_va_list(&self) -> Option<AdtId> {
-        let struct_ = self.resolve_lang_item(name![va_list])?.as_struct()?;
+        let struct_ = self.resolve_lang_item(LangItem::VaList)?.as_struct()?;
         Some(struct_.into())
     }
 }
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index 8df25c83c6e..3293534a068 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -8,9 +8,11 @@
 use std::{iter, sync::Arc};
 
 use chalk_ir::{cast::Cast, BoundVar, Goal, Mutability, TyVariableKind};
-use hir_def::{expr::ExprId, lang_item::LangItemTarget};
+use hir_def::{
+    expr::ExprId,
+    lang_item::{LangItem, LangItemTarget},
+};
 use stdx::always;
-use syntax::SmolStr;
 
 use crate::{
     autoderef::{Autoderef, AutoderefKind},
@@ -570,11 +572,10 @@ impl<'a> InferenceTable<'a> {
             reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone());
 
         let krate = self.trait_env.krate;
-        let coerce_unsized_trait =
-            match self.db.lang_item(krate, SmolStr::new_inline("coerce_unsized")) {
-                Some(LangItemTarget::TraitId(trait_)) => trait_,
-                _ => return Err(TypeError),
-            };
+        let coerce_unsized_trait = match self.db.lang_item(krate, LangItem::CoerceUnsized) {
+            Some(LangItemTarget::Trait(trait_)) => trait_,
+            _ => return Err(TypeError),
+        };
 
         let coerce_unsized_tref = {
             let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait);
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 6f347f6757b..7ae85d20611 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -29,7 +29,7 @@ use crate::{
         const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
     },
     mapping::{from_chalk, ToChalk},
-    method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
+    method_resolution::{self, lang_items_for_bin_op, VisibleFromModule},
     primitive::{self, UintTy},
     static_lifetime, to_chalk_trait_id,
     utils::{generics, Generics},
@@ -1008,7 +1008,7 @@ impl<'a> InferenceContext<'a> {
         let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
         let rhs_ty = self.table.new_type_var();
 
-        let trait_func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
+        let trait_func = lang_items_for_bin_op(op).and_then(|(name, lang_item)| {
             let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
             let func = self.db.trait_data(trait_id).method_by_name(&name)?;
             Some((trait_id, func))
diff --git a/crates/hir-ty/src/lang_items.rs b/crates/hir-ty/src/lang_items.rs
index afc54e729f9..5308c72161b 100644
--- a/crates/hir-ty/src/lang_items.rs
+++ b/crates/hir-ty/src/lang_items.rs
@@ -1,20 +1,19 @@
 //! Functions to detect special lang items
 
-use hir_def::{AdtId, HasModule};
-use hir_expand::name;
+use hir_def::{lang_item::LangItem, AdtId, HasModule};
 
 use crate::db::HirDatabase;
 
 pub fn is_box(adt: AdtId, db: &dyn HirDatabase) -> bool {
-    let owned_box = name![owned_box].to_smol_str();
     let krate = adt.module(db.upcast()).krate();
-    let box_adt = db.lang_item(krate, owned_box).and_then(|it| it.as_struct()).map(AdtId::from);
+    let box_adt =
+        db.lang_item(krate, LangItem::OwnedBox).and_then(|it| it.as_struct()).map(AdtId::from);
     Some(adt) == box_adt
 }
 
 pub fn is_unsafe_cell(adt: AdtId, db: &dyn HirDatabase) -> bool {
-    let owned_box = name![unsafe_cell].to_smol_str();
     let krate = adt.module(db.upcast()).krate();
-    let box_adt = db.lang_item(krate, owned_box).and_then(|it| it.as_struct()).map(AdtId::from);
+    let box_adt =
+        db.lang_item(krate, LangItem::UnsafeCell).and_then(|it| it.as_struct()).map(AdtId::from);
     Some(adt) == box_adt
 }
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 24973afb9ce..b1a7ad3e940 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -23,7 +23,7 @@ use hir_def::{
     generics::{
         TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
     },
-    lang_item::lang_attr,
+    lang_item::{lang_attr, LangItem},
     path::{GenericArg, ModPath, Path, PathKind, PathSegment, PathSegments},
     resolver::{HasResolver, Resolver, TypeNs},
     type_ref::{
@@ -40,7 +40,7 @@ use la_arena::ArenaMap;
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use stdx::{impl_from, never};
-use syntax::{ast, SmolStr};
+use syntax::ast;
 
 use crate::{
     all_super_traits,
@@ -954,7 +954,7 @@ impl<'a> TyLoweringContext<'a> {
             TypeBound::Path(path, TraitBoundModifier::Maybe) => {
                 let sized_trait = self
                     .db
-                    .lang_item(self.resolver.krate(), SmolStr::new_inline("sized"))
+                    .lang_item(self.resolver.krate(), LangItem::Sized)
                     .and_then(|lang_item| lang_item.as_trait());
                 // Don't lower associated type bindings as the only possible relaxed trait bound
                 // `?Sized` has no of them.
@@ -1150,7 +1150,7 @@ impl<'a> TyLoweringContext<'a> {
                 let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
                 let sized_trait = ctx
                     .db
-                    .lang_item(krate, SmolStr::new_inline("sized"))
+                    .lang_item(krate, LangItem::Sized)
                     .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
                 let sized_clause = sized_trait.map(|trait_id| {
                     let clause = WhereClause::Implemented(TraitRef {
@@ -1489,7 +1489,7 @@ fn implicitly_sized_clauses<'a>(
     let is_trait_def = matches!(def, GenericDefId::TraitId(..));
     let generic_args = &substitution.as_slice(Interner)[is_trait_def as usize..];
     let sized_trait = db
-        .lang_item(resolver.krate(), SmolStr::new_inline("sized"))
+        .lang_item(resolver.krate(), LangItem::Sized)
         .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
 
     sized_trait.into_iter().flat_map(move |sized_trait| {
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 64376e10bcc..858de000596 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -7,8 +7,9 @@ use std::{ops::ControlFlow, sync::Arc};
 use base_db::{CrateId, Edition};
 use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
 use hir_def::{
-    data::ImplData, item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId,
-    FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId,
+    data::ImplData, item_scope::ItemScope, lang_item::LangItem, nameres::DefMap, AssocItemId,
+    BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId,
+    ModuleId, TraitId,
 };
 use hir_expand::name::Name;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -437,49 +438,49 @@ pub fn def_crates(
     }
 }
 
-pub fn lang_names_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, Name)> {
+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), name!(add)),
-            ArithOp::Mul => (name!(mul), name!(mul)),
-            ArithOp::Sub => (name!(sub), name!(sub)),
-            ArithOp::Div => (name!(div), name!(div)),
-            ArithOp::Rem => (name!(rem), name!(rem)),
-            ArithOp::Shl => (name!(shl), name!(shl)),
-            ArithOp::Shr => (name!(shr), name!(shr)),
-            ArithOp::BitXor => (name!(bitxor), name!(bitxor)),
-            ArithOp::BitOr => (name!(bitor), name!(bitor)),
-            ArithOp::BitAnd => (name!(bitand), name!(bitand)),
+            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),
         },
         BinaryOp::Assignment { op: Some(aop) } => match aop {
-            ArithOp::Add => (name!(add_assign), name!(add_assign)),
-            ArithOp::Mul => (name!(mul_assign), name!(mul_assign)),
-            ArithOp::Sub => (name!(sub_assign), name!(sub_assign)),
-            ArithOp::Div => (name!(div_assign), name!(div_assign)),
-            ArithOp::Rem => (name!(rem_assign), name!(rem_assign)),
-            ArithOp::Shl => (name!(shl_assign), name!(shl_assign)),
-            ArithOp::Shr => (name!(shr_assign), name!(shr_assign)),
-            ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)),
-            ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)),
-            ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)),
+            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),
         },
         BinaryOp::CmpOp(cop) => match cop {
-            CmpOp::Eq { negated: false } => (name!(eq), name!(eq)),
-            CmpOp::Eq { negated: true } => (name!(ne), name!(eq)),
+            CmpOp::Eq { negated: false } => (name![eq], LangItem::PartialEq),
+            CmpOp::Eq { negated: true } => (name![ne], LangItem::PartialEq),
             CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
-                (name!(le), name!(partial_ord))
+                (name![le], LangItem::PartialOrd)
             }
             CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
-                (name!(lt), name!(partial_ord))
+                (name![lt], LangItem::PartialOrd)
             }
             CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
-                (name!(ge), name!(partial_ord))
+                (name![ge], LangItem::PartialOrd)
             }
             CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
-                (name!(gt), name!(partial_ord))
+                (name![gt], LangItem::PartialOrd)
             }
         },
         BinaryOp::Assignment { op: None } => return None,
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index 778a6b82047..3ab85c68f5b 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -7,9 +7,11 @@ use chalk_recursive::Cache;
 use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
 
 use base_db::CrateId;
-use hir_def::{lang_item::LangItemTarget, TraitId};
+use hir_def::{
+    lang_item::{LangItem, LangItemTarget},
+    TraitId,
+};
 use stdx::panic_context;
-use syntax::SmolStr;
 
 use crate::{
     db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
@@ -177,18 +179,18 @@ pub enum FnTrait {
 }
 
 impl FnTrait {
-    const fn lang_item_name(self) -> &'static str {
+    const fn lang_item(self) -> LangItem {
         match self {
-            FnTrait::FnOnce => "fn_once",
-            FnTrait::FnMut => "fn_mut",
-            FnTrait::Fn => "fn",
+            FnTrait::FnOnce => LangItem::FnOnce,
+            FnTrait::FnMut => LangItem::FnMut,
+            FnTrait::Fn => LangItem::Fn,
         }
     }
 
     pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
-        let target = db.lang_item(krate, SmolStr::new_inline(self.lang_item_name()))?;
+        let target = db.lang_item(krate, self.lang_item())?;
         match target {
-            LangItemTarget::TraitId(t) => Some(t),
+            LangItemTarget::Trait(t) => Some(t),
             _ => None,
         }
     }
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index 4f516e18be6..396cba89b67 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -11,6 +11,7 @@ use hir_def::{
         GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
         WherePredicateTypeTarget,
     },
+    lang_item::LangItem,
     resolver::{HasResolver, TypeNs},
     type_ref::{TraitBoundModifier, TypeRef},
     ConstParamId, FunctionId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId,
@@ -21,7 +22,6 @@ use intern::Interned;
 use itertools::Either;
 use rustc_hash::FxHashSet;
 use smallvec::{smallvec, SmallVec};
-use syntax::SmolStr;
 
 use crate::{
     db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, WhereClause,
@@ -29,9 +29,9 @@ use crate::{
 
 pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
     [
-        db.lang_item(krate, SmolStr::new_inline("fn")),
-        db.lang_item(krate, SmolStr::new_inline("fn_mut")),
-        db.lang_item(krate, SmolStr::new_inline("fn_once")),
+        db.lang_item(krate, LangItem::Fn),
+        db.lang_item(krate, LangItem::FnMut),
+        db.lang_item(krate, LangItem::FnOnce),
     ]
     .into_iter()
     .flatten()
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 55d3b609768..0d19420127f 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -4,6 +4,7 @@ use hir_def::{
     generics::{
         TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
     },
+    lang_item::LangItem,
     type_ref::{TypeBound, TypeRef},
     AdtId, GenericDefId,
 };
@@ -14,7 +15,6 @@ use hir_ty::{
     },
     Interner, TraitRefExt, WhereClause,
 };
-use syntax::SmolStr;
 
 use crate::{
     Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
@@ -261,8 +261,7 @@ impl HirDisplay for TypeParam {
             bounds.iter().cloned().map(|b| b.substitute(Interner, &substs)).collect();
         let krate = self.id.parent().krate(f.db).id;
         let sized_trait =
-            f.db.lang_item(krate, SmolStr::new_inline("sized"))
-                .and_then(|lang_item| lang_item.as_trait());
+            f.db.lang_item(krate, LangItem::Sized).and_then(|lang_item| lang_item.as_trait());
         let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() {
             WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait,
             _ => false,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 012812cea24..6ec39dfd73f 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -44,7 +44,7 @@ use hir_def::{
     expr::{BindingAnnotation, ExprOrPatId, LabelId, Pat, PatId},
     generics::{TypeOrConstParamData, TypeParamProvenance},
     item_tree::ItemTreeNode,
-    lang_item::LangItemTarget,
+    lang_item::{LangItem, LangItemTarget},
     layout::{Layout, LayoutError, ReprOptions},
     nameres::{self, diagnostics::DefDiagnostic},
     per_ns::PerNs,
@@ -1836,7 +1836,7 @@ pub struct Trait {
 
 impl Trait {
     pub fn lang(db: &dyn HirDatabase, krate: Crate, name: &Name) -> Option<Trait> {
-        db.lang_item(krate.into(), name.to_smol_str())
+        db.lang_item(krate.into(), LangItem::from_name(name)?)
             .and_then(LangItemTarget::as_trait)
             .map(Into::into)
     }
@@ -3009,7 +3009,7 @@ impl Type {
     /// This function is used in `.await` syntax completion.
     pub fn impls_into_future(&self, db: &dyn HirDatabase) -> bool {
         let trait_ = db
-            .lang_item(self.env.krate, SmolStr::new_inline("into_future"))
+            .lang_item(self.env.krate, LangItem::IntoFutureIntoFuture)
             .and_then(|it| {
                 let into_future_fn = it.as_function()?;
                 let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?;
@@ -3017,8 +3017,7 @@ impl Type {
                 Some(into_future_trait.id)
             })
             .or_else(|| {
-                let future_trait =
-                    db.lang_item(self.env.krate, SmolStr::new_inline("future_trait"))?;
+                let future_trait = db.lang_item(self.env.krate, LangItem::Future)?;
                 future_trait.as_trait()
             });
 
@@ -3111,9 +3110,9 @@ impl Type {
     }
 
     pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
-        let lang_item = db.lang_item(self.env.krate, SmolStr::new_inline("copy"));
+        let lang_item = db.lang_item(self.env.krate, LangItem::Copy);
         let copy_trait = match lang_item {
-            Some(LangItemTarget::TraitId(it)) => it,
+            Some(LangItemTarget::Trait(it)) => it,
             _ => return false,
         };
         self.impls_trait(db, copy_trait.into(), &[])
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 2354eb2c9cc..5e0c9933a7b 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -17,6 +17,7 @@ use hir_def::{
         Body, BodySourceMap,
     },
     expr::{ExprId, Pat, PatId},
+    lang_item::LangItem,
     macro_id_to_def_id,
     path::{ModPath, Path, PathKind},
     resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
@@ -37,7 +38,7 @@ use hir_ty::{
         record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
         UnsafeExpr,
     },
-    method_resolution::{self, lang_names_for_bin_op},
+    method_resolution::{self, lang_items_for_bin_op},
     Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext,
 };
 use itertools::Itertools;
@@ -294,12 +295,8 @@ impl SourceAnalyzer {
             }
         }
 
-        let future_trait = db
-            .lang_item(self.resolver.krate(), hir_expand::name![future_trait].to_smol_str())?
-            .as_trait()?;
-        let poll_fn = db
-            .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
-            .as_function()?;
+        let future_trait = db.lang_item(self.resolver.krate(), LangItem::Future)?.as_trait()?;
+        let poll_fn = db.lang_item(self.resolver.krate(), LangItem::FuturePoll)?.as_function()?;
         // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
         // doesn't have any generic parameters, so we skip building another subst for `poll()`.
         let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
@@ -311,14 +308,14 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         prefix_expr: &ast::PrefixExpr,
     ) -> Option<FunctionId> {
-        let lang_item_name = match prefix_expr.op_kind()? {
-            ast::UnaryOp::Deref => name![deref],
-            ast::UnaryOp::Not => name![not],
-            ast::UnaryOp::Neg => name![neg],
+        let (lang_item, fn_name) = match prefix_expr.op_kind()? {
+            ast::UnaryOp::Deref => (LangItem::Deref, name![deref]),
+            ast::UnaryOp::Not => (LangItem::Not, name![not]),
+            ast::UnaryOp::Neg => (LangItem::Neg, name![neg]),
         };
         let ty = self.ty_of_expr(db, &prefix_expr.expr()?)?;
 
-        let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+        let (op_trait, op_fn) = self.lang_trait_fn(db, lang_item, &fn_name)?;
         // HACK: subst for all methods coincides with that for their trait because the methods
         // don't have any generic parameters, so we skip building another subst for the methods.
         let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
@@ -334,9 +331,7 @@ 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 lang_item_name = name![index];
-
-        let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+        let (op_trait, op_fn) = self.lang_trait_fn(db, LangItem::Index, &name![index])?;
         // HACK: subst for all methods coincides with that for their trait because the methods
         // don't have any generic parameters, so we skip building another subst for the methods.
         let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
@@ -355,8 +350,8 @@ impl SourceAnalyzer {
         let lhs = self.ty_of_expr(db, &binop_expr.lhs()?)?;
         let rhs = self.ty_of_expr(db, &binop_expr.rhs()?)?;
 
-        let (op_trait, op_fn) = lang_names_for_bin_op(op)
-            .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
+        let (op_trait, op_fn) = lang_items_for_bin_op(op)
+            .and_then(|(name, lang_item)| self.lang_trait_fn(db, lang_item, &name))?;
         // HACK: subst for `index()` coincides with that for `Index` because `index()` itself
         // doesn't have any generic parameters, so we skip building another subst for `index()`.
         let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
@@ -374,8 +369,7 @@ impl SourceAnalyzer {
     ) -> Option<FunctionId> {
         let ty = self.ty_of_expr(db, &try_expr.expr()?)?;
 
-        let op_fn =
-            db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
+        let op_fn = db.lang_item(self.resolver.krate(), LangItem::TryTraitBranch)?.as_function()?;
         let op_trait = match op_fn.lookup(db.upcast()).container {
             ItemContainerId::TraitId(id) => id,
             _ => return None,
@@ -821,10 +815,10 @@ impl SourceAnalyzer {
     fn lang_trait_fn(
         &self,
         db: &dyn HirDatabase,
-        lang_trait: &Name,
+        lang_trait: LangItem,
         method_name: &Name,
     ) -> Option<(TraitId, FunctionId)> {
-        let trait_id = db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?;
+        let trait_id = db.lang_item(self.resolver.krate(), lang_trait)?.as_trait()?;
         let fn_id = db.trait_data(trait_id).method_by_name(method_name)?;
         Some((trait_id, fn_id))
     }
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index 8d5ab0061e5..046786580e7 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -7,6 +7,7 @@
 use std::{env, fs, iter, ops, path::PathBuf, process::Command};
 
 use anyhow::{format_err, Result};
+use base_db::CrateName;
 use la_arena::{Arena, Idx};
 use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::FxHashMap;
@@ -50,14 +51,16 @@ impl Sysroot {
         &self.src_root
     }
 
-    pub fn public_deps(&self) -> impl Iterator<Item = (&'static str, SysrootCrate, bool)> + '_ {
+    pub fn public_deps(&self) -> impl Iterator<Item = (CrateName, SysrootCrate, bool)> + '_ {
         // core is added as a dependency before std in order to
         // mimic rustcs dependency order
         ["core", "alloc", "std"]
             .into_iter()
             .zip(iter::repeat(true))
             .chain(iter::once(("test", false)))
-            .filter_map(move |(name, prelude)| Some((name, self.by_name(name)?, prelude)))
+            .filter_map(move |(name, prelude)| {
+                Some((CrateName::new(name).unwrap(), self.by_name(name)?, prelude))
+            })
     }
 
     pub fn proc_macro(&self) -> Option<SysrootCrate> {
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 9aa04eaa75a..755bf951999 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -1162,9 +1162,7 @@ fn sysroot_to_crate_graph(
     let public_deps = SysrootPublicDeps {
         deps: sysroot
             .public_deps()
-            .map(|(name, idx, prelude)| {
-                (CrateName::new(name).unwrap(), sysroot_crates[&idx], prelude)
-            })
+            .map(|(name, idx, prelude)| (name, sysroot_crates[&idx], prelude))
             .collect::<Vec<_>>(),
     };