hir_def/hir/
type_ref.rs

1//! HIR for references to types. Paths in these are not yet resolved. They can
2//! be directly created from an ast::TypeRef, without further queries.
3
4use std::fmt::Write;
5
6use hir_expand::name::Name;
7use intern::Symbol;
8use la_arena::Idx;
9use thin_vec::ThinVec;
10
11use crate::{
12    LifetimeParamId, TypeParamId,
13    builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
14    expr_store::{
15        ExpressionStore,
16        path::{GenericArg, Path},
17    },
18    hir::{ExprId, Literal},
19};
20
21#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
22pub enum Mutability {
23    Shared,
24    Mut,
25}
26
27impl Mutability {
28    pub fn from_mutable(mutable: bool) -> Mutability {
29        if mutable { Mutability::Mut } else { Mutability::Shared }
30    }
31
32    pub fn as_keyword_for_ref(self) -> &'static str {
33        match self {
34            Mutability::Shared => "",
35            Mutability::Mut => "mut ",
36        }
37    }
38
39    pub fn as_keyword_for_ptr(self) -> &'static str {
40        match self {
41            Mutability::Shared => "const ",
42            Mutability::Mut => "mut ",
43        }
44    }
45
46    /// Returns `true` if the mutability is [`Mut`].
47    ///
48    /// [`Mut`]: Mutability::Mut
49    #[must_use]
50    pub fn is_mut(&self) -> bool {
51        matches!(self, Self::Mut)
52    }
53
54    /// Returns `true` if the mutability is [`Shared`].
55    ///
56    /// [`Shared`]: Mutability::Shared
57    #[must_use]
58    pub fn is_shared(&self) -> bool {
59        matches!(self, Self::Shared)
60    }
61}
62
63#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
64pub enum Rawness {
65    RawPtr,
66    Ref,
67}
68
69impl Rawness {
70    pub fn from_raw(is_raw: bool) -> Rawness {
71        if is_raw { Rawness::RawPtr } else { Rawness::Ref }
72    }
73
74    pub fn is_raw(&self) -> bool {
75        matches!(self, Self::RawPtr)
76    }
77}
78
79#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
80/// A `TypeRefId` that is guaranteed to always be `TypeRef::Path`. We use this for things like
81/// impl's trait, that are always paths but need to be traced back to source code.
82pub struct PathId(TypeRefId);
83
84impl PathId {
85    #[inline]
86    pub fn from_type_ref_unchecked(type_ref: TypeRefId) -> Self {
87        Self(type_ref)
88    }
89
90    #[inline]
91    pub fn type_ref(self) -> TypeRefId {
92        self.0
93    }
94}
95
96#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
97pub struct TraitRef {
98    pub path: PathId,
99}
100
101#[derive(Clone, PartialEq, Eq, Hash, Debug)]
102pub struct FnType {
103    pub params: Box<[(Option<Name>, TypeRefId)]>,
104    pub is_varargs: bool,
105    pub is_unsafe: bool,
106    pub abi: Option<Symbol>,
107}
108
109impl FnType {
110    #[inline]
111    pub fn split_params_and_ret(&self) -> (&[(Option<Name>, TypeRefId)], TypeRefId) {
112        let (ret, params) = self.params.split_last().expect("should have at least return type");
113        (params, ret.1)
114    }
115}
116
117#[derive(Clone, PartialEq, Eq, Hash, Debug)]
118pub struct ArrayType {
119    pub ty: TypeRefId,
120    pub len: ConstRef,
121}
122
123#[derive(Clone, PartialEq, Eq, Hash, Debug)]
124pub struct RefType {
125    pub ty: TypeRefId,
126    pub lifetime: Option<LifetimeRefId>,
127    pub mutability: Mutability,
128}
129
130/// Compare ty::Ty
131#[derive(Clone, PartialEq, Eq, Hash, Debug)]
132pub enum TypeRef {
133    Never,
134    Placeholder,
135    Tuple(ThinVec<TypeRefId>),
136    Path(Path),
137    RawPtr(TypeRefId, Mutability),
138    // FIXME: Unbox this once `Idx` has a niche,
139    // as `RefType` should shrink by 4 bytes then
140    Reference(Box<RefType>),
141    Array(ArrayType),
142    Slice(TypeRefId),
143    /// A fn pointer. Last element of the vector is the return type.
144    Fn(Box<FnType>),
145    ImplTrait(ThinVec<TypeBound>),
146    DynTrait(ThinVec<TypeBound>),
147    TypeParam(TypeParamId),
148    Error,
149}
150
151#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
152const _: () = assert!(size_of::<TypeRef>() == 24);
153
154pub type TypeRefId = Idx<TypeRef>;
155
156pub type LifetimeRefId = Idx<LifetimeRef>;
157
158#[derive(Clone, PartialEq, Eq, Hash, Debug)]
159pub enum LifetimeRef {
160    Named(Name),
161    Static,
162    Placeholder,
163    Param(LifetimeParamId),
164    Error,
165}
166
167#[derive(Clone, PartialEq, Eq, Hash, Debug)]
168pub enum TypeBound {
169    Path(PathId, TraitBoundModifier),
170    ForLifetime(ThinVec<Name>, PathId),
171    Lifetime(LifetimeRefId),
172    Use(ThinVec<UseArgRef>),
173    Error,
174}
175
176#[cfg(target_pointer_width = "64")]
177const _: [(); 16] = [(); size_of::<TypeBound>()];
178
179#[derive(Clone, PartialEq, Eq, Hash, Debug)]
180pub enum UseArgRef {
181    Name(Name),
182    Lifetime(LifetimeRefId),
183}
184
185/// A modifier on a bound, currently this is only used for `?Sized`, where the
186/// modifier is `Maybe`.
187#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
188pub enum TraitBoundModifier {
189    None,
190    Maybe,
191}
192
193impl TypeRef {
194    pub(crate) fn unit() -> TypeRef {
195        TypeRef::Tuple(ThinVec::new())
196    }
197
198    pub fn walk(this: TypeRefId, map: &ExpressionStore, f: &mut impl FnMut(TypeRefId, &TypeRef)) {
199        go(this, f, map);
200
201        fn go(
202            type_ref_id: TypeRefId,
203            f: &mut impl FnMut(TypeRefId, &TypeRef),
204            map: &ExpressionStore,
205        ) {
206            let type_ref = &map[type_ref_id];
207            f(type_ref_id, type_ref);
208            match type_ref {
209                TypeRef::Fn(fn_) => {
210                    fn_.params.iter().for_each(|&(_, param_type)| go(param_type, f, map))
211                }
212                TypeRef::Tuple(types) => types.iter().for_each(|&t| go(t, f, map)),
213                TypeRef::RawPtr(type_ref, _) | TypeRef::Slice(type_ref) => go(*type_ref, f, map),
214                TypeRef::Reference(it) => go(it.ty, f, map),
215                TypeRef::Array(it) => go(it.ty, f, map),
216                TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
217                    for bound in bounds {
218                        match bound {
219                            &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => {
220                                go_path(&map[path], f, map)
221                            }
222                            TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
223                        }
224                    }
225                }
226                TypeRef::Path(path) => go_path(path, f, map),
227                TypeRef::Never | TypeRef::Placeholder | TypeRef::Error | TypeRef::TypeParam(_) => {}
228            };
229        }
230
231        fn go_path(path: &Path, f: &mut impl FnMut(TypeRefId, &TypeRef), map: &ExpressionStore) {
232            if let Some(type_ref) = path.type_anchor() {
233                go(type_ref, f, map);
234            }
235            for segment in path.segments().iter() {
236                if let Some(args_and_bindings) = segment.args_and_bindings {
237                    for arg in args_and_bindings.args.iter() {
238                        match arg {
239                            GenericArg::Type(type_ref) => {
240                                go(*type_ref, f, map);
241                            }
242                            GenericArg::Const(_) | GenericArg::Lifetime(_) => {}
243                        }
244                    }
245                    for binding in args_and_bindings.bindings.iter() {
246                        if let Some(type_ref) = binding.type_ref {
247                            go(type_ref, f, map);
248                        }
249                        for bound in binding.bounds.iter() {
250                            match bound {
251                                &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => {
252                                    go_path(&map[path], f, map)
253                                }
254                                TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
255                            }
256                        }
257                    }
258                }
259            }
260        }
261    }
262}
263
264impl TypeBound {
265    pub fn as_path<'a>(&self, map: &'a ExpressionStore) -> Option<(&'a Path, TraitBoundModifier)> {
266        match self {
267            &TypeBound::Path(p, m) => Some((&map[p], m)),
268            &TypeBound::ForLifetime(_, p) => Some((&map[p], TraitBoundModifier::None)),
269            TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None,
270        }
271    }
272}
273
274#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
275pub struct ConstRef {
276    pub expr: ExprId,
277}
278
279/// A literal constant value
280#[derive(Debug, Clone, PartialEq, Eq, Hash)]
281pub enum LiteralConstRef {
282    Int(i128),
283    UInt(u128),
284    Bool(bool),
285    Char(char),
286
287    /// Case of an unknown value that rustc might know but we don't
288    // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
289    // constants
290    // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177
291    // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
292    Unknown,
293}
294
295impl LiteralConstRef {
296    pub fn builtin_type(&self) -> BuiltinType {
297        match self {
298            LiteralConstRef::UInt(_) | LiteralConstRef::Unknown => {
299                BuiltinType::Uint(BuiltinUint::U128)
300            }
301            LiteralConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128),
302            LiteralConstRef::Char(_) => BuiltinType::Char,
303            LiteralConstRef::Bool(_) => BuiltinType::Bool,
304        }
305    }
306}
307
308impl From<Literal> for LiteralConstRef {
309    fn from(literal: Literal) -> Self {
310        match literal {
311            Literal::Char(c) => Self::Char(c),
312            Literal::Bool(flag) => Self::Bool(flag),
313            Literal::Int(num, _) => Self::Int(num),
314            Literal::Uint(num, _) => Self::UInt(num),
315            _ => Self::Unknown,
316        }
317    }
318}
319
320impl std::fmt::Display for LiteralConstRef {
321    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
322        match self {
323            LiteralConstRef::Int(num) => num.fmt(f),
324            LiteralConstRef::UInt(num) => num.fmt(f),
325            LiteralConstRef::Bool(flag) => flag.fmt(f),
326            LiteralConstRef::Char(c) => write!(f, "'{c}'"),
327            LiteralConstRef::Unknown => f.write_char('_'),
328        }
329    }
330}