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