1#[cfg(test)]
2#[path = "test.rs"]
3mod test;
4
5use std::ops::{Deref, DerefMut};
6use std::sync::Arc;
7
8use bincode::error::EncodeError;
9use cairo_lang_defs as defs;
10use cairo_lang_defs::cache::{
11 CachedCrateMetadata, DefCacheLoadingData, DefCacheSavingContext, LanguageElementCached,
12 SyntaxStablePtrIdCached,
13};
14use cairo_lang_defs::db::DefsGroup;
15use cairo_lang_defs::diagnostic_utils::StableLocation;
16use cairo_lang_defs::ids::{
17 FreeFunctionLongId, FunctionWithBodyId, ImplFunctionLongId, TraitFunctionLongId,
18};
19use cairo_lang_diagnostics::{DiagnosticAdded, Maybe, skip_diagnostic};
20use cairo_lang_filesystem::db::FilesGroup;
21use cairo_lang_filesystem::ids::CrateId;
22use cairo_lang_semantic::cache::{
23 ConcreteEnumCached, ConcreteVariantCached, ConstValueIdCached, ExprVarMemberPathCached,
24 ImplIdCached, MatchArmSelectorCached, SemanticCacheLoadingData, SemanticCacheSavingContext,
25 SemanticCacheSavingData, SemanticConcreteFunctionWithBodyCached, SemanticFunctionIdCached,
26 TypeIdCached, generate_crate_def_cache, generate_crate_semantic_cache,
27};
28use cairo_lang_semantic::db::SemanticGroup;
29use cairo_lang_semantic::expr::inference::InferenceError;
30use cairo_lang_semantic::items::function_with_body::FunctionWithBodySemantic;
31use cairo_lang_semantic::items::imp::ImplSemantic;
32use cairo_lang_semantic::items::macro_call::module_macro_modules;
33use cairo_lang_semantic::items::trt::TraitSemantic;
34use cairo_lang_semantic::types::TypeInfo;
35use cairo_lang_syntax::node::TypedStablePtr;
36use cairo_lang_syntax::node::ast::{ExprPtr, FunctionWithBodyPtr, TraitItemFunctionPtr};
37use cairo_lang_utils::Intern;
38use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
39use id_arena::Arena;
40use itertools::chain;
41use salsa::Database;
42use serde::{Deserialize, Serialize};
43use thiserror::Error;
44
45use crate::blocks::BlocksBuilder;
46use crate::ids::{
47 FunctionId, FunctionLongId, GeneratedFunction, GeneratedFunctionKey, LocationId, LoweredParam,
48 Signature,
49};
50use crate::lower::{MultiLowering, lower_semantic_function};
51use crate::objects::{
52 BlockId, MatchExternInfo, Statement, StatementCall, StatementConst, StatementStructDestructure,
53 VariableId,
54};
55use crate::{
56 Block, BlockEnd, Location, Lowered, MatchArm, MatchEnumInfo, MatchEnumValue, MatchInfo,
57 StatementDesnap, StatementEnumConstruct, StatementSnapshot, StatementStructConstruct,
58 VarRemapping, VarUsage, Variable,
59};
60
61type LookupCache = (CacheLookups, Vec<(DefsFunctionWithBodyIdCached, MultiLoweringCached)>);
62
63pub fn load_cached_crate_functions<'db>(
65 db: &'db dyn Database,
66 crate_id: CrateId<'db>,
67) -> Option<OrderedHashMap<defs::ids::FunctionWithBodyId<'db>, MultiLowering<'db>>> {
68 let blob_id = db.crate_config(crate_id)?.cache_file?;
69 let Some(content) = db.blob_content(blob_id) else {
70 return Default::default();
71 };
72
73 let semantic_loading_data = db.cached_crate_semantic_data(crate_id)?.loading_data;
74
75 let def_size = usize::from_be_bytes(content[..8].try_into().unwrap()); let semantic_start = 8 + def_size;
77 let semantic_size =
78 usize::from_be_bytes(content[semantic_start..semantic_start + 8].try_into().unwrap()); let lowering_start = semantic_start + semantic_size + 8;
81 let lowering_size =
82 usize::from_be_bytes(content[lowering_start..lowering_start + 8].try_into().unwrap()); let content = &content[lowering_start + 8..lowering_start + 8 + lowering_size];
85
86 let ((lookups, lowerings), _): (LookupCache, _) =
87 bincode::serde::decode_from_slice(content, bincode::config::standard()).unwrap_or_else(
88 |e| {
89 panic!(
90 "failed to deserialize lookup cache for crate `{}`: {e}",
91 crate_id.long(db).name().long(db),
92 )
93 },
94 );
95
96 let mut ctx = CacheLoadingContext::new(db, lookups, semantic_loading_data);
99
100 Some(
101 lowerings
102 .into_iter()
103 .map(|(function_id, lowering)| {
104 let function_id =
105 function_id.embed(&ctx.semantic_loading_data.defs_loading_data, ctx.db);
106
107 let lowering = lowering.embed(&mut ctx);
108 (function_id, lowering)
109 })
110 .collect::<OrderedHashMap<_, _>>(),
111 )
112}
113
114#[derive(Debug, Error)]
115pub enum CrateCacheError {
116 #[error("Failed compilation of crate.")]
117 CompilationFailed,
118 #[error("Cache encoding failed: {0}")]
119 EncodingError(#[from] EncodeError),
120}
121
122impl From<DiagnosticAdded> for CrateCacheError {
123 fn from(_e: DiagnosticAdded) -> Self {
124 Self::CompilationFailed
125 }
126}
127
128pub fn generate_crate_cache<'db>(
130 db: &'db dyn Database,
131 crate_id: CrateId<'db>,
132) -> Result<Vec<u8>, CrateCacheError> {
133 let modules = db.crate_modules(crate_id);
134 let mut function_ids = Vec::new();
135 for module_id in modules.iter() {
136 for module_id in chain!([module_id], module_macro_modules(db, true, *module_id)) {
137 for free_func in db.module_free_functions_ids(*module_id)?.iter() {
138 function_ids.push(FunctionWithBodyId::Free(*free_func));
139 }
140 for impl_id in db.module_impls_ids(*module_id)?.iter() {
141 for impl_func in db.impl_functions(*impl_id)?.values() {
142 function_ids.push(FunctionWithBodyId::Impl(*impl_func));
143 }
144 }
145 for trait_id in db.module_traits_ids(*module_id)?.iter() {
146 for trait_func in db.trait_functions(*trait_id)?.values() {
147 function_ids.push(FunctionWithBodyId::Trait(*trait_func));
148 }
149 }
150 }
151 }
152
153 let mut ctx = CacheSavingContext::new(db, crate_id);
154
155 let def_cache = generate_crate_def_cache(db, crate_id, &mut ctx.semantic_ctx.defs_ctx)?;
156 let semantic_cache = generate_crate_semantic_cache(crate_id, &mut ctx.semantic_ctx)?;
157
158 let cached = function_ids
159 .iter()
160 .filter_map(|id| {
161 db.function_body(*id).ok()?;
162 let multi = match lower_semantic_function(db, *id) {
163 Ok(multi) => multi,
164 Err(err) => return Some(Err(err)),
165 };
166
167 Some(Ok((
168 DefsFunctionWithBodyIdCached::new(*id, &mut ctx.semantic_ctx),
169 MultiLoweringCached::new(multi, &mut ctx),
170 )))
171 })
172 .collect::<Maybe<Vec<_>>>()?;
173
174 let mut artifact = Vec::<u8>::new();
175
176 let def = bincode::serde::encode_to_vec(
177 &(CachedCrateMetadata::new(crate_id, db), def_cache, &ctx.semantic_ctx.defs_ctx.lookups),
178 bincode::config::standard(),
179 )?;
180 artifact.extend(def.len().to_be_bytes());
181 artifact.extend(def);
182
183 let semantic = bincode::serde::encode_to_vec(
184 &(semantic_cache, &ctx.semantic_ctx.lookups),
185 bincode::config::standard(),
186 )?;
187 artifact.extend(semantic.len().to_be_bytes());
188 artifact.extend(semantic);
189
190 let lowered =
191 bincode::serde::encode_to_vec(&(&ctx.lookups, cached), bincode::config::standard())?;
192 artifact.extend(lowered.len().to_be_bytes());
193 artifact.extend(lowered);
194
195 Ok(artifact)
196}
197
198struct CacheLoadingContext<'db> {
200 lowered_variables_id: Vec<VariableId>,
202 db: &'db dyn Database,
203
204 data: CacheLoadingData<'db>,
206
207 semantic_loading_data: Arc<SemanticCacheLoadingData<'db>>,
208}
209
210impl<'db> CacheLoadingContext<'db> {
211 fn new(
212 db: &'db dyn Database,
213 lookups: CacheLookups,
214 semantic_loading_data: Arc<SemanticCacheLoadingData<'db>>,
215 ) -> Self {
216 Self {
217 lowered_variables_id: Vec::new(),
218 db,
219 data: CacheLoadingData {
220 function_ids: OrderedHashMap::default(),
221 location_ids: OrderedHashMap::default(),
222 lookups,
223 },
224 semantic_loading_data,
225 }
226 }
227}
228
229impl<'db> Deref for CacheLoadingContext<'db> {
230 type Target = CacheLoadingData<'db>;
231
232 fn deref(&self) -> &Self::Target {
233 &self.data
234 }
235}
236impl<'db> DerefMut for CacheLoadingContext<'db> {
237 fn deref_mut(&mut self) -> &mut Self::Target {
238 &mut self.data
239 }
240}
241
242struct CacheLoadingData<'db> {
244 function_ids: OrderedHashMap<FunctionIdCached, FunctionId<'db>>,
245 location_ids: OrderedHashMap<LocationIdCached, LocationId<'db>>,
246 lookups: CacheLookups,
247}
248impl Deref for CacheLoadingData<'_> {
249 type Target = CacheLookups;
250
251 fn deref(&self) -> &Self::Target {
252 &self.lookups
253 }
254}
255impl DerefMut for CacheLoadingData<'_> {
256 fn deref_mut(&mut self) -> &mut Self::Target {
257 &mut self.lookups
258 }
259}
260
261struct CacheSavingContext<'db> {
263 db: &'db dyn Database,
264 data: CacheSavingData<'db>,
265 semantic_ctx: SemanticCacheSavingContext<'db>,
266}
267impl<'db> Deref for CacheSavingContext<'db> {
268 type Target = CacheSavingData<'db>;
269
270 fn deref(&self) -> &Self::Target {
271 &self.data
272 }
273}
274impl DerefMut for CacheSavingContext<'_> {
275 fn deref_mut(&mut self) -> &mut Self::Target {
276 &mut self.data
277 }
278}
279impl<'db> CacheSavingContext<'db> {
280 fn new(db: &'db dyn Database, self_crate_id: CrateId<'db>) -> Self {
281 Self {
282 db,
283 data: CacheSavingData::default(),
284 semantic_ctx: SemanticCacheSavingContext {
285 db,
286 data: SemanticCacheSavingData::default(),
287 defs_ctx: DefCacheSavingContext::new(db, self_crate_id),
288 },
289 }
290 }
291}
292
293#[derive(Default)]
295struct CacheSavingData<'db> {
296 function_ids: OrderedHashMap<FunctionId<'db>, FunctionIdCached>,
297 location_ids: OrderedHashMap<LocationId<'db>, LocationIdCached>,
298 lookups: CacheLookups,
299}
300impl<'db> Deref for CacheSavingData<'db> {
301 type Target = CacheLookups;
302
303 fn deref(&self) -> &Self::Target {
304 &self.lookups
305 }
306}
307impl<'db> DerefMut for CacheSavingData<'db> {
308 fn deref_mut(&mut self) -> &mut Self::Target {
309 &mut self.lookups
310 }
311}
312
313#[derive(Serialize, Deserialize, Default)]
315struct CacheLookups {
316 function_ids_lookup: Vec<FunctionCached>,
317 location_ids_lookup: Vec<LocationCached>,
318}
319
320#[derive(Serialize, Deserialize, Hash, Eq, PartialEq)]
323enum DefsFunctionWithBodyIdCached {
324 Free(LanguageElementCached),
325 Impl(LanguageElementCached),
326 Trait(LanguageElementCached),
327}
328impl DefsFunctionWithBodyIdCached {
329 fn new<'db>(
330 id: defs::ids::FunctionWithBodyId<'db>,
331 ctx: &mut SemanticCacheSavingContext<'db>,
332 ) -> Self {
333 match id {
334 defs::ids::FunctionWithBodyId::Free(id) => DefsFunctionWithBodyIdCached::Free(
335 LanguageElementCached::new(id, &mut ctx.defs_ctx),
336 ),
337 defs::ids::FunctionWithBodyId::Impl(id) => DefsFunctionWithBodyIdCached::Impl(
338 LanguageElementCached::new(id, &mut ctx.defs_ctx),
339 ),
340 defs::ids::FunctionWithBodyId::Trait(id) => DefsFunctionWithBodyIdCached::Trait(
341 LanguageElementCached::new(id, &mut ctx.defs_ctx),
342 ),
343 }
344 }
345
346 fn embed<'db>(
347 self,
348 defs_loading_data: &Arc<DefCacheLoadingData<'db>>,
349 db: &'db dyn Database,
350 ) -> defs::ids::FunctionWithBodyId<'db> {
351 match self {
352 DefsFunctionWithBodyIdCached::Free(id) => {
353 let (module_id, function_stable_ptr) = id.get_embedded(defs_loading_data);
354 defs::ids::FunctionWithBodyId::Free(
355 FreeFunctionLongId(module_id, FunctionWithBodyPtr(function_stable_ptr))
356 .intern(db),
357 )
358 }
359 DefsFunctionWithBodyIdCached::Impl(id) => {
360 let (module_id, function_stable_ptr) = id.get_embedded(defs_loading_data);
361 defs::ids::FunctionWithBodyId::Impl(
362 ImplFunctionLongId(module_id, FunctionWithBodyPtr(function_stable_ptr))
363 .intern(db),
364 )
365 }
366 DefsFunctionWithBodyIdCached::Trait(id) => {
367 let (module_id, function_stable_ptr) = id.get_embedded(defs_loading_data);
368 defs::ids::FunctionWithBodyId::Trait(
369 TraitFunctionLongId(module_id, TraitItemFunctionPtr(function_stable_ptr))
370 .intern(db),
371 )
372 }
373 }
374 }
375}
376
377#[derive(Serialize, Deserialize)]
379struct MultiLoweringCached {
380 main_lowering: LoweredCached,
381 generated_lowerings: Vec<(GeneratedFunctionKeyCached, LoweredCached)>,
382}
383impl MultiLoweringCached {
384 fn new<'db>(lowering: MultiLowering<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
385 Self {
386 main_lowering: LoweredCached::new(lowering.main_lowering, ctx),
387 generated_lowerings: lowering
388 .generated_lowerings
389 .into_iter()
390 .map(|(key, lowered)| {
391 (GeneratedFunctionKeyCached::new(key, ctx), LoweredCached::new(lowered, ctx))
392 })
393 .collect(),
394 }
395 }
396 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MultiLowering<'db> {
397 MultiLowering {
398 main_lowering: self.main_lowering.embed(ctx),
399 generated_lowerings: self
400 .generated_lowerings
401 .into_iter()
402 .map(|(key, lowered)| (key.embed(ctx), lowered.embed(ctx)))
403 .collect(),
404 }
405 }
406}
407
408#[derive(Serialize, Deserialize)]
409struct LoweredCached {
410 signature: LoweredSignatureCached,
412 variables: Vec<VariableCached>,
414 blocks: Vec<BlockCached>,
416 parameters: Vec<usize>,
418}
419impl LoweredCached {
420 fn new<'db>(lowered: Lowered<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
421 Self {
422 signature: LoweredSignatureCached::new(lowered.signature, ctx),
423 variables: lowered
424 .variables
425 .into_iter()
426 .map(|var| VariableCached::new(var.1, ctx))
427 .collect(),
428 blocks: lowered
429 .blocks
430 .iter()
431 .map(|block: (BlockId, &Block<'_>)| BlockCached::new(block.1.clone(), ctx))
432 .collect(),
433 parameters: lowered.parameters.iter().map(|var| var.index()).collect(),
434 }
435 }
436 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Lowered<'db> {
437 ctx.lowered_variables_id.clear();
438 let mut variables = Arena::new();
439 for var in self.variables {
440 let id = variables.alloc(var.embed(ctx));
441 ctx.lowered_variables_id.push(id);
442 }
443
444 let mut blocks = BlocksBuilder::new();
445 for block in self.blocks {
446 blocks.alloc(block.embed(ctx));
447 }
448 Lowered {
449 diagnostics: Default::default(),
450 signature: self.signature.embed(ctx),
451 variables,
452 blocks: blocks.build().unwrap(),
453 parameters: self
454 .parameters
455 .into_iter()
456 .map(|var_id| ctx.lowered_variables_id[var_id])
457 .collect(),
458 }
459 }
460}
461
462#[derive(Serialize, Deserialize)]
463struct LoweredSignatureCached {
464 params: Vec<LoweredParamCached>,
466 extra_rets: Vec<ExprVarMemberPathCached>,
468 return_type: TypeIdCached,
470 implicits: Vec<TypeIdCached>,
472 panicable: bool,
474 location: LocationIdCached,
475}
476impl LoweredSignatureCached {
477 fn new<'db>(signature: Signature<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
478 Self {
479 params: signature
480 .params
481 .iter()
482 .map(|param| LoweredParamCached::new(param, ctx))
483 .collect(),
484 extra_rets: signature
485 .extra_rets
486 .into_iter()
487 .map(|var| ExprVarMemberPathCached::new(var, &mut ctx.semantic_ctx))
488 .collect(),
489
490 return_type: TypeIdCached::new(signature.return_type, &mut ctx.semantic_ctx),
491 implicits: signature
492 .implicits
493 .into_iter()
494 .map(|ty| TypeIdCached::new(ty, &mut ctx.semantic_ctx))
495 .collect(),
496 panicable: signature.panicable,
497 location: LocationIdCached::new(signature.location, ctx),
498 }
499 }
500 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Signature<'db> {
501 Signature {
502 params: self.params.into_iter().map(|var| var.embed(ctx)).collect(),
503 extra_rets: self
504 .extra_rets
505 .into_iter()
506 .map(|var| var.get_embedded(&ctx.semantic_loading_data, ctx.db))
507 .collect(),
508 return_type: self.return_type.get_embedded(&ctx.semantic_loading_data),
509 implicits: self
510 .implicits
511 .into_iter()
512 .map(|ty| ty.get_embedded(&ctx.semantic_loading_data))
513 .collect(),
514 panicable: self.panicable,
515 location: self.location.embed(ctx),
516 }
517 }
518}
519
520#[derive(Serialize, Deserialize)]
521struct LoweredParamCached {
522 ty: TypeIdCached,
523 stable_ptr: SyntaxStablePtrIdCached,
524}
525impl LoweredParamCached {
526 fn new<'db>(param: &LoweredParam<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
527 Self {
528 ty: TypeIdCached::new(param.ty, &mut ctx.semantic_ctx),
529 stable_ptr: SyntaxStablePtrIdCached::new(
530 param.stable_ptr.untyped(),
531 &mut ctx.semantic_ctx.defs_ctx,
532 ),
533 }
534 }
535 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> LoweredParam<'db> {
536 LoweredParam {
537 ty: self.ty.get_embedded(&ctx.semantic_loading_data),
538 stable_ptr: ExprPtr(
539 self.stable_ptr.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
540 ),
541 }
542 }
543}
544#[derive(Serialize, Deserialize)]
545struct VariableCached {
546 droppable: Option<ImplIdCached>,
547 copyable: Option<ImplIdCached>,
549 destruct_impl: Option<ImplIdCached>,
551 panic_destruct_impl: Option<ImplIdCached>,
553 ty: TypeIdCached,
555 location: LocationIdCached,
556}
557impl VariableCached {
558 fn new<'db>(variable: Variable<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
559 let TypeInfo { droppable, copyable, destruct_impl, panic_destruct_impl } = variable.info;
560 Self {
561 droppable: droppable
562 .map(|impl_id| ImplIdCached::new(impl_id, &mut ctx.semantic_ctx))
563 .ok(),
564 copyable: copyable
565 .map(|impl_id| ImplIdCached::new(impl_id, &mut ctx.semantic_ctx))
566 .ok(),
567 destruct_impl: destruct_impl
568 .map(|impl_id| ImplIdCached::new(impl_id, &mut ctx.semantic_ctx))
569 .ok(),
570 panic_destruct_impl: panic_destruct_impl
571 .map(|impl_id| ImplIdCached::new(impl_id, &mut ctx.semantic_ctx))
572 .ok(),
573 ty: TypeIdCached::new(variable.ty, &mut ctx.semantic_ctx),
574 location: LocationIdCached::new(variable.location, ctx),
575 }
576 }
577 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Variable<'db> {
578 Variable {
579 ty: self.ty.get_embedded(&ctx.semantic_loading_data),
580 location: self.location.embed(ctx),
581 info: TypeInfo {
582 droppable: self
583 .droppable
584 .map(|impl_id| impl_id.get_embedded(&ctx.semantic_loading_data))
585 .ok_or(InferenceError::Reported(skip_diagnostic())),
586 copyable: self
587 .copyable
588 .map(|impl_id| impl_id.get_embedded(&ctx.semantic_loading_data))
589 .ok_or(InferenceError::Reported(skip_diagnostic())),
590 destruct_impl: self
591 .destruct_impl
592 .map(|impl_id| impl_id.get_embedded(&ctx.semantic_loading_data))
593 .ok_or(InferenceError::Reported(skip_diagnostic())),
594 panic_destruct_impl: self
595 .panic_destruct_impl
596 .map(|impl_id| impl_id.get_embedded(&ctx.semantic_loading_data))
597 .ok_or(InferenceError::Reported(skip_diagnostic())),
598 },
599 }
600 }
601}
602
603#[derive(Serialize, Deserialize)]
604struct VarUsageCached {
605 var_id: usize,
607 location: LocationIdCached,
609}
610
611impl VarUsageCached {
612 fn new<'db>(var_usage: VarUsage<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
613 Self {
614 var_id: var_usage.var_id.index(),
615 location: LocationIdCached::new(var_usage.location, ctx),
616 }
617 }
618 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> VarUsage<'db> {
619 VarUsage {
620 var_id: ctx.lowered_variables_id[self.var_id],
621 location: self.location.embed(ctx),
622 }
623 }
624}
625
626#[derive(Serialize, Deserialize)]
627struct BlockCached {
628 statements: Vec<StatementCached>,
630 end: BlockEndCached,
632}
633impl BlockCached {
634 fn new<'db>(block: Block<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
635 Self {
636 statements: block
637 .statements
638 .into_iter()
639 .map(|stmt| StatementCached::new(stmt, ctx))
640 .collect(),
641 end: BlockEndCached::new(block.end, ctx),
642 }
643 }
644 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Block<'db> {
645 Block {
646 statements: self.statements.into_iter().map(|stmt| stmt.embed(ctx)).collect(),
647 end: self.end.embed(ctx),
648 }
649 }
650}
651#[derive(Serialize, Deserialize)]
652enum BlockEndCached {
653 NotSet,
656 Return(Vec<VarUsageCached>, LocationIdCached),
658 Panic(VarUsageCached),
660 Goto(usize, VarRemappingCached),
662 Match {
663 info: MatchInfoCached,
664 },
665}
666impl BlockEndCached {
667 fn new<'db>(block_end: BlockEnd<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
668 match block_end {
669 BlockEnd::Return(returns, location) => BlockEndCached::Return(
670 returns.iter().map(|var| VarUsageCached::new(*var, ctx)).collect(),
671 LocationIdCached::new(location, ctx),
672 ),
673 BlockEnd::Panic(data) => BlockEndCached::Panic(VarUsageCached::new(data, ctx)),
674 BlockEnd::Goto(block_id, remapping) => {
675 BlockEndCached::Goto(block_id.0, VarRemappingCached::new(remapping, ctx))
676 }
677 BlockEnd::NotSet => BlockEndCached::NotSet,
678 BlockEnd::Match { info } => {
679 BlockEndCached::Match { info: MatchInfoCached::new(info, ctx) }
680 }
681 }
682 }
683 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> BlockEnd<'db> {
684 match self {
685 BlockEndCached::Return(returns, location) => BlockEnd::Return(
686 returns.into_iter().map(|var_usage| var_usage.embed(ctx)).collect(),
687 location.embed(ctx),
688 ),
689 BlockEndCached::Panic(var_id) => BlockEnd::Panic(var_id.embed(ctx)),
690 BlockEndCached::Goto(block_id, remapping) => {
691 BlockEnd::Goto(BlockId(block_id), remapping.embed(ctx))
692 }
693 BlockEndCached::NotSet => BlockEnd::NotSet,
694 BlockEndCached::Match { info } => BlockEnd::Match { info: info.embed(ctx) },
695 }
696 }
697}
698
699#[derive(Serialize, Deserialize)]
700struct VarRemappingCached {
701 remapping: OrderedHashMap<usize, VarUsageCached>,
703}
704impl VarRemappingCached {
705 fn new<'db>(var_remapping: VarRemapping<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
706 Self {
707 remapping: var_remapping
708 .iter()
709 .map(|(dst, src)| (dst.index(), VarUsageCached::new(*src, ctx)))
710 .collect(),
711 }
712 }
713 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> VarRemapping<'db> {
714 let mut remapping = OrderedHashMap::default();
715 for (dst, src) in self.remapping {
716 remapping.insert(ctx.lowered_variables_id[dst], src.embed(ctx));
717 }
718 VarRemapping { remapping }
719 }
720}
721
722#[derive(Serialize, Deserialize)]
723enum MatchInfoCached {
724 Enum(MatchEnumInfoCached),
725 Extern(MatchExternInfoCached),
726 Value(MatchEnumValueCached),
727}
728impl MatchInfoCached {
729 fn new<'db>(match_info: MatchInfo<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
730 match match_info {
731 MatchInfo::Enum(info) => MatchInfoCached::Enum(MatchEnumInfoCached::new(info, ctx)),
732 MatchInfo::Extern(info) => {
733 MatchInfoCached::Extern(MatchExternInfoCached::new(info, ctx))
734 }
735 MatchInfo::Value(info) => MatchInfoCached::Value(MatchEnumValueCached::new(info, ctx)),
736 }
737 }
738 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchInfo<'db> {
739 match self {
740 MatchInfoCached::Enum(info) => MatchInfo::Enum(info.embed(ctx)),
741 MatchInfoCached::Extern(info) => MatchInfo::Extern(info.embed(ctx)),
742 MatchInfoCached::Value(info) => MatchInfo::Value(info.embed(ctx)),
743 }
744 }
745}
746
747#[derive(Serialize, Deserialize)]
748struct MatchEnumInfoCached {
749 concrete_enum_id: ConcreteEnumCached,
750 input: VarUsageCached,
752 arms: Vec<MatchArmCached>,
755 location: LocationIdCached,
756}
757impl MatchEnumInfoCached {
758 fn new<'db>(match_enum_info: MatchEnumInfo<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
759 Self {
760 concrete_enum_id: ConcreteEnumCached::new(
761 match_enum_info.concrete_enum_id,
762 &mut ctx.semantic_ctx,
763 ),
764 input: VarUsageCached::new(match_enum_info.input, ctx),
765 arms: match_enum_info
766 .arms
767 .into_iter()
768 .map(|arm| MatchArmCached::new(arm, ctx))
769 .collect(),
770 location: LocationIdCached::new(match_enum_info.location, ctx),
771 }
772 }
773 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchEnumInfo<'db> {
774 MatchEnumInfo {
775 concrete_enum_id: self
776 .concrete_enum_id
777 .get_embedded(&ctx.semantic_loading_data, ctx.db),
778 input: self.input.embed(ctx),
779 arms: self.arms.into_iter().map(|arm| arm.embed(ctx)).collect(),
780 location: self.location.embed(ctx),
781 }
782 }
783}
784
785#[derive(Serialize, Deserialize)]
786struct MatchExternInfoCached {
787 function: FunctionIdCached,
789 inputs: Vec<VarUsageCached>,
791 arms: Vec<MatchArmCached>,
794 location: LocationIdCached,
795}
796
797impl MatchExternInfoCached {
798 fn new<'db>(
799 match_extern_info: MatchExternInfo<'db>,
800 ctx: &mut CacheSavingContext<'db>,
801 ) -> Self {
802 Self {
803 function: FunctionIdCached::new(match_extern_info.function, ctx),
804 inputs: match_extern_info
805 .inputs
806 .iter()
807 .map(|var| VarUsageCached::new(*var, ctx))
808 .collect(),
809 arms: match_extern_info
810 .arms
811 .into_iter()
812 .map(|arm| MatchArmCached::new(arm, ctx))
813 .collect(),
814 location: LocationIdCached::new(match_extern_info.location, ctx),
815 }
816 }
817 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchExternInfo<'db> {
818 MatchExternInfo {
819 function: self.function.embed(ctx),
820 inputs: self.inputs.into_iter().map(|var_id| var_id.embed(ctx)).collect(),
821 arms: self.arms.into_iter().map(|arm| arm.embed(ctx)).collect(),
822 location: self.location.embed(ctx),
823 }
824 }
825}
826
827#[derive(Serialize, Deserialize)]
828struct MatchEnumValueCached {
829 num_of_arms: usize,
830
831 input: VarUsageCached,
833 arms: Vec<MatchArmCached>,
835 location: LocationIdCached,
836}
837
838impl MatchEnumValueCached {
839 fn new<'db>(match_enum_value: MatchEnumValue<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
840 Self {
841 num_of_arms: match_enum_value.num_of_arms,
842 input: VarUsageCached::new(match_enum_value.input, ctx),
843 arms: match_enum_value
844 .arms
845 .into_iter()
846 .map(|arm| MatchArmCached::new(arm, ctx))
847 .collect(),
848 location: LocationIdCached::new(match_enum_value.location, ctx),
849 }
850 }
851 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchEnumValue<'db> {
852 MatchEnumValue {
853 num_of_arms: self.num_of_arms,
854 input: self.input.embed(ctx),
855 arms: self.arms.into_iter().map(|arm| arm.embed(ctx)).collect(),
856 location: self.location.embed(ctx),
857 }
858 }
859}
860#[derive(Serialize, Deserialize)]
862struct MatchArmCached {
863 arm_selector: MatchArmSelectorCached,
865
866 block_id: usize,
868
869 var_ids: Vec<usize>,
871}
872
873impl MatchArmCached {
874 fn new<'db>(match_arm: MatchArm<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
875 Self {
876 arm_selector: MatchArmSelectorCached::new(
877 match_arm.arm_selector,
878 &mut ctx.semantic_ctx,
879 ),
880 block_id: match_arm.block_id.0,
881 var_ids: match_arm.var_ids.iter().map(|var| var.index()).collect(),
882 }
883 }
884 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchArm<'db> {
885 MatchArm {
886 arm_selector: self.arm_selector.get_embedded(&ctx.semantic_loading_data, ctx.db),
887 block_id: BlockId(self.block_id),
888 var_ids: self
889 .var_ids
890 .into_iter()
891 .map(|var_id| ctx.lowered_variables_id[var_id])
892 .collect(),
893 }
894 }
895}
896
897#[derive(Serialize, Deserialize)]
898enum StatementCached {
899 Const(StatementConstCached),
901
902 Call(StatementCallCached),
904
905 StructConstruct(StatementStructConstructCached),
907 StructDestructure(StatementStructDestructureCached),
908
909 EnumConstruct(StatementEnumConstructCached),
911
912 Snapshot(StatementSnapshotCached),
913 Desnap(StatementDesnapCached),
914}
915
916impl StatementCached {
917 fn new<'db>(stmt: Statement<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
918 match stmt {
919 Statement::Const(stmt) => StatementCached::Const(StatementConstCached::new(stmt, ctx)),
920 Statement::Call(stmt) => StatementCached::Call(StatementCallCached::new(stmt, ctx)),
921 Statement::StructConstruct(stmt) => {
922 StatementCached::StructConstruct(StatementStructConstructCached::new(stmt, ctx))
923 }
924 Statement::StructDestructure(stmt) => {
925 StatementCached::StructDestructure(StatementStructDestructureCached::new(stmt, ctx))
926 }
927 Statement::EnumConstruct(stmt) => {
928 StatementCached::EnumConstruct(StatementEnumConstructCached::new(stmt, ctx))
929 }
930 Statement::Snapshot(stmt) => {
931 StatementCached::Snapshot(StatementSnapshotCached::new(stmt, ctx))
932 }
933 Statement::Desnap(stmt) => {
934 StatementCached::Desnap(StatementDesnapCached::new(stmt, ctx))
935 }
936 }
937 }
938 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Statement<'db> {
939 match self {
940 StatementCached::Const(stmt) => Statement::Const(stmt.embed(ctx)),
941 StatementCached::Call(stmt) => Statement::Call(stmt.embed(ctx)),
942 StatementCached::StructConstruct(stmt) => Statement::StructConstruct(stmt.embed(ctx)),
943 StatementCached::StructDestructure(stmt) => {
944 Statement::StructDestructure(stmt.embed(ctx))
945 }
946 StatementCached::EnumConstruct(stmt) => Statement::EnumConstruct(stmt.embed(ctx)),
947 StatementCached::Snapshot(stmt) => Statement::Snapshot(stmt.embed(ctx)),
948 StatementCached::Desnap(stmt) => Statement::Desnap(stmt.embed(ctx)),
949 }
950 }
951}
952
953#[derive(Serialize, Deserialize)]
954struct StatementConstCached {
955 value: ConstValueIdCached,
957 output: usize,
959 boxed: bool,
961}
962impl StatementConstCached {
963 fn new<'db>(stmt: StatementConst<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
964 Self {
965 value: ConstValueIdCached::new(stmt.value, &mut ctx.semantic_ctx),
966 output: stmt.output.index(),
967 boxed: stmt.boxed,
968 }
969 }
970 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementConst<'db> {
971 StatementConst::new(
972 self.value.get_embedded(&ctx.semantic_loading_data),
973 ctx.lowered_variables_id[self.output],
974 self.boxed,
975 )
976 }
977}
978
979#[derive(Serialize, Deserialize)]
980struct StatementCallCached {
981 function: FunctionIdCached,
982 inputs: Vec<VarUsageCached>,
983 with_coupon: bool,
984 outputs: Vec<usize>,
985 location: LocationIdCached,
986 is_specialization_base_call: bool,
987}
988impl StatementCallCached {
989 fn new<'db>(stmt: StatementCall<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
990 Self {
991 function: FunctionIdCached::new(stmt.function, ctx),
992 inputs: stmt.inputs.iter().map(|var| VarUsageCached::new(*var, ctx)).collect(),
993 with_coupon: stmt.with_coupon,
994 outputs: stmt.outputs.iter().map(|var| var.index()).collect(),
995 location: LocationIdCached::new(stmt.location, ctx),
996 is_specialization_base_call: stmt.is_specialization_base_call,
997 }
998 }
999 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementCall<'db> {
1000 StatementCall {
1001 function: self.function.embed(ctx),
1002 inputs: self.inputs.into_iter().map(|var_id| var_id.embed(ctx)).collect(),
1003 with_coupon: self.with_coupon,
1004 outputs: self
1005 .outputs
1006 .into_iter()
1007 .map(|var_id| ctx.lowered_variables_id[var_id])
1008 .collect(),
1009 location: self.location.embed(ctx),
1010 is_specialization_base_call: self.is_specialization_base_call,
1011 }
1012 }
1013}
1014
1015#[derive(Serialize, Deserialize, Clone)]
1016enum FunctionCached {
1017 Semantic(SemanticFunctionIdCached),
1019 Generated(GeneratedFunctionCached),
1021}
1022impl FunctionCached {
1023 fn new<'db>(function: FunctionLongId<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1024 match function {
1025 FunctionLongId::Semantic(id) => {
1026 FunctionCached::Semantic(SemanticFunctionIdCached::new(id, &mut ctx.semantic_ctx))
1027 }
1028 FunctionLongId::Generated(id) => {
1029 FunctionCached::Generated(GeneratedFunctionCached::new(id, ctx))
1030 }
1031 FunctionLongId::Specialized(_) => {
1032 unreachable!("Specialization of functions only occurs post concretization.")
1033 }
1034 }
1035 }
1036 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> FunctionId<'db> {
1037 match self {
1038 FunctionCached::Semantic(id) => {
1039 FunctionLongId::Semantic(id.get_embedded(&ctx.semantic_loading_data))
1040 }
1041 FunctionCached::Generated(id) => FunctionLongId::Generated(id.embed(ctx)),
1042 }
1043 .intern(ctx.db)
1044 }
1045}
1046
1047#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash)]
1048struct FunctionIdCached(usize);
1049impl FunctionIdCached {
1050 fn new<'db>(function_id: FunctionId<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1051 if let Some(id) = ctx.function_ids.get(&function_id) {
1052 return *id;
1053 }
1054 let function = FunctionCached::new(function_id.long(ctx.db).clone(), ctx);
1055 let id = FunctionIdCached(ctx.function_ids_lookup.len());
1056 ctx.function_ids_lookup.push(function);
1057 ctx.function_ids.insert(function_id, id);
1058 id
1059 }
1060 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> FunctionId<'db> {
1061 if let Some(function_id) = ctx.function_ids.get(&self) {
1062 return *function_id;
1063 }
1064
1065 let function = ctx.function_ids_lookup[self.0].clone();
1066 let function_id = function.embed(ctx);
1067 ctx.function_ids.insert(self, function_id);
1068 function_id
1069 }
1070}
1071
1072#[derive(Serialize, Deserialize, Clone)]
1073struct GeneratedFunctionCached {
1074 parent: SemanticConcreteFunctionWithBodyCached,
1075 key: GeneratedFunctionKeyCached,
1076}
1077impl GeneratedFunctionCached {
1078 fn new<'db>(function: GeneratedFunction<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1079 Self {
1080 parent: SemanticConcreteFunctionWithBodyCached::new(
1081 function.parent,
1082 &mut ctx.semantic_ctx,
1083 ),
1084 key: GeneratedFunctionKeyCached::new(function.key, ctx),
1085 }
1086 }
1087 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> GeneratedFunction<'db> {
1088 GeneratedFunction {
1089 parent: self.parent.get_embedded(&ctx.semantic_loading_data, ctx.db),
1090 key: self.key.embed(ctx),
1091 }
1092 }
1093}
1094
1095#[derive(Serialize, Deserialize, Clone, Hash, PartialEq, Eq)]
1096enum GeneratedFunctionKeyCached {
1097 Loop(SyntaxStablePtrIdCached),
1098 TraitFunc(LanguageElementCached, SyntaxStablePtrIdCached),
1099}
1100
1101impl GeneratedFunctionKeyCached {
1102 fn new<'db>(key: GeneratedFunctionKey<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1103 match key {
1104 GeneratedFunctionKey::Loop(id) => GeneratedFunctionKeyCached::Loop(
1105 SyntaxStablePtrIdCached::new(id.untyped(), &mut ctx.semantic_ctx.defs_ctx),
1106 ),
1107 GeneratedFunctionKey::TraitFunc(id, stable_location) => {
1108 GeneratedFunctionKeyCached::TraitFunc(
1109 LanguageElementCached::new(id, &mut ctx.semantic_ctx.defs_ctx),
1110 SyntaxStablePtrIdCached::new(
1111 stable_location.stable_ptr(),
1112 &mut ctx.semantic_ctx.defs_ctx,
1113 ),
1114 )
1115 }
1116 }
1117 }
1118 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> GeneratedFunctionKey<'db> {
1119 match self {
1120 GeneratedFunctionKeyCached::Loop(id) => GeneratedFunctionKey::Loop(ExprPtr(
1121 id.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
1122 )),
1123 GeneratedFunctionKeyCached::TraitFunc(id, stable_location) => {
1124 let (module_id, stable_ptr) =
1125 id.get_embedded(&ctx.semantic_loading_data.defs_loading_data);
1126 GeneratedFunctionKey::TraitFunc(
1127 TraitFunctionLongId(module_id, TraitItemFunctionPtr(stable_ptr)).intern(ctx.db),
1128 StableLocation::new(
1129 stable_location.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
1130 ),
1131 )
1132 }
1133 }
1134 }
1135}
1136
1137#[derive(Serialize, Deserialize)]
1138struct StatementStructConstructCached {
1139 inputs: Vec<VarUsageCached>,
1140 output: usize,
1142}
1143impl StatementStructConstructCached {
1144 fn new<'db>(stmt: StatementStructConstruct<'db>, _ctx: &mut CacheSavingContext<'db>) -> Self {
1145 Self {
1146 inputs: stmt.inputs.iter().map(|var| VarUsageCached::new(*var, _ctx)).collect(),
1147 output: stmt.output.index(),
1148 }
1149 }
1150 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementStructConstruct<'db> {
1151 StatementStructConstruct {
1152 inputs: self.inputs.into_iter().map(|var_id| var_id.embed(ctx)).collect(),
1153 output: ctx.lowered_variables_id[self.output],
1154 }
1155 }
1156}
1157#[derive(Serialize, Deserialize)]
1158struct StatementStructDestructureCached {
1159 input: VarUsageCached,
1161 outputs: Vec<usize>,
1163}
1164impl StatementStructDestructureCached {
1165 fn new<'db>(stmt: StatementStructDestructure<'db>, _ctx: &mut CacheSavingContext<'db>) -> Self {
1166 Self {
1167 input: VarUsageCached::new(stmt.input, _ctx),
1168 outputs: stmt.outputs.iter().map(|var| var.index()).collect(),
1169 }
1170 }
1171 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementStructDestructure<'db> {
1172 StatementStructDestructure {
1173 input: self.input.embed(ctx),
1174 outputs: self
1175 .outputs
1176 .into_iter()
1177 .map(|var_id| ctx.lowered_variables_id[var_id])
1178 .collect(),
1179 }
1180 }
1181}
1182
1183#[derive(Serialize, Deserialize)]
1184struct StatementEnumConstructCached {
1185 variant: ConcreteVariantCached,
1186 input: VarUsageCached,
1188 output: usize,
1190}
1191impl StatementEnumConstructCached {
1192 fn new<'db>(stmt: StatementEnumConstruct<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1193 Self {
1194 variant: ConcreteVariantCached::new(stmt.variant, &mut ctx.semantic_ctx),
1195 input: VarUsageCached::new(stmt.input, ctx),
1196 output: stmt.output.index(),
1197 }
1198 }
1199 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementEnumConstruct<'db> {
1200 StatementEnumConstruct {
1201 variant: self.variant.get_embedded(&ctx.semantic_loading_data, ctx.db),
1202 input: self.input.embed(ctx),
1203 output: ctx.lowered_variables_id[self.output],
1204 }
1205 }
1206}
1207
1208#[derive(Serialize, Deserialize)]
1209struct StatementSnapshotCached {
1210 input: VarUsageCached,
1211 outputs: [usize; 2],
1212}
1213impl StatementSnapshotCached {
1214 fn new<'db>(stmt: StatementSnapshot<'db>, _ctx: &mut CacheSavingContext<'db>) -> Self {
1215 Self {
1216 input: VarUsageCached::new(stmt.input, _ctx),
1217 outputs: stmt.outputs.map(|var| var.index()),
1218 }
1219 }
1220 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementSnapshot<'db> {
1221 StatementSnapshot {
1222 input: self.input.embed(ctx),
1223 outputs: [
1224 ctx.lowered_variables_id[self.outputs[0]],
1225 ctx.lowered_variables_id[self.outputs[1]],
1226 ],
1227 }
1228 }
1229}
1230
1231#[derive(Serialize, Deserialize)]
1232struct StatementDesnapCached {
1233 input: VarUsageCached,
1234 output: usize,
1236}
1237impl StatementDesnapCached {
1238 fn new<'db>(stmt: StatementDesnap<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1239 Self { input: VarUsageCached::new(stmt.input, ctx), output: stmt.output.index() }
1240 }
1241 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementDesnap<'db> {
1242 StatementDesnap {
1243 input: self.input.embed(ctx),
1244 output: ctx.lowered_variables_id[self.output],
1245 }
1246 }
1247}
1248
1249#[derive(Serialize, Deserialize, Clone)]
1250struct LocationCached {
1251 stable_location: SyntaxStablePtrIdCached,
1253 inline_locations: Vec<SyntaxStablePtrIdCached>,
1255}
1256impl LocationCached {
1257 fn new<'db>(location: Location<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1258 Self {
1259 stable_location: SyntaxStablePtrIdCached::new(
1260 location.stable_location.stable_ptr(),
1261 &mut ctx.semantic_ctx.defs_ctx,
1262 ),
1263 inline_locations: location
1264 .inline_locations
1265 .iter()
1266 .map(|loc| {
1267 SyntaxStablePtrIdCached::new(loc.stable_ptr(), &mut ctx.semantic_ctx.defs_ctx)
1268 })
1269 .collect(),
1270 }
1271 }
1272 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Location<'db> {
1273 Location {
1274 stable_location: StableLocation::new(
1275 self.stable_location.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
1276 ),
1277 inline_locations: self
1278 .inline_locations
1279 .into_iter()
1280 .map(|loc| {
1281 StableLocation::new(
1282 loc.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
1283 )
1284 })
1285 .collect(),
1286 notes: Default::default(),
1287 }
1288 }
1289}
1290
1291#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash)]
1292struct LocationIdCached(usize);
1293
1294impl LocationIdCached {
1295 fn new<'db>(location_id: LocationId<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1296 if let Some(id) = ctx.location_ids.get(&location_id) {
1297 return *id;
1298 }
1299 let location = LocationCached::new(location_id.long(ctx.db).clone(), ctx);
1300 let id = LocationIdCached(ctx.location_ids_lookup.len());
1301 ctx.location_ids_lookup.push(location);
1302 ctx.location_ids.insert(location_id, id);
1303 id
1304 }
1305 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> LocationId<'db> {
1306 if let Some(location_id) = ctx.location_ids.get(&self) {
1307 return *location_id;
1308 }
1309 let location = ctx.location_ids_lookup[self.0].clone();
1310 let location = location.embed(ctx).intern(ctx.db);
1311 ctx.location_ids.insert(self, location);
1312 location
1313 }
1314}