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
65trait 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 $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 tcx.used_crate_source(crate_num)
418 .rmeta
419 .as_ref()
420 .map(|(path, _)| path.with_extension("fluxmeta"))
421}
422
423const 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}