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;
7
8extern crate rustc_hir;
9extern crate rustc_macros;
10extern crate rustc_metadata;
11extern crate rustc_middle;
12extern crate rustc_serialize;
13extern crate rustc_session;
14extern crate rustc_span;
15
16mod decoder;
17mod encoder;
18
19use std::{hash::Hash, path::PathBuf, rc::Rc};
20
21use decoder::decode_crate_metadata;
22use derive_where::derive_where;
23use flux_errors::FluxSession;
24use flux_macros::fluent_messages;
25use flux_middle::{
26    cstore::{CrateStore, OptResult},
27    def_id::{FluxDefId, FluxId},
28    fhir,
29    global_env::GlobalEnv,
30    queries::QueryResult,
31    rty,
32};
33use rustc_data_structures::unord::{ExtendUnord, UnordMap};
34use rustc_hir::{
35    def::DefKind,
36    def_id::{LOCAL_CRATE, LocalDefId},
37};
38use rustc_macros::{TyDecodable, TyEncodable};
39use rustc_middle::ty::TyCtxt;
40use rustc_session::config::OutFileName;
41use rustc_span::def_id::{CrateNum, DefId, DefIndex};
42
43pub use crate::encoder::encode_metadata;
44
45fluent_messages! { "../locales/en-US.ftl" }
46
47const METADATA_VERSION: u8 = 0;
48const METADATA_HEADER: &[u8] = &[b'f', b'l', b'u', b'x', 0, 0, 0, METADATA_VERSION];
49
50#[derive(Default)]
51pub struct CStore {
52    local_tables: UnordMap<CrateNum, Tables<DefIndex>>,
53    extern_tables: Tables<DefId>,
54}
55
56#[derive(Default, TyEncodable, TyDecodable)]
57pub struct CrateMetadata {
58    local_tables: Tables<DefIndex>,
59    extern_tables: Tables<DefId>,
60}
61
62/// Trait to deal with the fact that `assoc_refinmenents_of` and `assoc_refinements_def` use
63/// `FluxId<K>` as key;
64trait Key {
65    type KeyIndex;
66    fn crate_num(self) -> CrateNum;
67    fn to_index(self) -> Self::KeyIndex;
68    fn name(self, tcx: TyCtxt) -> String;
69}
70
71impl Key for DefId {
72    type KeyIndex = DefIndex;
73
74    fn crate_num(self) -> CrateNum {
75        self.krate
76    }
77
78    fn to_index(self) -> Self::KeyIndex {
79        self.index
80    }
81
82    fn name(self, tcx: TyCtxt) -> String {
83        tcx.def_path_str(self)
84    }
85}
86
87impl Key for FluxDefId {
88    type KeyIndex = FluxId<DefIndex>;
89
90    fn crate_num(self) -> CrateNum {
91        self.parent().krate
92    }
93
94    fn to_index(self) -> Self::KeyIndex {
95        self.index()
96    }
97
98    fn name(self, tcx: TyCtxt) -> String {
99        format!("{}::{}", tcx.def_path_str(self.parent()), self.name())
100    }
101}
102
103#[derive_where(Default)]
104#[derive(TyEncodable, TyDecodable)]
105pub struct Tables<K: Eq + Hash> {
106    generics_of: UnordMap<K, QueryResult<rty::Generics>>,
107    refinement_generics_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>>,
108    predicates_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::GenericPredicates>>>,
109    item_bounds: UnordMap<K, QueryResult<rty::EarlyBinder<rty::Clauses>>>,
110    assoc_refinements_of: UnordMap<K, QueryResult<rty::AssocRefinements>>,
111    assoc_refinements_def: UnordMap<FluxId<K>, QueryResult<rty::EarlyBinder<rty::Lambda>>>,
112    default_assoc_refinements_def:
113        UnordMap<FluxId<K>, QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>>,
114    sort_of_assoc_reft: UnordMap<FluxId<K>, QueryResult<rty::EarlyBinder<rty::FuncSort>>>,
115    fn_sig: UnordMap<K, QueryResult<rty::EarlyBinder<rty::PolyFnSig>>>,
116    adt_def: UnordMap<K, QueryResult<rty::AdtDef>>,
117    constant_info: UnordMap<K, QueryResult<rty::ConstantInfo>>,
118    adt_sort_def: UnordMap<K, QueryResult<rty::AdtSortDef>>,
119    variants: UnordMap<K, QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>>,
120    type_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::TyOrCtor>>>,
121    normalized_defns: Rc<rty::NormalizedDefns>,
122    func_sort: UnordMap<FluxId<K>, rty::PolyFuncSort>,
123}
124
125impl CStore {
126    pub fn load(tcx: TyCtxt, sess: &FluxSession) -> Self {
127        let mut cstore = CStore::default();
128        for crate_num in tcx.used_crates(()) {
129            let Some(path) = flux_metadata_extern_location(tcx, *crate_num) else { continue };
130            let Some(meta) = decode_crate_metadata(tcx, sess, path.as_path()) else { continue };
131            cstore.local_tables.insert(*crate_num, meta.local_tables);
132            cstore.merge_extern_tables(tcx, sess, meta.extern_tables);
133        }
134        cstore
135    }
136
137    fn merge_extern_tables(
138        &mut self,
139        tcx: TyCtxt,
140        sess: &FluxSession,
141        extern_tables: Tables<DefId>,
142    ) {
143        macro_rules! merge_extern_table {
144            ($self:expr, $tcx:expr, $table:ident, $extern_tables:expr) => {{
145                // This is technically observing the order because it has side effects, but it's ok
146                // because we emit a fatal error and abort the process
147                $extern_tables.$table.keys().map(|k| {
148                    if self.$table(*k).is_some() {
149                        sess.emit_fatal(errors::DuplicateSpec::new($tcx, *k));
150                    }
151                });
152                $self
153                    .extern_tables
154                    .$table
155                    .extend_unord(extern_tables.$table.into_items());
156            }};
157        }
158        merge_extern_table!(self, tcx, generics_of, extern_tables);
159        merge_extern_table!(self, tcx, refinement_generics_of, extern_tables);
160        merge_extern_table!(self, tcx, predicates_of, extern_tables);
161        merge_extern_table!(self, tcx, item_bounds, extern_tables);
162        merge_extern_table!(self, tcx, assoc_refinements_of, extern_tables);
163        merge_extern_table!(self, tcx, default_assoc_refinements_def, extern_tables);
164        merge_extern_table!(self, tcx, assoc_refinements_def, extern_tables);
165        merge_extern_table!(self, tcx, sort_of_assoc_reft, extern_tables);
166        merge_extern_table!(self, tcx, fn_sig, extern_tables);
167        merge_extern_table!(self, tcx, adt_def, extern_tables);
168        merge_extern_table!(self, tcx, adt_sort_def, extern_tables);
169        merge_extern_table!(self, tcx, variants, extern_tables);
170        merge_extern_table!(self, tcx, type_of, extern_tables);
171    }
172}
173
174macro_rules! get {
175    ($self:expr, $table:ident, $key:expr) => {{
176        let key = $key;
177        let this = $self;
178        if let Some(tables) = this.local_tables.get(&key.crate_num()) {
179            tables.$table.get(&key.to_index()).cloned()
180        } else {
181            this.extern_tables.$table.get(&key).cloned()
182        }
183    }};
184}
185
186impl CrateStore for CStore {
187    fn fn_sig(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::PolyFnSig>> {
188        get!(self, fn_sig, def_id)
189    }
190
191    fn adt_def(&self, def_id: DefId) -> OptResult<rty::AdtDef> {
192        get!(self, adt_def, def_id)
193    }
194
195    fn adt_sort_def(&self, def_id: DefId) -> OptResult<rty::AdtSortDef> {
196        get!(self, adt_sort_def, def_id)
197    }
198
199    fn variants(
200        &self,
201        def_id: DefId,
202    ) -> OptResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
203        get!(self, variants, def_id)
204    }
205
206    fn type_of(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::TyOrCtor>> {
207        get!(self, type_of, def_id)
208    }
209
210    fn generics_of(&self, def_id: DefId) -> OptResult<rty::Generics> {
211        get!(self, generics_of, def_id)
212    }
213
214    fn refinement_generics_of(
215        &self,
216        def_id: DefId,
217    ) -> OptResult<rty::EarlyBinder<rty::RefinementGenerics>> {
218        get!(self, refinement_generics_of, def_id)
219    }
220
221    fn item_bounds(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::Clauses>> {
222        get!(self, item_bounds, def_id)
223    }
224
225    fn predicates_of(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::GenericPredicates>> {
226        get!(self, predicates_of, def_id)
227    }
228
229    fn assoc_refinements_of(&self, def_id: DefId) -> OptResult<rty::AssocRefinements> {
230        get!(self, assoc_refinements_of, def_id)
231    }
232
233    fn assoc_refinements_def(&self, key: FluxDefId) -> OptResult<rty::EarlyBinder<rty::Lambda>> {
234        get!(self, assoc_refinements_def, key)
235    }
236
237    fn default_assoc_refinements_def(
238        &self,
239        key: FluxDefId,
240    ) -> OptResult<Option<rty::EarlyBinder<rty::Lambda>>> {
241        get!(self, default_assoc_refinements_def, key)
242    }
243
244    fn sort_of_assoc_reft(&self, key: FluxDefId) -> OptResult<rty::EarlyBinder<rty::FuncSort>> {
245        get!(self, sort_of_assoc_reft, key)
246    }
247
248    fn constant_info(&self, key: DefId) -> OptResult<rty::ConstantInfo> {
249        get!(self, constant_info, key)
250    }
251
252    fn normalized_defns(&self, krate: CrateNum) -> std::rc::Rc<rty::NormalizedDefns> {
253        self.local_tables[&krate].normalized_defns.clone()
254    }
255
256    fn func_sort(&self, key: FluxDefId) -> Option<rty::PolyFuncSort> {
257        get!(self, func_sort, key)
258    }
259}
260
261impl CrateMetadata {
262    fn new(genv: GlobalEnv) -> Self {
263        let mut local_tables = Tables::default();
264        encode_def_ids(
265            genv,
266            genv.iter_local_def_id().map(LocalDefId::to_def_id),
267            &mut local_tables,
268            DefId::to_index,
269            FluxDefId::to_index,
270        );
271        encode_flux_defs(genv, &mut local_tables);
272
273        let mut extern_tables = Tables::default();
274        encode_def_ids(
275            genv,
276            genv.iter_extern_def_id(),
277            &mut extern_tables,
278            |def_id| def_id,
279            |flux_id| flux_id,
280        );
281
282        CrateMetadata { local_tables, extern_tables }
283    }
284}
285
286fn encode_flux_defs(genv: GlobalEnv, tables: &mut Tables<DefIndex>) {
287    tables.normalized_defns = genv.normalized_defns(LOCAL_CRATE);
288
289    for (def_id, item) in genv.map().flux_items() {
290        let fhir::FluxItem::Func(_) = item else { continue };
291        tables
292            .func_sort
293            .insert(def_id.local_def_index(), genv.func_sort(def_id));
294    }
295}
296
297fn encode_def_ids<K: Eq + Hash + Copy>(
298    genv: GlobalEnv,
299    def_ids: impl IntoIterator<Item = DefId>,
300    tables: &mut Tables<K>,
301    did_to_key: fn(DefId) -> K,
302    assoc_id_to_key: fn(FluxDefId) -> FluxId<K>,
303) {
304    for def_id in def_ids {
305        let def_kind = genv.def_kind(def_id);
306        let key = did_to_key(def_id);
307
308        match def_kind {
309            DefKind::Trait => {
310                tables.generics_of.insert(key, genv.generics_of(def_id));
311                tables.predicates_of.insert(key, genv.predicates_of(def_id));
312                tables
313                    .refinement_generics_of
314                    .insert(key, genv.refinement_generics_of(def_id));
315                let assocs = genv.assoc_refinements_of(def_id);
316                if let Ok(assocs) = &assocs {
317                    for assoc_reft in &assocs.items {
318                        let def_id = assoc_reft.def_id();
319                        let key = assoc_id_to_key(def_id);
320                        tables
321                            .default_assoc_refinements_def
322                            .insert(key, genv.default_assoc_refinement_body(def_id));
323                        tables
324                            .sort_of_assoc_reft
325                            .insert(key, genv.sort_of_assoc_reft(def_id));
326                    }
327                }
328                tables.assoc_refinements_of.insert(key, assocs);
329            }
330            DefKind::Impl { of_trait } => {
331                tables.generics_of.insert(key, genv.generics_of(def_id));
332                tables.predicates_of.insert(key, genv.predicates_of(def_id));
333                tables
334                    .refinement_generics_of
335                    .insert(key, genv.refinement_generics_of(def_id));
336
337                if of_trait {
338                    let assocs = genv.assoc_refinements_of(def_id);
339                    if let Ok(assocs) = &assocs {
340                        for assoc_reft in &assocs.items {
341                            let def_id = assoc_reft.def_id();
342                            let key = assoc_id_to_key(def_id);
343                            tables
344                                .assoc_refinements_def
345                                .insert(key, genv.assoc_refinement_body(def_id));
346                            tables
347                                .sort_of_assoc_reft
348                                .insert(key, genv.sort_of_assoc_reft(def_id));
349                        }
350                    }
351                    tables.assoc_refinements_of.insert(key, assocs);
352                }
353            }
354            DefKind::Fn | DefKind::AssocFn => {
355                tables.generics_of.insert(key, genv.generics_of(def_id));
356                tables.predicates_of.insert(key, genv.predicates_of(def_id));
357                tables
358                    .refinement_generics_of
359                    .insert(key, genv.refinement_generics_of(def_id));
360                tables.fn_sig.insert(key, genv.fn_sig(def_id));
361            }
362            DefKind::Enum | DefKind::Struct => {
363                tables.generics_of.insert(key, genv.generics_of(def_id));
364                tables.predicates_of.insert(key, genv.predicates_of(def_id));
365                tables
366                    .refinement_generics_of
367                    .insert(key, genv.refinement_generics_of(def_id));
368                tables.adt_def.insert(key, genv.adt_def(def_id));
369                tables
370                    .adt_sort_def
371                    .insert(key, genv.adt_sort_def_of(def_id));
372                tables.variants.insert(key, genv.variants_of(def_id));
373                tables.type_of.insert(key, genv.type_of(def_id));
374            }
375            DefKind::TyAlias => {
376                tables.generics_of.insert(key, genv.generics_of(def_id));
377                tables.predicates_of.insert(key, genv.predicates_of(def_id));
378                tables
379                    .refinement_generics_of
380                    .insert(key, genv.refinement_generics_of(def_id));
381                tables.type_of.insert(key, genv.type_of(def_id));
382            }
383            DefKind::OpaqueTy => {
384                tables.generics_of.insert(key, genv.generics_of(def_id));
385                tables.predicates_of.insert(key, genv.predicates_of(def_id));
386                tables.item_bounds.insert(key, genv.item_bounds(def_id));
387                tables
388                    .refinement_generics_of
389                    .insert(key, genv.refinement_generics_of(def_id));
390            }
391            _ => {}
392        }
393    }
394}
395
396pub fn filename_for_metadata(tcx: TyCtxt) -> OutFileName {
397    match rustc_session::output::filename_for_metadata(tcx.sess, tcx.output_filenames(())) {
398        OutFileName::Real(path) => OutFileName::Real(path.with_extension("fluxmeta")),
399        OutFileName::Stdout => OutFileName::Stdout,
400    }
401}
402
403fn flux_metadata_extern_location(tcx: TyCtxt, crate_num: CrateNum) -> Option<PathBuf> {
404    // Since we only save metadata when `--emit=metadata` is passed, we also only load flux metadata
405    // when the crate source is a `.rmeta` file.
406    tcx.used_crate_source(crate_num)
407        .rmeta
408        .as_ref()
409        .map(|(path, _)| path.with_extension("fluxmeta"))
410}
411
412// Tags for encoding Symbol's
413const SYMBOL_STR: u8 = 0;
414const SYMBOL_OFFSET: u8 = 1;
415const SYMBOL_PREINTERNED: u8 = 2;
416
417mod errors {
418    use flux_errors::E0999;
419    use flux_macros::Diagnostic;
420    use rustc_middle::ty::TyCtxt;
421
422    use crate::Key;
423
424    #[derive(Diagnostic)]
425    #[diag(metadata_duplicate_spec, code = E0999)]
426    pub(super) struct DuplicateSpec {
427        def_name: String,
428    }
429
430    impl DuplicateSpec {
431        pub(super) fn new(tcx: TyCtxt, key: impl Key) -> Self {
432            Self { def_name: key.name(tcx) }
433        }
434    }
435}