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;
7extern crate rustc_hir;
8extern crate rustc_macros;
9extern crate rustc_metadata;
10extern crate rustc_middle;
11extern crate rustc_serialize;
12extern crate rustc_session;
13extern crate rustc_span;
14
15mod decoder;
16mod encoder;
17
18const TAG_FULL_SPAN: u8 = 0;
20const TAG_PARTIAL_SPAN: u8 = 1;
21
22use std::{hash::Hash, path::PathBuf, rc::Rc};
23
24use decoder::decode_crate_metadata;
25use derive_where::derive_where;
26use flux_errors::FluxSession;
27use flux_macros::fluent_messages;
28use flux_middle::{
29 cstore::{CrateStore, OptResult},
30 def_id::{FluxDefId, FluxId},
31 fhir,
32 global_env::GlobalEnv,
33 queries::QueryResult,
34 rty,
35};
36use rustc_data_structures::{
37 fx::FxHashMap,
38 unord::{ExtendUnord, UnordMap},
39};
40use rustc_hir::{
41 def::{CtorKind, DefKind},
42 def_id::{LOCAL_CRATE, LocalDefId},
43};
44use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
45use rustc_middle::ty::TyCtxt;
46use rustc_session::config::OutFileName;
47use rustc_span::{
48 SourceFile, Span, StableSourceFileId,
49 def_id::{CrateNum, DefId, DefIndex, StableCrateId},
50};
51
52pub use crate::encoder::encode_metadata;
53
54fluent_messages! { "../locales/en-US.ftl" }
55
56const METADATA_VERSION: u8 = 0;
57const METADATA_HEADER: &[u8] = &[b'f', b'l', b'u', b'x', 0, 0, 0, METADATA_VERSION];
58
59#[derive(Default)]
60pub struct CStore {
61 local_tables: UnordMap<CrateNum, Tables<DefIndex>>,
62 extern_tables: Tables<DefId>,
63}
64
65#[derive(Encodable, Decodable, Clone, Debug)]
72struct EncodedSourceFileId {
73 stable_source_file_id: StableSourceFileId,
74 stable_crate_id: StableCrateId,
75}
76
77impl EncodedSourceFileId {
78 #[inline]
79 fn new(tcx: TyCtxt<'_>, file: &SourceFile) -> EncodedSourceFileId {
80 EncodedSourceFileId {
81 stable_source_file_id: file.stable_id,
82 stable_crate_id: tcx.stable_crate_id(file.cnum),
83 }
84 }
85}
86
87#[derive(Default, Decodable, Encodable)]
89pub struct Footer {
90 file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
91 syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
92 expn_data: FxHashMap<(StableCrateId, u32), AbsoluteBytePos>,
93}
94#[derive(Encodable, Decodable, Eq, PartialEq, Hash, Clone, Copy, Debug)]
95struct SourceFileIndex(u32);
96
97#[derive(Encodable, Decodable, Clone, Copy)]
98pub struct AbsoluteBytePos(u64);
99
100impl AbsoluteBytePos {
101 fn new(pos: usize) -> AbsoluteBytePos {
102 AbsoluteBytePos(pos.try_into().unwrap())
103 }
104
105 fn to_usize(self) -> usize {
106 self.0 as usize
107 }
108}
109
110#[derive(Default, TyEncodable, TyDecodable)]
111pub struct CrateMetadata {
112 local_tables: Tables<DefIndex>,
113 extern_tables: Tables<DefId>,
114}
115
116trait Key {
119 type KeyIndex;
120 fn crate_num(self) -> CrateNum;
121 fn to_index(self) -> Self::KeyIndex;
122 fn name(self, tcx: TyCtxt) -> String;
123}
124
125impl Key for DefId {
126 type KeyIndex = DefIndex;
127
128 fn crate_num(self) -> CrateNum {
129 self.krate
130 }
131
132 fn to_index(self) -> Self::KeyIndex {
133 self.index
134 }
135
136 fn name(self, tcx: TyCtxt) -> String {
137 tcx.def_path_str(self)
138 }
139}
140
141impl Key for FluxDefId {
142 type KeyIndex = FluxId<DefIndex>;
143
144 fn crate_num(self) -> CrateNum {
145 self.parent().krate
146 }
147
148 fn to_index(self) -> Self::KeyIndex {
149 self.index()
150 }
151
152 fn name(self, tcx: TyCtxt) -> String {
153 format!("{}::{}", tcx.def_path_str(self.parent()), self.name())
154 }
155}
156
157#[derive_where(Default)]
158#[derive(TyEncodable, TyDecodable)]
159pub struct Tables<K: Eq + Hash> {
160 generics_of: UnordMap<K, QueryResult<rty::Generics>>,
161 refinement_generics_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>>,
162 predicates_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::GenericPredicates>>>,
163 item_bounds: UnordMap<K, QueryResult<rty::EarlyBinder<rty::Clauses>>>,
164 assoc_refinements_of: UnordMap<K, QueryResult<rty::AssocRefinements>>,
165 assoc_refinements_def: UnordMap<FluxId<K>, QueryResult<rty::EarlyBinder<rty::Lambda>>>,
166 default_assoc_refinements_def:
167 UnordMap<FluxId<K>, QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>>,
168 sort_of_assoc_reft: UnordMap<FluxId<K>, QueryResult<rty::EarlyBinder<rty::FuncSort>>>,
169 fn_sig: UnordMap<K, QueryResult<rty::EarlyBinder<rty::PolyFnSig>>>,
170 adt_def: UnordMap<K, QueryResult<rty::AdtDef>>,
171 constant_info: UnordMap<K, QueryResult<rty::ConstantInfo>>,
172 static_info: UnordMap<K, QueryResult<rty::StaticInfo>>,
173 adt_sort_def: UnordMap<K, QueryResult<rty::AdtSortDef>>,
174 variants_of: UnordMap<K, QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>>,
175 type_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::TyOrCtor>>>,
176 normalized_defns: Rc<rty::NormalizedDefns>,
177 func_sort: UnordMap<FluxId<K>, rty::PolyFuncSort>,
178 func_span: UnordMap<FluxId<K>, Span>,
179 sort_decl_param_count: UnordMap<FluxId<K>, usize>,
180 no_panic: UnordMap<K, bool>,
181}
182
183impl CStore {
184 pub fn load(tcx: TyCtxt, sess: &FluxSession) -> Self {
185 let mut cstore = CStore::default();
186 for crate_num in tcx.used_crates(()) {
187 let Some(path) = flux_metadata_extern_location(tcx, *crate_num) else { continue };
188 let Some(meta) = decode_crate_metadata(tcx, sess, path.as_path()) else { continue };
189 cstore.local_tables.insert(*crate_num, meta.local_tables);
190 cstore.merge_extern_tables(tcx, sess, meta.extern_tables);
191 }
192 cstore
193 }
194
195 fn merge_extern_tables(
196 &mut self,
197 tcx: TyCtxt,
198 sess: &FluxSession,
199 extern_tables: Tables<DefId>,
200 ) {
201 macro_rules! merge_extern_table {
202 ($self:expr, $tcx:expr, $table:ident, $extern_tables:expr) => {{
203 $extern_tables.$table.keys().map(|k| {
206 if self.$table(*k).is_some() {
207 sess.emit_fatal(errors::DuplicateSpec::new($tcx, *k));
208 }
209 });
210 $self
211 .extern_tables
212 .$table
213 .extend_unord(extern_tables.$table.into_items());
214 }};
215 }
216 merge_extern_table!(self, tcx, generics_of, extern_tables);
217 merge_extern_table!(self, tcx, refinement_generics_of, extern_tables);
218 merge_extern_table!(self, tcx, predicates_of, extern_tables);
219 merge_extern_table!(self, tcx, item_bounds, extern_tables);
220 merge_extern_table!(self, tcx, assoc_refinements_of, extern_tables);
221 merge_extern_table!(self, tcx, default_assoc_refinements_def, extern_tables);
222 merge_extern_table!(self, tcx, assoc_refinements_def, extern_tables);
223 merge_extern_table!(self, tcx, sort_of_assoc_reft, extern_tables);
224 merge_extern_table!(self, tcx, fn_sig, extern_tables);
225 merge_extern_table!(self, tcx, adt_def, extern_tables);
226 merge_extern_table!(self, tcx, adt_sort_def, extern_tables);
227 merge_extern_table!(self, tcx, variants_of, extern_tables);
228 merge_extern_table!(self, tcx, type_of, extern_tables);
229 merge_extern_table!(self, tcx, no_panic, extern_tables);
230 merge_extern_table!(self, tcx, static_info, extern_tables);
231 }
232}
233
234macro_rules! get {
235 ($self:expr, $table:ident, $key:expr) => {{
236 let key = $key;
237 let this = $self;
238 if let Some(tables) = this.local_tables.get(&key.crate_num()) {
239 tables.$table.get(&key.to_index()).cloned()
240 } else {
241 this.extern_tables.$table.get(&key).cloned()
242 }
243 }};
244}
245
246impl CrateStore for CStore {
247 fn fn_sig(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::PolyFnSig>> {
248 get!(self, fn_sig, def_id)
249 }
250
251 fn adt_def(&self, def_id: DefId) -> OptResult<rty::AdtDef> {
252 get!(self, adt_def, def_id)
253 }
254
255 fn adt_sort_def(&self, def_id: DefId) -> OptResult<rty::AdtSortDef> {
256 get!(self, adt_sort_def, def_id)
257 }
258
259 fn no_panic(&self, def_id: DefId) -> Option<bool> {
260 get!(self, no_panic, def_id)
261 }
262
263 fn variants_of(
264 &self,
265 def_id: DefId,
266 ) -> OptResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
267 get!(self, variants_of, def_id)
268 }
269
270 fn type_of(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::TyOrCtor>> {
271 get!(self, type_of, def_id)
272 }
273
274 fn generics_of(&self, def_id: DefId) -> OptResult<rty::Generics> {
275 get!(self, generics_of, def_id)
276 }
277
278 fn refinement_generics_of(
279 &self,
280 def_id: DefId,
281 ) -> OptResult<rty::EarlyBinder<rty::RefinementGenerics>> {
282 get!(self, refinement_generics_of, def_id)
283 }
284
285 fn item_bounds(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::Clauses>> {
286 get!(self, item_bounds, def_id)
287 }
288
289 fn predicates_of(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::GenericPredicates>> {
290 get!(self, predicates_of, def_id)
291 }
292
293 fn assoc_refinements_of(&self, def_id: DefId) -> OptResult<rty::AssocRefinements> {
294 get!(self, assoc_refinements_of, def_id)
295 }
296
297 fn assoc_refinements_def(&self, key: FluxDefId) -> OptResult<rty::EarlyBinder<rty::Lambda>> {
298 get!(self, assoc_refinements_def, key)
299 }
300
301 fn default_assoc_refinements_def(
302 &self,
303 key: FluxDefId,
304 ) -> OptResult<Option<rty::EarlyBinder<rty::Lambda>>> {
305 get!(self, default_assoc_refinements_def, key)
306 }
307
308 fn sort_of_assoc_reft(&self, key: FluxDefId) -> OptResult<rty::EarlyBinder<rty::FuncSort>> {
309 get!(self, sort_of_assoc_reft, key)
310 }
311
312 fn constant_info(&self, key: DefId) -> OptResult<rty::ConstantInfo> {
313 get!(self, constant_info, key)
314 }
315
316 fn static_info(&self, key: DefId) -> OptResult<rty::StaticInfo> {
317 get!(self, static_info, key)
318 }
319
320 fn normalized_defns(&self, krate: CrateNum) -> std::rc::Rc<rty::NormalizedDefns> {
321 self.local_tables[&krate].normalized_defns.clone()
322 }
323
324 fn func_sort(&self, key: FluxDefId) -> Option<rty::PolyFuncSort> {
325 get!(self, func_sort, key)
326 }
327
328 fn func_span(&self, key: FluxDefId) -> Option<Span> {
329 get!(self, func_span, key)
330 }
331
332 fn sort_decl_param_count(&self, key: FluxDefId) -> Option<usize> {
333 get!(self, sort_decl_param_count, key)
334 }
335}
336
337impl CrateMetadata {
338 fn new(genv: GlobalEnv) -> Self {
339 let mut local_tables = Tables::default();
340 encode_def_ids(
341 genv,
342 genv.iter_local_def_id().map(LocalDefId::to_def_id),
343 &mut local_tables,
344 DefId::to_index,
345 FluxDefId::to_index,
346 );
347 encode_flux_defs(genv, &mut local_tables);
348
349 let mut extern_tables = Tables::default();
350 encode_def_ids(
351 genv,
352 genv.iter_extern_def_id(),
353 &mut extern_tables,
354 |def_id| def_id,
355 |flux_id| flux_id,
356 );
357
358 CrateMetadata { local_tables, extern_tables }
359 }
360}
361
362fn encode_flux_defs(genv: GlobalEnv, tables: &mut Tables<DefIndex>) {
363 tables.normalized_defns = genv.normalized_defns(LOCAL_CRATE);
364
365 for (def_id, item) in genv.fhir_iter_flux_items() {
366 match item {
367 fhir::FluxItem::Func(spec_func) => {
368 tables
369 .func_sort
370 .insert(def_id.local_def_index(), genv.func_sort(def_id));
371 tables
372 .func_span
373 .insert(def_id.local_def_index(), spec_func.ident_span);
374 }
375 fhir::FluxItem::SortDecl(_sort_decl) => {
376 tables
377 .sort_decl_param_count
378 .insert(def_id.local_def_index(), genv.sort_decl_param_count(def_id));
379 }
380 fhir::FluxItem::PrimOpProp(_) | fhir::FluxItem::Qualifier(_) => {}
381 }
382 }
383}
384
385fn encode_def_ids<K: Eq + Hash + Copy>(
386 genv: GlobalEnv,
387 def_ids: impl IntoIterator<Item = DefId>,
388 tables: &mut Tables<K>,
389 did_to_key: fn(DefId) -> K,
390 assoc_id_to_key: fn(FluxDefId) -> FluxId<K>,
391) {
392 for def_id in def_ids {
393 let def_kind = genv.def_kind(def_id);
394 let key = did_to_key(def_id);
395
396 match def_kind {
397 DefKind::Trait => {
398 tables
399 .generics_of
400 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
401 tables
402 .predicates_of
403 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
404 tables.refinement_generics_of.insert(
405 key,
406 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
407 );
408 let assocs = genv.run_query_if_reached(def_id, GlobalEnv::assoc_refinements_of);
409 if let Ok(assocs) = &assocs {
410 for assoc_reft in &assocs.items {
411 let def_id = assoc_reft.def_id();
412 let key = assoc_id_to_key(def_id);
413 tables.default_assoc_refinements_def.insert(
414 key,
415 genv.run_query_if_reached(
416 def_id,
417 GlobalEnv::default_assoc_refinement_body,
418 ),
419 );
420 tables.sort_of_assoc_reft.insert(
421 key,
422 genv.run_query_if_reached(def_id, GlobalEnv::sort_of_assoc_reft),
423 );
424 }
425 }
426 tables.assoc_refinements_of.insert(key, assocs);
427 }
428 DefKind::Impl { of_trait } => {
429 tables
430 .generics_of
431 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
432 tables
433 .predicates_of
434 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
435 tables.refinement_generics_of.insert(
436 key,
437 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
438 );
439
440 if of_trait {
441 let assocs = genv.run_query_if_reached(def_id, GlobalEnv::assoc_refinements_of);
442 if let Ok(assocs) = &assocs {
443 for assoc_reft in &assocs.items {
444 let def_id = assoc_reft.def_id();
445 let key = assoc_id_to_key(def_id);
446 tables.assoc_refinements_def.insert(
447 key,
448 genv.run_query_if_reached(def_id, GlobalEnv::assoc_refinement_body),
449 );
450 tables.sort_of_assoc_reft.insert(
451 key,
452 genv.run_query_if_reached(def_id, GlobalEnv::sort_of_assoc_reft),
453 );
454 }
455 }
456 tables.assoc_refinements_of.insert(key, assocs);
457 }
458 }
459 DefKind::Fn | DefKind::AssocFn => {
460 tables
461 .generics_of
462 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
463 tables
464 .predicates_of
465 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
466 tables.refinement_generics_of.insert(
467 key,
468 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
469 );
470 tables
471 .fn_sig
472 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::fn_sig));
473 tables.no_panic.insert(key, genv.no_panic(def_id));
474 }
475 DefKind::Ctor(_, CtorKind::Fn) => {
476 tables
477 .generics_of
478 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
479 tables.refinement_generics_of.insert(
480 key,
481 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
482 );
483 tables
484 .fn_sig
485 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::fn_sig));
486 }
487 DefKind::Enum | DefKind::Struct => {
488 tables
489 .generics_of
490 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
491 tables
492 .predicates_of
493 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
494 tables.refinement_generics_of.insert(
495 key,
496 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
497 );
498 tables
499 .adt_def
500 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::adt_def));
501 tables
502 .adt_sort_def
503 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::adt_sort_def_of));
504 tables
505 .variants_of
506 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::variants_of));
507 tables
508 .type_of
509 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::type_of));
510 }
511 DefKind::TyAlias => {
512 tables
513 .generics_of
514 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
515 tables
516 .predicates_of
517 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
518 tables.refinement_generics_of.insert(
519 key,
520 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
521 );
522 tables
523 .type_of
524 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::type_of));
525 }
526 DefKind::OpaqueTy => {
527 tables
528 .generics_of
529 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
530 tables
531 .predicates_of
532 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
533 tables
534 .item_bounds
535 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::item_bounds));
536 tables.refinement_generics_of.insert(
537 key,
538 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
539 );
540 }
541 DefKind::Static { .. } => {
542 tables.static_info.insert(key, genv.static_info(def_id));
543 }
544 _ => {}
545 }
546 }
547}
548
549pub fn filename_for_metadata(tcx: TyCtxt) -> OutFileName {
550 match rustc_session::output::filename_for_metadata(tcx.sess, tcx.output_filenames(())) {
551 OutFileName::Real(path) => OutFileName::Real(path.with_extension("fluxmeta")),
552 OutFileName::Stdout => OutFileName::Stdout,
553 }
554}
555
556fn flux_metadata_extern_location(tcx: TyCtxt, crate_num: CrateNum) -> Option<PathBuf> {
557 tcx.used_crate_source(crate_num)
560 .rmeta
561 .as_ref()
562 .map(|(path, _)| path.with_extension("fluxmeta"))
563}
564
565const SYMBOL_STR: u8 = 0;
567const SYMBOL_OFFSET: u8 = 1;
568const SYMBOL_PREDEFINED: u8 = 2;
569
570mod errors {
571 use flux_errors::E0999;
572 use flux_macros::Diagnostic;
573 use rustc_middle::ty::TyCtxt;
574
575 use crate::Key;
576
577 #[derive(Diagnostic)]
578 #[diag(metadata_duplicate_spec, code = E0999)]
579 pub(super) struct DuplicateSpec {
580 def_name: String,
581 }
582
583 impl DuplicateSpec {
584 pub(super) fn new(tcx: TyCtxt, key: impl Key) -> Self {
585 Self { def_name: key.name(tcx) }
586 }
587 }
588}