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
63trait 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 $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 tcx.used_crate_source(crate_num)
406 .rmeta
407 .as_ref()
408 .map(|(path, _)| path.with_extension("fluxmeta"))
409}
410
411const 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}