1use cairo_lang_debug::DebugWithDb;
2use cairo_lang_defs::db::DefsGroup;
3use cairo_lang_defs::diagnostic_utils::StableLocation;
4use cairo_lang_defs::ids::{
5 EnumId, ExternTypeId, GenericParamId, GenericTypeId, LanguageElementId, ModuleId,
6 NamedLanguageElementId, StructId, TraitTypeId, UnstableSalsaId,
7};
8use cairo_lang_diagnostics::{DiagnosticAdded, Maybe};
9use cairo_lang_filesystem::db::FilesGroup;
10use cairo_lang_proc_macros::{HeapSize, SemanticObject};
11use cairo_lang_syntax::attribute::consts::MUST_USE_ATTR;
12use cairo_lang_syntax::node::ast::PathSegment;
13use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
14use cairo_lang_syntax::node::{TypedStablePtr, TypedSyntaxNode, ast};
15use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
16use cairo_lang_utils::{Intern, OptionFrom, define_short_id, extract_matches, try_extract_matches};
17use itertools::{Itertools, chain};
18use num_bigint::BigInt;
19use num_traits::Zero;
20use salsa::Database;
21use sha3::{Digest, Keccak256};
22
23use crate::corelib::{
24 CorelibSemantic, concrete_copy_trait, concrete_destruct_trait, concrete_drop_trait,
25 concrete_panic_destruct_trait, core_box_ty, get_usize_ty, unit_ty,
26};
27use crate::diagnostic::SemanticDiagnosticKind::*;
28use crate::diagnostic::{NotFoundItemType, SemanticDiagnostics, SemanticDiagnosticsBuilder};
29use crate::expr::compute::{ComputationContext, compute_expr_semantic};
30use crate::expr::inference::canonic::{CanonicalTrait, ResultNoErrEx};
31use crate::expr::inference::solver::{SemanticSolver, SolutionSet, enrich_lookup_context};
32use crate::expr::inference::{InferenceData, InferenceError, InferenceId, TypeVar};
33use crate::items::attribute::SemanticQueryAttrs;
34use crate::items::constant::{ConstValue, ConstValueId, resolve_const_expr_and_evaluate};
35use crate::items::enm::{EnumSemantic, SemanticEnumEx};
36use crate::items::extern_type::ExternTypeSemantic;
37use crate::items::generics::{GenericParamSemantic, displayable_concrete};
38use crate::items::imp::{ImplId, ImplLookupContext, ImplLookupContextId, ImplSemantic};
39use crate::items::structure::StructSemantic;
40use crate::resolve::{ResolutionContext, ResolvedConcreteItem, ResolvedGenericItem, Resolver};
41use crate::substitution::SemanticRewriter;
42use crate::{ConcreteTraitId, FunctionId, GenericArgumentId, semantic, semantic_object_for_id};
43
44#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update, HeapSize)]
45pub enum TypeLongId<'db> {
46 Concrete(ConcreteTypeId<'db>),
47 Tuple(Vec<TypeId<'db>>),
50 Snapshot(TypeId<'db>),
51 GenericParameter(GenericParamId<'db>),
52 Var(TypeVar<'db>),
53 Coupon(FunctionId<'db>),
54 FixedSizeArray {
55 type_id: TypeId<'db>,
56 size: ConstValueId<'db>,
57 },
58 ImplType(ImplTypeId<'db>),
59 Closure(ClosureTypeLongId<'db>),
60 Missing(#[dont_rewrite] DiagnosticAdded),
61}
62impl<'db> OptionFrom<TypeLongId<'db>> for ConcreteTypeId<'db> {
63 fn option_from(other: TypeLongId<'db>) -> Option<Self> {
64 try_extract_matches!(other, TypeLongId::Concrete)
65 }
66}
67
68define_short_id!(TypeId, TypeLongId<'db>);
69semantic_object_for_id!(TypeId, TypeLongId<'a>);
70impl<'db> TypeId<'db> {
71 pub fn missing(db: &'db dyn Database, diag_added: DiagnosticAdded) -> Self {
72 TypeLongId::Missing(diag_added).intern(db)
73 }
74
75 pub fn format(&self, db: &dyn Database) -> String {
76 self.long(db).format(db)
77 }
78
79 pub fn check_not_missing(&self, db: &dyn Database) -> Maybe<()> {
81 if let TypeLongId::Missing(diag_added) = self.long(db) { Err(*diag_added) } else { Ok(()) }
82 }
83
84 pub fn is_missing(&self, db: &dyn Database) -> bool {
86 self.check_not_missing(db).is_err()
87 }
88
89 pub fn is_unit(&self, db: &dyn Database) -> bool {
91 matches!(self.long(db), TypeLongId::Tuple(types) if types.is_empty())
92 }
93
94 pub fn head(&self, db: &'db dyn Database) -> Option<TypeHead<'db>> {
96 self.long(db).head(db)
97 }
98
99 pub fn is_fully_concrete(&self, db: &dyn Database) -> bool {
101 db.priv_type_is_fully_concrete(*self)
102 }
103
104 pub fn is_var_free(&self, db: &dyn Database) -> bool {
106 db.priv_type_is_var_free(*self)
107 }
108
109 pub fn is_phantom(&self, db: &dyn Database) -> bool {
113 self.long(db).is_phantom(db)
114 }
115
116 pub fn short_name(&self, db: &dyn Database) -> String {
118 db.priv_type_short_name(*self)
119 }
120}
121impl<'db> TypeLongId<'db> {
122 pub fn format(&self, db: &dyn Database) -> String {
123 format!("{:?}", self.debug(db))
124 }
125
126 pub fn head(&self, db: &'db dyn Database) -> Option<TypeHead<'db>> {
128 Some(match self {
129 TypeLongId::Concrete(concrete) => TypeHead::Concrete(concrete.generic_type(db)),
130 TypeLongId::Tuple(_) => TypeHead::Tuple,
131 TypeLongId::Snapshot(inner) => TypeHead::Snapshot(Box::new(inner.head(db)?)),
132 TypeLongId::Coupon(_) => TypeHead::Coupon,
133 TypeLongId::FixedSizeArray { .. } => TypeHead::FixedSizeArray,
134 TypeLongId::GenericParameter(generic_param_id) => TypeHead::Generic(*generic_param_id),
135 TypeLongId::Var(_)
136 | TypeLongId::Missing(_)
137 | TypeLongId::ImplType(_)
138 | TypeLongId::Closure(_) => {
139 return None;
140 }
141 })
142 }
143
144 pub fn is_phantom(&self, db: &dyn Database) -> bool {
149 match self {
150 TypeLongId::Concrete(id) => match id {
151 ConcreteTypeId::Struct(id) => {
152 let crate_id = id.struct_id(db).long(db).0.owning_crate(db);
153
154 db.declared_phantom_type_attributes(crate_id)
155 .iter()
156 .any(|attr| id.has_attr(db, attr.long(db)).unwrap_or_default())
157 }
158 ConcreteTypeId::Enum(id) => {
159 let crate_id = id.enum_id(db).long(db).0.owning_crate(db);
160
161 db.declared_phantom_type_attributes(crate_id)
162 .iter()
163 .any(|attr| id.has_attr(db, attr.long(db)).unwrap_or_default())
164 }
165 ConcreteTypeId::Extern(id) => {
166 let crate_id = id.extern_type_id(db).long(db).0.owning_crate(db);
167
168 db.declared_phantom_type_attributes(crate_id)
169 .iter()
170 .any(|attr| id.has_attr(db, attr.long(db)).unwrap_or_default())
171 }
172 },
173 TypeLongId::Tuple(inner) => inner.iter().any(|ty| ty.is_phantom(db)),
174 TypeLongId::FixedSizeArray { type_id, .. } => type_id.is_phantom(db),
175 TypeLongId::Snapshot(_)
176 | TypeLongId::GenericParameter(_)
177 | TypeLongId::Var(_)
178 | TypeLongId::Coupon(_)
179 | TypeLongId::ImplType(_)
180 | TypeLongId::Missing(_)
181 | TypeLongId::Closure(_) => false,
182 }
183 }
184
185 pub fn module_id(&self, db: &'db dyn Database) -> Option<ModuleId<'db>> {
187 match self {
188 TypeLongId::Concrete(concrete) => Some(concrete.generic_type(db).parent_module(db)),
189 TypeLongId::Snapshot(ty) => {
190 let (_n_snapshots, inner_ty) = peel_snapshots(db, *ty);
191 inner_ty.module_id(db)
192 }
193 TypeLongId::GenericParameter(_) => None,
194 TypeLongId::Var(_) => None,
195 TypeLongId::Coupon(function_id) => {
196 function_id.get_concrete(db).generic_function.module_id(db)
197 }
198 TypeLongId::Missing(_) => None,
199 TypeLongId::Tuple(_) => Some(db.core_info().tuple_submodule),
200 TypeLongId::ImplType(_) => None,
201 TypeLongId::FixedSizeArray { .. } => Some(db.core_info().fixed_size_array_submodule),
202 TypeLongId::Closure(closure) => {
203 if let Ok(function_id) = closure.parent_function {
204 function_id.get_concrete(db).generic_function.module_id(db)
205 } else {
206 None
207 }
208 }
209 }
210 }
211
212 pub fn extract_generic_params(
215 &self,
216 db: &'db dyn Database,
217 generic_parameters: &mut OrderedHashSet<GenericParamId<'db>>,
218 visited: &mut OrderedHashSet<TypeId<'db>>,
219 ) -> Maybe<()> {
220 match self {
221 TypeLongId::Concrete(concrete_type_id) => {
222 for garg in concrete_type_id.generic_args(db) {
223 garg.extract_generic_params(db, generic_parameters, visited)?;
224 }
225 }
226 TypeLongId::Tuple(tys) => {
227 for ty in tys {
228 ty.extract_generic_params(db, generic_parameters, visited)?
229 }
230 }
231 TypeLongId::Snapshot(ty) => {
232 ty.extract_generic_params(db, generic_parameters, visited)?
233 }
234 TypeLongId::GenericParameter(generic_param) => {
235 generic_parameters.insert(*generic_param);
236 }
237 TypeLongId::Var(_) => {}
238 TypeLongId::Coupon(_) => {}
239 TypeLongId::FixedSizeArray { type_id, .. } => {
240 type_id.extract_generic_params(db, generic_parameters, visited)?
241 }
242 TypeLongId::ImplType(impl_type_id) => {
243 let concrete_trait_id = impl_type_id.impl_id.concrete_trait(db)?;
244 for garg in concrete_trait_id.generic_args(db) {
245 garg.extract_generic_params(db, generic_parameters, visited)?;
246 }
247 }
248 TypeLongId::Closure(closure_ty) => {
249 for ty in chain!(
250 &closure_ty.param_tys,
251 &closure_ty.captured_types,
252 std::iter::once(&closure_ty.ret_ty)
253 ) {
254 ty.extract_generic_params(db, generic_parameters, visited)?
255 }
256 }
257 TypeLongId::Missing(diag_added) => return Err(*diag_added),
258 };
259 Ok(())
260 }
261}
262
263impl<'db> TypeId<'db> {
264 pub fn extract_generic_params(
267 self,
268 db: &'db dyn Database,
269 generic_parameters: &mut OrderedHashSet<GenericParamId<'db>>,
270 visited: &mut OrderedHashSet<TypeId<'db>>,
271 ) -> Maybe<()> {
272 if !visited.insert(self) {
273 return Ok(());
274 }
275 self.long(db).extract_generic_params(db, generic_parameters, visited)
276 }
277}
278impl<'db> DebugWithDb<'db> for TypeLongId<'db> {
279 type Db = dyn Database;
280
281 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
282 match self {
283 TypeLongId::Concrete(concrete) => write!(f, "{}", concrete.format(db)),
284 TypeLongId::Tuple(inner_types) => {
285 if inner_types.len() == 1 {
286 write!(f, "({},)", inner_types[0].format(db))
287 } else {
288 write!(f, "({})", inner_types.iter().map(|ty| ty.format(db)).join(", "))
289 }
290 }
291 TypeLongId::Snapshot(ty) => write!(f, "@{}", ty.format(db)),
292 TypeLongId::GenericParameter(generic_param) => {
293 write!(f, "{}", generic_param.name(db).map_or("_", |name| name.long(db)))
294 }
295 TypeLongId::ImplType(impl_type_id) => {
296 write!(
297 f,
298 "{:?}::{}",
299 impl_type_id.impl_id.debug(db),
300 impl_type_id.ty.name(db).long(db)
301 )
302 }
303 TypeLongId::Var(var) => write!(f, "?{}", var.id.0),
304 TypeLongId::Coupon(function_id) => write!(f, "{}::Coupon", function_id.full_path(db)),
305 TypeLongId::Missing(_) => write!(f, "<missing>"),
306 TypeLongId::FixedSizeArray { type_id, size } => {
307 write!(f, "[{}; {:?}]", type_id.format(db), size.debug(db))
308 }
309 TypeLongId::Closure(closure) => {
310 write!(f, "{:?}", closure.debug(db))
311 }
312 }
313 }
314}
315
316#[derive(Clone, Debug, Hash, PartialEq, Eq, salsa::Update)]
322pub enum TypeHead<'db> {
323 Concrete(GenericTypeId<'db>),
324 Snapshot(Box<TypeHead<'db>>),
325 Generic(GenericParamId<'db>),
326 Tuple,
327 Coupon,
328 FixedSizeArray,
329}
330
331#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update, HeapSize)]
332pub enum ConcreteTypeId<'db> {
333 Struct(ConcreteStructId<'db>),
334 Enum(ConcreteEnumId<'db>),
335 Extern(ConcreteExternTypeId<'db>),
336}
337impl<'db> ConcreteTypeId<'db> {
338 pub fn new(
339 db: &'db dyn Database,
340 generic_ty: GenericTypeId<'db>,
341 generic_args: Vec<semantic::GenericArgumentId<'db>>,
342 ) -> Self {
343 match generic_ty {
344 GenericTypeId::Struct(id) => ConcreteTypeId::Struct(
345 ConcreteStructLongId { struct_id: id, generic_args }.intern(db),
346 ),
347 GenericTypeId::Enum(id) => {
348 ConcreteTypeId::Enum(ConcreteEnumLongId { enum_id: id, generic_args }.intern(db))
349 }
350 GenericTypeId::Extern(id) => ConcreteTypeId::Extern(
351 ConcreteExternTypeLongId { extern_type_id: id, generic_args }.intern(db),
352 ),
353 }
354 }
355 pub fn generic_type(&self, db: &'db dyn Database) -> GenericTypeId<'db> {
356 match self {
357 ConcreteTypeId::Struct(id) => GenericTypeId::Struct(id.long(db).struct_id),
358 ConcreteTypeId::Enum(id) => GenericTypeId::Enum(id.long(db).enum_id),
359 ConcreteTypeId::Extern(id) => GenericTypeId::Extern(id.long(db).extern_type_id),
360 }
361 }
362 pub fn generic_args(&self, db: &'db dyn Database) -> Vec<semantic::GenericArgumentId<'db>> {
363 match self {
364 ConcreteTypeId::Struct(id) => id.long(db).generic_args.clone(),
365 ConcreteTypeId::Enum(id) => id.long(db).generic_args.clone(),
366 ConcreteTypeId::Extern(id) => id.long(db).generic_args.clone(),
367 }
368 }
369 pub fn format(&self, db: &dyn Database) -> String {
370 format!("{:?}", self.debug(db))
371 }
372
373 pub fn is_must_use(&self, db: &dyn Database) -> Maybe<bool> {
375 match self {
376 ConcreteTypeId::Struct(id) => id.has_attr(db, MUST_USE_ATTR),
377 ConcreteTypeId::Enum(id) => id.has_attr(db, MUST_USE_ATTR),
378 ConcreteTypeId::Extern(id) => id.has_attr(db, MUST_USE_ATTR),
379 }
380 }
381 pub fn is_fully_concrete(&self, db: &dyn Database) -> bool {
383 self.generic_args(db)
384 .iter()
385 .all(|generic_argument_id| generic_argument_id.is_fully_concrete(db))
386 }
387 pub fn is_var_free(&self, db: &dyn Database) -> bool {
389 self.generic_args(db).iter().all(|generic_argument_id| generic_argument_id.is_var_free(db))
390 }
391}
392impl<'db> DebugWithDb<'db> for ConcreteTypeId<'db> {
393 type Db = dyn Database;
394
395 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
396 write!(
397 f,
398 "{}",
399 displayable_concrete(db, &self.generic_type(db).format(db), &self.generic_args(db))
400 )
401 }
402}
403
404#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update, HeapSize)]
405pub struct ConcreteStructLongId<'db> {
406 pub struct_id: StructId<'db>,
407 pub generic_args: Vec<semantic::GenericArgumentId<'db>>,
408}
409define_short_id!(ConcreteStructId, ConcreteStructLongId<'db>);
410semantic_object_for_id!(ConcreteStructId, ConcreteStructLongId<'a>);
411impl<'db> ConcreteStructId<'db> {
412 pub fn struct_id(&self, db: &'db dyn Database) -> StructId<'db> {
413 self.long(db).struct_id
414 }
415}
416impl<'db> DebugWithDb<'db> for ConcreteStructLongId<'db> {
417 type Db = dyn Database;
418
419 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
420 write!(f, "{:?}", ConcreteTypeId::Struct(self.clone().intern(db)).debug(db))
421 }
422}
423
424#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update, HeapSize)]
425pub struct ConcreteEnumLongId<'db> {
426 pub enum_id: EnumId<'db>,
427 pub generic_args: Vec<semantic::GenericArgumentId<'db>>,
428}
429impl<'db> DebugWithDb<'db> for ConcreteEnumLongId<'db> {
430 type Db = dyn Database;
431
432 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
433 write!(f, "{:?}", ConcreteTypeId::Enum(self.clone().intern(db)).debug(db))
434 }
435}
436
437define_short_id!(ConcreteEnumId, ConcreteEnumLongId<'db>);
438semantic_object_for_id!(ConcreteEnumId, ConcreteEnumLongId<'a>);
439impl<'db> ConcreteEnumId<'db> {
440 pub fn enum_id(&self, db: &'db dyn Database) -> EnumId<'db> {
441 self.long(db).enum_id
442 }
443}
444
445#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update, HeapSize)]
446pub struct ConcreteExternTypeLongId<'db> {
447 pub extern_type_id: ExternTypeId<'db>,
448 pub generic_args: Vec<semantic::GenericArgumentId<'db>>,
449}
450define_short_id!(ConcreteExternTypeId, ConcreteExternTypeLongId<'db>);
451semantic_object_for_id!(ConcreteExternTypeId, ConcreteExternTypeLongId<'a>);
452impl<'db> ConcreteExternTypeId<'db> {
453 pub fn extern_type_id(&self, db: &'db dyn Database) -> ExternTypeId<'db> {
454 self.long(db).extern_type_id
455 }
456}
457
458#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update, HeapSize)]
460pub struct ClosureTypeLongId<'db> {
461 pub param_tys: Vec<TypeId<'db>>,
462 pub ret_ty: TypeId<'db>,
463 pub captured_types: Vec<TypeId<'db>>,
467 pub parent_function: Maybe<FunctionId<'db>>,
469 #[dont_rewrite]
471 pub params_location: StableLocation<'db>,
472}
473
474impl<'db> DebugWithDb<'db> for ClosureTypeLongId<'db> {
475 type Db = dyn Database;
476
477 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
478 write!(f, "{{closure@{:?}}}", self.params_location.debug(db))
479 }
480}
481
482#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject, HeapSize, salsa::Update)]
484pub struct ImplTypeId<'db> {
485 impl_id: ImplId<'db>,
487 ty: TraitTypeId<'db>,
489}
490impl<'db> ImplTypeId<'db> {
491 pub fn new(impl_id: ImplId<'db>, ty: TraitTypeId<'db>, db: &'db dyn Database) -> Self {
494 if let crate::items::imp::ImplLongId::Concrete(concrete_impl) = impl_id.long(db) {
495 let impl_def_id = concrete_impl.impl_def_id(db);
496 assert_eq!(Ok(ty.trait_id(db)), db.impl_def_trait(impl_def_id));
497 }
498
499 ImplTypeId { impl_id, ty }
500 }
501 pub fn impl_id(&self) -> ImplId<'db> {
502 self.impl_id
503 }
504 pub fn ty(&self) -> TraitTypeId<'db> {
505 self.ty
506 }
507 pub fn format(&self, db: &dyn Database) -> String {
508 format!("{}::{}", self.impl_id.name(db), self.ty.name(db).long(db))
509 }
510}
511impl<'db> DebugWithDb<'db> for ImplTypeId<'db> {
512 type Db = dyn Database;
513
514 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
515 write!(f, "{}", self.format(db))
516 }
517}
518
519#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, salsa::Update)]
521pub struct ImplTypeById<'db>(ImplTypeId<'db>);
522
523impl<'db> From<ImplTypeId<'db>> for ImplTypeById<'db> {
524 fn from(impl_type_id: ImplTypeId<'db>) -> Self {
525 Self(impl_type_id)
526 }
527}
528impl<'db> Ord for ImplTypeById<'db> {
529 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
530 self.0
531 .impl_id
532 .get_internal_id()
533 .cmp(&other.0.impl_id.get_internal_id())
534 .then_with(|| self.0.ty.get_internal_id().cmp(&other.0.ty.get_internal_id()))
535 }
536}
537impl<'db> PartialOrd for ImplTypeById<'db> {
538 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
539 Some(self.cmp(other))
540 }
541}
542
543pub fn resolve_type<'db>(
546 db: &'db dyn Database,
547 diagnostics: &mut SemanticDiagnostics<'db>,
548 resolver: &mut Resolver<'db>,
549 ty_syntax: &ast::Expr<'db>,
550) -> TypeId<'db> {
551 resolve_type_ex(db, diagnostics, resolver, ty_syntax, ResolutionContext::Default)
552}
553pub fn resolve_type_ex<'db>(
555 db: &'db dyn Database,
556 diagnostics: &mut SemanticDiagnostics<'db>,
557 resolver: &mut Resolver<'db>,
558 ty_syntax: &ast::Expr<'db>,
559 ctx: ResolutionContext<'db, '_>,
560) -> TypeId<'db> {
561 maybe_resolve_type(db, diagnostics, resolver, ty_syntax, ctx)
562 .unwrap_or_else(|diag_added| TypeId::missing(db, diag_added))
563}
564fn maybe_resolve_type<'db>(
565 db: &'db dyn Database,
566 diagnostics: &mut SemanticDiagnostics<'db>,
567 resolver: &mut Resolver<'db>,
568 ty_syntax: &ast::Expr<'db>,
569 mut ctx: ResolutionContext<'db, '_>,
570) -> Maybe<TypeId<'db>> {
571 Ok(match ty_syntax {
572 ast::Expr::Underscore(underscore) => {
573 resolver.inference().new_type_var(Some(underscore.stable_ptr(db).untyped()))
574 }
575 ast::Expr::Path(path) => {
576 match resolver.resolve_concrete_path_ex(
577 diagnostics,
578 path,
579 NotFoundItemType::Type,
580 ctx,
581 )? {
582 ResolvedConcreteItem::Type(ty) => ty,
583 _ => {
584 return Err(diagnostics.report(path.stable_ptr(db), NotAType));
585 }
586 }
587 }
588 ast::Expr::Parenthesized(expr_syntax) => {
589 resolve_type_ex(db, diagnostics, resolver, &expr_syntax.expr(db), ctx)
590 }
591 ast::Expr::Tuple(tuple_syntax) => {
592 let sub_tys = tuple_syntax
593 .expressions(db)
594 .elements(db)
595 .map(|subexpr_syntax| {
596 resolve_type_ex(
597 db,
598 diagnostics,
599 resolver,
600 &subexpr_syntax,
601 match ctx {
602 ResolutionContext::Default => ResolutionContext::Default,
603 ResolutionContext::ModuleItem(id) => ResolutionContext::ModuleItem(id),
604 ResolutionContext::Statement(ref mut env) => {
605 ResolutionContext::Statement(env)
606 }
607 },
608 )
609 })
610 .collect();
611 TypeLongId::Tuple(sub_tys).intern(db)
612 }
613 ast::Expr::Unary(unary_syntax)
614 if matches!(unary_syntax.op(db), ast::UnaryOperator::At(_)) =>
615 {
616 let ty = resolve_type_ex(db, diagnostics, resolver, &unary_syntax.expr(db), ctx);
617 TypeLongId::Snapshot(ty).intern(db)
618 }
619 ast::Expr::Unary(unary_syntax)
621 if matches!(unary_syntax.op(db), ast::UnaryOperator::Desnap(_)) =>
622 {
623 let ty = resolve_type_ex(db, diagnostics, resolver, &unary_syntax.expr(db), ctx);
624 if let Some(desnapped_ty) = try_extract_matches!(ty.long(db), TypeLongId::Snapshot) {
625 *desnapped_ty
626 } else {
627 return Err(diagnostics.report(ty_syntax.stable_ptr(db), DerefNonRef { ty }));
628 }
629 }
630 ast::Expr::Unary(unary_syntax)
631 if matches!(unary_syntax.op(db), ast::UnaryOperator::Reference(_)) =>
632 {
633 if !are_repr_ptrs_enabled(db, resolver.module_id) {
634 return Err(diagnostics.report(ty_syntax.stable_ptr(db), ReprPtrsDisabled));
635 }
636 let inner_ty = resolve_type_ex(db, diagnostics, resolver, &unary_syntax.expr(db), ctx);
637 let snapshot_ty = TypeLongId::Snapshot(inner_ty).intern(db);
638 core_box_ty(db, snapshot_ty)
639 }
640 ast::Expr::FixedSizeArray(array_syntax) => {
641 let Ok(ty) = &array_syntax.exprs(db).elements(db).exactly_one() else {
642 return Err(
643 diagnostics.report(ty_syntax.stable_ptr(db), FixedSizeArrayTypeNonSingleType)
644 );
645 };
646 let ty = resolve_type_ex(db, diagnostics, resolver, ty, ctx);
647 let size =
648 match extract_fixed_size_array_size(db, diagnostics, array_syntax, resolver)? {
649 Some(size) => size,
650 None => {
651 return Err(diagnostics
652 .report(ty_syntax.stable_ptr(db), FixedSizeArrayTypeEmptySize));
653 }
654 };
655 TypeLongId::FixedSizeArray { type_id: ty, size }.intern(db)
656 }
657 _ => {
658 return Err(diagnostics.report(ty_syntax.stable_ptr(db), UnknownType));
659 }
660 })
661}
662
663#[derive(Clone, Debug, PartialEq, Eq, salsa::Update)]
665pub enum ShallowGenericArg<'db> {
666 GenericParameter(GenericParamId<'db>),
668 GenericType(GenericTypeId<'db>),
670 Snapshot(Box<ShallowGenericArg<'db>>),
671 Tuple,
672 FixedSizeArray,
673}
674
675impl<'db> ShallowGenericArg<'db> {
676 pub fn module_id(&self, db: &'db dyn Database) -> Option<ModuleId<'db>> {
678 match self {
679 ShallowGenericArg::GenericParameter(_) => None,
680 ShallowGenericArg::GenericType(ty) => Some(ty.parent_module(db)),
681 ShallowGenericArg::Snapshot(inner) => inner.module_id(db),
682 ShallowGenericArg::Tuple => TypeLongId::Tuple(vec![]).module_id(db),
683 ShallowGenericArg::FixedSizeArray => TypeLongId::FixedSizeArray {
684 type_id: unit_ty(db),
685 size: ConstValue::Struct(vec![], unit_ty(db)).intern(db),
686 }
687 .module_id(db),
688 }
689 }
690 pub fn head(&self) -> TypeHead<'db> {
691 match self {
692 ShallowGenericArg::GenericParameter(param) => TypeHead::Generic(*param),
693 ShallowGenericArg::GenericType(ty) => TypeHead::Concrete(*ty),
694 ShallowGenericArg::Snapshot(inner) => TypeHead::Snapshot(Box::new(inner.head())),
695 ShallowGenericArg::Tuple => TypeHead::Tuple,
696 ShallowGenericArg::FixedSizeArray => TypeHead::FixedSizeArray,
697 }
698 }
699}
700pub fn maybe_resolve_shallow_generic_arg_type<'db>(
702 db: &'db dyn Database,
703 diagnostics: &mut SemanticDiagnostics<'db>,
704 resolver: &mut Resolver<'db>,
705 ty_syntax: &ast::Expr<'db>,
706) -> Option<ShallowGenericArg<'db>> {
707 Some(match ty_syntax {
708 ast::Expr::Path(path) => {
709 if let [PathSegment::Simple(path)] =
710 path.segments(db).elements(db).collect_vec().as_slice()
711 && let Some(ResolvedConcreteItem::Type(ty)) =
712 resolver.determine_base_item_in_local_scope(&path.ident(db))
713 {
714 let param = extract_matches!(ty.long(db), TypeLongId::GenericParameter);
715 return Some(ShallowGenericArg::GenericParameter(*param));
716 }
717
718 match resolver
719 .resolve_generic_path_with_args(
720 diagnostics,
721 path,
722 NotFoundItemType::Type,
723 ResolutionContext::Default,
724 )
725 .ok()?
726 {
727 ResolvedGenericItem::GenericType(ty) => ShallowGenericArg::GenericType(ty),
728 _ => {
729 return None;
730 }
731 }
732 }
733 ast::Expr::Parenthesized(expr_syntax) => maybe_resolve_shallow_generic_arg_type(
734 db,
735 diagnostics,
736 resolver,
737 &expr_syntax.expr(db),
738 )?,
739 ast::Expr::Tuple(_) => ShallowGenericArg::Tuple,
740 ast::Expr::Unary(unary_syntax)
741 if matches!(unary_syntax.op(db), ast::UnaryOperator::At(_)) =>
742 {
743 ShallowGenericArg::Snapshot(Box::new(maybe_resolve_shallow_generic_arg_type(
744 db,
745 diagnostics,
746 resolver,
747 &unary_syntax.expr(db),
748 )?))
749 }
750 ast::Expr::Unary(unary_syntax)
751 if matches!(unary_syntax.op(db), ast::UnaryOperator::Desnap(_)) =>
752 {
753 maybe_resolve_shallow_generic_arg_type(
754 db,
755 diagnostics,
756 resolver,
757 &unary_syntax.expr(db),
758 )?
759 }
760 ast::Expr::FixedSizeArray(_) => ShallowGenericArg::FixedSizeArray,
761 _ => {
762 return None;
763 }
764 })
765}
766
767pub fn extract_fixed_size_array_size<'db>(
770 db: &'db dyn Database,
771 diagnostics: &mut SemanticDiagnostics<'db>,
772 syntax: &ast::ExprFixedSizeArray<'db>,
773 resolver: &mut Resolver<'db>,
774) -> Maybe<Option<ConstValueId<'db>>> {
775 match syntax.size(db) {
776 ast::OptionFixedSizeArraySize::FixedSizeArraySize(size_clause) => {
777 let mut ctx = ComputationContext::new_global(db, diagnostics, resolver);
778 let size_expr_syntax = size_clause.size(db);
779 let size = compute_expr_semantic(&mut ctx, &size_expr_syntax);
780 let const_value = resolve_const_expr_and_evaluate(
781 db,
782 &mut ctx,
783 &size,
784 size_expr_syntax.stable_ptr(db).untyped(),
785 get_usize_ty(db),
786 false,
787 );
788 if matches!(
789 const_value.long(db),
790 ConstValue::Int(_, _) | ConstValue::Generic(_) | ConstValue::ImplConstant(_)
791 ) {
792 Ok(Some(const_value))
793 } else {
794 Err(diagnostics.report(syntax.stable_ptr(db), FixedSizeArrayNonNumericSize))
795 }
796 }
797 ast::OptionFixedSizeArraySize::Empty(_) => Ok(None),
798 }
799}
800
801pub fn verify_fixed_size_array_size<'db>(
803 db: &'db dyn Database,
804 diagnostics: &mut SemanticDiagnostics<'db>,
805 size: &BigInt,
806 syntax: &ast::ExprFixedSizeArray<'db>,
807) -> Maybe<()> {
808 if size > &BigInt::from(i16::MAX) {
809 return Err(diagnostics.report(syntax.stable_ptr(db), FixedSizeArraySizeTooBig));
810 }
811 Ok(())
812}
813
814#[derive(Clone, Debug, PartialEq, Eq, salsa::Update)]
815pub struct TypeInfo<'db> {
816 pub droppable: Result<ImplId<'db>, InferenceError<'db>>,
817 pub copyable: Result<ImplId<'db>, InferenceError<'db>>,
818 pub destruct_impl: Result<ImplId<'db>, InferenceError<'db>>,
819 pub panic_destruct_impl: Result<ImplId<'db>, InferenceError<'db>>,
820}
821
822pub fn get_impl_at_context<'db>(
824 db: &'db dyn Database,
825 lookup_context: ImplLookupContextId<'db>,
826 concrete_trait_id: ConcreteTraitId<'db>,
827 stable_ptr: Option<SyntaxStablePtrId<'db>>,
828) -> Result<ImplId<'db>, InferenceError<'db>> {
829 let constrains =
830 db.generic_params_type_constraints(lookup_context.long(db).generic_params.clone());
831 if constrains.is_empty() && concrete_trait_id.is_var_free(db) {
832 return solve_concrete_trait_no_constraints(db, lookup_context, concrete_trait_id);
833 }
834 let mut inference_data = InferenceData::new(InferenceId::NoContext);
835 let mut inference = inference_data.inference(db);
836 inference.conform_generic_params_type_constraints(constrains);
837 let impl_id = inference.new_impl_var(concrete_trait_id, stable_ptr, lookup_context);
840 if let Err(err_set) = inference.finalize_without_reporting() {
841 return Err(inference
842 .consume_error_without_reporting(err_set)
843 .expect("Error couldn't be already consumed"));
844 };
845 Ok(inference.rewrite(impl_id).no_err())
846}
847
848fn single_value_type(db: &dyn Database, ty: TypeId<'_>) -> Maybe<bool> {
850 Ok(match ty.long(db) {
851 TypeLongId::Concrete(concrete_type_id) => match concrete_type_id {
852 ConcreteTypeId::Struct(id) => {
853 for member in db.struct_members(id.struct_id(db))?.values() {
854 if !db.single_value_type(member.ty)? {
855 return Ok(false);
856 }
857 }
858 true
859 }
860 ConcreteTypeId::Enum(id) => {
861 let variants = db.enum_variants(id.enum_id(db))?;
862 if variants.len() != 1 {
863 return Ok(false);
864 }
865
866 db.single_value_type(
867 db.variant_semantic(id.enum_id(db), *variants.values().next().unwrap())?.ty,
868 )?
869 }
870 ConcreteTypeId::Extern(_) => false,
871 },
872 TypeLongId::Tuple(types) => {
873 for ty in types {
874 if !db.single_value_type(*ty)? {
875 return Ok(false);
876 }
877 }
878 true
879 }
880 TypeLongId::Snapshot(ty) => db.single_value_type(*ty)?,
881 TypeLongId::GenericParameter(_)
882 | TypeLongId::Var(_)
883 | TypeLongId::Missing(_)
884 | TypeLongId::Coupon(_)
885 | TypeLongId::ImplType(_)
886 | TypeLongId::Closure(_) => false,
887 TypeLongId::FixedSizeArray { type_id, size } => {
888 db.single_value_type(*type_id)?
889 || matches!(size.long(db),
890 ConstValue::Int(value, _) if value.is_zero())
891 }
892 })
893}
894
895#[salsa::tracked]
897fn single_value_type_tracked<'db>(db: &'db dyn Database, ty: TypeId<'db>) -> Maybe<bool> {
898 single_value_type(db, ty)
899}
900
901pub fn add_type_based_diagnostics<'db>(
903 db: &'db dyn Database,
904 diagnostics: &mut SemanticDiagnostics<'db>,
905 ty: TypeId<'db>,
906 stable_ptr: impl Into<SyntaxStablePtrId<'db>> + Copy,
907) {
908 if db.type_size_info(ty) == Ok(TypeSizeInformation::Infinite) {
909 diagnostics.report(stable_ptr, InfiniteSizeType(ty));
910 }
911 if let TypeLongId::Concrete(ConcreteTypeId::Extern(extrn)) = ty.long(db) {
912 let long_id = extrn.long(db);
913 if long_id.extern_type_id.name(db).long(db) == "Array"
914 && let [GenericArgumentId::Type(arg_ty)] = &long_id.generic_args[..]
915 && db.type_size_info(*arg_ty) == Ok(TypeSizeInformation::ZeroSized)
916 {
917 diagnostics.report(stable_ptr, ArrayOfZeroSizedElements(*arg_ty));
918 }
919 }
920}
921
922#[derive(Clone, Debug, PartialEq, Eq)]
923pub enum TypeSizeInformation {
924 Infinite,
928 ZeroSized,
930 Other,
932}
933
934fn type_size_info(db: &dyn Database, ty: TypeId<'_>) -> Maybe<TypeSizeInformation> {
936 match ty.long(db) {
937 TypeLongId::Concrete(concrete_type_id) => match concrete_type_id {
938 ConcreteTypeId::Struct(id) => {
939 if check_all_type_are_zero_sized(
940 db,
941 db.concrete_struct_members(*id)?.iter().map(|(_, member)| &member.ty),
942 )? {
943 return Ok(TypeSizeInformation::ZeroSized);
944 }
945 }
946 ConcreteTypeId::Enum(id) => {
947 for variant in &db.concrete_enum_variants(*id)? {
948 db.type_size_info(variant.ty)?;
950 }
951 }
952 ConcreteTypeId::Extern(_) => {}
953 },
954 TypeLongId::Tuple(types) => {
955 if check_all_type_are_zero_sized(db, types.iter())? {
956 return Ok(TypeSizeInformation::ZeroSized);
957 }
958 }
959 TypeLongId::Snapshot(ty) => {
960 if db.type_size_info(*ty)? == TypeSizeInformation::ZeroSized {
961 return Ok(TypeSizeInformation::ZeroSized);
962 }
963 }
964 TypeLongId::Closure(closure_ty) => {
965 if check_all_type_are_zero_sized(db, closure_ty.captured_types.iter())? {
966 return Ok(TypeSizeInformation::ZeroSized);
967 }
968 }
969 TypeLongId::Coupon(_) => return Ok(TypeSizeInformation::ZeroSized),
970 TypeLongId::GenericParameter(_)
971 | TypeLongId::Var(_)
972 | TypeLongId::Missing(_)
973 | TypeLongId::ImplType(_) => {}
974 TypeLongId::FixedSizeArray { type_id, size } => {
975 if matches!(size.long(db), ConstValue::Int(value,_) if value.is_zero())
976 || db.type_size_info(*type_id)? == TypeSizeInformation::ZeroSized
977 {
978 return Ok(TypeSizeInformation::ZeroSized);
979 }
980 }
981 }
982 Ok(TypeSizeInformation::Other)
983}
984
985#[salsa::tracked(cycle_result=type_size_info_cycle)]
987fn type_size_info_tracked<'db>(
988 db: &'db dyn Database,
989 ty: TypeId<'db>,
990) -> Maybe<TypeSizeInformation> {
991 type_size_info(db, ty)
992}
993
994fn check_all_type_are_zero_sized<'a>(
996 db: &dyn Database,
997 types: impl Iterator<Item = &'a TypeId<'a>>,
998) -> Maybe<bool> {
999 let mut zero_sized = true;
1000 for ty in types {
1001 if db.type_size_info(*ty)? != TypeSizeInformation::ZeroSized {
1002 zero_sized = false;
1003 }
1004 }
1005 Ok(zero_sized)
1006}
1007
1008fn type_size_info_cycle<'db>(
1010 _db: &'db dyn Database,
1011 _id: salsa::Id,
1012 _ty: TypeId<'db>,
1013) -> Maybe<TypeSizeInformation> {
1014 Ok(TypeSizeInformation::Infinite)
1015}
1016
1017fn type_info<'db>(
1021 db: &'db dyn Database,
1022 lookup_context: ImplLookupContextId<'db>,
1023 ty: TypeId<'db>,
1024) -> TypeInfo<'db> {
1025 let droppable = get_impl_at_context(db, lookup_context, concrete_drop_trait(db, ty), None);
1027 let copyable = get_impl_at_context(db, lookup_context, concrete_copy_trait(db, ty), None);
1028 let destruct_impl =
1029 get_impl_at_context(db, lookup_context, concrete_destruct_trait(db, ty), None);
1030 let panic_destruct_impl =
1031 get_impl_at_context(db, lookup_context, concrete_panic_destruct_trait(db, ty), None);
1032 TypeInfo { droppable, copyable, destruct_impl, panic_destruct_impl }
1033}
1034
1035#[salsa::tracked]
1037fn type_info_tracked<'db>(
1038 db: &'db dyn Database,
1039 lookup_context: ImplLookupContextId<'db>,
1040 ty: TypeId<'db>,
1041) -> TypeInfo<'db> {
1042 type_info(db, lookup_context, ty)
1043}
1044
1045fn solve_concrete_trait_no_constraints<'db>(
1048 db: &'db dyn Database,
1049 lookup_context: ImplLookupContextId<'db>,
1050 id: ConcreteTraitId<'db>,
1051) -> Result<ImplId<'db>, InferenceError<'db>> {
1052 let mut lookup_context = lookup_context.long(db).clone();
1053 enrich_lookup_context(db, id, &mut lookup_context);
1054 let lookup_context = lookup_context.intern(db);
1055 match db.canonic_trait_solutions(
1056 CanonicalTrait { id, mappings: Default::default() },
1057 lookup_context,
1058 Default::default(),
1059 )? {
1060 SolutionSet::None => Err(InferenceError::NoImplsFound(id)),
1061 SolutionSet::Unique(solution) => Ok(solution.0),
1062 SolutionSet::Ambiguous(ambiguity) => Err(InferenceError::Ambiguity(ambiguity)),
1063 }
1064}
1065
1066fn copyable<'db>(
1068 db: &'db dyn Database,
1069 ty: TypeId<'db>,
1070) -> Result<ImplId<'db>, InferenceError<'db>> {
1071 solve_concrete_trait_no_constraints(
1072 db,
1073 ImplLookupContext::new_from_type(ty, db).intern(db),
1074 concrete_copy_trait(db, ty),
1075 )
1076}
1077
1078#[salsa::tracked]
1080fn copyable_tracked<'db>(
1081 db: &'db dyn Database,
1082 ty: TypeId<'db>,
1083) -> Result<ImplId<'db>, InferenceError<'db>> {
1084 copyable(db, ty)
1085}
1086
1087fn droppable<'db>(
1089 db: &'db dyn Database,
1090 ty: TypeId<'db>,
1091) -> Result<ImplId<'db>, InferenceError<'db>> {
1092 solve_concrete_trait_no_constraints(
1093 db,
1094 ImplLookupContext::new_from_type(ty, db).intern(db),
1095 concrete_drop_trait(db, ty),
1096 )
1097}
1098
1099#[salsa::tracked]
1101fn droppable_tracked<'db>(
1102 db: &'db dyn Database,
1103 ty: TypeId<'db>,
1104) -> Result<ImplId<'db>, InferenceError<'db>> {
1105 droppable(db, ty)
1106}
1107
1108fn priv_type_is_fully_concrete(db: &dyn Database, ty: TypeId<'_>) -> bool {
1110 match ty.long(db) {
1111 TypeLongId::Concrete(concrete_type_id) => concrete_type_id.is_fully_concrete(db),
1112 TypeLongId::Tuple(types) => types.iter().all(|ty| ty.is_fully_concrete(db)),
1113 TypeLongId::Snapshot(ty) => ty.is_fully_concrete(db),
1114 TypeLongId::GenericParameter(_)
1115 | TypeLongId::Var(_)
1116 | TypeLongId::Missing(_)
1117 | TypeLongId::ImplType(_) => false,
1118 TypeLongId::Coupon(function_id) => function_id.is_fully_concrete(db),
1119 TypeLongId::FixedSizeArray { type_id, size } => {
1120 type_id.is_fully_concrete(db) && size.is_fully_concrete(db)
1121 }
1122 TypeLongId::Closure(closure) => {
1123 closure.parent_function.map(|id| id.is_fully_concrete(db)).unwrap_or(true)
1124 && closure.param_tys.iter().all(|param| param.is_fully_concrete(db))
1125 && closure.ret_ty.is_fully_concrete(db)
1126 }
1127 }
1128}
1129
1130#[salsa::tracked]
1132pub fn priv_type_is_fully_concrete_tracked<'db>(db: &'db dyn Database, ty: TypeId<'db>) -> bool {
1133 priv_type_is_fully_concrete(db, ty)
1134}
1135
1136pub fn priv_type_is_var_free<'db>(db: &'db dyn Database, ty: TypeId<'db>) -> bool {
1137 match ty.long(db) {
1138 TypeLongId::Concrete(concrete_type_id) => concrete_type_id.is_var_free(db),
1139 TypeLongId::Tuple(types) => types.iter().all(|ty| ty.is_var_free(db)),
1140 TypeLongId::Snapshot(ty) => ty.is_var_free(db),
1141 TypeLongId::Var(_) => false,
1142 TypeLongId::GenericParameter(_) | TypeLongId::Missing(_) => true,
1143 TypeLongId::Coupon(function_id) => function_id.is_var_free(db),
1144 TypeLongId::FixedSizeArray { type_id, size } => {
1145 type_id.is_var_free(db) && size.is_var_free(db)
1146 }
1147 TypeLongId::ImplType(_) => false,
1150 TypeLongId::Closure(closure) => {
1151 chain!(&closure.captured_types, &closure.param_tys).all(|param| param.is_var_free(db))
1152 && closure.ret_ty.is_var_free(db)
1153 }
1154 }
1155}
1156
1157#[salsa::tracked]
1159pub fn priv_type_is_var_free_tracked<'db>(db: &'db dyn Database, ty: TypeId<'db>) -> bool {
1160 priv_type_is_var_free(db, ty)
1161}
1162
1163pub fn priv_type_short_name(db: &dyn Database, ty: TypeId<'_>) -> String {
1164 match ty.long(db) {
1165 TypeLongId::Concrete(concrete_type_id) => {
1166 let mut result = concrete_type_id.generic_type(db).format(db);
1167 let mut generic_args = concrete_type_id.generic_args(db).into_iter().peekable();
1168 if generic_args.peek().is_some() {
1169 result.push_str("::<h0x");
1170 let mut hasher = Keccak256::new();
1171 for arg in generic_args {
1172 hasher.update(arg.short_name(db).as_bytes());
1173 }
1174 for c in hasher.finalize() {
1175 result.push_str(&format!("{c:x}"));
1176 }
1177 result.push('>');
1178 }
1179 result
1180 }
1181 TypeLongId::Tuple(types) => {
1182 let mut result = String::from("(h0x");
1183 let mut hasher = Keccak256::new();
1184 for ty in types {
1185 hasher.update(ty.short_name(db).as_bytes());
1186 }
1187 for c in hasher.finalize() {
1188 result.push_str(&format!("{c:x}"));
1189 }
1190 result.push(')');
1191 result
1192 }
1193 TypeLongId::Snapshot(ty) => {
1194 format!("@{}", ty.short_name(db))
1195 }
1196 TypeLongId::FixedSizeArray { type_id, size } => {
1197 format!("[{}; {:?}", type_id.short_name(db), size.debug(db))
1198 }
1199 other => other.format(db),
1200 }
1201}
1202
1203#[salsa::tracked]
1204pub fn priv_type_short_name_tracked<'db>(db: &'db dyn Database, ty: TypeId<'db>) -> String {
1205 priv_type_short_name(db, ty)
1206}
1207
1208pub fn peel_snapshots<'db>(db: &'db dyn Database, ty: TypeId<'db>) -> (usize, TypeLongId<'db>) {
1211 peel_snapshots_ex(db, ty.long(db).clone())
1212}
1213
1214pub fn peel_snapshots_ex<'db>(
1216 db: &'db dyn Database,
1217 mut long_ty: TypeLongId<'db>,
1218) -> (usize, TypeLongId<'db>) {
1219 let mut n_snapshots = 0;
1220 while let TypeLongId::Snapshot(ty) = long_ty {
1221 long_ty = ty.long(db).clone();
1222 n_snapshots += 1;
1223 }
1224 (n_snapshots, long_ty)
1225}
1226
1227pub fn wrap_in_snapshots<'db>(
1229 db: &'db dyn Database,
1230 mut ty: TypeId<'db>,
1231 n_snapshots: usize,
1232) -> TypeId<'db> {
1233 for _ in 0..n_snapshots {
1234 ty = TypeLongId::Snapshot(ty).intern(db);
1235 }
1236 ty
1237}
1238
1239pub(crate) fn are_coupons_enabled(db: &dyn Database, module_id: ModuleId<'_>) -> bool {
1241 let owning_crate = module_id.owning_crate(db);
1242 let Some(config) = db.crate_config(owning_crate) else { return false };
1243 config.settings.experimental_features.coupons
1244}
1245
1246pub(crate) fn are_repr_ptrs_enabled(db: &dyn Database, module_id: ModuleId<'_>) -> bool {
1248 let owning_crate = module_id.owning_crate(db);
1249 db.crate_config(owning_crate)
1250 .is_some_and(|config| config.settings.experimental_features.repr_ptrs)
1251}
1252
1253pub trait TypesSemantic<'db>: Database {
1255 fn generic_type_generic_params(
1257 &'db self,
1258 generic_type: GenericTypeId<'db>,
1259 ) -> Maybe<&'db [semantic::GenericParam<'db>]> {
1260 match generic_type {
1261 GenericTypeId::Struct(id) => self.struct_generic_params(id),
1262 GenericTypeId::Enum(id) => self.enum_generic_params(id),
1263 GenericTypeId::Extern(id) => self.extern_type_declaration_generic_params(id),
1264 }
1265 }
1266 fn single_value_type(&'db self, ty: TypeId<'db>) -> Maybe<bool> {
1271 single_value_type_tracked(self.as_dyn_database(), ty)
1272 }
1273 fn type_size_info(&'db self, ty: TypeId<'db>) -> Maybe<TypeSizeInformation> {
1275 type_size_info_tracked(self.as_dyn_database(), ty)
1276 }
1277 fn type_info(
1279 &'db self,
1280 lookup_context: ImplLookupContextId<'db>,
1281 ty: TypeId<'db>,
1282 ) -> TypeInfo<'db> {
1283 type_info_tracked(self.as_dyn_database(), lookup_context, ty)
1284 }
1285 fn copyable(&'db self, ty: TypeId<'db>) -> Result<ImplId<'db>, InferenceError<'db>> {
1287 copyable_tracked(self.as_dyn_database(), ty)
1288 }
1289 fn droppable(&'db self, ty: TypeId<'db>) -> Result<ImplId<'db>, InferenceError<'db>> {
1291 droppable_tracked(self.as_dyn_database(), ty)
1292 }
1293}
1294impl<'db, T: Database + ?Sized> TypesSemantic<'db> for T {}
1295
1296pub trait PrivTypesSemantic<'db>: Database {
1298 fn priv_type_is_fully_concrete(&self, ty: TypeId<'db>) -> bool {
1300 priv_type_is_fully_concrete_tracked(self.as_dyn_database(), ty)
1301 }
1302 fn priv_type_is_var_free(&self, ty: TypeId<'db>) -> bool {
1304 priv_type_is_var_free_tracked(self.as_dyn_database(), ty)
1305 }
1306 fn priv_type_short_name(&self, ty: TypeId<'db>) -> String {
1308 priv_type_short_name_tracked(self.as_dyn_database(), ty)
1309 }
1310}
1311impl<'db, T: Database + ?Sized> PrivTypesSemantic<'db> for T {}