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(&TypeRef)) {
199        go(this, f, map);
200
201        fn go(type_ref: TypeRefId, f: &mut impl FnMut(&TypeRef), map: &ExpressionStore) {
202            let type_ref = &map[type_ref];
203            f(type_ref);
204            match type_ref {
205                TypeRef::Fn(fn_) => {
206                    fn_.params.iter().for_each(|&(_, param_type)| go(param_type, f, map))
207                }
208                TypeRef::Tuple(types) => types.iter().for_each(|&t| go(t, f, map)),
209                TypeRef::RawPtr(type_ref, _) | TypeRef::Slice(type_ref) => go(*type_ref, f, map),
210                TypeRef::Reference(it) => go(it.ty, f, map),
211                TypeRef::Array(it) => go(it.ty, f, map),
212                TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
213                    for bound in bounds {
214                        match bound {
215                            &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => {
216                                go_path(&map[path], f, map)
217                            }
218                            TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
219                        }
220                    }
221                }
222                TypeRef::Path(path) => go_path(path, f, map),
223                TypeRef::Never | TypeRef::Placeholder | TypeRef::Error | TypeRef::TypeParam(_) => {}
224            };
225        }
226
227        fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef), map: &ExpressionStore) {
228            if let Some(type_ref) = path.type_anchor() {
229                go(type_ref, f, map);
230            }
231            for segment in path.segments().iter() {
232                if let Some(args_and_bindings) = segment.args_and_bindings {
233                    for arg in args_and_bindings.args.iter() {
234                        match arg {
235                            GenericArg::Type(type_ref) => {
236                                go(*type_ref, f, map);
237                            }
238                            GenericArg::Const(_) | GenericArg::Lifetime(_) => {}
239                        }
240                    }
241                    for binding in args_and_bindings.bindings.iter() {
242                        if let Some(type_ref) = binding.type_ref {
243                            go(type_ref, f, map);
244                        }
245                        for bound in binding.bounds.iter() {
246                            match bound {
247                                &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => {
248                                    go_path(&map[path], f, map)
249                                }
250                                TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
251                            }
252                        }
253                    }
254                }
255            }
256        }
257    }
258}
259
260impl TypeBound {
261    pub fn as_path<'a>(&self, map: &'a ExpressionStore) -> Option<(&'a Path, TraitBoundModifier)> {
262        match self {
263            &TypeBound::Path(p, m) => Some((&map[p], m)),
264            &TypeBound::ForLifetime(_, p) => Some((&map[p], TraitBoundModifier::None)),
265            TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None,
266        }
267    }
268}
269
270#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
271pub struct ConstRef {
272    pub expr: ExprId,
273}
274
275/// A literal constant value
276#[derive(Debug, Clone, PartialEq, Eq, Hash)]
277pub enum LiteralConstRef {
278    Int(i128),
279    UInt(u128),
280    Bool(bool),
281    Char(char),
282
283    /// Case of an unknown value that rustc might know but we don't
284    // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
285    // constants
286    // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177
287    // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
288    Unknown,
289}
290
291impl LiteralConstRef {
292    pub fn builtin_type(&self) -> BuiltinType {
293        match self {
294            LiteralConstRef::UInt(_) | LiteralConstRef::Unknown => {
295                BuiltinType::Uint(BuiltinUint::U128)
296            }
297            LiteralConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128),
298            LiteralConstRef::Char(_) => BuiltinType::Char,
299            LiteralConstRef::Bool(_) => BuiltinType::Bool,
300        }
301    }
302}
303
304impl From<Literal> for LiteralConstRef {
305    fn from(literal: Literal) -> Self {
306        match literal {
307            Literal::Char(c) => Self::Char(c),
308            Literal::Bool(flag) => Self::Bool(flag),
309            Literal::Int(num, _) => Self::Int(num),
310            Literal::Uint(num, _) => Self::UInt(num),
311            _ => Self::Unknown,
312        }
313    }
314}
315
316impl std::fmt::Display for LiteralConstRef {
317    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
318        match self {
319            LiteralConstRef::Int(num) => num.fmt(f),
320            LiteralConstRef::UInt(num) => num.fmt(f),
321            LiteralConstRef::Bool(flag) => flag.fmt(f),
322            LiteralConstRef::Char(c) => write!(f, "'{c}'"),
323            LiteralConstRef::Unknown => f.write_char('_'),
324        }
325    }
326}