1use std::{
2 fs,
3 io::{self, Read},
4 mem,
5 path::Path,
6};
7
8use flux_common::bug;
9use flux_errors::FluxSession;
10use rustc_data_structures::sync::HashMapExt;
11use rustc_hir::def_id::DefId;
12use rustc_middle::{
13 implement_ty_decoder,
14 ty::{self, TyCtxt},
15};
16use rustc_serialize::{Decodable, Decoder as _, opaque::MemDecoder};
17use rustc_session::StableCrateId;
18use rustc_span::{
19 BytePos, Span, SpanDecoder, StableSourceFileId, Symbol, SyntaxContext,
20 def_id::{CrateNum, DefIndex},
21};
22use rustc_type_ir::TyDecoder;
23
24use crate::{CrateMetadata, METADATA_HEADER, SYMBOL_OFFSET, SYMBOL_PREINTERNED, SYMBOL_STR};
25
26struct DecodeContext<'a, 'tcx> {
27 tcx: TyCtxt<'tcx>,
28 opaque: MemDecoder<'a>,
29}
30
31pub(super) fn decode_crate_metadata(
32 tcx: TyCtxt,
33 sess: &FluxSession,
34 path: &Path,
35) -> Option<CrateMetadata> {
36 let mut file = match fs::File::open(path) {
37 Ok(file) => file,
38 Err(err) if let io::ErrorKind::NotFound = err.kind() => return None,
39 Err(err) => sess.emit_fatal(errors::DecodeFileError::new(path, err)),
40 };
41 let mut buf = vec![];
42 file.read_to_end(&mut buf)
43 .unwrap_or_else(|err| sess.emit_fatal(errors::DecodeFileError::new(path, err)));
44
45 if !buf.starts_with(METADATA_HEADER) {
46 bug!("incompatible metadata version");
47 }
48
49 let mut decoder =
50 DecodeContext { tcx, opaque: MemDecoder::new(&buf, METADATA_HEADER.len()).unwrap() };
51 Some(CrateMetadata::decode(&mut decoder))
52}
53
54implement_ty_decoder!(DecodeContext<'a, 'tcx>);
55
56impl SpanDecoder for DecodeContext<'_, '_> {
57 fn decode_attr_id(&mut self) -> rustc_ast::AttrId {
58 self.tcx.sess.psess.attr_id_generator.mk_attr_id()
59 }
60
61 fn decode_crate_num(&mut self) -> CrateNum {
62 let stable_id = StableCrateId::decode(self);
63 self.tcx.stable_crate_id_to_crate_num(stable_id)
64 }
65
66 fn decode_def_index(&mut self) -> DefIndex {
67 DefIndex::from_u32(self.read_u32())
68 }
69
70 fn decode_def_id(&mut self) -> DefId {
71 DefId { krate: Decodable::decode(self), index: Decodable::decode(self) }
72 }
73
74 fn decode_syntax_context(&mut self) -> rustc_span::SyntaxContext {
75 bug!("cannot decode `SyntaxContext` with `DecodeContext`");
76 }
77
78 fn decode_expn_id(&mut self) -> rustc_span::ExpnId {
79 bug!("cannot decode `ExpnId` with `DecodeContext`");
80 }
81
82 fn decode_span(&mut self) -> rustc_span::Span {
83 let sm = self.tcx.sess.source_map();
84 let pos = [(); 2].map(|_| {
85 let ssfi = StableSourceFileId::decode(self);
86 let rel_bp = BytePos::decode(self);
87 sm.source_file_by_stable_id(ssfi)
92 .map_or(BytePos(0), |sf| sf.start_pos + rel_bp)
93 });
94 Span::new(pos[0], pos[1], SyntaxContext::root(), None)
95 }
96
97 fn decode_symbol(&mut self) -> rustc_span::Symbol {
98 let tag = self.read_u8();
99
100 match tag {
101 SYMBOL_STR => {
102 let s = self.read_str();
103 Symbol::intern(s)
104 }
105 SYMBOL_OFFSET => {
106 let pos = self.read_usize();
108
109 self.opaque.with_position(pos, |d| {
111 let s = d.read_str();
112 Symbol::intern(s)
113 })
114 }
115 SYMBOL_PREINTERNED => {
116 let symbol_index = self.read_u32();
117 Symbol::new_from_decoded(symbol_index)
118 }
119 _ => unreachable!(),
120 }
121 }
122}
123
124impl<'tcx> TyDecoder for DecodeContext<'_, 'tcx> {
125 type I = TyCtxt<'tcx>;
126
127 const CLEAR_CROSS_CRATE: bool = true;
128
129 fn interner(&self) -> Self::I {
130 self.tcx
131 }
132
133 fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> ty::Ty<'tcx>
134 where
135 F: FnOnce(&mut Self) -> ty::Ty<'tcx>,
136 {
137 let tcx = self.tcx;
138
139 let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
140
141 if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
142 return ty;
143 }
144
145 let ty = or_insert_with(self);
146 tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty);
148 ty
149 }
150
151 fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
152 where
153 F: FnOnce(&mut Self) -> R,
154 {
155 let new_opaque = self.opaque.split_at(pos);
156 let old_opaque = mem::replace(&mut self.opaque, new_opaque);
157 let r = f(self);
158 self.opaque = old_opaque;
159 r
160 }
161
162 fn decode_alloc_id(&mut self) -> rustc_middle::mir::interpret::AllocId {
163 bug!("Encoding `interpret::AllocId` is not supported")
164 }
165}
166
167mod errors {
168 use std::{io, path::Path};
169
170 use flux_errors::E0999;
171 use flux_macros::Diagnostic;
172
173 #[derive(Diagnostic)]
174 #[diag(metadata_decode_file_error, code = E0999)]
175 pub(super) struct DecodeFileError<'a> {
176 path: &'a Path,
177 err: io::Error,
178 }
179
180 impl<'a> DecodeFileError<'a> {
181 pub(super) fn new(path: &'a Path, err: io::Error) -> Self {
182 Self { path, err }
183 }
184 }
185}