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(
214 &self,
215 db: &'db dyn Database,
216 generic_parameters: &mut OrderedHashSet<GenericParamId<'db>>,
217 ) -> Maybe<()> {
218 match self {
219 TypeLongId::Concrete(concrete_type_id) => {
220 for garg in concrete_type_id.generic_args(db) {
221 garg.extract_generic_params(db, generic_parameters)?;
222 }
223 }
224 TypeLongId::Tuple(tys) => {
225 for ty in tys {
226 ty.long(db).extract_generic_params(db, generic_parameters)?
227 }
228 }
229 TypeLongId::Snapshot(ty) => {
230 ty.long(db).extract_generic_params(db, generic_parameters)?
231 }
232 TypeLongId::GenericParameter(generic_param) => {
233 generic_parameters.insert(*generic_param);
234 }
235 TypeLongId::Var(_) => {}
236 TypeLongId::Coupon(_) => {}
237 TypeLongId::FixedSizeArray { type_id, .. } => {
238 type_id.long(db).extract_generic_params(db, generic_parameters)?
239 }
240 TypeLongId::ImplType(impl_type_id) => {
241 let concrete_trait_id = impl_type_id.impl_id.concrete_trait(db)?;
242 for garg in concrete_trait_id.generic_args(db) {
243 garg.extract_generic_params(db, generic_parameters)?;
244 }
245 }
246 TypeLongId::Closure(closure_ty) => {
247 for ty in chain!(
248 &closure_ty.param_tys,
249 &closure_ty.captured_types,
250 std::iter::once(&closure_ty.ret_ty)
251 ) {
252 ty.long(db).extract_generic_params(db, generic_parameters)?
253 }
254 }
255 TypeLongId::Missing(diag_added) => return Err(*diag_added),
256 };
257 Ok(())
258 }
259}
260impl<'db> DebugWithDb<'db> for TypeLongId<'db> {
261 type Db = dyn Database;
262
263 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
264 match self {
265 TypeLongId::Concrete(concrete) => write!(f, "{}", concrete.format(db)),
266 TypeLongId::Tuple(inner_types) => {
267 if inner_types.len() == 1 {
268 write!(f, "({},)", inner_types[0].format(db))
269 } else {
270 write!(f, "({})", inner_types.iter().map(|ty| ty.format(db)).join(", "))
271 }
272 }
273 TypeLongId::Snapshot(ty) => write!(f, "@{}", ty.format(db)),
274 TypeLongId::GenericParameter(generic_param) => {
275 write!(f, "{}", generic_param.name(db).map_or("_", |name| name.long(db)))
276 }
277 TypeLongId::ImplType(impl_type_id) => {
278 write!(
279 f,
280 "{:?}::{}",
281 impl_type_id.impl_id.debug(db),
282 impl_type_id.ty.name(db).long(db)
283 )
284 }
285 TypeLongId::Var(var) => write!(f, "?{}", var.id.0),
286 TypeLongId::Coupon(function_id) => write!(f, "{}::Coupon", function_id.full_path(db)),
287 TypeLongId::Missing(_) => write!(f, "<missing>"),
288 TypeLongId::FixedSizeArray { type_id, size } => {
289 write!(f, "[{}; {:?}]", type_id.format(db), size.debug(db))
290 }
291 TypeLongId::Closure(closure) => {
292 write!(f, "{:?}", closure.debug(db))
293 }
294 }
295 }
296}
297
298#[derive(Clone, Debug, Hash, PartialEq, Eq, salsa::Update)]
304pub enum TypeHead<'db> {
305 Concrete(GenericTypeId<'db>),
306 Snapshot(Box<TypeHead<'db>>),
307 Generic(GenericParamId<'db>),
308 Tuple,
309 Coupon,
310 FixedSizeArray,
311}
312
313#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update, HeapSize)]
314pub enum ConcreteTypeId<'db> {
315 Struct(ConcreteStructId<'db>),
316 Enum(ConcreteEnumId<'db>),
317 Extern(ConcreteExternTypeId<'db>),
318}
319impl<'db> ConcreteTypeId<'db> {
320 pub fn new(
321 db: &'db dyn Database,
322 generic_ty: GenericTypeId<'db>,
323 generic_args: Vec<semantic::GenericArgumentId<'db>>,
324 ) -> Self {
325 match generic_ty {
326 GenericTypeId::Struct(id) => ConcreteTypeId::Struct(
327 ConcreteStructLongId { struct_id: id, generic_args }.intern(db),
328 ),
329 GenericTypeId::Enum(id) => {
330 ConcreteTypeId::Enum(ConcreteEnumLongId { enum_id: id, generic_args }.intern(db))
331 }
332 GenericTypeId::Extern(id) => ConcreteTypeId::Extern(
333 ConcreteExternTypeLongId { extern_type_id: id, generic_args }.intern(db),
334 ),
335 }
336 }
337 pub fn generic_type(&self, db: &'db dyn Database) -> GenericTypeId<'db> {
338 match self {
339 ConcreteTypeId::Struct(id) => GenericTypeId::Struct(id.long(db).struct_id),
340 ConcreteTypeId::Enum(id) => GenericTypeId::Enum(id.long(db).enum_id),
341 ConcreteTypeId::Extern(id) => GenericTypeId::Extern(id.long(db).extern_type_id),
342 }
343 }
344 pub fn generic_args(&self, db: &'db dyn Database) -> Vec<semantic::GenericArgumentId<'db>> {
345 match self {
346 ConcreteTypeId::Struct(id) => id.long(db).generic_args.clone(),
347 ConcreteTypeId::Enum(id) => id.long(db).generic_args.clone(),
348 ConcreteTypeId::Extern(id) => id.long(db).generic_args.clone(),
349 }
350 }
351 pub fn format(&self, db: &dyn Database) -> String {
352 format!("{:?}", self.debug(db))
353 }
354
355 pub fn is_must_use(&self, db: &dyn Database) -> Maybe<bool> {
357 match self {
358 ConcreteTypeId::Struct(id) => id.has_attr(db, MUST_USE_ATTR),
359 ConcreteTypeId::Enum(id) => id.has_attr(db, MUST_USE_ATTR),
360 ConcreteTypeId::Extern(id) => id.has_attr(db, MUST_USE_ATTR),
361 }
362 }
363 pub fn is_fully_concrete(&self, db: &dyn Database) -> bool {
365 self.generic_args(db)
366 .iter()
367 .all(|generic_argument_id| generic_argument_id.is_fully_concrete(db))
368 }
369 pub fn is_var_free(&self, db: &dyn Database) -> bool {
371 self.generic_args(db).iter().all(|generic_argument_id| generic_argument_id.is_var_free(db))
372 }
373}
374impl<'db> DebugWithDb<'db> for ConcreteTypeId<'db> {
375 type Db = dyn Database;
376
377 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
378 write!(
379 f,
380 "{}",
381 displayable_concrete(db, &self.generic_type(db).format(db), &self.generic_args(db))
382 )
383 }
384}
385
386#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update, HeapSize)]
387pub struct ConcreteStructLongId<'db> {
388 pub struct_id: StructId<'db>,
389 pub generic_args: Vec<semantic::GenericArgumentId<'db>>,
390}
391define_short_id!(ConcreteStructId, ConcreteStructLongId<'db>);
392semantic_object_for_id!(ConcreteStructId, ConcreteStructLongId<'a>);
393impl<'db> ConcreteStructId<'db> {
394 pub fn struct_id(&self, db: &'db dyn Database) -> StructId<'db> {
395 self.long(db).struct_id
396 }
397}
398impl<'db> DebugWithDb<'db> for ConcreteStructLongId<'db> {
399 type Db = dyn Database;
400
401 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
402 write!(f, "{:?}", ConcreteTypeId::Struct(self.clone().intern(db)).debug(db))
403 }
404}
405
406#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update, HeapSize)]
407pub struct ConcreteEnumLongId<'db> {
408 pub enum_id: EnumId<'db>,
409 pub generic_args: Vec<semantic::GenericArgumentId<'db>>,
410}
411impl<'db> DebugWithDb<'db> for ConcreteEnumLongId<'db> {
412 type Db = dyn Database;
413
414 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
415 write!(f, "{:?}", ConcreteTypeId::Enum(self.clone().intern(db)).debug(db))
416 }
417}
418
419define_short_id!(ConcreteEnumId, ConcreteEnumLongId<'db>);
420semantic_object_for_id!(ConcreteEnumId, ConcreteEnumLongId<'a>);
421impl<'db> ConcreteEnumId<'db> {
422 pub fn enum_id(&self, db: &'db dyn Database) -> EnumId<'db> {
423 self.long(db).enum_id
424 }
425}
426
427#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update, HeapSize)]
428pub struct ConcreteExternTypeLongId<'db> {
429 pub extern_type_id: ExternTypeId<'db>,
430 pub generic_args: Vec<semantic::GenericArgumentId<'db>>,
431}
432define_short_id!(ConcreteExternTypeId, ConcreteExternTypeLongId<'db>);
433semantic_object_for_id!(ConcreteExternTypeId, ConcreteExternTypeLongId<'a>);
434impl<'db> ConcreteExternTypeId<'db> {
435 pub fn extern_type_id(&self, db: &'db dyn Database) -> ExternTypeId<'db> {
436 self.long(db).extern_type_id
437 }
438}
439
440#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update, HeapSize)]
442pub struct ClosureTypeLongId<'db> {
443 pub param_tys: Vec<TypeId<'db>>,
444 pub ret_ty: TypeId<'db>,
445 pub captured_types: Vec<TypeId<'db>>,
449 pub parent_function: Maybe<FunctionId<'db>>,
451 #[dont_rewrite]
453 pub params_location: StableLocation<'db>,
454}
455
456impl<'db> DebugWithDb<'db> for ClosureTypeLongId<'db> {
457 type Db = dyn Database;
458
459 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
460 write!(f, "{{closure@{:?}}}", self.params_location.debug(db))
461 }
462}
463
464#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, SemanticObject, HeapSize, salsa::Update)]
466pub struct ImplTypeId<'db> {
467 impl_id: ImplId<'db>,
469 ty: TraitTypeId<'db>,
471}
472impl<'db> ImplTypeId<'db> {
473 pub fn new(impl_id: ImplId<'db>, ty: TraitTypeId<'db>, db: &'db dyn Database) -> Self {
476 if let crate::items::imp::ImplLongId::Concrete(concrete_impl) = impl_id.long(db) {
477 let impl_def_id = concrete_impl.impl_def_id(db);
478 assert_eq!(Ok(ty.trait_id(db)), db.impl_def_trait(impl_def_id));
479 }
480
481 ImplTypeId { impl_id, ty }
482 }
483 pub fn impl_id(&self) -> ImplId<'db> {
484 self.impl_id
485 }
486 pub fn ty(&self) -> TraitTypeId<'db> {
487 self.ty
488 }
489 pub fn format(&self, db: &dyn Database) -> String {
490 format!("{}::{}", self.impl_id.name(db), self.ty.name(db).long(db))
491 }
492}
493impl<'db> DebugWithDb<'db> for ImplTypeId<'db> {
494 type Db = dyn Database;
495
496 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
497 write!(f, "{}", self.format(db))
498 }
499}
500
501#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, salsa::Update)]
503pub struct ImplTypeById<'db>(ImplTypeId<'db>);
504
505impl<'db> From<ImplTypeId<'db>> for ImplTypeById<'db> {
506 fn from(impl_type_id: ImplTypeId<'db>) -> Self {
507 Self(impl_type_id)
508 }
509}
510impl<'db> Ord for ImplTypeById<'db> {
511 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
512 self.0
513 .impl_id
514 .get_internal_id()
515 .cmp(&other.0.impl_id.get_internal_id())
516 .then_with(|| self.0.ty.get_internal_id().cmp(&other.0.ty.get_internal_id()))
517 }
518}
519impl<'db> PartialOrd for ImplTypeById<'db> {
520 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
521 Some(self.cmp(other))
522 }
523}
524
525pub fn resolve_type<'db>(
528 db: &'db dyn Database,
529 diagnostics: &mut SemanticDiagnostics<'db>,
530 resolver: &mut Resolver<'db>,
531 ty_syntax: &ast::Expr<'db>,
532) -> TypeId<'db> {
533 resolve_type_ex(db, diagnostics, resolver, ty_syntax, ResolutionContext::Default)
534}
535pub fn resolve_type_ex<'db>(
537 db: &'db dyn Database,
538 diagnostics: &mut SemanticDiagnostics<'db>,
539 resolver: &mut Resolver<'db>,
540 ty_syntax: &ast::Expr<'db>,
541 ctx: ResolutionContext<'db, '_>,
542) -> TypeId<'db> {
543 maybe_resolve_type(db, diagnostics, resolver, ty_syntax, ctx)
544 .unwrap_or_else(|diag_added| TypeId::missing(db, diag_added))
545}
546fn maybe_resolve_type<'db>(
547 db: &'db dyn Database,
548 diagnostics: &mut SemanticDiagnostics<'db>,
549 resolver: &mut Resolver<'db>,
550 ty_syntax: &ast::Expr<'db>,
551 mut ctx: ResolutionContext<'db, '_>,
552) -> Maybe<TypeId<'db>> {
553 Ok(match ty_syntax {
554 ast::Expr::Underscore(underscore) => {
555 resolver.inference().new_type_var(Some(underscore.stable_ptr(db).untyped()))
556 }
557 ast::Expr::Path(path) => {
558 match resolver.resolve_concrete_path_ex(
559 diagnostics,
560 path,
561 NotFoundItemType::Type,
562 ctx,
563 )? {
564 ResolvedConcreteItem::Type(ty) => ty,
565 _ => {
566 return Err(diagnostics.report(path.stable_ptr(db), NotAType));
567 }
568 }
569 }
570 ast::Expr::Parenthesized(expr_syntax) => {
571 resolve_type_ex(db, diagnostics, resolver, &expr_syntax.expr(db), ctx)
572 }
573 ast::Expr::Tuple(tuple_syntax) => {
574 let sub_tys = tuple_syntax
575 .expressions(db)
576 .elements(db)
577 .map(|subexpr_syntax| {
578 resolve_type_ex(
579 db,
580 diagnostics,
581 resolver,
582 &subexpr_syntax,
583 match ctx {
584 ResolutionContext::Default => ResolutionContext::Default,
585 ResolutionContext::ModuleItem(id) => ResolutionContext::ModuleItem(id),
586 ResolutionContext::Statement(ref mut env) => {
587 ResolutionContext::Statement(env)
588 }
589 },
590 )
591 })
592 .collect();
593 TypeLongId::Tuple(sub_tys).intern(db)
594 }
595 ast::Expr::Unary(unary_syntax)
596 if matches!(unary_syntax.op(db), ast::UnaryOperator::At(_)) =>
597 {
598 let ty = resolve_type_ex(db, diagnostics, resolver, &unary_syntax.expr(db), ctx);
599 TypeLongId::Snapshot(ty).intern(db)
600 }
601 ast::Expr::Unary(unary_syntax)
603 if matches!(unary_syntax.op(db), ast::UnaryOperator::Desnap(_)) =>
604 {
605 let ty = resolve_type_ex(db, diagnostics, resolver, &unary_syntax.expr(db), ctx);
606 if let Some(desnapped_ty) = try_extract_matches!(ty.long(db), TypeLongId::Snapshot) {
607 *desnapped_ty
608 } else {
609 return Err(diagnostics.report(ty_syntax.stable_ptr(db), DerefNonRef { ty }));
610 }
611 }
612 ast::Expr::Unary(unary_syntax)
613 if matches!(unary_syntax.op(db), ast::UnaryOperator::Reference(_)) =>
614 {
615 if !are_repr_ptrs_enabled(db, resolver.module_id) {
616 return Err(diagnostics.report(ty_syntax.stable_ptr(db), ReprPtrsDisabled));
617 }
618 let inner_ty = resolve_type_ex(db, diagnostics, resolver, &unary_syntax.expr(db), ctx);
619 let snapshot_ty = TypeLongId::Snapshot(inner_ty).intern(db);
620 core_box_ty(db, snapshot_ty)
621 }
622 ast::Expr::FixedSizeArray(array_syntax) => {
623 let Ok(ty) = &array_syntax.exprs(db).elements(db).exactly_one() else {
624 return Err(
625 diagnostics.report(ty_syntax.stable_ptr(db), FixedSizeArrayTypeNonSingleType)
626 );
627 };
628 let ty = resolve_type_ex(db, diagnostics, resolver, ty, ctx);
629 let size =
630 match extract_fixed_size_array_size(db, diagnostics, array_syntax, resolver)? {
631 Some(size) => size,
632 None => {
633 return Err(diagnostics
634 .report(ty_syntax.stable_ptr(db), FixedSizeArrayTypeEmptySize));
635 }
636 };
637 TypeLongId::FixedSizeArray { type_id: ty, size }.intern(db)
638 }
639 _ => {
640 return Err(diagnostics.report(ty_syntax.stable_ptr(db), UnknownType));
641 }
642 })
643}
644
645#[derive(Clone, Debug, PartialEq, Eq, salsa::Update)]
647pub enum ShallowGenericArg<'db> {
648 GenericParameter(GenericParamId<'db>),
650 GenericType(GenericTypeId<'db>),
652 Snapshot(Box<ShallowGenericArg<'db>>),
653 Tuple,
654 FixedSizeArray,
655}
656
657impl<'db> ShallowGenericArg<'db> {
658 pub fn module_id(&self, db: &'db dyn Database) -> Option<ModuleId<'db>> {
660 match self {
661 ShallowGenericArg::GenericParameter(_) => None,
662 ShallowGenericArg::GenericType(ty) => Some(ty.parent_module(db)),
663 ShallowGenericArg::Snapshot(inner) => inner.module_id(db),
664 ShallowGenericArg::Tuple => TypeLongId::Tuple(vec![]).module_id(db),
665 ShallowGenericArg::FixedSizeArray => TypeLongId::FixedSizeArray {
666 type_id: unit_ty(db),
667 size: ConstValue::Struct(vec![], unit_ty(db)).intern(db),
668 }
669 .module_id(db),
670 }
671 }
672 pub fn head(&self) -> TypeHead<'db> {
673 match self {
674 ShallowGenericArg::GenericParameter(param) => TypeHead::Generic(*param),
675 ShallowGenericArg::GenericType(ty) => TypeHead::Concrete(*ty),
676 ShallowGenericArg::Snapshot(inner) => TypeHead::Snapshot(Box::new(inner.head())),
677 ShallowGenericArg::Tuple => TypeHead::Tuple,
678 ShallowGenericArg::FixedSizeArray => TypeHead::FixedSizeArray,
679 }
680 }
681}
682pub fn maybe_resolve_shallow_generic_arg_type<'db>(
684 db: &'db dyn Database,
685 diagnostics: &mut SemanticDiagnostics<'db>,
686 resolver: &mut Resolver<'db>,
687 ty_syntax: &ast::Expr<'db>,
688) -> Option<ShallowGenericArg<'db>> {
689 Some(match ty_syntax {
690 ast::Expr::Path(path) => {
691 if let [PathSegment::Simple(path)] =
692 path.segments(db).elements(db).collect_vec().as_slice()
693 && let Some(ResolvedConcreteItem::Type(ty)) =
694 resolver.determine_base_item_in_local_scope(&path.ident(db))
695 {
696 let param = extract_matches!(ty.long(db), TypeLongId::GenericParameter);
697 return Some(ShallowGenericArg::GenericParameter(*param));
698 }
699
700 match resolver
701 .resolve_generic_path_with_args(
702 diagnostics,
703 path,
704 NotFoundItemType::Type,
705 ResolutionContext::Default,
706 )
707 .ok()?
708 {
709 ResolvedGenericItem::GenericType(ty) => ShallowGenericArg::GenericType(ty),
710 _ => {
711 return None;
712 }
713 }
714 }
715 ast::Expr::Parenthesized(expr_syntax) => maybe_resolve_shallow_generic_arg_type(
716 db,
717 diagnostics,
718 resolver,
719 &expr_syntax.expr(db),
720 )?,
721 ast::Expr::Tuple(_) => ShallowGenericArg::Tuple,
722 ast::Expr::Unary(unary_syntax)
723 if matches!(unary_syntax.op(db), ast::UnaryOperator::At(_)) =>
724 {
725 ShallowGenericArg::Snapshot(Box::new(maybe_resolve_shallow_generic_arg_type(
726 db,
727 diagnostics,
728 resolver,
729 &unary_syntax.expr(db),
730 )?))
731 }
732 ast::Expr::Unary(unary_syntax)
733 if matches!(unary_syntax.op(db), ast::UnaryOperator::Desnap(_)) =>
734 {
735 maybe_resolve_shallow_generic_arg_type(
736 db,
737 diagnostics,
738 resolver,
739 &unary_syntax.expr(db),
740 )?
741 }
742 ast::Expr::FixedSizeArray(_) => ShallowGenericArg::FixedSizeArray,
743 _ => {
744 return None;
745 }
746 })
747}
748
749pub fn extract_fixed_size_array_size<'db>(
752 db: &'db dyn Database,
753 diagnostics: &mut SemanticDiagnostics<'db>,
754 syntax: &ast::ExprFixedSizeArray<'db>,
755 resolver: &mut Resolver<'db>,
756) -> Maybe<Option<ConstValueId<'db>>> {
757 match syntax.size(db) {
758 ast::OptionFixedSizeArraySize::FixedSizeArraySize(size_clause) => {
759 let mut ctx = ComputationContext::new_global(db, diagnostics, resolver);
760 let size_expr_syntax = size_clause.size(db);
761 let size = compute_expr_semantic(&mut ctx, &size_expr_syntax);
762 let const_value = resolve_const_expr_and_evaluate(
763 db,
764 &mut ctx,
765 &size,
766 size_expr_syntax.stable_ptr(db).untyped(),
767 get_usize_ty(db),
768 false,
769 );
770 if matches!(
771 const_value.long(db),
772 ConstValue::Int(_, _) | ConstValue::Generic(_) | ConstValue::ImplConstant(_)
773 ) {
774 Ok(Some(const_value))
775 } else {
776 Err(diagnostics.report(syntax.stable_ptr(db), FixedSizeArrayNonNumericSize))
777 }
778 }
779 ast::OptionFixedSizeArraySize::Empty(_) => Ok(None),
780 }
781}
782
783pub fn verify_fixed_size_array_size<'db>(
785 db: &'db dyn Database,
786 diagnostics: &mut SemanticDiagnostics<'db>,
787 size: &BigInt,
788 syntax: &ast::ExprFixedSizeArray<'db>,
789) -> Maybe<()> {
790 if size > &BigInt::from(i16::MAX) {
791 return Err(diagnostics.report(syntax.stable_ptr(db), FixedSizeArraySizeTooBig));
792 }
793 Ok(())
794}
795
796#[derive(Clone, Debug, PartialEq, Eq, salsa::Update)]
797pub struct TypeInfo<'db> {
798 pub droppable: Result<ImplId<'db>, InferenceError<'db>>,
799 pub copyable: Result<ImplId<'db>, InferenceError<'db>>,
800 pub destruct_impl: Result<ImplId<'db>, InferenceError<'db>>,
801 pub panic_destruct_impl: Result<ImplId<'db>, InferenceError<'db>>,
802}
803
804pub fn get_impl_at_context<'db>(
806 db: &'db dyn Database,
807 lookup_context: ImplLookupContextId<'db>,
808 concrete_trait_id: ConcreteTraitId<'db>,
809 stable_ptr: Option<SyntaxStablePtrId<'db>>,
810) -> Result<ImplId<'db>, InferenceError<'db>> {
811 let constrains =
812 db.generic_params_type_constraints(lookup_context.long(db).generic_params.clone());
813 if constrains.is_empty() && concrete_trait_id.is_var_free(db) {
814 return solve_concrete_trait_no_constraints(db, lookup_context, concrete_trait_id);
815 }
816 let mut inference_data = InferenceData::new(InferenceId::NoContext);
817 let mut inference = inference_data.inference(db);
818 inference.conform_generic_params_type_constraints(constrains);
819 let impl_id = inference.new_impl_var(concrete_trait_id, stable_ptr, lookup_context);
822 if let Err(err_set) = inference.finalize_without_reporting() {
823 return Err(inference
824 .consume_error_without_reporting(err_set)
825 .expect("Error couldn't be already consumed"));
826 };
827 Ok(inference.rewrite(impl_id).no_err())
828}
829
830fn single_value_type(db: &dyn Database, ty: TypeId<'_>) -> Maybe<bool> {
832 Ok(match ty.long(db) {
833 TypeLongId::Concrete(concrete_type_id) => match concrete_type_id {
834 ConcreteTypeId::Struct(id) => {
835 for member in db.struct_members(id.struct_id(db))?.values() {
836 if !db.single_value_type(member.ty)? {
837 return Ok(false);
838 }
839 }
840 true
841 }
842 ConcreteTypeId::Enum(id) => {
843 let variants = db.enum_variants(id.enum_id(db))?;
844 if variants.len() != 1 {
845 return Ok(false);
846 }
847
848 db.single_value_type(
849 db.variant_semantic(id.enum_id(db), *variants.values().next().unwrap())?.ty,
850 )?
851 }
852 ConcreteTypeId::Extern(_) => false,
853 },
854 TypeLongId::Tuple(types) => {
855 for ty in types {
856 if !db.single_value_type(*ty)? {
857 return Ok(false);
858 }
859 }
860 true
861 }
862 TypeLongId::Snapshot(ty) => db.single_value_type(*ty)?,
863 TypeLongId::GenericParameter(_)
864 | TypeLongId::Var(_)
865 | TypeLongId::Missing(_)
866 | TypeLongId::Coupon(_)
867 | TypeLongId::ImplType(_)
868 | TypeLongId::Closure(_) => false,
869 TypeLongId::FixedSizeArray { type_id, size } => {
870 db.single_value_type(*type_id)?
871 || matches!(size.long(db),
872 ConstValue::Int(value, _) if value.is_zero())
873 }
874 })
875}
876
877#[salsa::tracked]
879fn single_value_type_tracked<'db>(db: &'db dyn Database, ty: TypeId<'db>) -> Maybe<bool> {
880 single_value_type(db, ty)
881}
882
883pub fn add_type_based_diagnostics<'db>(
885 db: &'db dyn Database,
886 diagnostics: &mut SemanticDiagnostics<'db>,
887 ty: TypeId<'db>,
888 stable_ptr: impl Into<SyntaxStablePtrId<'db>> + Copy,
889) {
890 if db.type_size_info(ty) == Ok(TypeSizeInformation::Infinite) {
891 diagnostics.report(stable_ptr, InfiniteSizeType(ty));
892 }
893 if let TypeLongId::Concrete(ConcreteTypeId::Extern(extrn)) = ty.long(db) {
894 let long_id = extrn.long(db);
895 if long_id.extern_type_id.name(db).long(db) == "Array"
896 && let [GenericArgumentId::Type(arg_ty)] = &long_id.generic_args[..]
897 && db.type_size_info(*arg_ty) == Ok(TypeSizeInformation::ZeroSized)
898 {
899 diagnostics.report(stable_ptr, ArrayOfZeroSizedElements(*arg_ty));
900 }
901 }
902}
903
904#[derive(Clone, Debug, PartialEq, Eq)]
905pub enum TypeSizeInformation {
906 Infinite,
910 ZeroSized,
912 Other,
914}
915
916fn type_size_info(db: &dyn Database, ty: TypeId<'_>) -> Maybe<TypeSizeInformation> {
918 match ty.long(db) {
919 TypeLongId::Concrete(concrete_type_id) => match concrete_type_id {
920 ConcreteTypeId::Struct(id) => {
921 if check_all_type_are_zero_sized(
922 db,
923 db.concrete_struct_members(*id)?.iter().map(|(_, member)| &member.ty),
924 )? {
925 return Ok(TypeSizeInformation::ZeroSized);
926 }
927 }
928 ConcreteTypeId::Enum(id) => {
929 for variant in &db.concrete_enum_variants(*id)? {
930 db.type_size_info(variant.ty)?;
932 }
933 }
934 ConcreteTypeId::Extern(_) => {}
935 },
936 TypeLongId::Tuple(types) => {
937 if check_all_type_are_zero_sized(db, types.iter())? {
938 return Ok(TypeSizeInformation::ZeroSized);
939 }
940 }
941 TypeLongId::Snapshot(ty) => {
942 if db.type_size_info(*ty)? == TypeSizeInformation::ZeroSized {
943 return Ok(TypeSizeInformation::ZeroSized);
944 }
945 }
946 TypeLongId::Closure(closure_ty) => {
947 if check_all_type_are_zero_sized(db, closure_ty.captured_types.iter())? {
948 return Ok(TypeSizeInformation::ZeroSized);
949 }
950 }
951 TypeLongId::Coupon(_) => return Ok(TypeSizeInformation::ZeroSized),
952 TypeLongId::GenericParameter(_)
953 | TypeLongId::Var(_)
954 | TypeLongId::Missing(_)
955 | TypeLongId::ImplType(_) => {}
956 TypeLongId::FixedSizeArray { type_id, size } => {
957 if matches!(size.long(db), ConstValue::Int(value,_) if value.is_zero())
958 || db.type_size_info(*type_id)? == TypeSizeInformation::ZeroSized
959 {
960 return Ok(TypeSizeInformation::ZeroSized);
961 }
962 }
963 }
964 Ok(TypeSizeInformation::Other)
965}
966
967#[salsa::tracked(cycle_result=type_size_info_cycle)]
969fn type_size_info_tracked<'db>(
970 db: &'db dyn Database,
971 ty: TypeId<'db>,
972) -> Maybe<TypeSizeInformation> {
973 type_size_info(db, ty)
974}
975
976fn check_all_type_are_zero_sized<'a>(
978 db: &dyn Database,
979 types: impl Iterator<Item = &'a TypeId<'a>>,
980) -> Maybe<bool> {
981 let mut zero_sized = true;
982 for ty in types {
983 if db.type_size_info(*ty)? != TypeSizeInformation::ZeroSized {
984 zero_sized = false;
985 }
986 }
987 Ok(zero_sized)
988}
989
990fn type_size_info_cycle<'db>(
992 _db: &'db dyn Database,
993 _id: salsa::Id,
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 {}