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    cstore::{CrateStore, OptResult},
30    def_id::{FluxDefId, FluxId},
31    fhir,
32    global_env::GlobalEnv,
33    queries::QueryResult,
34    rty,
35};
36use rustc_data_structures::{
37    fx::FxHashMap,
38    unord::{ExtendUnord, UnordMap},
39};
40use rustc_hir::{
41    def::{CtorKind, DefKind},
42    def_id::{LOCAL_CRATE, LocalDefId},
43};
44use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
45use rustc_middle::ty::TyCtxt;
46use rustc_session::config::OutFileName;
47use rustc_span::{
48    SourceFile, Span, StableSourceFileId,
49    def_id::{CrateNum, DefId, DefIndex, StableCrateId},
50};
51
52pub use crate::encoder::encode_metadata;
53
54fluent_messages! { "../locales/en-US.ftl" }
55
56const METADATA_VERSION: u8 = 0;
57const METADATA_HEADER: &[u8] = &[b'f', b'l', b'u', b'x', 0, 0, 0, METADATA_VERSION];
58
59#[derive(Default)]
60pub struct CStore {
61    local_tables: UnordMap<CrateNum, Tables<DefIndex>>,
62    extern_tables: Tables<DefId>,
63}
64
65/// From CREUSOT: used to store the info about source files
66/// An `EncodedSourceFileId` is the same as a `StableSourceFileId` except that
67/// the source crate is represented as a [StableCrateId] instead of as a
68/// `CrateNum`. This way `EncodedSourceFileId` can be encoded and decoded
69/// without any additional context, i.e. with a simple `opaque::Decoder` (which
70/// is the only thing available when decoding the [Footer].
71#[derive(Encodable, Decodable, Clone, Debug)]
72struct EncodedSourceFileId {
73    stable_source_file_id: StableSourceFileId,
74    stable_crate_id: StableCrateId,
75}
76
77impl EncodedSourceFileId {
78    #[inline]
79    fn new(tcx: TyCtxt<'_>, file: &SourceFile) -> EncodedSourceFileId {
80        EncodedSourceFileId {
81            stable_source_file_id: file.stable_id,
82            stable_crate_id: tcx.stable_crate_id(file.cnum),
83        }
84    }
85}
86
87// Taken from CREUSOT; used to store the info about syntax contexts
88#[derive(Default, Decodable, Encodable)]
89pub struct Footer {
90    file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
91    syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
92    expn_data: FxHashMap<(StableCrateId, u32), AbsoluteBytePos>,
93}
94#[derive(Encodable, Decodable, Eq, PartialEq, Hash, Clone, Copy, Debug)]
95struct SourceFileIndex(u32);
96
97#[derive(Encodable, Decodable, Clone, Copy)]
98pub struct AbsoluteBytePos(u64);
99
100impl AbsoluteBytePos {
101    fn new(pos: usize) -> AbsoluteBytePos {
102        AbsoluteBytePos(pos.try_into().unwrap())
103    }
104
105    fn to_usize(self) -> usize {
106        self.0 as usize
107    }
108}
109
110#[derive(Default, TyEncodable, TyDecodable)]
111pub struct CrateMetadata {
112    local_tables: Tables<DefIndex>,
113    extern_tables: Tables<DefId>,
114}
115
116/// Trait to deal with the fact that `assoc_refinmenents_of` and `assoc_refinements_def` use
117/// `FluxId<K>` as key;
118trait Key {
119    type KeyIndex;
120    fn crate_num(self) -> CrateNum;
121    fn to_index(self) -> Self::KeyIndex;
122    fn name(self, tcx: TyCtxt) -> String;
123}
124
125impl Key for DefId {
126    type KeyIndex = DefIndex;
127
128    fn crate_num(self) -> CrateNum {
129        self.krate
130    }
131
132    fn to_index(self) -> Self::KeyIndex {
133        self.index
134    }
135
136    fn name(self, tcx: TyCtxt) -> String {
137        tcx.def_path_str(self)
138    }
139}
140
141impl Key for FluxDefId {
142    type KeyIndex = FluxId<DefIndex>;
143
144    fn crate_num(self) -> CrateNum {
145        self.parent().krate
146    }
147
148    fn to_index(self) -> Self::KeyIndex {
149        self.index()
150    }
151
152    fn name(self, tcx: TyCtxt) -> String {
153        format!("{}::{}", tcx.def_path_str(self.parent()), self.name())
154    }
155}
156
157#[derive_where(Default)]
158#[derive(TyEncodable, TyDecodable)]
159pub struct Tables<K: Eq + Hash> {
160    generics_of: UnordMap<K, QueryResult<rty::Generics>>,
161    refinement_generics_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>>,
162    predicates_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::GenericPredicates>>>,
163    item_bounds: UnordMap<K, QueryResult<rty::EarlyBinder<rty::Clauses>>>,
164    assoc_refinements_of: UnordMap<K, QueryResult<rty::AssocRefinements>>,
165    assoc_refinements_def: UnordMap<FluxId<K>, QueryResult<rty::EarlyBinder<rty::Lambda>>>,
166    default_assoc_refinements_def:
167        UnordMap<FluxId<K>, QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>>,
168    sort_of_assoc_reft: UnordMap<FluxId<K>, QueryResult<rty::EarlyBinder<rty::FuncSort>>>,
169    fn_sig: UnordMap<K, QueryResult<rty::EarlyBinder<rty::PolyFnSig>>>,
170    adt_def: UnordMap<K, QueryResult<rty::AdtDef>>,
171    constant_info: UnordMap<K, QueryResult<rty::ConstantInfo>>,
172    adt_sort_def: UnordMap<K, QueryResult<rty::AdtSortDef>>,
173    variants_of: UnordMap<K, QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>>,
174    type_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::TyOrCtor>>>,
175    normalized_defns: Rc<rty::NormalizedDefns>,
176    func_sort: UnordMap<FluxId<K>, rty::PolyFuncSort>,
177    func_span: UnordMap<FluxId<K>, Span>,
178    sort_decl_param_count: UnordMap<FluxId<K>, usize>,
179    no_panic: UnordMap<K, bool>,
180}
181
182impl CStore {
183    pub fn load(tcx: TyCtxt, sess: &FluxSession) -> Self {
184        let mut cstore = CStore::default();
185        for crate_num in tcx.used_crates(()) {
186            let Some(path) = flux_metadata_extern_location(tcx, *crate_num) else { continue };
187            let Some(meta) = decode_crate_metadata(tcx, sess, path.as_path()) else { continue };
188            cstore.local_tables.insert(*crate_num, meta.local_tables);
189            cstore.merge_extern_tables(tcx, sess, meta.extern_tables);
190        }
191        cstore
192    }
193
194    fn merge_extern_tables(
195        &mut self,
196        tcx: TyCtxt,
197        sess: &FluxSession,
198        extern_tables: Tables<DefId>,
199    ) {
200        macro_rules! merge_extern_table {
201            ($self:expr, $tcx:expr, $table:ident, $extern_tables:expr) => {{
202                // This is technically observing the order because it has side effects, but it's ok
203                // because we emit a fatal error and abort the process
204                $extern_tables.$table.keys().map(|k| {
205                    if self.$table(*k).is_some() {
206                        sess.emit_fatal(errors::DuplicateSpec::new($tcx, *k));
207                    }
208                });
209                $self
210                    .extern_tables
211                    .$table
212                    .extend_unord(extern_tables.$table.into_items());
213            }};
214        }
215        merge_extern_table!(self, tcx, generics_of, extern_tables);
216        merge_extern_table!(self, tcx, refinement_generics_of, extern_tables);
217        merge_extern_table!(self, tcx, predicates_of, extern_tables);
218        merge_extern_table!(self, tcx, item_bounds, extern_tables);
219        merge_extern_table!(self, tcx, assoc_refinements_of, extern_tables);
220        merge_extern_table!(self, tcx, default_assoc_refinements_def, extern_tables);
221        merge_extern_table!(self, tcx, assoc_refinements_def, extern_tables);
222        merge_extern_table!(self, tcx, sort_of_assoc_reft, extern_tables);
223        merge_extern_table!(self, tcx, fn_sig, extern_tables);
224        merge_extern_table!(self, tcx, adt_def, extern_tables);
225        merge_extern_table!(self, tcx, adt_sort_def, extern_tables);
226        merge_extern_table!(self, tcx, variants_of, extern_tables);
227        merge_extern_table!(self, tcx, type_of, extern_tables);
228        merge_extern_table!(self, tcx, no_panic, extern_tables);
229    }
230}
231
232macro_rules! get {
233    ($self:expr, $table:ident, $key:expr) => {{
234        let key = $key;
235        let this = $self;
236        if let Some(tables) = this.local_tables.get(&key.crate_num()) {
237            tables.$table.get(&key.to_index()).cloned()
238        } else {
239            this.extern_tables.$table.get(&key).cloned()
240        }
241    }};
242}
243
244impl CrateStore for CStore {
245    fn fn_sig(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::PolyFnSig>> {
246        get!(self, fn_sig, def_id)
247    }
248
249    fn adt_def(&self, def_id: DefId) -> OptResult<rty::AdtDef> {
250        get!(self, adt_def, def_id)
251    }
252
253    fn adt_sort_def(&self, def_id: DefId) -> OptResult<rty::AdtSortDef> {
254        get!(self, adt_sort_def, def_id)
255    }
256
257    fn no_panic(&self, def_id: DefId) -> Option<bool> {
258        get!(self, no_panic, def_id)
259    }
260
261    fn variants_of(
262        &self,
263        def_id: DefId,
264    ) -> OptResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
265        get!(self, variants_of, def_id)
266    }
267
268    fn type_of(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::TyOrCtor>> {
269        get!(self, type_of, def_id)
270    }
271
272    fn generics_of(&self, def_id: DefId) -> OptResult<rty::Generics> {
273        get!(self, generics_of, def_id)
274    }
275
276    fn refinement_generics_of(
277        &self,
278        def_id: DefId,
279    ) -> OptResult<rty::EarlyBinder<rty::RefinementGenerics>> {
280        get!(self, refinement_generics_of, def_id)
281    }
282
283    fn item_bounds(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::Clauses>> {
284        get!(self, item_bounds, def_id)
285    }
286
287    fn predicates_of(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::GenericPredicates>> {
288        get!(self, predicates_of, def_id)
289    }
290
291    fn assoc_refinements_of(&self, def_id: DefId) -> OptResult<rty::AssocRefinements> {
292        get!(self, assoc_refinements_of, def_id)
293    }
294
295    fn assoc_refinements_def(&self, key: FluxDefId) -> OptResult<rty::EarlyBinder<rty::Lambda>> {
296        get!(self, assoc_refinements_def, key)
297    }
298
299    fn default_assoc_refinements_def(
300        &self,
301        key: FluxDefId,
302    ) -> OptResult<Option<rty::EarlyBinder<rty::Lambda>>> {
303        get!(self, default_assoc_refinements_def, key)
304    }
305
306    fn sort_of_assoc_reft(&self, key: FluxDefId) -> OptResult<rty::EarlyBinder<rty::FuncSort>> {
307        get!(self, sort_of_assoc_reft, key)
308    }
309
310    fn constant_info(&self, key: DefId) -> OptResult<rty::ConstantInfo> {
311        get!(self, constant_info, key)
312    }
313
314    fn normalized_defns(&self, krate: CrateNum) -> std::rc::Rc<rty::NormalizedDefns> {
315        self.local_tables[&krate].normalized_defns.clone()
316    }
317
318    fn func_sort(&self, key: FluxDefId) -> Option<rty::PolyFuncSort> {
319        get!(self, func_sort, key)
320    }
321
322    fn func_span(&self, key: FluxDefId) -> Option<Span> {
323        get!(self, func_span, key)
324    }
325
326    fn sort_decl_param_count(&self, key: FluxDefId) -> Option<usize> {
327        get!(self, sort_decl_param_count, key)
328    }
329}
330
331impl CrateMetadata {
332    fn new(genv: GlobalEnv) -> Self {
333        let mut local_tables = Tables::default();
334        encode_def_ids(
335            genv,
336            genv.iter_local_def_id().map(LocalDefId::to_def_id),
337            &mut local_tables,
338            DefId::to_index,
339            FluxDefId::to_index,
340        );
341        encode_flux_defs(genv, &mut local_tables);
342
343        let mut extern_tables = Tables::default();
344        encode_def_ids(
345            genv,
346            genv.iter_extern_def_id(),
347            &mut extern_tables,
348            |def_id| def_id,
349            |flux_id| flux_id,
350        );
351
352        CrateMetadata { local_tables, extern_tables }
353    }
354}
355
356fn encode_flux_defs(genv: GlobalEnv, tables: &mut Tables<DefIndex>) {
357    tables.normalized_defns = genv.normalized_defns(LOCAL_CRATE);
358
359    for (def_id, item) in genv.fhir_iter_flux_items() {
360        match item {
361            fhir::FluxItem::Func(spec_func) => {
362                tables
363                    .func_sort
364                    .insert(def_id.local_def_index(), genv.func_sort(def_id));
365                tables
366                    .func_span
367                    .insert(def_id.local_def_index(), spec_func.ident_span);
368            }
369            fhir::FluxItem::SortDecl(_sort_decl) => {
370                tables
371                    .sort_decl_param_count
372                    .insert(def_id.local_def_index(), genv.sort_decl_param_count(def_id));
373            }
374            fhir::FluxItem::PrimOpProp(_) | fhir::FluxItem::Qualifier(_) => {}
375        }
376    }
377}
378
379fn encode_def_ids<K: Eq + Hash + Copy>(
380    genv: GlobalEnv,
381    def_ids: impl IntoIterator<Item = DefId>,
382    tables: &mut Tables<K>,
383    did_to_key: fn(DefId) -> K,
384    assoc_id_to_key: fn(FluxDefId) -> FluxId<K>,
385) {
386    for def_id in def_ids {
387        let def_kind = genv.def_kind(def_id);
388        let key = did_to_key(def_id);
389
390        match def_kind {
391            DefKind::Trait => {
392                tables.generics_of.insert(key, genv.generics_of(def_id));
393                tables.predicates_of.insert(key, genv.predicates_of(def_id));
394                tables
395                    .refinement_generics_of
396                    .insert(key, genv.refinement_generics_of(def_id));
397                let assocs = genv.assoc_refinements_of(def_id);
398                if let Ok(assocs) = &assocs {
399                    for assoc_reft in &assocs.items {
400                        let def_id = assoc_reft.def_id();
401                        let key = assoc_id_to_key(def_id);
402                        tables
403                            .default_assoc_refinements_def
404                            .insert(key, genv.default_assoc_refinement_body(def_id));
405                        tables
406                            .sort_of_assoc_reft
407                            .insert(key, genv.sort_of_assoc_reft(def_id));
408                    }
409                }
410                tables.assoc_refinements_of.insert(key, assocs);
411            }
412            DefKind::Impl { of_trait } => {
413                tables.generics_of.insert(key, genv.generics_of(def_id));
414                tables.predicates_of.insert(key, genv.predicates_of(def_id));
415                tables
416                    .refinement_generics_of
417                    .insert(key, genv.refinement_generics_of(def_id));
418
419                if of_trait {
420                    let assocs = genv.assoc_refinements_of(def_id);
421                    if let Ok(assocs) = &assocs {
422                        for assoc_reft in &assocs.items {
423                            let def_id = assoc_reft.def_id();
424                            let key = assoc_id_to_key(def_id);
425                            tables
426                                .assoc_refinements_def
427                                .insert(key, genv.assoc_refinement_body(def_id));
428                            tables
429                                .sort_of_assoc_reft
430                                .insert(key, genv.sort_of_assoc_reft(def_id));
431                        }
432                    }
433                    tables.assoc_refinements_of.insert(key, assocs);
434                }
435            }
436            DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) => {
437                tables.generics_of.insert(key, genv.generics_of(def_id));
438                tables.predicates_of.insert(key, genv.predicates_of(def_id));
439                tables
440                    .refinement_generics_of
441                    .insert(key, genv.refinement_generics_of(def_id));
442                tables.fn_sig.insert(key, genv.fn_sig(def_id));
443                tables.no_panic.insert(key, genv.no_panic(def_id));
444            }
445            DefKind::Enum | DefKind::Struct => {
446                tables.generics_of.insert(key, genv.generics_of(def_id));
447                tables.predicates_of.insert(key, genv.predicates_of(def_id));
448                tables
449                    .refinement_generics_of
450                    .insert(key, genv.refinement_generics_of(def_id));
451                tables.adt_def.insert(key, genv.adt_def(def_id));
452                tables
453                    .adt_sort_def
454                    .insert(key, genv.adt_sort_def_of(def_id));
455                tables.variants_of.insert(key, genv.variants_of(def_id));
456                tables.type_of.insert(key, genv.type_of(def_id));
457            }
458            DefKind::TyAlias => {
459                tables.generics_of.insert(key, genv.generics_of(def_id));
460                tables.predicates_of.insert(key, genv.predicates_of(def_id));
461                tables
462                    .refinement_generics_of
463                    .insert(key, genv.refinement_generics_of(def_id));
464                tables.type_of.insert(key, genv.type_of(def_id));
465            }
466            DefKind::OpaqueTy => {
467                tables.generics_of.insert(key, genv.generics_of(def_id));
468                tables.predicates_of.insert(key, genv.predicates_of(def_id));
469                tables.item_bounds.insert(key, genv.item_bounds(def_id));
470                tables
471                    .refinement_generics_of
472                    .insert(key, genv.refinement_generics_of(def_id));
473            }
474            _ => {}
475        }
476    }
477}
478
479pub fn filename_for_metadata(tcx: TyCtxt) -> OutFileName {
480    match rustc_session::output::filename_for_metadata(tcx.sess, tcx.output_filenames(())) {
481        OutFileName::Real(path) => OutFileName::Real(path.with_extension("fluxmeta")),
482        OutFileName::Stdout => OutFileName::Stdout,
483    }
484}
485
486fn flux_metadata_extern_location(tcx: TyCtxt, crate_num: CrateNum) -> Option<PathBuf> {
487    // Since we only save metadata when `--emit=metadata` is passed, we also only load flux metadata
488    // when the crate source is a `.rmeta` file.
489    tcx.used_crate_source(crate_num)
490        .rmeta
491        .as_ref()
492        .map(|(path, _)| path.with_extension("fluxmeta"))
493}
494
495// Tags for encoding Symbol's
496const SYMBOL_STR: u8 = 0;
497const SYMBOL_OFFSET: u8 = 1;
498const SYMBOL_PREDEFINED: u8 = 2;
499
500mod errors {
501    use flux_errors::E0999;
502    use flux_macros::Diagnostic;
503    use rustc_middle::ty::TyCtxt;
504
505    use crate::Key;
506
507    #[derive(Diagnostic)]
508    #[diag(metadata_duplicate_spec, code = E0999)]
509    pub(super) struct DuplicateSpec {
510        def_name: String,
511    }
512
513    impl DuplicateSpec {
514        pub(super) fn new(tcx: TyCtxt, key: impl Key) -> Self {
515            Self { def_name: key.name(tcx) }
516        }
517    }
518}