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