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