1//! Detecting lang items.
2//!
3//! Language items are items that represent concepts intrinsic to the language
4//! itself. Examples are:
5//!
6//! * Traits that specify "kinds"; e.g., `Sync`, `Send`.
7//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
8//! * Functions called by the compiler itself.
910use rustc_hir::LangItem;
11use rustc_hir::def_id::DefId;
12use rustc_span::Span;
13use rustc_target::spec::PanicStrategy;
1415use crate::ty::{self, TyCtxt};
1617impl<'tcx> TyCtxt<'tcx> {
18/// Returns the `DefId` for a given `LangItem`.
19 /// If not found, fatally aborts compilation.
20pub fn require_lang_item(self, lang_item: LangItem, span: Span) -> DefId {
21self.lang_items().get(lang_item).unwrap_or_else(|| {
22self.dcx().emit_fatal(crate::error::RequiresLangItem { span, name: lang_item.name() });
23 })
24 }
2526pub fn is_lang_item(self, def_id: DefId, lang_item: LangItem) -> bool {
27self.lang_items().get(lang_item) == Some(def_id)
28 }
2930pub fn as_lang_item(self, def_id: DefId) -> Option<LangItem> {
31self.lang_items().from_def_id(def_id)
32 }
3334/// Given a [`DefId`] of one of the [`Fn`], [`FnMut`] or [`FnOnce`] traits,
35 /// returns a corresponding [`ty::ClosureKind`].
36 /// For any other [`DefId`] return `None`.
37pub fn fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> {
38match self.as_lang_item(id)? {
39 LangItem::Fn => Some(ty::ClosureKind::Fn),
40 LangItem::FnMut => Some(ty::ClosureKind::FnMut),
41 LangItem::FnOnce => Some(ty::ClosureKind::FnOnce),
42_ => None,
43 }
44 }
4546/// Given a [`DefId`] of one of the `AsyncFn`, `AsyncFnMut` or `AsyncFnOnce` traits,
47 /// returns a corresponding [`ty::ClosureKind`].
48 /// For any other [`DefId`] return `None`.
49pub fn async_fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> {
50match self.as_lang_item(id)? {
51 LangItem::AsyncFn => Some(ty::ClosureKind::Fn),
52 LangItem::AsyncFnMut => Some(ty::ClosureKind::FnMut),
53 LangItem::AsyncFnOnce => Some(ty::ClosureKind::FnOnce),
54_ => None,
55 }
56 }
5758/// Given a [`DefId`], returns whether it is one of the built-in callable
59 /// traits: `Fn`/`FnMut`/`FnOnce` or `AsyncFn`/`AsyncFnMut`/`AsyncFnOnce`.
60 ///
61 /// These built-in callable traits all model their inputs using the
62 /// `rust-call` ABI, which is tupled at the type level.
63pub fn is_callable_trait(self, id: DefId) -> bool {
64#[allow(non_exhaustive_omitted_patterns)] match self.as_lang_item(id) {
Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce | LangItem::AsyncFn
| LangItem::AsyncFnMut | LangItem::AsyncFnOnce) => true,
_ => false,
}matches!(
65self.as_lang_item(id),
66Some(
67 LangItem::Fn
68 | LangItem::FnMut
69 | LangItem::FnOnce
70 | LangItem::AsyncFn
71 | LangItem::AsyncFnMut
72 | LangItem::AsyncFnOnce
73 )
74 )75 }
7677/// Given a [`ty::ClosureKind`], get the [`DefId`] of its corresponding `Fn`-family
78 /// trait, if it is defined.
79pub fn fn_trait_kind_to_def_id(self, kind: ty::ClosureKind) -> Option<DefId> {
80let items = self.lang_items();
81match kind {
82 ty::ClosureKind::Fn => items.fn_trait(),
83 ty::ClosureKind::FnMut => items.fn_mut_trait(),
84 ty::ClosureKind::FnOnce => items.fn_once_trait(),
85 }
86 }
8788/// Given a [`ty::ClosureKind`], get the [`DefId`] of its corresponding `Fn`-family
89 /// trait, if it is defined.
90pub fn async_fn_trait_kind_to_def_id(self, kind: ty::ClosureKind) -> Option<DefId> {
91let items = self.lang_items();
92match kind {
93 ty::ClosureKind::Fn => items.async_fn_trait(),
94 ty::ClosureKind::FnMut => items.async_fn_mut_trait(),
95 ty::ClosureKind::FnOnce => items.async_fn_once_trait(),
96 }
97 }
9899/// Returns `true` if `id` is a `DefId` of [`Fn`], [`FnMut`] or [`FnOnce`] traits.
100pub fn is_fn_trait(self, id: DefId) -> bool {
101self.fn_trait_kind_from_def_id(id).is_some()
102 }
103}
104105/// Returns `true` if the specified `lang_item` must be present for this
106/// compilation.
107///
108/// Not all lang items are always required for each compilation, particularly in
109/// the case of panic=abort. In these situations some lang items are injected by
110/// crates and don't actually need to be defined in libstd.
111pub fn required(tcx: TyCtxt<'_>, lang_item: LangItem) -> bool {
112// If we're not compiling with unwinding, we won't actually need these
113 // symbols. Other panic runtimes ensure that the relevant symbols are
114 // available to link things together, but they're never exercised.
115match tcx.sess.panic_strategy() {
116 PanicStrategy::Abort => {
117lang_item != LangItem::EhPersonality && lang_item != LangItem::EhCatchTypeinfo118 }
119 PanicStrategy::Unwind => true,
120 PanicStrategy::ImmediateAbort => false,
121 }
122}