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