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