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