Skip to main content

flux_metadata/
lib.rs

1#![allow(incomplete_features)]
2#![feature(rustc_private, specialization, if_let_guard)]
3
4extern crate rustc_ast;
5extern crate rustc_data_structures;
6extern crate rustc_errors;
7extern crate rustc_hir;
8extern crate rustc_macros;
9extern crate rustc_metadata;
10extern crate rustc_middle;
11extern crate rustc_serialize;
12extern crate rustc_session;
13extern crate rustc_span;
14
15mod decoder;
16mod encoder;
17
18// Tags used for encoding Spans:
19const TAG_FULL_SPAN: u8 = 0;
20const TAG_PARTIAL_SPAN: u8 = 1;
21
22use std::{hash::Hash, path::PathBuf, rc::Rc};
23
24use decoder::decode_crate_metadata;
25use derive_where::derive_where;
26use flux_errors::FluxSession;
27use flux_macros::fluent_messages;
28use flux_middle::{
29    PanicSpec,
30    call_graph::NodeKey,
31    cstore::{CrateStore, OptResult},
32    def_id::{FluxDefId, FluxId},
33    fhir,
34    global_env::GlobalEnv,
35    queries::QueryResult,
36    rty,
37};
38use rustc_data_structures::{
39    fx::FxHashMap,
40    unord::{ExtendUnord, UnordMap, UnordSet},
41};
42use rustc_hir::{
43    def::{CtorKind, DefKind},
44    def_id::{LOCAL_CRATE, LocalDefId},
45};
46use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
47use rustc_middle::ty::TyCtxt;
48use rustc_session::config::OutFileName;
49use rustc_span::{
50    SourceFile, Span, StableSourceFileId,
51    def_id::{CrateNum, DefId, DefIndex, StableCrateId},
52};
53
54pub use crate::encoder::encode_metadata;
55
56fluent_messages! { "../locales/en-US.ftl" }
57
58const METADATA_VERSION: u8 = 0;
59const METADATA_HEADER: &[u8] = &[b'f', b'l', b'u', b'x', 0, 0, 0, METADATA_VERSION];
60
61#[derive(Default)]
62pub struct CStore<'tcx> {
63    local_tables: UnordMap<CrateNum, Tables<'tcx, DefIndex>>,
64    extern_tables: Tables<'tcx, DefId>,
65}
66
67/// From CREUSOT: used to store the info about source files
68/// An `EncodedSourceFileId` is the same as a `StableSourceFileId` except that
69/// the source crate is represented as a [StableCrateId] instead of as a
70/// `CrateNum`. This way `EncodedSourceFileId` can be encoded and decoded
71/// without any additional context, i.e. with a simple `opaque::Decoder` (which
72/// is the only thing available when decoding the [Footer].
73#[derive(Encodable, Decodable, Clone, Debug)]
74struct EncodedSourceFileId {
75    stable_source_file_id: StableSourceFileId,
76    stable_crate_id: StableCrateId,
77}
78
79impl EncodedSourceFileId {
80    #[inline]
81    fn new(tcx: TyCtxt<'_>, file: &SourceFile) -> EncodedSourceFileId {
82        EncodedSourceFileId {
83            stable_source_file_id: file.stable_id,
84            stable_crate_id: tcx.stable_crate_id(file.cnum),
85        }
86    }
87}
88
89// Taken from CREUSOT; used to store the info about syntax contexts
90#[derive(Default, Decodable, Encodable)]
91pub struct Footer {
92    file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
93    syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
94    expn_data: FxHashMap<(StableCrateId, u32), AbsoluteBytePos>,
95}
96#[derive(Encodable, Decodable, Eq, PartialEq, Hash, Clone, Copy, Debug)]
97struct SourceFileIndex(u32);
98
99#[derive(Encodable, Decodable, Clone, Copy)]
100pub struct AbsoluteBytePos(u64);
101
102impl AbsoluteBytePos {
103    fn new(pos: usize) -> AbsoluteBytePos {
104        AbsoluteBytePos(pos.try_into().unwrap())
105    }
106
107    fn to_usize(self) -> usize {
108        self.0 as usize
109    }
110}
111
112#[derive(Default, TyEncodable, TyDecodable)]
113pub struct CrateMetadata<'tcx> {
114    local_tables: Tables<'tcx, DefIndex>,
115    extern_tables: Tables<'tcx, DefId>,
116}
117
118/// Trait to deal with the fact that `assoc_refinmenents_of` and `assoc_refinements_def` use
119/// `FluxId<K>` as key;
120trait Key {
121    type KeyIndex;
122    fn crate_num(self) -> CrateNum;
123    fn to_index(self) -> Self::KeyIndex;
124    fn name(self, tcx: TyCtxt) -> String;
125}
126
127impl Key for DefId {
128    type KeyIndex = DefIndex;
129
130    fn crate_num(self) -> CrateNum {
131        self.krate
132    }
133
134    fn to_index(self) -> Self::KeyIndex {
135        self.index
136    }
137
138    fn name(self, tcx: TyCtxt) -> String {
139        tcx.def_path_str(self)
140    }
141}
142
143impl Key for FluxDefId {
144    type KeyIndex = FluxId<DefIndex>;
145
146    fn crate_num(self) -> CrateNum {
147        self.parent().krate
148    }
149
150    fn to_index(self) -> Self::KeyIndex {
151        self.index()
152    }
153
154    fn name(self, tcx: TyCtxt) -> String {
155        format!("{}::{}", tcx.def_path_str(self.parent()), self.name())
156    }
157}
158
159#[derive_where(Default)]
160#[derive(TyEncodable, TyDecodable)]
161pub struct Tables<'tcx, K: Eq + Hash> {
162    generics_of: UnordMap<K, QueryResult<rty::Generics>>,
163    refinement_generics_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>>,
164    predicates_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::GenericPredicates>>>,
165    item_bounds: UnordMap<K, QueryResult<rty::EarlyBinder<rty::Clauses>>>,
166    assoc_refinements_of: UnordMap<K, QueryResult<rty::AssocRefinements>>,
167    assoc_refinements_def: UnordMap<FluxId<K>, QueryResult<rty::EarlyBinder<rty::Lambda>>>,
168    default_assoc_refinements_def:
169        UnordMap<FluxId<K>, QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>>,
170    sort_of_assoc_reft: UnordMap<FluxId<K>, QueryResult<rty::EarlyBinder<rty::FuncSort>>>,
171    fn_sig: UnordMap<K, QueryResult<rty::EarlyBinder<rty::PolyFnSig>>>,
172    adt_def: UnordMap<K, QueryResult<rty::AdtDef>>,
173    constant_info: UnordMap<K, QueryResult<rty::ConstantInfo>>,
174    static_info: UnordMap<K, QueryResult<rty::StaticInfo>>,
175    adt_sort_def: UnordMap<K, QueryResult<rty::AdtSortDef>>,
176    variants_of: UnordMap<K, QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>>,
177    type_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::TyOrCtor>>>,
178    normalized_defns: Rc<rty::NormalizedDefns>,
179    flux_module_children: UnordMap<K, Vec<fhir::FluxModChild>>,
180    func_sort: UnordMap<FluxId<K>, rty::PolyFuncSort>,
181    func_span: UnordMap<FluxId<K>, Span>,
182    sort_decl_param_count: UnordMap<FluxId<K>, usize>,
183    no_panic: UnordMap<K, bool>,
184    assume_parametric_params: UnordMap<K, UnordSet<u32>>,
185    spec_attr_span: UnordMap<K, Span>,
186    no_panic_specs: UnordMap<NodeKey<'tcx>, PanicSpec>,
187}
188
189impl<'tcx> CStore<'tcx> {
190    pub fn load(tcx: TyCtxt<'tcx>, sess: &FluxSession) -> Self {
191        let mut cstore = CStore::default();
192        for crate_num in tcx.used_crates(()) {
193            let Some(path) = flux_metadata_extern_location(tcx, *crate_num) else { continue };
194            let Some(meta) = decode_crate_metadata(tcx, sess, path.as_path()) else { continue };
195            cstore.local_tables.insert(*crate_num, meta.local_tables);
196            cstore.merge_extern_tables(tcx, sess, meta.extern_tables);
197        }
198        cstore
199    }
200
201    fn merge_extern_tables(
202        &mut self,
203        tcx: TyCtxt,
204        sess: &FluxSession,
205        extern_tables: Tables<'tcx, DefId>,
206    ) {
207        macro_rules! merge_extern_table {
208            ($self:expr, $tcx:expr, $table:ident, $extern_tables:expr) => {{
209                // This is technically observing the order because it has side effects, but it's ok
210                // because we emit a fatal error and abort the process
211                $extern_tables.$table.keys().map(|k| {
212                    if self.$table(*k).is_some() {
213                        sess.emit_fatal(errors::DuplicateSpec::new($tcx, *k));
214                    }
215                });
216                $self
217                    .extern_tables
218                    .$table
219                    .extend_unord(extern_tables.$table.into_items());
220            }};
221        }
222        merge_extern_table!(self, tcx, generics_of, extern_tables);
223        merge_extern_table!(self, tcx, refinement_generics_of, extern_tables);
224        merge_extern_table!(self, tcx, predicates_of, extern_tables);
225        merge_extern_table!(self, tcx, item_bounds, extern_tables);
226        merge_extern_table!(self, tcx, assoc_refinements_of, extern_tables);
227        merge_extern_table!(self, tcx, default_assoc_refinements_def, extern_tables);
228        merge_extern_table!(self, tcx, assoc_refinements_def, extern_tables);
229        merge_extern_table!(self, tcx, sort_of_assoc_reft, extern_tables);
230        merge_extern_table!(self, tcx, fn_sig, extern_tables);
231        merge_extern_table!(self, tcx, adt_def, extern_tables);
232        merge_extern_table!(self, tcx, adt_sort_def, extern_tables);
233        merge_extern_table!(self, tcx, variants_of, extern_tables);
234        merge_extern_table!(self, tcx, type_of, extern_tables);
235        merge_extern_table!(self, tcx, no_panic, extern_tables);
236        merge_extern_table!(self, tcx, assume_parametric_params, extern_tables);
237        merge_extern_table!(self, tcx, spec_attr_span, extern_tables);
238        merge_extern_table!(self, tcx, static_info, extern_tables);
239    }
240}
241
242macro_rules! get {
243    ($self:expr, $table:ident, $key:expr) => {{
244        let key = $key;
245        let this = $self;
246        if let Some(tables) = this.local_tables.get(&key.crate_num()) {
247            tables.$table.get(&key.to_index()).cloned()
248        } else {
249            this.extern_tables.$table.get(&key).cloned()
250        }
251    }};
252}
253
254/// Same as `get!` but returns a reference into the tables instead of cloning
255macro_rules! get_ref {
256    ($self:expr, $table:ident, $key:expr) => {{
257        let key = $key;
258        let this = $self;
259        if let Some(tables) = this.local_tables.get(&key.crate_num()) {
260            tables.$table.get(&key.to_index())
261        } else {
262            this.extern_tables.$table.get(&key)
263        }
264    }};
265}
266
267impl<'tcx> CrateStore<'tcx> for CStore<'tcx> {
268    fn fn_sig(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::PolyFnSig>> {
269        get!(self, fn_sig, def_id)
270    }
271
272    fn adt_def(&self, def_id: DefId) -> OptResult<rty::AdtDef> {
273        get!(self, adt_def, def_id)
274    }
275
276    fn adt_sort_def(&self, def_id: DefId) -> OptResult<rty::AdtSortDef> {
277        get!(self, adt_sort_def, def_id)
278    }
279
280    fn no_panic(&self, def_id: DefId) -> Option<bool> {
281        get!(self, no_panic, def_id)
282    }
283
284    fn assume_parametric_params(&self, def_id: DefId) -> Option<UnordSet<u32>> {
285        get!(self, assume_parametric_params, def_id)
286    }
287
288    fn variants_of(
289        &self,
290        def_id: DefId,
291    ) -> OptResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
292        get!(self, variants_of, def_id)
293    }
294
295    fn type_of(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::TyOrCtor>> {
296        get!(self, type_of, def_id)
297    }
298
299    fn generics_of(&self, def_id: DefId) -> OptResult<rty::Generics> {
300        get!(self, generics_of, def_id)
301    }
302
303    fn refinement_generics_of(
304        &self,
305        def_id: DefId,
306    ) -> OptResult<rty::EarlyBinder<rty::RefinementGenerics>> {
307        get!(self, refinement_generics_of, def_id)
308    }
309
310    fn item_bounds(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::Clauses>> {
311        get!(self, item_bounds, def_id)
312    }
313
314    fn predicates_of(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::GenericPredicates>> {
315        get!(self, predicates_of, def_id)
316    }
317
318    fn assoc_refinements_of(&self, def_id: DefId) -> OptResult<rty::AssocRefinements> {
319        get!(self, assoc_refinements_of, def_id)
320    }
321
322    fn assoc_refinements_def(&self, key: FluxDefId) -> OptResult<rty::EarlyBinder<rty::Lambda>> {
323        get!(self, assoc_refinements_def, key)
324    }
325
326    fn default_assoc_refinements_def(
327        &self,
328        key: FluxDefId,
329    ) -> OptResult<Option<rty::EarlyBinder<rty::Lambda>>> {
330        get!(self, default_assoc_refinements_def, key)
331    }
332
333    fn sort_of_assoc_reft(&self, key: FluxDefId) -> OptResult<rty::EarlyBinder<rty::FuncSort>> {
334        get!(self, sort_of_assoc_reft, key)
335    }
336
337    fn constant_info(&self, key: DefId) -> OptResult<rty::ConstantInfo> {
338        get!(self, constant_info, key)
339    }
340
341    fn static_info(&self, key: DefId) -> OptResult<rty::StaticInfo> {
342        get!(self, static_info, key)
343    }
344
345    fn normalized_defns(&self, krate: CrateNum) -> std::rc::Rc<rty::NormalizedDefns> {
346        self.local_tables[&krate].normalized_defns.clone()
347    }
348
349    fn flux_module_children(&self, def_id: DefId) -> Option<&[fhir::FluxModChild]> {
350        get_ref!(self, flux_module_children, def_id).map(Vec::as_slice)
351    }
352
353    fn inferred_no_panic(&self, krate: CrateNum) -> Rc<UnordMap<NodeKey<'tcx>, PanicSpec>> {
354        // TODO: Some transitive deps (e.g. `hashbrown`) have no flux metadata. Return
355        // an empty map (conservative: MightPanic) until the proper fix is in place.
356        // See notes/hashbrown-inferred-no-panic.txt.
357        Rc::new(
358            self.local_tables
359                .get(&krate)
360                .map(|t| t.no_panic_specs.clone())
361                .unwrap_or_default(),
362        )
363    }
364
365    fn has_crate(&self, krate: CrateNum) -> bool {
366        self.local_tables.contains_key(&krate)
367    }
368
369    fn func_sort(&self, key: FluxDefId) -> Option<rty::PolyFuncSort> {
370        get!(self, func_sort, key)
371    }
372
373    fn func_span(&self, key: FluxDefId) -> Option<Span> {
374        get!(self, func_span, key)
375    }
376
377    fn sort_decl_param_count(&self, key: FluxDefId) -> Option<usize> {
378        get!(self, sort_decl_param_count, key)
379    }
380
381    fn spec_attr_span(&self, def_id: DefId) -> Option<Span> {
382        get!(self, spec_attr_span, def_id)
383    }
384}
385
386impl<'tcx> CrateMetadata<'tcx> {
387    #[allow(
388        clippy::disallowed_methods,
389        reason = "we seed the call graph with non-dummy local def ids, so the traversal should never reach dummy extern spec items."
390    )]
391    fn new(genv: GlobalEnv<'_, 'tcx>) -> Self {
392        let mut local_tables = Tables::default();
393        encode_def_ids(
394            genv,
395            genv.iter_local_def_id().map(LocalDefId::to_def_id),
396            &mut local_tables,
397            DefId::to_index,
398            FluxDefId::to_index,
399        );
400        encode_flux_defs(genv, &mut local_tables);
401        // Serialize the `NodeKey`-keyed map filtered to nodes of locally-defined functions (source
402        // items + monomorphizations). Only `Item`-kind instances carry a meaningful spec; shims and
403        // other non-`Item` instances are `Leaf`/`MightPanic` and not worth storing. Downstream
404        // crates reconstruct these keys for exact/identity lookups (`inferred_no_panic_external`).
405        local_tables.no_panic_specs = genv
406            .inferred_no_panic_local()
407            .items()
408            .filter(|(key, _)| key.is_local_item())
409            .map(|(key, spec)| (*key, *spec))
410            .collect();
411
412        let mut extern_tables = Tables::default();
413        encode_def_ids(
414            genv,
415            genv.iter_extern_def_id(),
416            &mut extern_tables,
417            |def_id| def_id,
418            |flux_id| flux_id,
419        );
420
421        CrateMetadata { local_tables, extern_tables }
422    }
423}
424
425fn encode_flux_defs<'tcx>(genv: GlobalEnv<'_, 'tcx>, tables: &mut Tables<'tcx, DefIndex>) {
426    tables.normalized_defns = genv.normalized_defns(LOCAL_CRATE);
427
428    encode_flux_module_children(genv, tables);
429    for (def_id, item) in genv.fhir_iter_flux_items() {
430        match item {
431            fhir::FluxItem::Func(spec_func) => {
432                tables
433                    .func_sort
434                    .insert(def_id.local_def_index(), genv.func_sort(def_id));
435                tables
436                    .func_span
437                    .insert(def_id.local_def_index(), spec_func.ident_span);
438            }
439            fhir::FluxItem::SortDecl(_sort_decl) => {
440                tables
441                    .sort_decl_param_count
442                    .insert(def_id.local_def_index(), genv.sort_decl_param_count(def_id));
443            }
444            fhir::FluxItem::PrimOpProp(_) | fhir::FluxItem::Qualifier(_) => {}
445        }
446    }
447}
448
449#[allow(clippy::disallowed_methods, reason = "`flux_items_by_parent` is the source of truth")]
450fn encode_flux_module_children<'tcx>(
451    genv: GlobalEnv<'_, 'tcx>,
452    tables: &mut Tables<'tcx, DefIndex>,
453) {
454    let specs = genv.collect_specs();
455    for parent in specs.flux_items_by_parent.keys() {
456        let children = genv.flux_module_children(parent.def_id.to_def_id());
457        tables
458            .flux_module_children
459            .insert(parent.def_id.local_def_index, children.to_vec());
460    }
461}
462
463fn encode_def_ids<'tcx, K: Eq + Hash + Copy>(
464    genv: GlobalEnv<'_, 'tcx>,
465    def_ids: impl IntoIterator<Item = DefId>,
466    tables: &mut Tables<'tcx, K>,
467    did_to_key: fn(DefId) -> K,
468    assoc_id_to_key: fn(FluxDefId) -> FluxId<K>,
469) {
470    for def_id in def_ids {
471        let def_kind = genv.def_kind(def_id);
472        let key = did_to_key(def_id);
473
474        match def_kind {
475            DefKind::Trait => {
476                tables
477                    .generics_of
478                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
479                tables
480                    .predicates_of
481                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
482                tables.refinement_generics_of.insert(
483                    key,
484                    genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
485                );
486                let assocs = genv.run_query_if_reached(def_id, GlobalEnv::assoc_refinements_of);
487                if let Ok(assocs) = &assocs {
488                    for assoc_reft in &assocs.items {
489                        let def_id = assoc_reft.def_id();
490                        let key = assoc_id_to_key(def_id);
491                        tables.default_assoc_refinements_def.insert(
492                            key,
493                            genv.run_query_if_reached(
494                                def_id,
495                                GlobalEnv::default_assoc_refinement_body,
496                            ),
497                        );
498                        tables.sort_of_assoc_reft.insert(
499                            key,
500                            genv.run_query_if_reached(def_id, GlobalEnv::sort_of_assoc_reft),
501                        );
502                    }
503                }
504                tables.assoc_refinements_of.insert(key, assocs);
505            }
506            DefKind::Impl { of_trait } => {
507                tables
508                    .generics_of
509                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
510                tables
511                    .predicates_of
512                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
513                tables.refinement_generics_of.insert(
514                    key,
515                    genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
516                );
517
518                if of_trait {
519                    let assocs = genv.run_query_if_reached(def_id, GlobalEnv::assoc_refinements_of);
520                    if let Ok(assocs) = &assocs {
521                        for assoc_reft in &assocs.items {
522                            let def_id = assoc_reft.def_id();
523                            let key = assoc_id_to_key(def_id);
524                            tables.assoc_refinements_def.insert(
525                                key,
526                                genv.run_query_if_reached(def_id, GlobalEnv::assoc_refinement_body),
527                            );
528                            tables.sort_of_assoc_reft.insert(
529                                key,
530                                genv.run_query_if_reached(def_id, GlobalEnv::sort_of_assoc_reft),
531                            );
532                        }
533                    }
534                    tables.assoc_refinements_of.insert(key, assocs);
535                }
536            }
537            DefKind::Fn | DefKind::AssocFn => {
538                tables
539                    .generics_of
540                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
541                tables
542                    .predicates_of
543                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
544                tables.refinement_generics_of.insert(
545                    key,
546                    genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
547                );
548                tables
549                    .fn_sig
550                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::fn_sig));
551                tables.no_panic.insert(key, genv.no_panic(def_id));
552                tables
553                    .assume_parametric_params
554                    .insert(key, genv.assume_parametric_params(def_id));
555                if let Some(span) = genv.spec_attr_span(def_id) {
556                    tables.spec_attr_span.insert(key, span);
557                }
558            }
559            DefKind::Ctor(_, CtorKind::Fn) => {
560                tables
561                    .generics_of
562                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
563                tables.refinement_generics_of.insert(
564                    key,
565                    genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
566                );
567                tables
568                    .fn_sig
569                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::fn_sig));
570            }
571            DefKind::Enum | DefKind::Struct => {
572                tables
573                    .generics_of
574                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
575                tables
576                    .predicates_of
577                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
578                tables.refinement_generics_of.insert(
579                    key,
580                    genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
581                );
582                tables
583                    .adt_def
584                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::adt_def));
585                tables
586                    .adt_sort_def
587                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::adt_sort_def_of));
588                tables
589                    .variants_of
590                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::variants_of));
591                tables
592                    .type_of
593                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::type_of));
594            }
595            DefKind::TyAlias => {
596                tables
597                    .generics_of
598                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
599                tables
600                    .predicates_of
601                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
602                tables.refinement_generics_of.insert(
603                    key,
604                    genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
605                );
606                tables
607                    .type_of
608                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::type_of));
609            }
610            DefKind::OpaqueTy => {
611                tables
612                    .generics_of
613                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
614                tables
615                    .predicates_of
616                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
617                tables
618                    .item_bounds
619                    .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::item_bounds));
620                tables.refinement_generics_of.insert(
621                    key,
622                    genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
623                );
624            }
625            DefKind::Static { .. } => {
626                tables.static_info.insert(key, genv.static_info(def_id));
627            }
628            _ => {}
629        }
630    }
631}
632
633pub fn filename_for_metadata(tcx: TyCtxt) -> OutFileName {
634    match rustc_session::output::filename_for_metadata(tcx.sess, tcx.output_filenames(())) {
635        OutFileName::Real(path) => OutFileName::Real(path.with_extension("fluxmeta")),
636        OutFileName::Stdout => OutFileName::Stdout,
637    }
638}
639
640fn flux_metadata_extern_location(tcx: TyCtxt, crate_num: CrateNum) -> Option<PathBuf> {
641    // Since we only save metadata when `--emit=metadata` is passed, we also only load flux metadata
642    // when the crate source is a `.rmeta` file.
643    tcx.used_crate_source(crate_num)
644        .rmeta
645        .as_ref()
646        .map(|path| path.with_extension("fluxmeta"))
647}
648
649// Tags for encoding Symbol's
650const SYMBOL_STR: u8 = 0;
651const SYMBOL_OFFSET: u8 = 1;
652const SYMBOL_PREDEFINED: u8 = 2;
653
654mod errors {
655    use flux_errors::E0999;
656    use flux_macros::Diagnostic;
657    use rustc_middle::ty::TyCtxt;
658
659    use crate::Key;
660
661    #[derive(Diagnostic)]
662    #[diag(metadata_duplicate_spec, code = E0999)]
663    pub(super) struct DuplicateSpec {
664        def_name: String,
665    }
666
667    impl DuplicateSpec {
668        pub(super) fn new(tcx: TyCtxt, key: impl Key) -> Self {
669            Self { def_name: key.name(tcx) }
670        }
671    }
672}