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(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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
281pub enum LiteralConstRef {
282 Int(i128),
283 UInt(u128),
284 Bool(bool),
285 Char(char),
286
287 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}