1use 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 #[must_use]
50 pub fn is_mut(&self) -> bool {
51 matches!(self, Self::Mut)
52 }
53
54 #[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)]
80pub 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#[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 Reference(Box<RefType>),
141 Array(ArrayType),
142 Slice(TypeRefId),
143 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#[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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
277pub enum LiteralConstRef {
278 Int(i128),
279 UInt(u128),
280 Bool(bool),
281 Char(char),
282
283 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}