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
422 .blocks
423 .iter()
424 .map(|block: (BlockId, &Block<'_>)| BlockCached::new(block.1.clone(), ctx))
425 .collect(),
426 parameters: lowered.parameters.iter().map(|var| var.index()).collect(),
427 }
428 }
429 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Lowered<'db> {
430 ctx.lowered_variables_id.clear();
431 let mut variables = Arena::new();
432 for var in self.variables {
433 let id = variables.alloc(var.embed(ctx));
434 ctx.lowered_variables_id.push(id);
435 }
436
437 let mut blocks = BlocksBuilder::new();
438 for block in self.blocks {
439 blocks.alloc(block.embed(ctx));
440 }
441 Lowered {
442 diagnostics: Default::default(),
443 signature: self.signature.embed(ctx),
444 variables,
445 blocks: blocks.build().unwrap(),
446 parameters: self
447 .parameters
448 .into_iter()
449 .map(|var_id| ctx.lowered_variables_id[var_id])
450 .collect(),
451 }
452 }
453}
454
455#[derive(Serialize, Deserialize)]
456struct LoweredSignatureCached {
457 params: Vec<LoweredParamCached>,
459 extra_rets: Vec<ExprVarMemberPathCached>,
461 return_type: TypeIdCached,
463 implicits: Vec<TypeIdCached>,
465 panicable: bool,
467 location: LocationIdCached,
468}
469impl LoweredSignatureCached {
470 fn new<'db>(signature: Signature<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
471 Self {
472 params: signature
473 .params
474 .iter()
475 .map(|param| LoweredParamCached::new(param, ctx))
476 .collect(),
477 extra_rets: signature
478 .extra_rets
479 .into_iter()
480 .map(|var| ExprVarMemberPathCached::new(var, &mut ctx.semantic_ctx))
481 .collect(),
482
483 return_type: TypeIdCached::new(signature.return_type, &mut ctx.semantic_ctx),
484 implicits: signature
485 .implicits
486 .into_iter()
487 .map(|ty| TypeIdCached::new(ty, &mut ctx.semantic_ctx))
488 .collect(),
489 panicable: signature.panicable,
490 location: LocationIdCached::new(signature.location, ctx),
491 }
492 }
493 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Signature<'db> {
494 Signature {
495 params: self.params.into_iter().map(|var| var.embed(ctx)).collect(),
496 extra_rets: self
497 .extra_rets
498 .into_iter()
499 .map(|var| var.get_embedded(&ctx.semantic_loading_data, ctx.db))
500 .collect(),
501 return_type: self.return_type.get_embedded(&ctx.semantic_loading_data),
502 implicits: self
503 .implicits
504 .into_iter()
505 .map(|ty| ty.get_embedded(&ctx.semantic_loading_data))
506 .collect(),
507 panicable: self.panicable,
508 location: self.location.embed(ctx),
509 }
510 }
511}
512
513#[derive(Serialize, Deserialize)]
514struct LoweredParamCached {
515 ty: TypeIdCached,
516 stable_ptr: SyntaxStablePtrIdCached,
517}
518impl LoweredParamCached {
519 fn new<'db>(param: &LoweredParam<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
520 Self {
521 ty: TypeIdCached::new(param.ty, &mut ctx.semantic_ctx),
522 stable_ptr: SyntaxStablePtrIdCached::new(
523 param.stable_ptr.untyped(),
524 &mut ctx.semantic_ctx.defs_ctx,
525 ),
526 }
527 }
528 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> LoweredParam<'db> {
529 LoweredParam {
530 ty: self.ty.get_embedded(&ctx.semantic_loading_data),
531 stable_ptr: ExprPtr(
532 self.stable_ptr.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
533 ),
534 }
535 }
536}
537#[derive(Serialize, Deserialize)]
538struct VariableCached {
539 droppable: Option<ImplIdCached>,
540 copyable: Option<ImplIdCached>,
542 destruct_impl: Option<ImplIdCached>,
544 panic_destruct_impl: Option<ImplIdCached>,
546 ty: TypeIdCached,
548 location: LocationIdCached,
549}
550impl VariableCached {
551 fn new<'db>(variable: Variable<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
552 let TypeInfo { droppable, copyable, destruct_impl, panic_destruct_impl } = variable.info;
553 Self {
554 droppable: droppable
555 .map(|impl_id| ImplIdCached::new(impl_id, &mut ctx.semantic_ctx))
556 .ok(),
557 copyable: copyable
558 .map(|impl_id| ImplIdCached::new(impl_id, &mut ctx.semantic_ctx))
559 .ok(),
560 destruct_impl: destruct_impl
561 .map(|impl_id| ImplIdCached::new(impl_id, &mut ctx.semantic_ctx))
562 .ok(),
563 panic_destruct_impl: panic_destruct_impl
564 .map(|impl_id| ImplIdCached::new(impl_id, &mut ctx.semantic_ctx))
565 .ok(),
566 ty: TypeIdCached::new(variable.ty, &mut ctx.semantic_ctx),
567 location: LocationIdCached::new(variable.location, ctx),
568 }
569 }
570 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Variable<'db> {
571 Variable {
572 ty: self.ty.get_embedded(&ctx.semantic_loading_data),
573 location: self.location.embed(ctx),
574 info: TypeInfo {
575 droppable: self
576 .droppable
577 .map(|impl_id| impl_id.get_embedded(&ctx.semantic_loading_data))
578 .ok_or(InferenceError::Reported(skip_diagnostic())),
579 copyable: self
580 .copyable
581 .map(|impl_id| impl_id.get_embedded(&ctx.semantic_loading_data))
582 .ok_or(InferenceError::Reported(skip_diagnostic())),
583 destruct_impl: self
584 .destruct_impl
585 .map(|impl_id| impl_id.get_embedded(&ctx.semantic_loading_data))
586 .ok_or(InferenceError::Reported(skip_diagnostic())),
587 panic_destruct_impl: self
588 .panic_destruct_impl
589 .map(|impl_id| impl_id.get_embedded(&ctx.semantic_loading_data))
590 .ok_or(InferenceError::Reported(skip_diagnostic())),
591 },
592 }
593 }
594}
595
596#[derive(Serialize, Deserialize)]
597struct VarUsageCached {
598 var_id: usize,
600 location: LocationIdCached,
602}
603
604impl VarUsageCached {
605 fn new<'db>(var_usage: VarUsage<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
606 Self {
607 var_id: var_usage.var_id.index(),
608 location: LocationIdCached::new(var_usage.location, ctx),
609 }
610 }
611 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> VarUsage<'db> {
612 VarUsage {
613 var_id: ctx.lowered_variables_id[self.var_id],
614 location: self.location.embed(ctx),
615 }
616 }
617}
618
619#[derive(Serialize, Deserialize)]
620struct BlockCached {
621 statements: Vec<StatementCached>,
623 end: BlockEndCached,
625}
626impl BlockCached {
627 fn new<'db>(block: Block<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
628 Self {
629 statements: block
630 .statements
631 .into_iter()
632 .map(|stmt| StatementCached::new(stmt, ctx))
633 .collect(),
634 end: BlockEndCached::new(block.end, ctx),
635 }
636 }
637 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Block<'db> {
638 Block {
639 statements: self.statements.into_iter().map(|stmt| stmt.embed(ctx)).collect(),
640 end: self.end.embed(ctx),
641 }
642 }
643}
644#[derive(Serialize, Deserialize)]
645enum BlockEndCached {
646 NotSet,
649 Return(Vec<VarUsageCached>, LocationIdCached),
651 Panic(VarUsageCached),
653 Goto(usize, VarRemappingCached),
655 Match {
656 info: MatchInfoCached,
657 },
658}
659impl BlockEndCached {
660 fn new<'db>(block_end: BlockEnd<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
661 match block_end {
662 BlockEnd::Return(returns, location) => BlockEndCached::Return(
663 returns.iter().map(|var| VarUsageCached::new(*var, ctx)).collect(),
664 LocationIdCached::new(location, ctx),
665 ),
666 BlockEnd::Panic(data) => BlockEndCached::Panic(VarUsageCached::new(data, ctx)),
667 BlockEnd::Goto(block_id, remapping) => {
668 BlockEndCached::Goto(block_id.0, VarRemappingCached::new(remapping, ctx))
669 }
670 BlockEnd::NotSet => BlockEndCached::NotSet,
671 BlockEnd::Match { info } => {
672 BlockEndCached::Match { info: MatchInfoCached::new(info, ctx) }
673 }
674 }
675 }
676 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> BlockEnd<'db> {
677 match self {
678 BlockEndCached::Return(returns, location) => BlockEnd::Return(
679 returns.into_iter().map(|var_usage| var_usage.embed(ctx)).collect(),
680 location.embed(ctx),
681 ),
682 BlockEndCached::Panic(var_id) => BlockEnd::Panic(var_id.embed(ctx)),
683 BlockEndCached::Goto(block_id, remapping) => {
684 BlockEnd::Goto(BlockId(block_id), remapping.embed(ctx))
685 }
686 BlockEndCached::NotSet => BlockEnd::NotSet,
687 BlockEndCached::Match { info } => BlockEnd::Match { info: info.embed(ctx) },
688 }
689 }
690}
691
692#[derive(Serialize, Deserialize)]
693struct VarRemappingCached {
694 remapping: OrderedHashMap<usize, VarUsageCached>,
696}
697impl VarRemappingCached {
698 fn new<'db>(var_remapping: VarRemapping<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
699 Self {
700 remapping: var_remapping
701 .iter()
702 .map(|(dst, src)| (dst.index(), VarUsageCached::new(*src, ctx)))
703 .collect(),
704 }
705 }
706 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> VarRemapping<'db> {
707 let mut remapping = OrderedHashMap::default();
708 for (dst, src) in self.remapping {
709 remapping.insert(ctx.lowered_variables_id[dst], src.embed(ctx));
710 }
711 VarRemapping { remapping }
712 }
713}
714
715#[derive(Serialize, Deserialize)]
716enum MatchInfoCached {
717 Enum(MatchEnumInfoCached),
718 Extern(MatchExternInfoCached),
719 Value(MatchEnumValueCached),
720}
721impl MatchInfoCached {
722 fn new<'db>(match_info: MatchInfo<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
723 match match_info {
724 MatchInfo::Enum(info) => MatchInfoCached::Enum(MatchEnumInfoCached::new(info, ctx)),
725 MatchInfo::Extern(info) => {
726 MatchInfoCached::Extern(MatchExternInfoCached::new(info, ctx))
727 }
728 MatchInfo::Value(info) => MatchInfoCached::Value(MatchEnumValueCached::new(info, ctx)),
729 }
730 }
731 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchInfo<'db> {
732 match self {
733 MatchInfoCached::Enum(info) => MatchInfo::Enum(info.embed(ctx)),
734 MatchInfoCached::Extern(info) => MatchInfo::Extern(info.embed(ctx)),
735 MatchInfoCached::Value(info) => MatchInfo::Value(info.embed(ctx)),
736 }
737 }
738}
739
740#[derive(Serialize, Deserialize)]
741struct MatchEnumInfoCached {
742 concrete_enum_id: ConcreteEnumCached,
743 input: VarUsageCached,
745 arms: Vec<MatchArmCached>,
748 location: LocationIdCached,
749}
750impl MatchEnumInfoCached {
751 fn new<'db>(match_enum_info: MatchEnumInfo<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
752 Self {
753 concrete_enum_id: ConcreteEnumCached::new(
754 match_enum_info.concrete_enum_id,
755 &mut ctx.semantic_ctx,
756 ),
757 input: VarUsageCached::new(match_enum_info.input, ctx),
758 arms: match_enum_info
759 .arms
760 .into_iter()
761 .map(|arm| MatchArmCached::new(arm, ctx))
762 .collect(),
763 location: LocationIdCached::new(match_enum_info.location, ctx),
764 }
765 }
766 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchEnumInfo<'db> {
767 MatchEnumInfo {
768 concrete_enum_id: self
769 .concrete_enum_id
770 .get_embedded(&ctx.semantic_loading_data, ctx.db),
771 input: self.input.embed(ctx),
772 arms: self.arms.into_iter().map(|arm| arm.embed(ctx)).collect(),
773 location: self.location.embed(ctx),
774 }
775 }
776}
777
778#[derive(Serialize, Deserialize)]
779struct MatchExternInfoCached {
780 function: FunctionIdCached,
782 inputs: Vec<VarUsageCached>,
784 arms: Vec<MatchArmCached>,
787 location: LocationIdCached,
788}
789
790impl MatchExternInfoCached {
791 fn new<'db>(
792 match_extern_info: MatchExternInfo<'db>,
793 ctx: &mut CacheSavingContext<'db>,
794 ) -> Self {
795 Self {
796 function: FunctionIdCached::new(match_extern_info.function, ctx),
797 inputs: match_extern_info
798 .inputs
799 .iter()
800 .map(|var| VarUsageCached::new(*var, ctx))
801 .collect(),
802 arms: match_extern_info
803 .arms
804 .into_iter()
805 .map(|arm| MatchArmCached::new(arm, ctx))
806 .collect(),
807 location: LocationIdCached::new(match_extern_info.location, ctx),
808 }
809 }
810 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchExternInfo<'db> {
811 MatchExternInfo {
812 function: self.function.embed(ctx),
813 inputs: self.inputs.into_iter().map(|var_id| var_id.embed(ctx)).collect(),
814 arms: self.arms.into_iter().map(|arm| arm.embed(ctx)).collect(),
815 location: self.location.embed(ctx),
816 }
817 }
818}
819
820#[derive(Serialize, Deserialize)]
821struct MatchEnumValueCached {
822 num_of_arms: usize,
823
824 input: VarUsageCached,
826 arms: Vec<MatchArmCached>,
828 location: LocationIdCached,
829}
830
831impl MatchEnumValueCached {
832 fn new<'db>(match_enum_value: MatchEnumValue<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
833 Self {
834 num_of_arms: match_enum_value.num_of_arms,
835 input: VarUsageCached::new(match_enum_value.input, ctx),
836 arms: match_enum_value
837 .arms
838 .into_iter()
839 .map(|arm| MatchArmCached::new(arm, ctx))
840 .collect(),
841 location: LocationIdCached::new(match_enum_value.location, ctx),
842 }
843 }
844 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchEnumValue<'db> {
845 MatchEnumValue {
846 num_of_arms: self.num_of_arms,
847 input: self.input.embed(ctx),
848 arms: self.arms.into_iter().map(|arm| arm.embed(ctx)).collect(),
849 location: self.location.embed(ctx),
850 }
851 }
852}
853#[derive(Serialize, Deserialize)]
855struct MatchArmCached {
856 arm_selector: MatchArmSelectorCached,
858
859 block_id: usize,
861
862 var_ids: Vec<usize>,
864}
865
866impl MatchArmCached {
867 fn new<'db>(match_arm: MatchArm<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
868 Self {
869 arm_selector: MatchArmSelectorCached::new(
870 match_arm.arm_selector,
871 &mut ctx.semantic_ctx,
872 ),
873 block_id: match_arm.block_id.0,
874 var_ids: match_arm.var_ids.iter().map(|var| var.index()).collect(),
875 }
876 }
877 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchArm<'db> {
878 MatchArm {
879 arm_selector: self.arm_selector.get_embedded(&ctx.semantic_loading_data, ctx.db),
880 block_id: BlockId(self.block_id),
881 var_ids: self
882 .var_ids
883 .into_iter()
884 .map(|var_id| ctx.lowered_variables_id[var_id])
885 .collect(),
886 }
887 }
888}
889
890#[derive(Serialize, Deserialize)]
891enum StatementCached {
892 Const(StatementConstCached),
894
895 Call(StatementCallCached),
897
898 StructConstruct(StatementStructConstructCached),
900 StructDestructure(StatementStructDestructureCached),
901
902 EnumConstruct(StatementEnumConstructCached),
904
905 IntoBox(StatementIntoBoxCached),
907 Unbox(StatementUnboxCached),
908
909 Snapshot(StatementSnapshotCached),
910 Desnap(StatementDesnapCached),
911}
912
913impl StatementCached {
914 fn new<'db>(stmt: Statement<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
915 match stmt {
916 Statement::Const(stmt) => StatementCached::Const(StatementConstCached::new(stmt, ctx)),
917 Statement::Call(stmt) => StatementCached::Call(StatementCallCached::new(stmt, ctx)),
918 Statement::StructConstruct(stmt) => {
919 StatementCached::StructConstruct(StatementStructConstructCached::new(stmt, ctx))
920 }
921 Statement::StructDestructure(stmt) => {
922 StatementCached::StructDestructure(StatementStructDestructureCached::new(stmt, ctx))
923 }
924 Statement::EnumConstruct(stmt) => {
925 StatementCached::EnumConstruct(StatementEnumConstructCached::new(stmt, ctx))
926 }
927 Statement::Snapshot(stmt) => {
928 StatementCached::Snapshot(StatementSnapshotCached::new(stmt, ctx))
929 }
930 Statement::Desnap(stmt) => {
931 StatementCached::Desnap(StatementDesnapCached::new(stmt, ctx))
932 }
933 Statement::IntoBox(stmt) => {
934 StatementCached::IntoBox(StatementIntoBoxCached::new(stmt, ctx))
935 }
936 Statement::Unbox(stmt) => StatementCached::Unbox(StatementUnboxCached::new(stmt, ctx)),
937 }
938 }
939 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Statement<'db> {
940 match self {
941 StatementCached::Const(stmt) => Statement::Const(stmt.embed(ctx)),
942 StatementCached::Call(stmt) => Statement::Call(stmt.embed(ctx)),
943 StatementCached::StructConstruct(stmt) => Statement::StructConstruct(stmt.embed(ctx)),
944 StatementCached::StructDestructure(stmt) => {
945 Statement::StructDestructure(stmt.embed(ctx))
946 }
947 StatementCached::EnumConstruct(stmt) => Statement::EnumConstruct(stmt.embed(ctx)),
948 StatementCached::Snapshot(stmt) => Statement::Snapshot(stmt.embed(ctx)),
949 StatementCached::Desnap(stmt) => Statement::Desnap(stmt.embed(ctx)),
950 StatementCached::IntoBox(stmt) => Statement::IntoBox(stmt.embed(ctx)),
951 StatementCached::Unbox(stmt) => Statement::Unbox(stmt.embed(ctx)),
952 }
953 }
954}
955
956#[derive(Serialize, Deserialize)]
957struct StatementConstCached {
958 value: ConstValueIdCached,
960 output: usize,
962 boxed: bool,
964}
965impl StatementConstCached {
966 fn new<'db>(stmt: StatementConst<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
967 Self {
968 value: ConstValueIdCached::new(stmt.value, &mut ctx.semantic_ctx),
969 output: stmt.output.index(),
970 boxed: stmt.boxed,
971 }
972 }
973 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementConst<'db> {
974 StatementConst::new(
975 self.value.get_embedded(&ctx.semantic_loading_data),
976 ctx.lowered_variables_id[self.output],
977 self.boxed,
978 )
979 }
980}
981
982#[derive(Serialize, Deserialize)]
983struct StatementCallCached {
984 function: FunctionIdCached,
985 inputs: Vec<VarUsageCached>,
986 with_coupon: bool,
987 outputs: Vec<usize>,
988 location: LocationIdCached,
989 is_specialization_base_call: bool,
990}
991impl StatementCallCached {
992 fn new<'db>(stmt: StatementCall<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
993 Self {
994 function: FunctionIdCached::new(stmt.function, ctx),
995 inputs: stmt.inputs.iter().map(|var| VarUsageCached::new(*var, ctx)).collect(),
996 with_coupon: stmt.with_coupon,
997 outputs: stmt.outputs.iter().map(|var| var.index()).collect(),
998 location: LocationIdCached::new(stmt.location, ctx),
999 is_specialization_base_call: stmt.is_specialization_base_call,
1000 }
1001 }
1002 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementCall<'db> {
1003 StatementCall {
1004 function: self.function.embed(ctx),
1005 inputs: self.inputs.into_iter().map(|var_id| var_id.embed(ctx)).collect(),
1006 with_coupon: self.with_coupon,
1007 outputs: self
1008 .outputs
1009 .into_iter()
1010 .map(|var_id| ctx.lowered_variables_id[var_id])
1011 .collect(),
1012 location: self.location.embed(ctx),
1013 is_specialization_base_call: self.is_specialization_base_call,
1014 }
1015 }
1016}
1017
1018#[derive(Serialize, Deserialize, Clone)]
1019enum FunctionCached {
1020 Semantic(SemanticFunctionIdCached),
1022 Generated(GeneratedFunctionCached),
1024}
1025impl FunctionCached {
1026 fn new<'db>(function: FunctionLongId<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1027 match function {
1028 FunctionLongId::Semantic(id) => {
1029 FunctionCached::Semantic(SemanticFunctionIdCached::new(id, &mut ctx.semantic_ctx))
1030 }
1031 FunctionLongId::Generated(id) => {
1032 FunctionCached::Generated(GeneratedFunctionCached::new(id, ctx))
1033 }
1034 FunctionLongId::Specialized(_) => {
1035 unreachable!("Specialization of functions only occurs post concretization.")
1036 }
1037 }
1038 }
1039 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> FunctionId<'db> {
1040 match self {
1041 FunctionCached::Semantic(id) => {
1042 FunctionLongId::Semantic(id.get_embedded(&ctx.semantic_loading_data))
1043 }
1044 FunctionCached::Generated(id) => FunctionLongId::Generated(id.embed(ctx)),
1045 }
1046 .intern(ctx.db)
1047 }
1048}
1049
1050#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash)]
1051struct FunctionIdCached(usize);
1052impl FunctionIdCached {
1053 fn new<'db>(function_id: FunctionId<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1054 if let Some(id) = ctx.function_ids.get(&function_id) {
1055 return *id;
1056 }
1057 let function = FunctionCached::new(function_id.long(ctx.db).clone(), ctx);
1058 let id = FunctionIdCached(ctx.function_ids_lookup.len());
1059 ctx.function_ids_lookup.push(function);
1060 ctx.function_ids.insert(function_id, id);
1061 id
1062 }
1063 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> FunctionId<'db> {
1064 if let Some(function_id) = ctx.function_ids.get(&self) {
1065 return *function_id;
1066 }
1067
1068 let function = ctx.function_ids_lookup[self.0].clone();
1069 let function_id = function.embed(ctx);
1070 ctx.function_ids.insert(self, function_id);
1071 function_id
1072 }
1073}
1074
1075#[derive(Serialize, Deserialize, Clone)]
1076struct GeneratedFunctionCached {
1077 parent: SemanticConcreteFunctionWithBodyCached,
1078 key: GeneratedFunctionKeyCached,
1079}
1080impl GeneratedFunctionCached {
1081 fn new<'db>(function: GeneratedFunction<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1082 Self {
1083 parent: SemanticConcreteFunctionWithBodyCached::new(
1084 function.parent,
1085 &mut ctx.semantic_ctx,
1086 ),
1087 key: GeneratedFunctionKeyCached::new(function.key, ctx),
1088 }
1089 }
1090 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> GeneratedFunction<'db> {
1091 GeneratedFunction {
1092 parent: self.parent.get_embedded(&ctx.semantic_loading_data, ctx.db),
1093 key: self.key.embed(ctx),
1094 }
1095 }
1096}
1097
1098#[derive(Serialize, Deserialize, Clone, Hash, PartialEq, Eq)]
1099enum GeneratedFunctionKeyCached {
1100 Loop(SyntaxStablePtrIdCached),
1101 TraitFunc(LanguageElementCached, SyntaxStablePtrIdCached),
1102}
1103
1104impl GeneratedFunctionKeyCached {
1105 fn new<'db>(key: GeneratedFunctionKey<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1106 match key {
1107 GeneratedFunctionKey::Loop(id) => GeneratedFunctionKeyCached::Loop(
1108 SyntaxStablePtrIdCached::new(id.untyped(), &mut ctx.semantic_ctx.defs_ctx),
1109 ),
1110 GeneratedFunctionKey::TraitFunc(id, stable_location) => {
1111 GeneratedFunctionKeyCached::TraitFunc(
1112 LanguageElementCached::new(id, &mut ctx.semantic_ctx.defs_ctx),
1113 SyntaxStablePtrIdCached::new(
1114 stable_location.stable_ptr(),
1115 &mut ctx.semantic_ctx.defs_ctx,
1116 ),
1117 )
1118 }
1119 }
1120 }
1121 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> GeneratedFunctionKey<'db> {
1122 match self {
1123 GeneratedFunctionKeyCached::Loop(id) => GeneratedFunctionKey::Loop(ExprPtr(
1124 id.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
1125 )),
1126 GeneratedFunctionKeyCached::TraitFunc(id, stable_location) => {
1127 let (module_id, stable_ptr) =
1128 id.get_embedded(&ctx.semantic_loading_data.defs_loading_data);
1129 GeneratedFunctionKey::TraitFunc(
1130 TraitFunctionLongId(module_id, TraitItemFunctionPtr(stable_ptr)).intern(ctx.db),
1131 StableLocation::new(
1132 stable_location.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
1133 ),
1134 )
1135 }
1136 }
1137 }
1138}
1139
1140#[derive(Serialize, Deserialize)]
1141struct StatementStructConstructCached {
1142 inputs: Vec<VarUsageCached>,
1143 output: usize,
1145}
1146impl StatementStructConstructCached {
1147 fn new<'db>(stmt: StatementStructConstruct<'db>, _ctx: &mut CacheSavingContext<'db>) -> Self {
1148 Self {
1149 inputs: stmt.inputs.iter().map(|var| VarUsageCached::new(*var, _ctx)).collect(),
1150 output: stmt.output.index(),
1151 }
1152 }
1153 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementStructConstruct<'db> {
1154 StatementStructConstruct {
1155 inputs: self.inputs.into_iter().map(|var_id| var_id.embed(ctx)).collect(),
1156 output: ctx.lowered_variables_id[self.output],
1157 }
1158 }
1159}
1160#[derive(Serialize, Deserialize)]
1161struct StatementStructDestructureCached {
1162 input: VarUsageCached,
1164 outputs: Vec<usize>,
1166}
1167impl StatementStructDestructureCached {
1168 fn new<'db>(stmt: StatementStructDestructure<'db>, _ctx: &mut CacheSavingContext<'db>) -> Self {
1169 Self {
1170 input: VarUsageCached::new(stmt.input, _ctx),
1171 outputs: stmt.outputs.iter().map(|var| var.index()).collect(),
1172 }
1173 }
1174 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementStructDestructure<'db> {
1175 StatementStructDestructure {
1176 input: self.input.embed(ctx),
1177 outputs: self
1178 .outputs
1179 .into_iter()
1180 .map(|var_id| ctx.lowered_variables_id[var_id])
1181 .collect(),
1182 }
1183 }
1184}
1185
1186#[derive(Serialize, Deserialize)]
1187struct StatementEnumConstructCached {
1188 variant: ConcreteVariantCached,
1189 input: VarUsageCached,
1191 output: usize,
1193}
1194impl StatementEnumConstructCached {
1195 fn new<'db>(stmt: StatementEnumConstruct<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1196 Self {
1197 variant: ConcreteVariantCached::new(stmt.variant, &mut ctx.semantic_ctx),
1198 input: VarUsageCached::new(stmt.input, ctx),
1199 output: stmt.output.index(),
1200 }
1201 }
1202 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementEnumConstruct<'db> {
1203 StatementEnumConstruct {
1204 variant: self.variant.get_embedded(&ctx.semantic_loading_data, ctx.db),
1205 input: self.input.embed(ctx),
1206 output: ctx.lowered_variables_id[self.output],
1207 }
1208 }
1209}
1210
1211#[derive(Serialize, Deserialize)]
1212struct StatementSnapshotCached {
1213 input: VarUsageCached,
1214 outputs: [usize; 2],
1215}
1216impl StatementSnapshotCached {
1217 fn new<'db>(stmt: StatementSnapshot<'db>, _ctx: &mut CacheSavingContext<'db>) -> Self {
1218 Self {
1219 input: VarUsageCached::new(stmt.input, _ctx),
1220 outputs: stmt.outputs.map(|var| var.index()),
1221 }
1222 }
1223 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementSnapshot<'db> {
1224 StatementSnapshot {
1225 input: self.input.embed(ctx),
1226 outputs: [
1227 ctx.lowered_variables_id[self.outputs[0]],
1228 ctx.lowered_variables_id[self.outputs[1]],
1229 ],
1230 }
1231 }
1232}
1233
1234#[derive(Serialize, Deserialize)]
1235struct StatementDesnapCached {
1236 input: VarUsageCached,
1237 output: usize,
1239}
1240impl StatementDesnapCached {
1241 fn new<'db>(stmt: StatementDesnap<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1242 Self { input: VarUsageCached::new(stmt.input, ctx), output: stmt.output.index() }
1243 }
1244 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementDesnap<'db> {
1245 StatementDesnap {
1246 input: self.input.embed(ctx),
1247 output: ctx.lowered_variables_id[self.output],
1248 }
1249 }
1250}
1251
1252#[derive(Serialize, Deserialize)]
1253struct StatementIntoBoxCached {
1254 input: VarUsageCached,
1255 output: usize,
1256}
1257impl StatementIntoBoxCached {
1258 fn new<'db>(stmt: StatementIntoBox<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1259 Self { input: VarUsageCached::new(stmt.input, ctx), output: stmt.output.index() }
1260 }
1261 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementIntoBox<'db> {
1262 StatementIntoBox {
1263 input: self.input.embed(ctx),
1264 output: ctx.lowered_variables_id[self.output],
1265 }
1266 }
1267}
1268
1269#[derive(Serialize, Deserialize)]
1270struct StatementUnboxCached {
1271 input: VarUsageCached,
1272 output: usize,
1273}
1274impl StatementUnboxCached {
1275 fn new<'db>(stmt: StatementUnbox<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1276 Self { input: VarUsageCached::new(stmt.input, ctx), output: stmt.output.index() }
1277 }
1278 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementUnbox<'db> {
1279 StatementUnbox {
1280 input: self.input.embed(ctx),
1281 output: ctx.lowered_variables_id[self.output],
1282 }
1283 }
1284}
1285
1286#[derive(Serialize, Deserialize, Clone)]
1287struct LocationCached {
1288 stable_location: SyntaxStablePtrIdCached,
1290 inline_locations: Vec<SyntaxStablePtrIdCached>,
1292}
1293impl LocationCached {
1294 fn new<'db>(location: Location<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1295 Self {
1296 stable_location: SyntaxStablePtrIdCached::new(
1297 location.stable_location.stable_ptr(),
1298 &mut ctx.semantic_ctx.defs_ctx,
1299 ),
1300 inline_locations: location
1301 .inline_locations
1302 .iter()
1303 .map(|loc| {
1304 SyntaxStablePtrIdCached::new(loc.stable_ptr(), &mut ctx.semantic_ctx.defs_ctx)
1305 })
1306 .collect(),
1307 }
1308 }
1309 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Location<'db> {
1310 Location {
1311 stable_location: StableLocation::new(
1312 self.stable_location.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
1313 ),
1314 inline_locations: self
1315 .inline_locations
1316 .into_iter()
1317 .map(|loc| {
1318 StableLocation::new(
1319 loc.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
1320 )
1321 })
1322 .collect(),
1323 notes: Default::default(),
1324 }
1325 }
1326}
1327
1328#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash)]
1329struct LocationIdCached(usize);
1330
1331impl LocationIdCached {
1332 fn new<'db>(location_id: LocationId<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1333 if let Some(id) = ctx.location_ids.get(&location_id) {
1334 return *id;
1335 }
1336 let location = LocationCached::new(location_id.long(ctx.db).clone(), ctx);
1337 let id = LocationIdCached(ctx.location_ids_lookup.len());
1338 ctx.location_ids_lookup.push(location);
1339 ctx.location_ids.insert(location_id, id);
1340 id
1341 }
1342 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> LocationId<'db> {
1343 if let Some(location_id) = ctx.location_ids.get(&self) {
1344 return *location_id;
1345 }
1346 let location = ctx.location_ids_lookup[self.0].clone();
1347 let location = location.embed(ctx).intern(ctx.db);
1348 ctx.location_ids.insert(self, location);
1349 location
1350 }
1351}