Skip to main content

cairo_lang_defs/cache/
mod.rs

1use std::hash::{Hash, Hasher};
2use std::ops::{Deref, DerefMut};
3use std::path::PathBuf;
4use std::sync::Arc;
5
6use cairo_lang_diagnostics::{DiagnosticNote, Severity};
7use cairo_lang_filesystem::db::FilesGroup;
8use cairo_lang_filesystem::flag::{Flag, FlagsGroup};
9use cairo_lang_filesystem::ids::{
10    CodeMapping, CrateId, CrateLongId, FileId, FileKind, FileLongId, SmolStrId, SpanInFile,
11    VirtualFile,
12};
13use cairo_lang_filesystem::span::{TextSpan, TextWidth};
14use cairo_lang_parser::db::ParserGroup;
15use cairo_lang_syntax::node::ast::{
16    FunctionWithBodyPtr, GenericParamPtr, ItemConstantPtr, ItemEnumPtr, ItemExternFunctionPtr,
17    ItemExternTypePtr, ItemImplAliasPtr, ItemImplPtr, ItemInlineMacroPtr, ItemMacroDeclarationPtr,
18    ItemModulePtr, ItemStructPtr, ItemTraitPtr, ItemTypeAliasPtr, UsePathLeafPtr, UsePathStarPtr,
19};
20use cairo_lang_syntax::node::green::{GreenNode, GreenNodeDetails};
21use cairo_lang_syntax::node::ids::{GreenId, SyntaxStablePtrId};
22use cairo_lang_syntax::node::kind::SyntaxKind;
23use cairo_lang_syntax::node::{SyntaxNode, SyntaxNodeId, TypedSyntaxNode, ast};
24use cairo_lang_utils::Intern;
25use cairo_lang_utils::ordered_hash_map::{Entry, OrderedHashMap};
26use salsa::Database;
27use serde::{Deserialize, Serialize};
28use thiserror::Error;
29
30use crate::db::{
31    ModuleData, ModuleDataCacheAndLoadingData, ModuleFilesData, ModuleNamedItemsData,
32    ModuleTypesData, ModuleUnnamedItemsData,
33};
34use crate::ids::{
35    ConstantId, ConstantLongId, EnumId, EnumLongId, ExternFunctionId, ExternFunctionLongId,
36    ExternTypeId, ExternTypeLongId, FreeFunctionId, FreeFunctionLongId, GenericParamId,
37    GenericParamLongId, GlobalUseId, GlobalUseLongId, ImplAliasId, ImplAliasLongId, ImplDefId,
38    ImplDefLongId, LanguageElementId, MacroCallId, MacroCallLongId, MacroDeclarationId,
39    MacroDeclarationLongId, ModuleId, ModuleItemId, ModuleTypeAliasId, ModuleTypeAliasLongId,
40    PluginGeneratedFileId, PluginGeneratedFileLongId, StructId, StructLongId, SubmoduleId,
41    SubmoduleLongId, TraitId, TraitLongId, UseId, UseLongId,
42};
43use crate::plugin::{DynGeneratedFileAuxData, PluginDiagnostic};
44
45/// The index of the `external` section in a crate cache blob.
46pub const EXTERNAL_CACHE_SECTION: u8 = 0;
47
48/// The index of the `def` section in a crate cache blob.
49pub const DEF_CACHE_SECTION: u8 = EXTERNAL_CACHE_SECTION + 1;
50
51/// Metadata for a cached crate.
52#[derive(Serialize, Deserialize)]
53pub struct CachedCrateMetadata {
54    /// Hash of the settings the crate was compiled with.
55    pub settings: Option<u64>,
56    /// The version of the compiler that compiled the crate.
57    pub compiler_version: String,
58    /// The global flags the crate was compiled with.
59    pub global_flags: OrderedHashMap<String, Flag>,
60}
61
62impl CachedCrateMetadata {
63    /// Creates a new [CachedCrateMetadata] from the input crate with the current settings.
64    pub fn new(crate_id: CrateId<'_>, db: &dyn Database) -> Self {
65        let settings = db.crate_config(crate_id).map(|config| &config.settings).map(|v| {
66            let mut hasher = xxhash_rust::xxh3::Xxh3::default();
67            v.hash(&mut hasher);
68            hasher.finish()
69        });
70        let compiler_version = env!("CARGO_PKG_VERSION").to_string();
71        let global_flags =
72            db.flags().iter().map(|(flag_id, flag)| (flag_id.long(db).0.clone(), *flag)).collect();
73        Self { settings, compiler_version, global_flags }
74    }
75}
76
77/// Validates that the metadata of the cached crate is valid.
78fn validate_metadata(crate_id: CrateId<'_>, metadata: &CachedCrateMetadata, db: &dyn Database) {
79    let current_metadata = CachedCrateMetadata::new(crate_id, db);
80
81    if current_metadata.compiler_version != metadata.compiler_version {
82        panic!("Cached crate was compiled with a different compiler version.");
83    }
84    if current_metadata.settings != metadata.settings {
85        panic!("Cached crate was compiled with different settings.");
86    }
87
88    if !current_metadata.global_flags.eq_unordered(&metadata.global_flags) {
89        panic!("Cached crate was compiled with different global flags.");
90    }
91}
92
93type DefCache<'db> = (CachedCrateMetadata, CrateDefCache<'db>, DefCacheLookups);
94
95/// Load the cached lowering of a crate if it has a cache file configuration.
96pub fn load_cached_crate_modules<'db>(
97    db: &'db dyn Database,
98    crate_id: CrateId<'db>,
99) -> Option<ModuleDataCacheAndLoadingData<'db>> {
100    let blob_id = db.crate_config(crate_id)?.cache_file?;
101    let Some(content) = db.blob_content(blob_id) else {
102        return Default::default();
103    };
104
105    let (metadata, module_data, defs_lookups): DefCache<'_> =
106        CacheBlobReader::read_section(db, content, DEF_CACHE_SECTION, crate_id);
107
108    validate_metadata(crate_id, &metadata, db);
109
110    let mut ctx = DefCacheLoadingContext::new(db, defs_lookups, crate_id);
111    Some((
112        module_data
113            .0
114            .into_iter()
115            .map(|(module_id, module_data)| {
116                let module_id = module_id.embed(&mut ctx);
117
118                let module_data = module_data.embed(&mut ctx);
119                (module_id, module_data)
120            })
121            .collect::<OrderedHashMap<_, _>>()
122            .into(),
123        ctx.data.into(),
124    ))
125}
126
127/// An error produced while encoding or decoding a crate cache blob.
128#[derive(Debug, Error)]
129pub enum CacheError {
130    #[error("Cache encoding/decoding failed: {0}")]
131    Postcard(#[from] postcard::Error),
132}
133
134/// Serializes `section` and appends it to a cache blob as one length-prefixed section: a big-endian
135/// `u64` byte length followed by the payload. Sections are read back in write order by
136/// [`CacheBlobReader`].
137pub fn write_cache_section<T: Serialize>(
138    blob: &mut Vec<u8>,
139    section: &T,
140) -> Result<(), CacheError> {
141    let section = postcard::to_allocvec(section)?;
142    blob.extend(section.len().to_be_bytes());
143    blob.extend(section);
144    Ok(())
145}
146
147/// A cursor over the length-prefixed sections of a crate cache blob (see [`write_cache_section`]).
148///
149/// A blob is a sequence of sections in the order `[external, def, semantic, lowering]`; each
150/// consumer advances past the sections preceding the one it needs with [`Self::next_section`].
151/// Use [`Self::read_section`] to read and parse a specific section only.
152/// Each section should have its index as a const in the cache mod, see [`EXTERNAL_CACHE_SECTION`]
153/// et al.
154#[derive(Debug, Clone, Copy)]
155pub struct CacheBlobReader<'a> {
156    content: &'a [u8],
157}
158
159impl<'a> CacheBlobReader<'a> {
160    pub fn new(content: &'a [u8]) -> Self {
161        Self { content }
162    }
163
164    /// Returns the next section's payload and advances the cursor past it. Panics if the blob is
165    /// truncated mid-section.
166    pub fn next_section(&mut self) -> &'a [u8] {
167        let size = usize::from_be_bytes(
168            self.content
169                .get(..8)
170                .unwrap_or_else(|| panic!("cache blob is truncated"))
171                .try_into()
172                .unwrap(),
173        );
174        let section =
175            self.content.get(8..8 + size).unwrap_or_else(|| panic!("cache blob is truncated"));
176        self.content = &self.content[8 + size..];
177        section
178    }
179
180    /// Returns the section's parse to T result. Panics if the
181    /// blob is truncated mid-section.
182    pub fn read_section<'db, T: for<'b> Deserialize<'b>>(
183        db: &'db dyn Database,
184        content: &'a [u8],
185        section: u8,
186        crate_id: CrateId<'db>,
187    ) -> T {
188        let mut reader = CacheBlobReader::new(content);
189        for _ in 0..section {
190            reader.next_section();
191        }
192        let content = reader.next_section();
193        postcard::from_bytes(content).unwrap_or_else(|e| {
194            panic!(
195                "failed to deserialize cache section {section} for crate `{}`: {e}",
196                crate_id.long(db).name().long(db),
197            )
198        })
199    }
200}
201
202#[derive(Serialize, Deserialize)]
203pub struct CrateDefCache<'db>(Vec<(ModuleIdCached, ModuleDataCached<'db>)>);
204
205impl<'db> CrateDefCache<'db> {
206    pub fn new(modules: Vec<(ModuleIdCached, ModuleDataCached<'db>)>) -> Self {
207        Self(modules)
208    }
209}
210
211/// Context for loading cache into the database.
212struct DefCacheLoadingContext<'db> {
213    /// The variable ids of the flat lowered that is currently being loaded.
214    db: &'db dyn Database,
215
216    /// data for loading the entire cache into the database.
217    data: DefCacheLoadingData<'db>,
218}
219
220impl<'db> DefCacheLoadingContext<'db> {
221    pub fn new(
222        db: &'db dyn Database,
223        lookups: DefCacheLookups,
224        self_crate_id: CrateId<'db>,
225    ) -> Self {
226        let mut res = Self { db, data: DefCacheLoadingData::new(lookups, self_crate_id) };
227        res.embed_lookups();
228        res
229    }
230    fn embed_lookups(&mut self) {
231        for id in 0..self.lookups.green_ids_lookup.len() {
232            let id = GreenIdCached(id);
233            let embed = id.embed(self);
234            self.reverse_green_ids.insert(embed, id);
235        }
236        for id in 0..self.lookups.crate_ids_lookup.len() {
237            CrateIdCached::Other(id).embed(self);
238        }
239        for id in 0..self.lookups.file_ids_lookup.len() {
240            FileIdCached(id).embed(self);
241        }
242
243        for id in 0..self.lookups.syntax_node_lookup.len() {
244            SyntaxNodeCached(id).embed(self);
245        }
246
247        for id in 0..self.lookups.submodule_ids_lookup.len() {
248            SubmoduleIdCached(id).embed(self);
249        }
250        for id in 0..self.lookups.constant_ids_lookup.len() {
251            ConstantIdCached(id).embed(self);
252        }
253        for id in 0..self.lookups.use_ids_lookup.len() {
254            UseIdCached(id).embed(self);
255        }
256        for id in 0..self.lookups.free_function_ids_lookup.len() {
257            FreeFunctionIdCached(id).embed(self);
258        }
259        for id in 0..self.lookups.struct_ids_lookup.len() {
260            StructIdCached(id).embed(self);
261        }
262        for id in 0..self.lookups.enum_ids_lookup.len() {
263            EnumIdCached(id).embed(self);
264        }
265        for id in 0..self.lookups.type_alias_ids_lookup.len() {
266            ModuleTypeAliasIdCached(id).embed(self);
267        }
268        for id in 0..self.lookups.impl_alias_ids_lookup.len() {
269            ImplAliasIdCached(id).embed(self);
270        }
271        for id in 0..self.lookups.trait_ids_lookup.len() {
272            TraitIdCached(id).embed(self);
273        }
274        for id in 0..self.lookups.impl_def_ids_lookup.len() {
275            ImplDefIdCached(id).embed(self);
276        }
277        for id in 0..self.lookups.extern_type_ids_lookup.len() {
278            ExternTypeIdCached(id).embed(self);
279        }
280        for id in 0..self.lookups.extern_function_ids_lookup.len() {
281            ExternFunctionIdCached(id).embed(self);
282        }
283        for id in 0..self.lookups.global_use_ids_lookup.len() {
284            GlobalUseIdCached(id).embed(self);
285        }
286    }
287}
288
289impl<'db> Deref for DefCacheLoadingContext<'db> {
290    type Target = DefCacheLoadingData<'db>;
291
292    fn deref(&self) -> &Self::Target {
293        &self.data
294    }
295}
296impl DerefMut for DefCacheLoadingContext<'_> {
297    fn deref_mut(&mut self) -> &mut Self::Target {
298        &mut self.data
299    }
300}
301
302/// Data for loading cache into the database.
303#[derive(PartialEq, Eq, salsa::Update)]
304pub struct DefCacheLoadingData<'db> {
305    green_ids: OrderedHashMap<GreenIdCached, GreenId<'db>>,
306    reverse_green_ids: OrderedHashMap<GreenId<'db>, GreenIdCached>,
307    crate_ids: OrderedHashMap<CrateIdCached, CrateId<'db>>,
308    reverse_syntax_node_lookup: OrderedHashMap<SyntaxNodeIdCached, SyntaxNodeCached>,
309    syntax_nodes: OrderedHashMap<SyntaxNodeCached, SyntaxNode<'db>>,
310    submodule_ids: OrderedHashMap<SubmoduleIdCached, SubmoduleId<'db>>,
311    constant_ids: OrderedHashMap<ConstantIdCached, ConstantId<'db>>,
312    use_ids: OrderedHashMap<UseIdCached, UseId<'db>>,
313    free_function_ids: OrderedHashMap<FreeFunctionIdCached, FreeFunctionId<'db>>,
314    struct_ids: OrderedHashMap<StructIdCached, StructId<'db>>,
315    enum_ids: OrderedHashMap<EnumIdCached, EnumId<'db>>,
316    type_alias_ids: OrderedHashMap<ModuleTypeAliasIdCached, ModuleTypeAliasId<'db>>,
317    impl_alias_ids: OrderedHashMap<ImplAliasIdCached, ImplAliasId<'db>>,
318    trait_ids: OrderedHashMap<TraitIdCached, TraitId<'db>>,
319    impl_def_ids: OrderedHashMap<ImplDefIdCached, ImplDefId<'db>>,
320    extern_type_ids: OrderedHashMap<ExternTypeIdCached, ExternTypeId<'db>>,
321    extern_function_ids: OrderedHashMap<ExternFunctionIdCached, ExternFunctionId<'db>>,
322    macro_declaration_ids: OrderedHashMap<MacroDeclarationIdCached, MacroDeclarationId<'db>>,
323    macro_call_ids: OrderedHashMap<MacroCallIdCached, MacroCallId<'db>>,
324    global_use_ids: OrderedHashMap<GlobalUseIdCached, GlobalUseId<'db>>,
325
326    file_ids: OrderedHashMap<FileIdCached, FileId<'db>>,
327    self_crate_id: CrateId<'db>,
328    lookups: DefCacheLookups,
329}
330
331impl<'db> DefCacheLoadingData<'db> {
332    fn new(lookups: DefCacheLookups, self_crate_id: CrateId<'db>) -> Self {
333        Self {
334            green_ids: OrderedHashMap::default(),
335            reverse_green_ids: OrderedHashMap::default(),
336            reverse_syntax_node_lookup: lookups
337                .syntax_node_lookup
338                .iter()
339                .enumerate()
340                .map(|(index, syntax_node)| (syntax_node.clone(), SyntaxNodeCached(index)))
341                .collect(),
342            syntax_nodes: OrderedHashMap::default(),
343            crate_ids: OrderedHashMap::default(),
344            submodule_ids: OrderedHashMap::default(),
345            constant_ids: OrderedHashMap::default(),
346            use_ids: OrderedHashMap::default(),
347            free_function_ids: OrderedHashMap::default(),
348            struct_ids: OrderedHashMap::default(),
349            enum_ids: OrderedHashMap::default(),
350            type_alias_ids: OrderedHashMap::default(),
351            impl_alias_ids: OrderedHashMap::default(),
352            trait_ids: OrderedHashMap::default(),
353            impl_def_ids: OrderedHashMap::default(),
354            extern_type_ids: OrderedHashMap::default(),
355            extern_function_ids: OrderedHashMap::default(),
356            macro_declaration_ids: OrderedHashMap::default(),
357            macro_call_ids: OrderedHashMap::default(),
358            global_use_ids: OrderedHashMap::default(),
359
360            file_ids: OrderedHashMap::default(),
361            self_crate_id,
362            lookups,
363        }
364    }
365}
366
367impl<'db> std::fmt::Debug for DefCacheLoadingData<'db> {
368    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
369        f.debug_struct("DefCacheLoadingData").finish()
370    }
371}
372
373impl<'db> Deref for DefCacheLoadingData<'db> {
374    type Target = DefCacheLookups;
375
376    fn deref(&self) -> &Self::Target {
377        &self.lookups
378    }
379}
380impl<'db> DerefMut for DefCacheLoadingData<'db> {
381    fn deref_mut(&mut self) -> &mut Self::Target {
382        &mut self.lookups
383    }
384}
385
386/// Context for saving cache from the database.
387pub struct DefCacheSavingContext<'db> {
388    db: &'db dyn Database,
389    data: DefCacheSavingData<'db>,
390    self_crate_id: CrateId<'db>,
391}
392impl<'db> Deref for DefCacheSavingContext<'db> {
393    type Target = DefCacheSavingData<'db>;
394
395    fn deref(&self) -> &Self::Target {
396        &self.data
397    }
398}
399impl DerefMut for DefCacheSavingContext<'_> {
400    fn deref_mut(&mut self) -> &mut Self::Target {
401        &mut self.data
402    }
403}
404impl<'db> DefCacheSavingContext<'db> {
405    pub fn new(db: &'db dyn Database, self_crate_id: CrateId<'db>) -> Self {
406        Self { db, data: DefCacheSavingData::default(), self_crate_id }
407    }
408
409    /// The external-file content table, written as its own blob section (read back by the
410    /// `external_file_contents` query).
411    pub fn external_file_contents(
412        &self,
413    ) -> &OrderedHashMap<ExternalFileKey, ExternalFileContentCached> {
414        &self.data.external_file_contents
415    }
416}
417
418/// Data for saving cache from the database.
419#[derive(Default)]
420pub struct DefCacheSavingData<'db> {
421    green_ids: OrderedHashMap<GreenId<'db>, GreenIdCached>,
422    crate_ids: OrderedHashMap<CrateId<'db>, CrateIdCached>,
423    submodule_ids: OrderedHashMap<SubmoduleId<'db>, SubmoduleIdCached>,
424    constant_ids: OrderedHashMap<ConstantId<'db>, ConstantIdCached>,
425    use_ids: OrderedHashMap<UseId<'db>, UseIdCached>,
426    free_function_ids: OrderedHashMap<FreeFunctionId<'db>, FreeFunctionIdCached>,
427    struct_ids: OrderedHashMap<StructId<'db>, StructIdCached>,
428    enum_ids: OrderedHashMap<EnumId<'db>, EnumIdCached>,
429    type_alias_ids: OrderedHashMap<ModuleTypeAliasId<'db>, ModuleTypeAliasIdCached>,
430    impl_alias_ids: OrderedHashMap<ImplAliasId<'db>, ImplAliasIdCached>,
431    trait_ids: OrderedHashMap<TraitId<'db>, TraitIdCached>,
432    impl_def_ids: OrderedHashMap<ImplDefId<'db>, ImplDefIdCached>,
433    extern_type_ids: OrderedHashMap<ExternTypeId<'db>, ExternTypeIdCached>,
434    extern_function_ids: OrderedHashMap<ExternFunctionId<'db>, ExternFunctionIdCached>,
435    global_use_ids: OrderedHashMap<GlobalUseId<'db>, GlobalUseIdCached>,
436    macro_declaration_ids: OrderedHashMap<MacroDeclarationId<'db>, MacroDeclarationIdCached>,
437    macro_call_ids: OrderedHashMap<MacroCallId<'db>, MacroCallIdCached>,
438
439    syntax_nodes: OrderedHashMap<SyntaxNode<'db>, SyntaxNodeCached>,
440    file_ids: OrderedHashMap<FileId<'db>, FileIdCached>,
441
442    /// External (plugin-generated) file content, written as its own blob section in cache.
443    external_file_contents: OrderedHashMap<ExternalFileKey, ExternalFileContentCached>,
444
445    pub lookups: DefCacheLookups,
446}
447
448impl<'db> Deref for DefCacheSavingData<'db> {
449    type Target = DefCacheLookups;
450
451    fn deref(&self) -> &Self::Target {
452        &self.lookups
453    }
454}
455impl<'db> DerefMut for DefCacheSavingData<'db> {
456    fn deref_mut(&mut self) -> &mut Self::Target {
457        &mut self.lookups
458    }
459}
460
461#[derive(Serialize, Deserialize)]
462pub struct ModuleDataCached<'db> {
463    items: Vec<ModuleItemIdCached>,
464
465    constants: OrderedHashMap<ConstantIdCached, TypeSyntaxNodeCached<'db, ast::ItemConstant<'db>>>,
466    submodules: OrderedHashMap<SubmoduleIdCached, TypeSyntaxNodeCached<'db, ast::ItemModule<'db>>>,
467    uses: OrderedHashMap<UseIdCached, TypeSyntaxNodeCached<'db, ast::UsePathLeaf<'db>>>,
468    free_functions:
469        OrderedHashMap<FreeFunctionIdCached, TypeSyntaxNodeCached<'db, ast::FunctionWithBody<'db>>>,
470    structs: OrderedHashMap<StructIdCached, TypeSyntaxNodeCached<'db, ast::ItemStruct<'db>>>,
471    enums: OrderedHashMap<EnumIdCached, TypeSyntaxNodeCached<'db, ast::ItemEnum<'db>>>,
472    type_aliases:
473        OrderedHashMap<ModuleTypeAliasIdCached, TypeSyntaxNodeCached<'db, ast::ItemTypeAlias<'db>>>,
474    impl_aliases:
475        OrderedHashMap<ImplAliasIdCached, TypeSyntaxNodeCached<'db, ast::ItemImplAlias<'db>>>,
476    traits: OrderedHashMap<TraitIdCached, TypeSyntaxNodeCached<'db, ast::ItemTrait<'db>>>,
477    impls: OrderedHashMap<ImplDefIdCached, TypeSyntaxNodeCached<'db, ast::ItemImpl<'db>>>,
478    extern_types:
479        OrderedHashMap<ExternTypeIdCached, TypeSyntaxNodeCached<'db, ast::ItemExternType<'db>>>,
480    extern_functions: OrderedHashMap<
481        ExternFunctionIdCached,
482        TypeSyntaxNodeCached<'db, ast::ItemExternFunction<'db>>,
483    >,
484    macro_declarations: OrderedHashMap<
485        MacroDeclarationIdCached,
486        TypeSyntaxNodeCached<'db, ast::ItemMacroDeclaration<'db>>,
487    >,
488    global_uses:
489        OrderedHashMap<GlobalUseIdCached, TypeSyntaxNodeCached<'db, ast::UsePathStar<'db>>>,
490    macro_calls:
491        OrderedHashMap<MacroCallIdCached, TypeSyntaxNodeCached<'db, ast::ItemInlineMacro<'db>>>,
492
493    files: Vec<FileIdCached>,
494
495    generated_file_aux_data: OrderedHashMap<FileIdCached, Option<DynGeneratedFileAuxData>>,
496    plugin_diagnostics: Vec<(ModuleIdCached, PluginDiagnosticCached)>,
497    diagnostics_notes: PluginFileDiagnosticNotesCached,
498}
499impl<'db> ModuleDataCached<'db> {
500    pub fn new(
501        db: &'db dyn Database,
502        module_data: ModuleData<'db>,
503        ctx: &mut DefCacheSavingContext<'db>,
504    ) -> Self {
505        Self {
506            items: module_data
507                .items(db)
508                .iter()
509                .map(|id| ModuleItemIdCached::new(*id, ctx))
510                .collect(),
511            constants: module_data
512                .constants(db)
513                .iter()
514                .map(|(id, node)| {
515                    (ConstantIdCached::new(*id, ctx), TypeSyntaxNodeCached::new(node.clone(), ctx))
516                })
517                .collect(),
518
519            submodules: module_data
520                .submodules(db)
521                .iter()
522                .map(|(id, node)| {
523                    (SubmoduleIdCached::new(*id, ctx), TypeSyntaxNodeCached::new(node.clone(), ctx))
524                })
525                .collect(),
526
527            uses: module_data
528                .uses(db)
529                .iter()
530                .map(|(id, node)| {
531                    (UseIdCached::new(*id, ctx), TypeSyntaxNodeCached::new(node.clone(), ctx))
532                })
533                .collect(),
534            free_functions: module_data
535                .free_functions(db)
536                .iter()
537                .map(|(id, node)| {
538                    (
539                        FreeFunctionIdCached::new(*id, ctx),
540                        TypeSyntaxNodeCached::new(node.clone(), ctx),
541                    )
542                })
543                .collect(),
544            structs: module_data
545                .structs(db)
546                .iter()
547                .map(|(id, node)| {
548                    (StructIdCached::new(*id, ctx), TypeSyntaxNodeCached::new(node.clone(), ctx))
549                })
550                .collect(),
551            enums: module_data
552                .enums(db)
553                .iter()
554                .map(|(id, node)| {
555                    (EnumIdCached::new(*id, ctx), TypeSyntaxNodeCached::new(node.clone(), ctx))
556                })
557                .collect(),
558            type_aliases: module_data
559                .type_aliases(db)
560                .iter()
561                .map(|(id, node)| {
562                    (
563                        ModuleTypeAliasIdCached::new(*id, ctx),
564                        TypeSyntaxNodeCached::new(node.clone(), ctx),
565                    )
566                })
567                .collect(),
568            impl_aliases: module_data
569                .impl_aliases(db)
570                .iter()
571                .map(|(id, node)| {
572                    (ImplAliasIdCached::new(*id, ctx), TypeSyntaxNodeCached::new(node.clone(), ctx))
573                })
574                .collect(),
575            traits: module_data
576                .traits(db)
577                .iter()
578                .map(|(id, node)| {
579                    (TraitIdCached::new(*id, ctx), TypeSyntaxNodeCached::new(node.clone(), ctx))
580                })
581                .collect(),
582            impls: module_data
583                .impls(db)
584                .iter()
585                .map(|(id, node)| {
586                    (ImplDefIdCached::new(*id, ctx), TypeSyntaxNodeCached::new(node.clone(), ctx))
587                })
588                .collect(),
589            extern_types: module_data
590                .extern_types(db)
591                .iter()
592                .map(|(id, node)| {
593                    (
594                        ExternTypeIdCached::new(*id, ctx),
595                        TypeSyntaxNodeCached::new(node.clone(), ctx),
596                    )
597                })
598                .collect(),
599            extern_functions: module_data
600                .extern_functions(db)
601                .iter()
602                .map(|(id, node)| {
603                    (
604                        ExternFunctionIdCached::new(*id, ctx),
605                        TypeSyntaxNodeCached::new(node.clone(), ctx),
606                    )
607                })
608                .collect(),
609
610            macro_declarations: module_data
611                .macro_declarations(db)
612                .iter()
613                .map(|(id, node)| {
614                    (
615                        MacroDeclarationIdCached::new(*id, ctx),
616                        TypeSyntaxNodeCached::new(node.clone(), ctx),
617                    )
618                })
619                .collect(),
620            global_uses: module_data
621                .global_uses(db)
622                .iter()
623                .map(|(id, node)| {
624                    (GlobalUseIdCached::new(*id, ctx), TypeSyntaxNodeCached::new(node.clone(), ctx))
625                })
626                .collect(),
627            macro_calls: module_data
628                .macro_calls(db)
629                .iter()
630                .map(|(id, node)| {
631                    (MacroCallIdCached::new(*id, ctx), TypeSyntaxNodeCached::new(node.clone(), ctx))
632                })
633                .collect(),
634            files: module_data.files(db).iter().map(|id| FileIdCached::new(*id, ctx)).collect(),
635            generated_file_aux_data: module_data
636                .generated_file_aux_data(db)
637                .iter()
638                .map(|(file, aux_data)| (FileIdCached::new(*file, ctx), aux_data.clone()))
639                .collect(),
640
641            plugin_diagnostics: module_data
642                .plugin_diagnostics(db)
643                .iter()
644                .map(|(file_id, diagnostic)| {
645                    (
646                        ModuleIdCached::new(*file_id, ctx),
647                        PluginDiagnosticCached::new(diagnostic, ctx),
648                    )
649                })
650                .collect(),
651            diagnostics_notes: module_data
652                .diagnostics_notes(db)
653                .iter()
654                .map(|(file_id, note)| {
655                    (FileIdCached::new(*file_id, ctx), DiagnosticNoteCached::new(note.clone(), ctx))
656                })
657                .collect(),
658        }
659    }
660    fn embed(self, ctx: &mut DefCacheLoadingContext<'db>) -> ModuleData<'db> {
661        ModuleData::new(
662            ctx.db,
663            self.items.iter().map(|id| id.embed(ctx)).collect(),
664            ModuleTypesData::new(
665                ctx.db,
666                self.structs.iter().map(|(id, node)| (id.embed(ctx), node.embed(ctx))).collect(),
667                self.enums.iter().map(|(id, node)| (id.embed(ctx), node.embed(ctx))).collect(),
668                self.type_aliases
669                    .iter()
670                    .map(|(id, node)| (id.embed(ctx), node.embed(ctx)))
671                    .collect(),
672                self.extern_types
673                    .iter()
674                    .map(|(id, node)| (id.embed(ctx), node.embed(ctx)))
675                    .collect(),
676            ),
677            ModuleNamedItemsData::new(
678                ctx.db,
679                self.constants.iter().map(|(id, node)| (id.embed(ctx), node.embed(ctx))).collect(),
680                self.submodules.iter().map(|(id, node)| (id.embed(ctx), node.embed(ctx))).collect(),
681                self.uses.iter().map(|(id, node)| (id.embed(ctx), node.embed(ctx))).collect(),
682                self.free_functions
683                    .iter()
684                    .map(|(id, node)| (id.embed(ctx), node.embed(ctx)))
685                    .collect(),
686                self.impl_aliases
687                    .iter()
688                    .map(|(id, node)| (id.embed(ctx), node.embed(ctx)))
689                    .collect(),
690                self.traits.iter().map(|(id, node)| (id.embed(ctx), node.embed(ctx))).collect(),
691                self.impls.iter().map(|(id, node)| (id.embed(ctx), node.embed(ctx))).collect(),
692                self.extern_functions
693                    .iter()
694                    .map(|(id, node)| (id.embed(ctx), node.embed(ctx)))
695                    .collect(),
696                self.macro_declarations
697                    .iter()
698                    .map(|(id, node)| (id.embed(ctx), node.embed(ctx)))
699                    .collect(),
700            ),
701            ModuleUnnamedItemsData::new(
702                ctx.db,
703                self.global_uses
704                    .iter()
705                    .map(|(id, node)| (id.embed(ctx), node.embed(ctx)))
706                    .collect(),
707                self.macro_calls
708                    .iter()
709                    .map(|(id, node)| (id.embed(ctx), node.embed(ctx)))
710                    .collect(),
711            ),
712            ModuleFilesData::new(
713                ctx.db,
714                self.files.iter().map(|id| id.embed(ctx)).collect(),
715                self.generated_file_aux_data
716                    .into_iter()
717                    .map(|(file, aux_data)| (file.embed(ctx), aux_data))
718                    .collect(),
719                self.plugin_diagnostics
720                    .into_iter()
721                    .map(|(file_id, diagnostic)| (file_id.embed(ctx), diagnostic.embed(ctx)))
722                    .collect(),
723                self.diagnostics_notes
724                    .into_iter()
725                    .map(|(file_id, note)| (file_id.embed(ctx), note.embed(ctx)))
726                    .collect(),
727            ),
728        )
729    }
730}
731
732/// Saved interned items for the cache.
733#[derive(Serialize, Deserialize, Default, PartialEq, Eq, salsa::Update)]
734pub struct DefCacheLookups {
735    green_ids_lookup: Vec<GreenNodeCached>,
736    crate_ids_lookup: Vec<CrateCached>,
737    submodule_ids_lookup: Vec<SubmoduleCached>,
738    constant_ids_lookup: Vec<ConstantCached>,
739    use_ids_lookup: Vec<UseCached>,
740    free_function_ids_lookup: Vec<FreeFunctionCached>,
741    struct_ids_lookup: Vec<StructCached>,
742    enum_ids_lookup: Vec<EnumCached>,
743    type_alias_ids_lookup: Vec<ModuleTypeAliasCached>,
744    impl_alias_ids_lookup: Vec<ImplAliasCached>,
745    trait_ids_lookup: Vec<TraitCached>,
746    impl_def_ids_lookup: Vec<ImplDefCached>,
747    extern_type_ids_lookup: Vec<ExternTypeCached>,
748    extern_function_ids_lookup: Vec<ExternFunctionCached>,
749    global_use_ids_lookup: Vec<GlobalUseCached>,
750    macro_declaration_ids_lookup: Vec<MacroDeclarationCached>,
751    macro_call_ids_lookup: Vec<MacroCallCached>,
752
753    syntax_node_lookup: Vec<SyntaxNodeIdCached>,
754    file_ids_lookup: Vec<FileCached>,
755}
756
757#[derive(Serialize, Deserialize, Clone)]
758struct TypeSyntaxNodeCached<'db, T: TypedSyntaxNode<'db>> {
759    syntax_node: SyntaxNodeCached,
760    _marker: std::marker::PhantomData<&'db T>,
761}
762impl<'db, T: TypedSyntaxNode<'db>> TypeSyntaxNodeCached<'db, T> {
763    fn new(syntax_node: T, ctx: &mut DefCacheSavingContext<'db>) -> Self {
764        Self {
765            syntax_node: SyntaxNodeCached::new(syntax_node.as_syntax_node(), ctx),
766            _marker: std::marker::PhantomData,
767        }
768    }
769    fn embed(&self, ctx: &mut DefCacheLoadingContext<'db>) -> T {
770        T::from_syntax_node(ctx.db, self.syntax_node.embed(ctx))
771    }
772}
773
774#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
775pub struct GenericParamCached {
776    language_element: LanguageElementCached,
777}
778impl GenericParamCached {
779    pub fn new<'db>(
780        generic_param_id: GenericParamId<'db>,
781        ctx: &mut DefCacheSavingContext<'db>,
782    ) -> Self {
783        Self { language_element: LanguageElementCached::new(generic_param_id, ctx) }
784    }
785
786    pub fn get_embedded<'db>(
787        self,
788        data: &Arc<DefCacheLoadingData<'db>>,
789        db: &'db dyn Database,
790    ) -> GenericParamId<'db> {
791        let (module_id, stable_ptr) = self.language_element.get_embedded(data);
792        GenericParamLongId(module_id, GenericParamPtr(stable_ptr)).intern(db)
793    }
794}
795
796#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq)]
797pub enum ModuleIdCached {
798    CrateRoot(CrateIdCached),
799    Submodule(SubmoduleIdCached),
800    MacroCall { id: MacroCallIdCached, generated_file_id: FileIdCached, is_expose: bool },
801}
802impl ModuleIdCached {
803    pub fn new<'db>(module_id: ModuleId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
804        match module_id {
805            ModuleId::CrateRoot(crate_id) => {
806                ModuleIdCached::CrateRoot(CrateIdCached::new(crate_id, ctx))
807            }
808            ModuleId::Submodule(submodule_id) => {
809                ModuleIdCached::Submodule(SubmoduleIdCached::new(submodule_id, ctx))
810            }
811            ModuleId::MacroCall { id, generated_file_id, is_expose } => ModuleIdCached::MacroCall {
812                id: MacroCallIdCached::new(id, ctx),
813                generated_file_id: FileIdCached::new(generated_file_id, ctx),
814                is_expose,
815            },
816        }
817    }
818    fn embed<'db>(&self, ctx: &mut DefCacheLoadingContext<'db>) -> ModuleId<'db> {
819        match self {
820            ModuleIdCached::CrateRoot(crate_id) => ModuleId::CrateRoot(crate_id.embed(ctx)),
821            ModuleIdCached::Submodule(submodule_id) => ModuleId::Submodule(submodule_id.embed(ctx)),
822            ModuleIdCached::MacroCall { id, generated_file_id, is_expose } => ModuleId::MacroCall {
823                id: id.embed(ctx),
824                generated_file_id: generated_file_id.embed(ctx),
825                is_expose: *is_expose,
826            },
827        }
828    }
829    pub fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> ModuleId<'db> {
830        match self {
831            ModuleIdCached::CrateRoot(crate_id) => ModuleId::CrateRoot(crate_id.get_embedded(data)),
832            ModuleIdCached::Submodule(submodule_id) => {
833                ModuleId::Submodule(submodule_id.get_embedded(data))
834            }
835            ModuleIdCached::MacroCall { id, generated_file_id, is_expose } => ModuleId::MacroCall {
836                id: id.get_embedded(data),
837                generated_file_id: generated_file_id.get_embedded(data),
838                is_expose,
839            },
840        }
841    }
842}
843
844#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
845enum CrateCached {
846    Real { name: String, discriminator: Option<String> },
847    Virtual { name: String, file_id: FileIdCached, settings: String },
848}
849impl CrateCached {
850    fn new<'db>(crate_id: CrateLongId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
851        match crate_id {
852            CrateLongId::Real { name, discriminator } => {
853                CrateCached::Real { name: name.to_string(ctx.db), discriminator }
854            }
855            CrateLongId::Virtual { name, file_id, settings, cache_file: _ } => {
856                CrateCached::Virtual {
857                    name: name.to_string(ctx.db),
858                    file_id: FileIdCached::new(file_id, ctx),
859                    settings,
860                }
861            }
862        }
863    }
864    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> CrateLongId<'db> {
865        match self {
866            CrateCached::Real { name, discriminator } => {
867                CrateLongId::Real { name: SmolStrId::from(ctx.db, name), discriminator }
868            }
869            CrateCached::Virtual { name, file_id, settings } => {
870                CrateLongId::Virtual {
871                    name: SmolStrId::from(ctx.db, name),
872                    file_id: file_id.embed(ctx),
873                    settings,
874                    cache_file: None, // todo: if two virtual crates are supported
875                }
876            }
877        }
878    }
879}
880#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
881pub enum CrateIdCached {
882    SelfCrate,
883    Other(usize),
884}
885impl CrateIdCached {
886    fn new<'db>(crate_id: CrateId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
887        if crate_id == ctx.self_crate_id {
888            return CrateIdCached::SelfCrate;
889        }
890        if let Some(id) = ctx.crate_ids.get(&crate_id) {
891            return *id;
892        }
893        let crate_long_id = CrateCached::new(crate_id.long(ctx.db).clone(), ctx);
894        let id = CrateIdCached::Other(ctx.crate_ids_lookup.len());
895        ctx.crate_ids_lookup.push(crate_long_id);
896        ctx.crate_ids.insert(crate_id, id);
897        id
898    }
899    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> CrateId<'db> {
900        let CrateIdCached::Other(id) = self else {
901            return ctx.self_crate_id;
902        };
903
904        if let Some(crate_id) = ctx.crate_ids.get(&self) {
905            return *crate_id;
906        }
907        let crate_long_id = ctx.crate_ids_lookup[id].clone();
908        let crate_id = crate_long_id.embed(ctx).intern(ctx.db);
909        ctx.data.crate_ids.insert(self, crate_id);
910        crate_id
911    }
912    fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> CrateId<'db> {
913        let CrateIdCached::Other(_) = self else {
914            return data.self_crate_id;
915        };
916        data.crate_ids[&self]
917    }
918}
919
920#[derive(Serialize, Deserialize, Copy, Clone)]
921pub enum ModuleItemIdCached {
922    Constant(ConstantIdCached),
923    Submodule(SubmoduleIdCached),
924    Use(UseIdCached),
925    FreeFunction(FreeFunctionIdCached),
926    Struct(StructIdCached),
927    Enum(EnumIdCached),
928    TypeAlias(ModuleTypeAliasIdCached),
929    ImplAlias(ImplAliasIdCached),
930    Trait(TraitIdCached),
931    Impl(ImplDefIdCached),
932    ExternType(ExternTypeIdCached),
933    ExternFunction(ExternFunctionIdCached),
934    MacroDeclaration(MacroDeclarationIdCached),
935}
936
937impl ModuleItemIdCached {
938    pub fn new<'db>(
939        module_item_id: ModuleItemId<'db>,
940        ctx: &mut DefCacheSavingContext<'db>,
941    ) -> Self {
942        match module_item_id {
943            ModuleItemId::Constant(constant_id) => {
944                ModuleItemIdCached::Constant(ConstantIdCached::new(constant_id, ctx))
945            }
946            ModuleItemId::Submodule(submodule_id) => {
947                ModuleItemIdCached::Submodule(SubmoduleIdCached::new(submodule_id, ctx))
948            }
949            ModuleItemId::Use(use_id) => ModuleItemIdCached::Use(UseIdCached::new(use_id, ctx)),
950            ModuleItemId::FreeFunction(free_function_id) => {
951                ModuleItemIdCached::FreeFunction(FreeFunctionIdCached::new(free_function_id, ctx))
952            }
953            ModuleItemId::Struct(struct_id) => {
954                ModuleItemIdCached::Struct(StructIdCached::new(struct_id, ctx))
955            }
956            ModuleItemId::Enum(enum_id) => {
957                ModuleItemIdCached::Enum(EnumIdCached::new(enum_id, ctx))
958            }
959            ModuleItemId::TypeAlias(type_alias_id) => {
960                ModuleItemIdCached::TypeAlias(ModuleTypeAliasIdCached::new(type_alias_id, ctx))
961            }
962            ModuleItemId::ImplAlias(impl_alias_id) => {
963                ModuleItemIdCached::ImplAlias(ImplAliasIdCached::new(impl_alias_id, ctx))
964            }
965            ModuleItemId::Trait(trait_id) => {
966                ModuleItemIdCached::Trait(TraitIdCached::new(trait_id, ctx))
967            }
968            ModuleItemId::Impl(impl_def_id) => {
969                ModuleItemIdCached::Impl(ImplDefIdCached::new(impl_def_id, ctx))
970            }
971            ModuleItemId::ExternType(extern_type_id) => {
972                ModuleItemIdCached::ExternType(ExternTypeIdCached::new(extern_type_id, ctx))
973            }
974            ModuleItemId::ExternFunction(extern_function_id) => ModuleItemIdCached::ExternFunction(
975                ExternFunctionIdCached::new(extern_function_id, ctx),
976            ),
977            ModuleItemId::MacroDeclaration(macro_declaration_id) => {
978                ModuleItemIdCached::MacroDeclaration(MacroDeclarationIdCached::new(
979                    macro_declaration_id,
980                    ctx,
981                ))
982            }
983        }
984    }
985    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ModuleItemId<'db> {
986        match self {
987            ModuleItemIdCached::Constant(constant_id) => {
988                ModuleItemId::Constant(constant_id.embed(ctx))
989            }
990            ModuleItemIdCached::Submodule(submodule_id) => {
991                ModuleItemId::Submodule(submodule_id.embed(ctx))
992            }
993            ModuleItemIdCached::Use(use_id) => ModuleItemId::Use(use_id.embed(ctx)),
994            ModuleItemIdCached::FreeFunction(free_function_id) => {
995                ModuleItemId::FreeFunction(free_function_id.embed(ctx))
996            }
997            ModuleItemIdCached::Struct(struct_id) => ModuleItemId::Struct(struct_id.embed(ctx)),
998            ModuleItemIdCached::Enum(enum_id) => ModuleItemId::Enum(enum_id.embed(ctx)),
999            ModuleItemIdCached::TypeAlias(type_alias_id) => {
1000                ModuleItemId::TypeAlias(type_alias_id.embed(ctx))
1001            }
1002            ModuleItemIdCached::ImplAlias(impl_alias_id) => {
1003                ModuleItemId::ImplAlias(impl_alias_id.embed(ctx))
1004            }
1005            ModuleItemIdCached::Trait(trait_id) => ModuleItemId::Trait(trait_id.embed(ctx)),
1006            ModuleItemIdCached::Impl(impl_def_id) => ModuleItemId::Impl(impl_def_id.embed(ctx)),
1007            ModuleItemIdCached::ExternType(extern_type_id) => {
1008                ModuleItemId::ExternType(extern_type_id.embed(ctx))
1009            }
1010            ModuleItemIdCached::ExternFunction(extern_function_id) => {
1011                ModuleItemId::ExternFunction(extern_function_id.embed(ctx))
1012            }
1013            ModuleItemIdCached::MacroDeclaration(macro_declaration_id) => {
1014                ModuleItemId::MacroDeclaration(macro_declaration_id.embed(ctx))
1015            }
1016        }
1017    }
1018    pub fn get_embedded<'db>(&self, data: &Arc<DefCacheLoadingData<'db>>) -> ModuleItemId<'db> {
1019        match self {
1020            ModuleItemIdCached::Constant(id) => ModuleItemId::Constant(id.get_embedded(data)),
1021            ModuleItemIdCached::Submodule(id) => ModuleItemId::Submodule(id.get_embedded(data)),
1022            ModuleItemIdCached::Use(id) => ModuleItemId::Use(id.get_embedded(data)),
1023            ModuleItemIdCached::FreeFunction(id) => {
1024                ModuleItemId::FreeFunction(id.get_embedded(data))
1025            }
1026            ModuleItemIdCached::Struct(id) => ModuleItemId::Struct(id.get_embedded(data)),
1027            ModuleItemIdCached::Enum(id) => ModuleItemId::Enum(id.get_embedded(data)),
1028            ModuleItemIdCached::TypeAlias(id) => ModuleItemId::TypeAlias(id.get_embedded(data)),
1029            ModuleItemIdCached::ImplAlias(id) => ModuleItemId::ImplAlias(id.get_embedded(data)),
1030            ModuleItemIdCached::Trait(id) => ModuleItemId::Trait(id.get_embedded(data)),
1031            ModuleItemIdCached::Impl(id) => ModuleItemId::Impl(id.get_embedded(data)),
1032            ModuleItemIdCached::ExternType(id) => ModuleItemId::ExternType(id.get_embedded(data)),
1033            ModuleItemIdCached::ExternFunction(id) => {
1034                ModuleItemId::ExternFunction(id.get_embedded(data))
1035            }
1036            ModuleItemIdCached::MacroDeclaration(id) => {
1037                ModuleItemId::MacroDeclaration(id.get_embedded(data))
1038            }
1039        }
1040    }
1041}
1042
1043#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1044struct ConstantCached {
1045    language_element: LanguageElementCached,
1046}
1047impl ConstantCached {
1048    fn new<'db>(constant_id: ConstantId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1049        Self { language_element: LanguageElementCached::new(constant_id, ctx) }
1050    }
1051    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ConstantLongId<'db> {
1052        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1053
1054        ConstantLongId(module_id, ItemConstantPtr(stable_ptr))
1055    }
1056}
1057
1058#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1059pub struct ConstantIdCached(usize);
1060
1061impl ConstantIdCached {
1062    fn new<'db>(id: ConstantId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1063        if let Some(cached_id) = ctx.constant_ids.get(&id) {
1064            return *cached_id;
1065        }
1066        let cached = ConstantCached::new(id, ctx);
1067        let cached_id = ConstantIdCached(ctx.constant_ids_lookup.len());
1068        ctx.constant_ids_lookup.push(cached);
1069        ctx.constant_ids.insert(id, cached_id);
1070        cached_id
1071    }
1072    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ConstantId<'db> {
1073        if let Some(id) = ctx.constant_ids.get(&self) {
1074            return *id;
1075        }
1076        let cached = ctx.constant_ids_lookup[self.0].clone();
1077        let id = cached.embed(ctx).intern(ctx.db);
1078        ctx.constant_ids.insert(self, id);
1079        id
1080    }
1081    pub fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> ConstantId<'db> {
1082        data.constant_ids[&self]
1083    }
1084}
1085
1086#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1087struct SubmoduleCached {
1088    language_element: LanguageElementCached,
1089}
1090impl SubmoduleCached {
1091    fn new<'db>(submodule_id: SubmoduleId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1092        Self { language_element: LanguageElementCached::new(submodule_id, ctx) }
1093    }
1094    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> SubmoduleLongId<'db> {
1095        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1096
1097        SubmoduleLongId(module_id, ItemModulePtr(stable_ptr))
1098    }
1099}
1100
1101#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1102pub struct SubmoduleIdCached(usize);
1103
1104impl SubmoduleIdCached {
1105    fn new<'db>(id: SubmoduleId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1106        if let Some(cached_id) = ctx.submodule_ids.get(&id) {
1107            return *cached_id;
1108        }
1109        let cached = SubmoduleCached::new(id, ctx);
1110        let cached_id = SubmoduleIdCached(ctx.submodule_ids_lookup.len());
1111        ctx.submodule_ids_lookup.push(cached);
1112        ctx.submodule_ids.insert(id, cached_id);
1113        cached_id
1114    }
1115    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> SubmoduleId<'db> {
1116        if let Some(id) = ctx.submodule_ids.get(&self) {
1117            return *id;
1118        }
1119        let cached = ctx.submodule_ids_lookup[self.0].clone();
1120        let id = cached.embed(ctx).intern(ctx.db);
1121        ctx.submodule_ids.insert(self, id);
1122        id
1123    }
1124    fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> SubmoduleId<'db> {
1125        data.submodule_ids[&self]
1126    }
1127}
1128
1129#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1130struct UseCached {
1131    language_element: LanguageElementCached,
1132}
1133impl UseCached {
1134    fn new<'db>(use_id: UseId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1135        Self { language_element: LanguageElementCached::new(use_id, ctx) }
1136    }
1137    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> UseLongId<'db> {
1138        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1139
1140        UseLongId(module_id, UsePathLeafPtr(stable_ptr))
1141    }
1142}
1143
1144#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1145pub struct UseIdCached(usize);
1146
1147impl UseIdCached {
1148    fn new<'db>(id: UseId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1149        if let Some(cached_id) = ctx.use_ids.get(&id) {
1150            return *cached_id;
1151        }
1152        let cached = UseCached::new(id, ctx);
1153        let cached_id = UseIdCached(ctx.use_ids_lookup.len());
1154        ctx.use_ids_lookup.push(cached);
1155        ctx.use_ids.insert(id, cached_id);
1156        cached_id
1157    }
1158    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> UseId<'db> {
1159        if let Some(id) = ctx.use_ids.get(&self) {
1160            return *id;
1161        }
1162        let cached = ctx.use_ids_lookup[self.0].clone();
1163        let id = cached.embed(ctx).intern(ctx.db);
1164        ctx.use_ids.insert(self, id);
1165        id
1166    }
1167    pub fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> UseId<'db> {
1168        data.use_ids[&self]
1169    }
1170}
1171
1172#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1173struct FreeFunctionCached {
1174    language_element: LanguageElementCached,
1175}
1176impl FreeFunctionCached {
1177    fn new<'db>(
1178        free_function_id: FreeFunctionId<'db>,
1179        ctx: &mut DefCacheSavingContext<'db>,
1180    ) -> Self {
1181        Self { language_element: LanguageElementCached::new(free_function_id, ctx) }
1182    }
1183    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> FreeFunctionLongId<'db> {
1184        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1185
1186        FreeFunctionLongId(module_id, FunctionWithBodyPtr(stable_ptr))
1187    }
1188}
1189
1190#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1191pub struct FreeFunctionIdCached(usize);
1192
1193impl FreeFunctionIdCached {
1194    fn new<'db>(id: FreeFunctionId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1195        if let Some(cached_id) = ctx.free_function_ids.get(&id) {
1196            return *cached_id;
1197        }
1198        let cached = FreeFunctionCached::new(id, ctx);
1199        let cached_id = FreeFunctionIdCached(ctx.free_function_ids_lookup.len());
1200        ctx.free_function_ids_lookup.push(cached);
1201        ctx.free_function_ids.insert(id, cached_id);
1202        cached_id
1203    }
1204    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> FreeFunctionId<'db> {
1205        if let Some(id) = ctx.free_function_ids.get(&self) {
1206            return *id;
1207        }
1208        let cached = ctx.free_function_ids_lookup[self.0].clone();
1209        let id = cached.embed(ctx).intern(ctx.db);
1210        ctx.free_function_ids.insert(self, id);
1211        id
1212    }
1213    pub fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> FreeFunctionId<'db> {
1214        data.free_function_ids[&self]
1215    }
1216}
1217
1218#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1219struct StructCached {
1220    language_element: LanguageElementCached,
1221}
1222impl StructCached {
1223    fn new<'db>(struct_id: StructId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1224        Self { language_element: LanguageElementCached::new(struct_id, ctx) }
1225    }
1226    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> StructLongId<'db> {
1227        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1228
1229        StructLongId(module_id, ItemStructPtr(stable_ptr))
1230    }
1231}
1232
1233#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1234pub struct StructIdCached(usize);
1235
1236impl StructIdCached {
1237    fn new<'db>(id: StructId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1238        if let Some(cached_id) = ctx.struct_ids.get(&id) {
1239            return *cached_id;
1240        }
1241        let cached = StructCached::new(id, ctx);
1242        let cached_id = StructIdCached(ctx.struct_ids_lookup.len());
1243        ctx.struct_ids_lookup.push(cached);
1244        ctx.struct_ids.insert(id, cached_id);
1245        cached_id
1246    }
1247    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> StructId<'db> {
1248        if let Some(id) = ctx.struct_ids.get(&self) {
1249            return *id;
1250        }
1251        let cached = ctx.struct_ids_lookup[self.0].clone();
1252        let id = cached.embed(ctx).intern(ctx.db);
1253        ctx.struct_ids.insert(self, id);
1254        id
1255    }
1256    pub fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> StructId<'db> {
1257        data.struct_ids[&self]
1258    }
1259}
1260
1261#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1262struct EnumCached {
1263    language_element: LanguageElementCached,
1264}
1265impl EnumCached {
1266    fn new<'db>(enum_id: EnumId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1267        Self { language_element: LanguageElementCached::new(enum_id, ctx) }
1268    }
1269    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> EnumLongId<'db> {
1270        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1271
1272        EnumLongId(module_id, ItemEnumPtr(stable_ptr))
1273    }
1274}
1275
1276#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1277pub struct EnumIdCached(usize);
1278
1279impl EnumIdCached {
1280    fn new<'db>(id: EnumId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1281        if let Some(cached_id) = ctx.enum_ids.get(&id) {
1282            return *cached_id;
1283        }
1284        let cached = EnumCached::new(id, ctx);
1285        let cached_id = EnumIdCached(ctx.enum_ids_lookup.len());
1286        ctx.enum_ids_lookup.push(cached);
1287        ctx.enum_ids.insert(id, cached_id);
1288        cached_id
1289    }
1290    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> EnumId<'db> {
1291        if let Some(id) = ctx.enum_ids.get(&self) {
1292            return *id;
1293        }
1294        let cached = ctx.enum_ids_lookup[self.0].clone();
1295        let id = cached.embed(ctx).intern(ctx.db);
1296        ctx.enum_ids.insert(self, id);
1297        id
1298    }
1299    pub fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> EnumId<'db> {
1300        data.enum_ids[&self]
1301    }
1302}
1303
1304#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1305struct ModuleTypeAliasCached {
1306    language_element: LanguageElementCached,
1307}
1308impl ModuleTypeAliasCached {
1309    fn new<'db>(
1310        type_alias_id: ModuleTypeAliasId<'db>,
1311        ctx: &mut DefCacheSavingContext<'db>,
1312    ) -> Self {
1313        Self { language_element: LanguageElementCached::new(type_alias_id, ctx) }
1314    }
1315    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ModuleTypeAliasLongId<'db> {
1316        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1317
1318        ModuleTypeAliasLongId(module_id, ItemTypeAliasPtr(stable_ptr))
1319    }
1320}
1321
1322#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1323pub struct ModuleTypeAliasIdCached(usize);
1324
1325impl ModuleTypeAliasIdCached {
1326    fn new<'db>(id: ModuleTypeAliasId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1327        if let Some(cached_id) = ctx.type_alias_ids.get(&id) {
1328            return *cached_id;
1329        }
1330        let cached = ModuleTypeAliasCached::new(id, ctx);
1331        let cached_id = ModuleTypeAliasIdCached(ctx.type_alias_ids_lookup.len());
1332        ctx.type_alias_ids_lookup.push(cached);
1333        ctx.type_alias_ids.insert(id, cached_id);
1334        cached_id
1335    }
1336    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ModuleTypeAliasId<'db> {
1337        if let Some(id) = ctx.type_alias_ids.get(&self) {
1338            return *id;
1339        }
1340        let cached = ctx.type_alias_ids_lookup[self.0].clone();
1341        let id = cached.embed(ctx).intern(ctx.db);
1342        ctx.type_alias_ids.insert(self, id);
1343        id
1344    }
1345    pub fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> ModuleTypeAliasId<'db> {
1346        data.type_alias_ids[&self]
1347    }
1348}
1349
1350#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1351struct ImplAliasCached {
1352    language_element: LanguageElementCached,
1353}
1354impl ImplAliasCached {
1355    fn new<'db>(impl_alias_id: ImplAliasId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1356        Self { language_element: LanguageElementCached::new(impl_alias_id, ctx) }
1357    }
1358    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ImplAliasLongId<'db> {
1359        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1360
1361        ImplAliasLongId(module_id, ItemImplAliasPtr(stable_ptr))
1362    }
1363}
1364
1365#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1366pub struct ImplAliasIdCached(usize);
1367
1368impl ImplAliasIdCached {
1369    pub fn new<'db>(id: ImplAliasId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1370        if let Some(cached_id) = ctx.impl_alias_ids.get(&id) {
1371            return *cached_id;
1372        }
1373        let cached = ImplAliasCached::new(id, ctx);
1374        let cached_id = ImplAliasIdCached(ctx.impl_alias_ids_lookup.len());
1375        ctx.impl_alias_ids_lookup.push(cached);
1376        ctx.impl_alias_ids.insert(id, cached_id);
1377        cached_id
1378    }
1379    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ImplAliasId<'db> {
1380        if let Some(id) = ctx.impl_alias_ids.get(&self) {
1381            return *id;
1382        }
1383        let cached = ctx.impl_alias_ids_lookup[self.0].clone();
1384        let id = cached.embed(ctx).intern(ctx.db);
1385        ctx.impl_alias_ids.insert(self, id);
1386        id
1387    }
1388    pub fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> ImplAliasId<'db> {
1389        data.impl_alias_ids[&self]
1390    }
1391}
1392
1393#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1394struct TraitCached {
1395    language_element: LanguageElementCached,
1396}
1397impl TraitCached {
1398    fn new<'db>(trait_id: TraitId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1399        Self { language_element: LanguageElementCached::new(trait_id, ctx) }
1400    }
1401    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> TraitLongId<'db> {
1402        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1403
1404        TraitLongId(module_id, ItemTraitPtr(stable_ptr))
1405    }
1406}
1407
1408#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1409pub struct TraitIdCached(usize);
1410
1411impl TraitIdCached {
1412    fn new<'db>(id: TraitId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1413        if let Some(cached_id) = ctx.trait_ids.get(&id) {
1414            return *cached_id;
1415        }
1416        let cached = TraitCached::new(id, ctx);
1417        let cached_id = TraitIdCached(ctx.trait_ids_lookup.len());
1418        ctx.trait_ids_lookup.push(cached);
1419        ctx.trait_ids.insert(id, cached_id);
1420        cached_id
1421    }
1422    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> TraitId<'db> {
1423        if let Some(id) = ctx.trait_ids.get(&self) {
1424            return *id;
1425        }
1426        let cached = ctx.trait_ids_lookup[self.0].clone();
1427        let id = cached.embed(ctx).intern(ctx.db);
1428        ctx.trait_ids.insert(self, id);
1429        id
1430    }
1431    pub fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> TraitId<'db> {
1432        data.trait_ids[&self]
1433    }
1434}
1435
1436#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1437struct ImplDefCached {
1438    language_element: LanguageElementCached,
1439}
1440impl ImplDefCached {
1441    fn new<'db>(impl_def_id: ImplDefId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1442        Self { language_element: LanguageElementCached::new(impl_def_id, ctx) }
1443    }
1444    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ImplDefLongId<'db> {
1445        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1446
1447        ImplDefLongId(module_id, ItemImplPtr(stable_ptr))
1448    }
1449}
1450
1451#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1452pub struct ImplDefIdCached(usize);
1453
1454impl ImplDefIdCached {
1455    pub fn new<'db>(id: ImplDefId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1456        if let Some(cached_id) = ctx.impl_def_ids.get(&id) {
1457            return *cached_id;
1458        }
1459        let cached = ImplDefCached::new(id, ctx);
1460        let cached_id = ImplDefIdCached(ctx.impl_def_ids_lookup.len());
1461        ctx.impl_def_ids_lookup.push(cached);
1462        ctx.impl_def_ids.insert(id, cached_id);
1463        cached_id
1464    }
1465
1466    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ImplDefId<'db> {
1467        if let Some(id) = ctx.impl_def_ids.get(&self) {
1468            return *id;
1469        }
1470        let cached = ctx.impl_def_ids_lookup[self.0].clone();
1471        let id = cached.embed(ctx).intern(ctx.db);
1472        ctx.impl_def_ids.insert(self, id);
1473        id
1474    }
1475
1476    pub fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> ImplDefId<'db> {
1477        data.impl_def_ids[&self]
1478    }
1479}
1480
1481#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1482struct ExternTypeCached {
1483    language_element: LanguageElementCached,
1484}
1485impl ExternTypeCached {
1486    fn new<'db>(extern_type_id: ExternTypeId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1487        Self { language_element: LanguageElementCached::new(extern_type_id, ctx) }
1488    }
1489    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ExternTypeLongId<'db> {
1490        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1491
1492        ExternTypeLongId(module_id, ItemExternTypePtr(stable_ptr))
1493    }
1494}
1495
1496#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1497pub struct ExternTypeIdCached(usize);
1498
1499impl ExternTypeIdCached {
1500    fn new<'db>(id: ExternTypeId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1501        if let Some(cached_id) = ctx.extern_type_ids.get(&id) {
1502            return *cached_id;
1503        }
1504        let cached = ExternTypeCached::new(id, ctx);
1505        let cached_id = ExternTypeIdCached(ctx.extern_type_ids_lookup.len());
1506        ctx.extern_type_ids_lookup.push(cached);
1507        ctx.extern_type_ids.insert(id, cached_id);
1508        cached_id
1509    }
1510    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ExternTypeId<'db> {
1511        if let Some(id) = ctx.extern_type_ids.get(&self) {
1512            return *id;
1513        }
1514        let cached = ctx.extern_type_ids_lookup[self.0].clone();
1515        let id = cached.embed(ctx).intern(ctx.db);
1516        ctx.extern_type_ids.insert(self, id);
1517        id
1518    }
1519    pub fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> ExternTypeId<'db> {
1520        data.extern_type_ids[&self]
1521    }
1522}
1523
1524#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1525struct ExternFunctionCached {
1526    language_element: LanguageElementCached,
1527}
1528impl ExternFunctionCached {
1529    fn new<'db>(
1530        extern_function_id: ExternFunctionId<'db>,
1531        ctx: &mut DefCacheSavingContext<'db>,
1532    ) -> Self {
1533        Self { language_element: LanguageElementCached::new(extern_function_id, ctx) }
1534    }
1535    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ExternFunctionLongId<'db> {
1536        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1537
1538        ExternFunctionLongId(module_id, ItemExternFunctionPtr(stable_ptr))
1539    }
1540}
1541
1542#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1543pub struct ExternFunctionIdCached(usize);
1544
1545impl ExternFunctionIdCached {
1546    fn new<'db>(id: ExternFunctionId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1547        if let Some(cached_id) = ctx.extern_function_ids.get(&id) {
1548            return *cached_id;
1549        }
1550        let cached = ExternFunctionCached::new(id, ctx);
1551        let cached_id = ExternFunctionIdCached(ctx.extern_function_ids_lookup.len());
1552        ctx.extern_function_ids_lookup.push(cached);
1553        ctx.extern_function_ids.insert(id, cached_id);
1554        cached_id
1555    }
1556    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> ExternFunctionId<'db> {
1557        if let Some(id) = ctx.extern_function_ids.get(&self) {
1558            return *id;
1559        }
1560        let cached = ctx.extern_function_ids_lookup[self.0].clone();
1561        let id = cached.embed(ctx).intern(ctx.db);
1562        ctx.extern_function_ids.insert(self, id);
1563        id
1564    }
1565    pub fn get_embedded<'db>(self, data: &Arc<DefCacheLoadingData<'db>>) -> ExternFunctionId<'db> {
1566        data.extern_function_ids[&self]
1567    }
1568}
1569#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1570struct MacroDeclarationCached {
1571    language_element: LanguageElementCached,
1572}
1573
1574impl MacroDeclarationCached {
1575    fn new<'db>(
1576        macro_declaration_id: MacroDeclarationId<'db>,
1577        ctx: &mut DefCacheSavingContext<'db>,
1578    ) -> Self {
1579        Self { language_element: LanguageElementCached::new(macro_declaration_id, ctx) }
1580    }
1581    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> MacroDeclarationLongId<'db> {
1582        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1583
1584        MacroDeclarationLongId(module_id, ItemMacroDeclarationPtr(stable_ptr))
1585    }
1586}
1587
1588#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1589pub struct MacroDeclarationIdCached(usize);
1590
1591impl MacroDeclarationIdCached {
1592    fn new<'db>(id: MacroDeclarationId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1593        if let Some(cached_id) = ctx.macro_declaration_ids.get(&id) {
1594            return *cached_id;
1595        }
1596        let cached = MacroDeclarationCached::new(id, ctx);
1597        let cached_id = MacroDeclarationIdCached(ctx.macro_declaration_ids_lookup.len());
1598        ctx.macro_declaration_ids_lookup.push(cached);
1599        ctx.macro_declaration_ids.insert(id, cached_id);
1600        cached_id
1601    }
1602    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> MacroDeclarationId<'db> {
1603        if let Some(id) = ctx.macro_declaration_ids.get(&self) {
1604            return *id;
1605        }
1606        let cached = ctx.macro_declaration_ids_lookup[self.0].clone();
1607        let id = cached.embed(ctx).intern(ctx.db);
1608        ctx.macro_declaration_ids.insert(self, id);
1609        id
1610    }
1611    pub fn get_embedded<'db>(
1612        self,
1613        data: &Arc<DefCacheLoadingData<'db>>,
1614    ) -> MacroDeclarationId<'db> {
1615        data.macro_declaration_ids[&self]
1616    }
1617}
1618
1619#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1620struct MacroCallCached {
1621    language_element: LanguageElementCached,
1622}
1623impl MacroCallCached {
1624    fn new<'db>(macro_call: MacroCallId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1625        Self { language_element: LanguageElementCached::new(macro_call, ctx) }
1626    }
1627
1628    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> MacroCallLongId<'db> {
1629        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1630        MacroCallLongId(module_id, ItemInlineMacroPtr(stable_ptr))
1631    }
1632}
1633
1634#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1635pub struct MacroCallIdCached(usize);
1636impl MacroCallIdCached {
1637    fn new<'db>(id: MacroCallId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1638        if let Some(cached_id) = ctx.macro_call_ids.get(&id) {
1639            return *cached_id;
1640        }
1641        let cached = MacroCallCached::new(id, ctx);
1642        let id_cached = MacroCallIdCached(ctx.macro_call_ids_lookup.len());
1643        ctx.macro_call_ids_lookup.push(cached);
1644        ctx.macro_call_ids.insert(id, id_cached);
1645        id_cached
1646    }
1647    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> MacroCallId<'db> {
1648        if let Some(id) = ctx.macro_call_ids.get(&self) {
1649            return *id;
1650        }
1651        let cached = ctx.macro_call_ids_lookup[self.0].clone();
1652        let id = cached.embed(ctx).intern(ctx.db);
1653        ctx.macro_call_ids.insert(self, id);
1654        id
1655    }
1656    fn get_embedded<'db>(&self, data: &Arc<DefCacheLoadingData<'db>>) -> MacroCallId<'db> {
1657        data.macro_call_ids[self]
1658    }
1659}
1660
1661#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1662struct GlobalUseCached {
1663    language_element: LanguageElementCached,
1664}
1665impl GlobalUseCached {
1666    fn new<'db>(global_use_id: GlobalUseId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1667        Self { language_element: LanguageElementCached::new(global_use_id, ctx) }
1668    }
1669    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> GlobalUseLongId<'db> {
1670        let (module_id, stable_ptr) = self.language_element.embed(ctx);
1671
1672        GlobalUseLongId(module_id, UsePathStarPtr(stable_ptr))
1673    }
1674}
1675
1676#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash, salsa::Update)]
1677pub struct GlobalUseIdCached(usize);
1678
1679impl GlobalUseIdCached {
1680    pub fn new<'db>(id: GlobalUseId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1681        if let Some(cached_id) = ctx.global_use_ids.get(&id) {
1682            return *cached_id;
1683        }
1684        let cached = GlobalUseCached::new(id, ctx);
1685        let cached_id = GlobalUseIdCached(ctx.global_use_ids_lookup.len());
1686        ctx.global_use_ids_lookup.push(cached);
1687        ctx.global_use_ids.insert(id, cached_id);
1688        cached_id
1689    }
1690    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> GlobalUseId<'db> {
1691        if let Some(id) = ctx.global_use_ids.get(&self) {
1692            return *id;
1693        }
1694        let cached = ctx.global_use_ids_lookup[self.0].clone();
1695        let id = cached.embed(ctx).intern(ctx.db);
1696        ctx.global_use_ids.insert(self, id);
1697        id
1698    }
1699    pub fn get_embedded<'db>(&self, data: &Arc<DefCacheLoadingData<'db>>) -> GlobalUseId<'db> {
1700        data.global_use_ids[self]
1701    }
1702}
1703
1704#[derive(Serialize, Deserialize, Clone, Copy, Hash, Eq, PartialEq, salsa::Update, Debug)]
1705struct SyntaxNodeCached(usize);
1706
1707#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
1708enum SyntaxNodeIdCached {
1709    /// A file root (any kind: on-disk, virtual, or external). On load the root is re-derived via
1710    /// `db.file_syntax` — the canonical tree, never a detached duplicate — rather than rebuilt from
1711    /// stored green, and without re-entering module data (so cache load can't cycle).
1712    Root(FileIdCached),
1713    /// A non-root node, identified by its `parent` plus the child's `key_fields`, `kind`, and
1714    /// `index`.
1715    Child {
1716        parent: SyntaxNodeCached,
1717        kind: SyntaxKind,
1718        key_fields: Vec<GreenIdCached>,
1719        index: usize,
1720    },
1721}
1722
1723impl SyntaxNodeIdCached {
1724    fn new<'db>(ctx: &mut DefCacheSavingContext<'db>, id: &SyntaxNodeId<'db>) -> Self {
1725        match id {
1726            SyntaxNodeId::Root(file_id) => Self::Root(FileIdCached::new(*file_id, ctx)),
1727            SyntaxNodeId::Child { parent, kind, key_fields, index } => Self::Child {
1728                parent: SyntaxNodeCached::new(*parent, ctx),
1729                kind: *kind,
1730                key_fields: key_fields.into_iter().map(|id| GreenIdCached::new(*id, ctx)).collect(),
1731                index: *index,
1732            },
1733        }
1734    }
1735
1736    fn from_raw(
1737        ctx: &mut DefCacheLoadingContext<'_>,
1738        parent: SyntaxNodeCached,
1739        kind: SyntaxKind,
1740        index: usize,
1741        key_fields: &[GreenId<'_>],
1742    ) -> Option<Self> {
1743        let mut cached_key_fields = Vec::with_capacity(key_fields.len());
1744        for id in key_fields {
1745            let Some(cached_id) = ctx.reverse_green_ids.get(id) else {
1746                // Green ID not found in cache, this child can't be reconstructed
1747                return None;
1748            };
1749            cached_key_fields.push(*cached_id);
1750        }
1751        Some(Self::Child { parent, kind, key_fields: cached_key_fields, index })
1752    }
1753}
1754
1755impl SyntaxNodeCached {
1756    fn new<'db>(syntax_node: SyntaxNode<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1757        if let Some(res) = ctx.syntax_nodes.get(&syntax_node) {
1758            return *res;
1759        }
1760        let db = ctx.db;
1761        // Cache the green node and all its children to ensure they're available during load
1762        let green = syntax_node.green_node(db);
1763        GreenIdCached::new(green.clone().intern(db), ctx);
1764
1765        let id = SyntaxNodeIdCached::new(ctx, syntax_node.raw_id(db));
1766        let cached_node = SyntaxNodeCached(ctx.syntax_node_lookup.len());
1767        ctx.syntax_node_lookup.push(id);
1768        ctx.syntax_nodes.insert(syntax_node, cached_node);
1769        cached_node
1770    }
1771    fn embed<'db>(&self, ctx: &mut DefCacheLoadingContext<'db>) -> SyntaxNode<'db> {
1772        if let Some(node) = ctx.syntax_nodes.get(self) {
1773            return *node;
1774        }
1775        let id_cached = ctx.syntax_node_lookup[self.0].clone();
1776        match &id_cached {
1777            SyntaxNodeIdCached::Root(file_id) => {
1778                // Re-derive the canonical tree via `file_syntax`; walking `get_children` below
1779                // lands the cached stable ptrs on those canonical nodes. See
1780                // `SyntaxNodeIdCached::Root`.
1781                let fid = file_id.embed(ctx);
1782                let syntax = ctx.db.file_syntax(fid).unwrap_or_else(|_| {
1783                    panic!(
1784                        "defs cache: cannot re-derive syntax for file {:?}; its content must be \
1785                         available to load the cache",
1786                        fid.long(ctx.db)
1787                    )
1788                });
1789                ctx.syntax_nodes.insert(*self, syntax);
1790            }
1791            SyntaxNodeIdCached::Child { parent, .. } => {
1792                let parent_node = parent.embed(ctx);
1793                let children = parent_node.get_children(ctx.db);
1794                // For each child, create the cached syntax node ID and insert into syntax_nodes map
1795                for child in children {
1796                    let SyntaxNodeId::Child { kind, index, key_fields, .. } = child.raw_id(ctx.db)
1797                    else {
1798                        panic!("Unexpected SyntaxNodeId type root when creating child");
1799                    };
1800                    let Some(child_id) =
1801                        SyntaxNodeIdCached::from_raw(ctx, *parent, *kind, *index, key_fields)
1802                    else {
1803                        continue;
1804                    };
1805                    // Check if this child was cached during save
1806                    let Some(&child_cached) = ctx.reverse_syntax_node_lookup.get(&child_id) else {
1807                        continue;
1808                    };
1809                    ctx.syntax_nodes.insert(child_cached, *child);
1810                }
1811            }
1812        };
1813        *ctx.syntax_nodes
1814            .get(self)
1815            .unwrap_or_else(|| panic!("Failed to find syntax node {:?} after embedding", self.0))
1816    }
1817    fn get_embedded<'db>(&self, data: &Arc<DefCacheLoadingData<'db>>) -> SyntaxNode<'db> {
1818        data.syntax_nodes[self]
1819    }
1820}
1821
1822#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq)]
1823pub struct LanguageElementCached {
1824    module_id: ModuleIdCached,
1825    stable_ptr: SyntaxStablePtrIdCached,
1826}
1827impl LanguageElementCached {
1828    pub fn new<'db, T: LanguageElementId<'db> + 'db>(
1829        language_element: T,
1830        ctx: &mut DefCacheSavingContext<'db>,
1831    ) -> Self {
1832        Self {
1833            module_id: ModuleIdCached::new(language_element.parent_module(ctx.db), ctx),
1834            stable_ptr: SyntaxStablePtrIdCached::new(
1835                language_element.untyped_stable_ptr(ctx.db),
1836                ctx,
1837            ),
1838        }
1839    }
1840    fn embed<'db>(
1841        self,
1842        ctx: &mut DefCacheLoadingContext<'db>,
1843    ) -> (ModuleId<'db>, SyntaxStablePtrId<'db>) {
1844        let module_id = self.module_id.embed(ctx);
1845        let stable_ptr = self.stable_ptr.embed(ctx);
1846        (module_id, stable_ptr)
1847    }
1848    pub fn get_embedded<'db>(
1849        self,
1850        data: &Arc<DefCacheLoadingData<'db>>,
1851    ) -> (ModuleId<'db>, SyntaxStablePtrId<'db>) {
1852        let module_id = self.module_id.get_embedded(data);
1853        let stable_ptr = self.stable_ptr.get_embedded(data);
1854        (module_id, stable_ptr)
1855    }
1856}
1857
1858#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1859enum GreenNodeDetailsCached {
1860    Token(String),
1861    Node { children: Vec<GreenIdCached>, width: TextWidth },
1862}
1863
1864impl GreenNodeDetailsCached {
1865    fn new<'db>(
1866        green_node_details: &GreenNodeDetails<'db>,
1867        ctx: &mut DefCacheSavingContext<'db>,
1868    ) -> GreenNodeDetailsCached {
1869        match green_node_details {
1870            GreenNodeDetails::Token(token) => {
1871                GreenNodeDetailsCached::Token(token.long(ctx.db).to_string())
1872            }
1873            GreenNodeDetails::Node { children, width } => GreenNodeDetailsCached::Node {
1874                children: children.iter().map(|child| GreenIdCached::new(*child, ctx)).collect(),
1875                width: *width,
1876            },
1877        }
1878    }
1879    fn embed<'db>(&self, ctx: &mut DefCacheLoadingContext<'db>) -> GreenNodeDetails<'db> {
1880        match self {
1881            GreenNodeDetailsCached::Token(token) => {
1882                GreenNodeDetails::Token(SmolStrId::from(ctx.db, token))
1883            }
1884            GreenNodeDetailsCached::Node { children, width } => GreenNodeDetails::Node {
1885                children: children.iter().map(|child| child.embed(ctx)).collect(),
1886                width: *width,
1887            },
1888        }
1889    }
1890}
1891
1892#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1893struct GreenNodeCached {
1894    kind: SyntaxKind,
1895    details: GreenNodeDetailsCached,
1896}
1897impl GreenNodeCached {
1898    fn new<'db>(green_node: &GreenNode<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1899        Self {
1900            kind: green_node.kind,
1901            details: GreenNodeDetailsCached::new(&green_node.details, ctx),
1902        }
1903    }
1904    fn embed<'db>(&self, ctx: &mut DefCacheLoadingContext<'db>) -> GreenNode<'db> {
1905        GreenNode { kind: self.kind, details: self.details.embed(ctx) }
1906    }
1907}
1908
1909#[derive(Serialize, Deserialize, Clone, Copy, Eq, Hash, PartialEq, salsa::Update, Debug)]
1910struct GreenIdCached(usize);
1911
1912impl GreenIdCached {
1913    fn new<'db>(id: GreenId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1914        if let Some(cached_id) = ctx.green_ids.get(&id) {
1915            return *cached_id;
1916        }
1917        let cached = GreenNodeCached::new(id.long(ctx.db), ctx);
1918        let cached_id = GreenIdCached(ctx.green_ids_lookup.len());
1919        ctx.green_ids_lookup.push(cached);
1920        ctx.green_ids.insert(id, cached_id);
1921        cached_id
1922    }
1923    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> GreenId<'db> {
1924        if let Some(id) = ctx.green_ids.get(&self) {
1925            return *id;
1926        }
1927        let cached = ctx.green_ids_lookup[self.0].clone();
1928        let id = cached.embed(ctx).intern(ctx.db);
1929        ctx.green_ids.insert(self, id);
1930        id
1931    }
1932}
1933#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
1934enum FileCached {
1935    OnDisk(PathBuf),
1936    Virtual(VirtualFileCached),
1937    External(PluginGeneratedFileCached),
1938}
1939
1940impl FileCached {
1941    fn new<'db>(file: &FileLongId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
1942        match file {
1943            FileLongId::OnDisk(path) => FileCached::OnDisk(path.clone()),
1944            FileLongId::Virtual(virtual_file) => {
1945                FileCached::Virtual(VirtualFileCached::new(virtual_file, ctx))
1946            }
1947            FileLongId::External(external_file) => {
1948                FileCached::External(PluginGeneratedFileCached::new(
1949                    PluginGeneratedFileId::from_intern_id(*external_file),
1950                    ctx,
1951                ))
1952            }
1953        }
1954    }
1955    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> FileLongId<'db> {
1956        match self {
1957            FileCached::OnDisk(path) => FileLongId::OnDisk(path),
1958            FileCached::Virtual(virtual_file) => FileLongId::Virtual(virtual_file.embed(ctx)),
1959            FileCached::External(external_file) => {
1960                FileLongId::External(external_file.embed(ctx).as_intern_id())
1961            }
1962        }
1963    }
1964}
1965
1966/// Portable, parse-free identity for an external file — the key into the external-file content
1967/// table. Computed during cache load by reading only already-materialized fields, so it never
1968/// parses or re-runs plugins (which would cycle back into the cache).
1969#[derive(Serialize, Deserialize, Clone, Eq, Hash, PartialEq, Debug)]
1970pub enum ExternalFileKey {
1971    /// An on-disk file, identified by its path.
1972    OnDisk(PathBuf),
1973    /// A virtual file: parent (key + span), name, and a content hash (hashed, not stored, so a
1974    /// shared ancestor isn't duplicated across keys).
1975    Virtual { parent: Option<(Box<ExternalFileKey>, TextSpan)>, name: String, content_hash: u64 },
1976    /// A plugin-generated file: the parent file's key, the stable-ptr offset within it, and name.
1977    Generated { parent: Box<ExternalFileKey>, offset: u32, name: String },
1978}
1979
1980impl ExternalFileKey {
1981    /// Computes the key for `file_id`; see the type docs for why this is parse/plugin/mint-free.
1982    pub(crate) fn new<'db>(db: &'db dyn Database, file_id: FileId<'db>) -> Self {
1983        match file_id.long(db) {
1984            FileLongId::OnDisk(path) => ExternalFileKey::OnDisk(path.clone()),
1985            FileLongId::Virtual(vf) => ExternalFileKey::Virtual {
1986                parent: vf.parent.map(|parent| {
1987                    (Box::new(ExternalFileKey::new(db, parent.file_id)), parent.span)
1988                }),
1989                name: vf.name.long(db).to_string(),
1990                content_hash: {
1991                    let mut hasher = xxhash_rust::xxh3::Xxh3::default();
1992                    vf.content.long(db).as_str().hash(&mut hasher);
1993                    hasher.finish()
1994                },
1995            },
1996            FileLongId::External(external_id) => {
1997                let long_id = PluginGeneratedFileId::from_intern_id(*external_id).long(db);
1998                ExternalFileKey::Generated {
1999                    parent: Box::new(ExternalFileKey::new(db, long_id.stable_ptr.file_id(db))),
2000                    offset: long_id.stable_ptr.0.offset(db).as_u32(),
2001                    name: long_id.name.clone(),
2002                }
2003            }
2004        }
2005    }
2006}
2007
2008/// An external file's content, enough to rebuild its `VirtualFile` on load. `parent` and `name` are
2009/// not stored — they come from the runtime `PluginGeneratedFileLongId` at lookup.
2010#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
2011pub struct ExternalFileContentCached {
2012    content: String,
2013    code_mappings: Vec<CodeMapping>,
2014    kind: FileKind,
2015    original_item_removed: bool,
2016}
2017
2018impl ExternalFileContentCached {
2019    fn new<'db>(virtual_file: &VirtualFile<'db>, db: &'db dyn Database) -> Self {
2020        Self {
2021            content: virtual_file.content.to_string(db),
2022            code_mappings: virtual_file.code_mappings.to_vec(),
2023            kind: virtual_file.kind,
2024            original_item_removed: virtual_file.original_item_removed,
2025        }
2026    }
2027
2028    /// Rebuilds the `VirtualFile`; `parent` and `name` come from the runtime stable ptr / long id.
2029    pub(crate) fn to_virtual_file<'db>(
2030        &self,
2031        db: &'db dyn Database,
2032        name: &str,
2033        parent: Option<SpanInFile<'db>>,
2034    ) -> VirtualFile<'db> {
2035        VirtualFile {
2036            parent,
2037            name: SmolStrId::from(db, name),
2038            content: SmolStrId::from(db, self.content.clone()),
2039            code_mappings: self.code_mappings.clone().into(),
2040            kind: self.kind,
2041            original_item_removed: self.original_item_removed,
2042        }
2043    }
2044}
2045
2046#[derive(Serialize, Deserialize, Clone, Copy, Eq, Hash, PartialEq, salsa::Update, Debug)]
2047pub struct FileIdCached(usize);
2048impl FileIdCached {
2049    fn new<'db>(id: FileId<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
2050        if let Some(cached_id) = ctx.file_ids.get(&id) {
2051            return *cached_id;
2052        }
2053        let long_id = id.long(ctx.db);
2054        // For external (plugin-generated) files, also cache their content so `ext_as_virtual` can
2055        // serve it from the blob instead of re-running plugins.
2056        if let FileLongId::External(external_id) = long_id {
2057            // Distinct `FileId`s can map to the same `ExternalFileKey` (the key is coarser), so
2058            // dedup against the keys already stored in `external_file_contents`.
2059            let key = ExternalFileKey::new(ctx.db, id);
2060            let virtual_file = cairo_lang_filesystem::db::ext_as_virtual(ctx.db, *external_id);
2061            let content = ExternalFileContentCached::new(virtual_file, ctx.db);
2062            match ctx.external_file_contents.entry(key) {
2063                Entry::Vacant(entry) => {
2064                    entry.insert(content);
2065                }
2066                // Two distinct external files collapsing to one key must carry identical content,
2067                // else the load would serve the wrong bytes. Holds today (generated files have
2068                // distinct parent+offset); guard it so a future key change fails loud, not silent.
2069                Entry::Occupied(entry) => debug_assert!(
2070                    *entry.get() == content,
2071                    "external file content key collision with differing content"
2072                ),
2073            }
2074        }
2075        let cached = FileCached::new(long_id, ctx);
2076        let cached_id = FileIdCached(ctx.file_ids_lookup.len());
2077        ctx.file_ids_lookup.push(cached);
2078        ctx.file_ids.insert(id, cached_id);
2079        cached_id
2080    }
2081    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> FileId<'db> {
2082        if let Some(id) = ctx.file_ids.get(&self) {
2083            return *id;
2084        }
2085        let cached = ctx.file_ids_lookup[self.0].clone();
2086        let id = cached.embed(ctx).intern(ctx.db);
2087        ctx.file_ids.insert(self, id);
2088        id
2089    }
2090    fn get_embedded<'db>(&self, data: &Arc<DefCacheLoadingData<'db>>) -> FileId<'db> {
2091        data.file_ids[self]
2092    }
2093}
2094
2095#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
2096struct VirtualFileCached {
2097    parent: Option<SpanInFileCached>,
2098    name: String,
2099    content: String,
2100    code_mappings: Vec<CodeMapping>,
2101    kind: FileKind,
2102    original_item_removed: bool,
2103}
2104
2105impl VirtualFileCached {
2106    fn new<'db>(virtual_file: &VirtualFile<'db>, ctx: &mut DefCacheSavingContext<'db>) -> Self {
2107        Self {
2108            parent: virtual_file.parent.map(|parent| SpanInFileCached::new(&parent, ctx)),
2109            name: virtual_file.name.to_string(ctx.db),
2110            content: virtual_file.content.to_string(ctx.db),
2111            code_mappings: virtual_file.code_mappings.to_vec(),
2112            kind: virtual_file.kind,
2113            original_item_removed: virtual_file.original_item_removed,
2114        }
2115    }
2116    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> VirtualFile<'db> {
2117        VirtualFile {
2118            parent: self.parent.map(|parent| parent.embed(ctx)),
2119            name: SmolStrId::from(ctx.db, self.name),
2120            content: SmolStrId::from(ctx.db, self.content),
2121            code_mappings: self.code_mappings.into(),
2122            kind: self.kind,
2123            original_item_removed: self.original_item_removed,
2124        }
2125    }
2126}
2127
2128#[derive(Serialize, Deserialize, Clone, Copy, Eq, Hash, PartialEq, salsa::Update)]
2129pub struct SyntaxStablePtrIdCached(SyntaxNodeCached);
2130
2131impl SyntaxStablePtrIdCached {
2132    pub fn new<'db>(
2133        stable_ptr: SyntaxStablePtrId<'db>,
2134        ctx: &mut DefCacheSavingContext<'db>,
2135    ) -> Self {
2136        Self(SyntaxNodeCached::new(stable_ptr.0, ctx))
2137    }
2138
2139    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> SyntaxStablePtrId<'db> {
2140        SyntaxStablePtrId(self.0.embed(ctx))
2141    }
2142
2143    pub fn get_embedded<'db>(
2144        &self,
2145        data: &Arc<DefCacheLoadingData<'db>>,
2146    ) -> SyntaxStablePtrId<'db> {
2147        SyntaxStablePtrId(self.0.get_embedded(data))
2148    }
2149}
2150
2151#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
2152struct PluginGeneratedFileCached {
2153    module_id: ModuleIdCached,
2154    stable_ptr: SyntaxStablePtrIdCached,
2155    name: String,
2156}
2157
2158impl PluginGeneratedFileCached {
2159    fn new<'db>(
2160        plugin_generated_file: PluginGeneratedFileId<'db>,
2161        ctx: &mut DefCacheSavingContext<'db>,
2162    ) -> Self {
2163        let long_id = plugin_generated_file.long(ctx.db);
2164        Self {
2165            module_id: ModuleIdCached::new(long_id.module_id, ctx),
2166            stable_ptr: SyntaxStablePtrIdCached::new(long_id.stable_ptr, ctx),
2167            name: long_id.name.clone(),
2168        }
2169    }
2170    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> PluginGeneratedFileId<'db> {
2171        let module_id = self.module_id.embed(ctx);
2172        let stable_ptr = self.stable_ptr.embed(ctx);
2173        let long_id = PluginGeneratedFileLongId { module_id, stable_ptr, name: self.name };
2174        long_id.intern(ctx.db)
2175    }
2176}
2177
2178#[derive(Serialize, Deserialize, Clone)]
2179enum SeverityCached {
2180    Error,
2181    Warning,
2182}
2183
2184#[derive(Serialize, Deserialize, Clone)]
2185struct PluginDiagnosticCached {
2186    stable_ptr: SyntaxStablePtrIdCached,
2187    message: String,
2188    severity: SeverityCached,
2189    inner_span: Option<(TextWidth, TextWidth)>,
2190}
2191
2192impl PluginDiagnosticCached {
2193    fn new<'db>(
2194        diagnostic: &PluginDiagnostic<'db>,
2195        ctx: &mut DefCacheSavingContext<'db>,
2196    ) -> PluginDiagnosticCached {
2197        PluginDiagnosticCached {
2198            stable_ptr: SyntaxStablePtrIdCached::new(diagnostic.stable_ptr, ctx),
2199            message: diagnostic.message.clone(),
2200            severity: match diagnostic.severity {
2201                Severity::Error => SeverityCached::Error,
2202                Severity::Warning => SeverityCached::Warning,
2203            },
2204            inner_span: diagnostic.inner_span,
2205        }
2206    }
2207    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> PluginDiagnostic<'db> {
2208        PluginDiagnostic {
2209            stable_ptr: self.stable_ptr.embed(ctx),
2210            message: self.message,
2211            severity: match self.severity {
2212                SeverityCached::Error => Severity::Error,
2213                SeverityCached::Warning => Severity::Warning,
2214            },
2215            inner_span: self.inner_span,
2216            error_code: None,
2217        }
2218    }
2219}
2220
2221type PluginFileDiagnosticNotesCached = OrderedHashMap<FileIdCached, DiagnosticNoteCached>;
2222
2223#[derive(Serialize, Deserialize, Clone)]
2224struct DiagnosticNoteCached {
2225    text: String,
2226    location: Option<SpanInFileCached>,
2227}
2228
2229impl DiagnosticNoteCached {
2230    fn new<'db>(
2231        note: DiagnosticNote<'db>,
2232        ctx: &mut DefCacheSavingContext<'db>,
2233    ) -> DiagnosticNoteCached {
2234        DiagnosticNoteCached {
2235            text: note.text.clone(),
2236            location: note.location.map(|location| SpanInFileCached::new(&location, ctx)),
2237        }
2238    }
2239    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> DiagnosticNote<'db> {
2240        DiagnosticNote {
2241            text: self.text,
2242            location: self.location.map(|location| location.embed(ctx)),
2243        }
2244    }
2245}
2246
2247#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
2248struct SpanInFileCached {
2249    file_id: FileIdCached,
2250    span: TextSpan,
2251}
2252
2253impl SpanInFileCached {
2254    fn new<'db>(
2255        location: &SpanInFile<'db>,
2256        ctx: &mut DefCacheSavingContext<'db>,
2257    ) -> SpanInFileCached {
2258        SpanInFileCached { file_id: FileIdCached::new(location.file_id, ctx), span: location.span }
2259    }
2260    fn embed<'db>(self, ctx: &mut DefCacheLoadingContext<'db>) -> SpanInFile<'db> {
2261        SpanInFile { file_id: self.file_id.embed(ctx), span: self.span }
2262    }
2263}