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