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