]> git.lizzy.rs Git - rust.git/blob - crates/hir_expand/src/name.rs
Merge #10839
[rust.git] / crates / hir_expand / src / name.rs
1 //! See [`Name`].
2
3 use std::fmt;
4
5 use syntax::{ast, SmolStr};
6
7 /// `Name` is a wrapper around string, which is used in hir for both references
8 /// and declarations. In theory, names should also carry hygiene info, but we are
9 /// not there yet!
10 #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
11 pub struct Name(Repr);
12
13 #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
14 enum Repr {
15     Text(SmolStr),
16     TupleField(usize),
17 }
18
19 impl fmt::Display for Name {
20     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21         match &self.0 {
22             Repr::Text(text) => fmt::Display::fmt(&text, f),
23             Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
24         }
25     }
26 }
27
28 impl Name {
29     /// Note: this is private to make creating name from random string hard.
30     /// Hopefully, this should allow us to integrate hygiene cleaner in the
31     /// future, and to switch to interned representation of names.
32     const fn new_text(text: SmolStr) -> Name {
33         Name(Repr::Text(text))
34     }
35
36     pub fn new_tuple_field(idx: usize) -> Name {
37         Name(Repr::TupleField(idx))
38     }
39
40     pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
41         Self::new_text(lt.text().into())
42     }
43
44     /// Shortcut to create inline plain text name
45     const fn new_inline(text: &str) -> Name {
46         Name::new_text(SmolStr::new_inline(text))
47     }
48
49     /// Resolve a name from the text of token.
50     fn resolve(raw_text: &str) -> Name {
51         match raw_text.strip_prefix("r#") {
52             Some(text) => Name::new_text(SmolStr::new(text)),
53             None => Name::new_text(raw_text.into()),
54         }
55     }
56
57     /// A fake name for things missing in the source code.
58     ///
59     /// For example, `impl Foo for {}` should be treated as a trait impl for a
60     /// type with a missing name. Similarly, `struct S { : u32 }` should have a
61     /// single field with a missing name.
62     ///
63     /// Ideally, we want a `gensym` semantics for missing names -- each missing
64     /// name is equal only to itself. It's not clear how to implement this in
65     /// salsa though, so we punt on that bit for a moment.
66     pub const fn missing() -> Name {
67         Name::new_inline("[missing name]")
68     }
69
70     /// Returns the tuple index this name represents if it is a tuple field.
71     pub fn as_tuple_index(&self) -> Option<usize> {
72         match self.0 {
73             Repr::TupleField(idx) => Some(idx),
74             _ => None,
75         }
76     }
77
78     /// Returns the text this name represents if it isn't a tuple field.
79     pub fn as_text(&self) -> Option<SmolStr> {
80         match &self.0 {
81             Repr::Text(it) => Some(it.clone()),
82             _ => None,
83         }
84     }
85
86     /// Returns the textual representation of this name as a [`SmolStr`].
87     /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in
88     /// the general case.
89     pub fn to_smol_str(&self) -> SmolStr {
90         match &self.0 {
91             Repr::Text(it) => it.clone(),
92             Repr::TupleField(it) => SmolStr::new(&it.to_string()),
93         }
94     }
95 }
96
97 pub trait AsName {
98     fn as_name(&self) -> Name;
99 }
100
101 impl AsName for ast::NameRef {
102     fn as_name(&self) -> Name {
103         match self.as_tuple_field() {
104             Some(idx) => Name::new_tuple_field(idx),
105             None => Name::resolve(&self.text()),
106         }
107     }
108 }
109
110 impl AsName for ast::Name {
111     fn as_name(&self) -> Name {
112         Name::resolve(&self.text())
113     }
114 }
115
116 impl AsName for ast::NameOrNameRef {
117     fn as_name(&self) -> Name {
118         match self {
119             ast::NameOrNameRef::Name(it) => it.as_name(),
120             ast::NameOrNameRef::NameRef(it) => it.as_name(),
121         }
122     }
123 }
124
125 impl AsName for tt::Ident {
126     fn as_name(&self) -> Name {
127         Name::resolve(&self.text)
128     }
129 }
130
131 impl AsName for ast::FieldKind {
132     fn as_name(&self) -> Name {
133         match self {
134             ast::FieldKind::Name(nr) => nr.as_name(),
135             ast::FieldKind::Index(idx) => {
136                 let idx = idx.text().parse::<usize>().unwrap_or(0);
137                 Name::new_tuple_field(idx)
138             }
139         }
140     }
141 }
142
143 impl AsName for base_db::Dependency {
144     fn as_name(&self) -> Name {
145         Name::new_text(SmolStr::new(&*self.name))
146     }
147 }
148
149 pub mod known {
150     macro_rules! known_names {
151         ($($ident:ident),* $(,)?) => {
152             $(
153                 #[allow(bad_style)]
154                 pub const $ident: super::Name =
155                     super::Name::new_inline(stringify!($ident));
156             )*
157         };
158     }
159
160     known_names!(
161         // Primitives
162         isize,
163         i8,
164         i16,
165         i32,
166         i64,
167         i128,
168         usize,
169         u8,
170         u16,
171         u32,
172         u64,
173         u128,
174         f32,
175         f64,
176         bool,
177         char,
178         str,
179         // Special names
180         macro_rules,
181         doc,
182         cfg,
183         cfg_attr,
184         register_attr,
185         register_tool,
186         // Components of known path (value or mod name)
187         std,
188         core,
189         alloc,
190         iter,
191         ops,
192         future,
193         result,
194         boxed,
195         option,
196         prelude,
197         rust_2015,
198         rust_2018,
199         rust_2021,
200         v1,
201         // Components of known path (type name)
202         Iterator,
203         IntoIterator,
204         Item,
205         Try,
206         Ok,
207         Future,
208         Result,
209         Option,
210         Output,
211         Target,
212         Box,
213         RangeFrom,
214         RangeFull,
215         RangeInclusive,
216         RangeToInclusive,
217         RangeTo,
218         Range,
219         Neg,
220         Not,
221         None,
222         Index,
223         // Components of known path (function name)
224         filter_map,
225         next,
226         iter_mut,
227         len,
228         is_empty,
229         // Builtin macros
230         asm,
231         assert,
232         column,
233         compile_error,
234         concat_idents,
235         concat,
236         const_format_args,
237         core_panic,
238         env,
239         file,
240         format_args_nl,
241         format_args,
242         global_asm,
243         include_bytes,
244         include_str,
245         include,
246         line,
247         llvm_asm,
248         log_syntax,
249         module_path,
250         option_env,
251         std_panic,
252         stringify,
253         trace_macros,
254         // Builtin derives
255         Copy,
256         Clone,
257         Default,
258         Debug,
259         Hash,
260         Ord,
261         PartialOrd,
262         Eq,
263         PartialEq,
264         // Builtin attributes
265         bench,
266         cfg_accessible,
267         cfg_eval,
268         derive,
269         global_allocator,
270         test,
271         test_case,
272         // Safe intrinsics
273         abort,
274         add_with_overflow,
275         bitreverse,
276         bswap,
277         caller_location,
278         ctlz,
279         ctpop,
280         cttz,
281         discriminant_value,
282         forget,
283         likely,
284         maxnumf32,
285         maxnumf64,
286         min_align_of_val,
287         min_align_of,
288         minnumf32,
289         minnumf64,
290         mul_with_overflow,
291         needs_drop,
292         ptr_guaranteed_eq,
293         ptr_guaranteed_ne,
294         rotate_left,
295         rotate_right,
296         rustc_peek,
297         saturating_add,
298         saturating_sub,
299         size_of_val,
300         size_of,
301         sub_with_overflow,
302         type_id,
303         type_name,
304         unlikely,
305         variant_count,
306         wrapping_add,
307         wrapping_mul,
308         wrapping_sub,
309         // known methods of lang items
310         add,
311         mul,
312         sub,
313         div,
314         rem,
315         shl,
316         shr,
317         bitxor,
318         bitor,
319         bitand,
320         add_assign,
321         mul_assign,
322         sub_assign,
323         div_assign,
324         rem_assign,
325         shl_assign,
326         shr_assign,
327         bitxor_assign,
328         bitor_assign,
329         bitand_assign,
330         eq,
331         ne,
332         ge,
333         gt,
334         le,
335         lt,
336     );
337
338     // self/Self cannot be used as an identifier
339     pub const SELF_PARAM: super::Name = super::Name::new_inline("self");
340     pub const SELF_TYPE: super::Name = super::Name::new_inline("Self");
341
342     pub const STATIC_LIFETIME: super::Name = super::Name::new_inline("'static");
343
344     #[macro_export]
345     macro_rules! name {
346         (self) => {
347             $crate::name::known::SELF_PARAM
348         };
349         (Self) => {
350             $crate::name::known::SELF_TYPE
351         };
352         ('static) => {
353             $crate::name::known::STATIC_LIFETIME
354         };
355         ($ident:ident) => {
356             $crate::name::known::$ident
357         };
358     }
359 }
360
361 pub use crate::name;