]> git.lizzy.rs Git - rust.git/blob - src/librustc_metadata/tyencode.rs
Rollup merge of #31031 - brson:issue-30123, r=nikomatsakis
[rust.git] / src / librustc_metadata / tyencode.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // Type encoding
12
13 #![allow(unused_must_use)] // as with encoding, everything is a no-fail MemWriter
14 #![allow(non_camel_case_types)]
15
16 use std::cell::RefCell;
17 use std::io::Cursor;
18 use std::io::prelude::*;
19
20 use middle::def_id::DefId;
21 use middle::region;
22 use middle::subst;
23 use middle::subst::VecPerParamSpace;
24 use middle::ty::ParamTy;
25 use middle::ty::{self, Ty};
26 use rustc::util::nodemap::FnvHashMap;
27
28 use rustc_front::hir;
29
30 use syntax::abi::Abi;
31 use syntax::ast;
32 use syntax::errors::Handler;
33
34 use rbml::leb128;
35 use encoder;
36
37 pub struct ctxt<'a, 'tcx: 'a> {
38     pub diag: &'a Handler,
39     // Def -> str Callback:
40     pub ds: fn(DefId) -> String,
41     // The type context.
42     pub tcx: &'a ty::ctxt<'tcx>,
43     pub abbrevs: &'a abbrev_map<'tcx>
44 }
45
46 impl<'a, 'tcx> encoder::EncodeContext<'a, 'tcx> {
47     pub fn ty_str_ctxt<'b>(&'b self) -> ctxt<'b, 'tcx> {
48         ctxt {
49             diag: self.tcx.sess.diagnostic(),
50             ds: encoder::def_to_string,
51             tcx: self.tcx,
52             abbrevs: &self.type_abbrevs
53         }
54     }
55 }
56
57 // Compact string representation for Ty values. API TyStr & parse_from_str.
58 // Extra parameters are for converting to/from def_ids in the string rep.
59 // Whatever format you choose should not contain pipe characters.
60 pub struct ty_abbrev {
61     s: Vec<u8>
62 }
63
64 pub type abbrev_map<'tcx> = RefCell<FnvHashMap<Ty<'tcx>, ty_abbrev>>;
65
66 pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) {
67     match cx.abbrevs.borrow_mut().get(&t) {
68         Some(a) => { w.write_all(&a.s); return; }
69         None => {}
70     }
71
72     let pos = w.position();
73
74     match t.sty {
75         ty::TyBool => { write!(w, "b"); }
76         ty::TyChar => { write!(w, "c"); }
77         ty::TyInt(t) => {
78             match t {
79                 ast::TyIs => write!(w, "is"),
80                 ast::TyI8 => write!(w, "MB"),
81                 ast::TyI16 => write!(w, "MW"),
82                 ast::TyI32 => write!(w, "ML"),
83                 ast::TyI64 => write!(w, "MD")
84             };
85         }
86         ty::TyUint(t) => {
87             match t {
88                 ast::TyUs => write!(w, "us"),
89                 ast::TyU8 => write!(w, "Mb"),
90                 ast::TyU16 => write!(w, "Mw"),
91                 ast::TyU32 => write!(w, "Ml"),
92                 ast::TyU64 => write!(w, "Md")
93             };
94         }
95         ty::TyFloat(t) => {
96             match t {
97                 ast::TyF32 => write!(w, "Mf"),
98                 ast::TyF64 => write!(w, "MF"),
99             };
100         }
101         ty::TyEnum(def, substs) => {
102             write!(w, "t[{}|", (cx.ds)(def.did));
103             enc_substs(w, cx, substs);
104             write!(w, "]");
105         }
106         ty::TyTrait(box ty::TraitTy { ref principal,
107                                        ref bounds }) => {
108             write!(w, "x[");
109             enc_trait_ref(w, cx, principal.0);
110             enc_existential_bounds(w, cx, bounds);
111             write!(w, "]");
112         }
113         ty::TyTuple(ref ts) => {
114             write!(w, "T[");
115             for t in ts { enc_ty(w, cx, *t); }
116             write!(w, "]");
117         }
118         ty::TyBox(typ) => { write!(w, "~"); enc_ty(w, cx, typ); }
119         ty::TyRawPtr(mt) => { write!(w, "*"); enc_mt(w, cx, mt); }
120         ty::TyRef(r, mt) => {
121             write!(w, "&");
122             enc_region(w, cx, *r);
123             enc_mt(w, cx, mt);
124         }
125         ty::TyArray(t, sz) => {
126             write!(w, "V");
127             enc_ty(w, cx, t);
128             write!(w, "/{}|", sz);
129         }
130         ty::TySlice(t) => {
131             write!(w, "V");
132             enc_ty(w, cx, t);
133             write!(w, "/|");
134         }
135         ty::TyStr => {
136             write!(w, "v");
137         }
138         ty::TyBareFn(Some(def_id), f) => {
139             write!(w, "F");
140             write!(w, "{}|", (cx.ds)(def_id));
141             enc_bare_fn_ty(w, cx, f);
142         }
143         ty::TyBareFn(None, f) => {
144             write!(w, "G");
145             enc_bare_fn_ty(w, cx, f);
146         }
147         ty::TyInfer(_) => {
148             cx.diag.bug("cannot encode inference variable types");
149         }
150         ty::TyParam(ParamTy {space, idx, name}) => {
151             write!(w, "p[{}|{}|{}]", idx, space.to_uint(), name);
152         }
153         ty::TyStruct(def, substs) => {
154             write!(w, "a[{}|", (cx.ds)(def.did));
155             enc_substs(w, cx, substs);
156             write!(w, "]");
157         }
158         ty::TyClosure(def, ref substs) => {
159             write!(w, "k[{}|", (cx.ds)(def));
160             enc_substs(w, cx, &substs.func_substs);
161             for ty in &substs.upvar_tys {
162                 enc_ty(w, cx, ty);
163             }
164             write!(w, ".");
165             write!(w, "]");
166         }
167         ty::TyProjection(ref data) => {
168             write!(w, "P[");
169             enc_trait_ref(w, cx, data.trait_ref);
170             write!(w, "{}]", data.item_name);
171         }
172         ty::TyError => {
173             write!(w, "e");
174         }
175     }
176
177     let end = w.position();
178     let len = end - pos;
179
180     let mut abbrev = Cursor::new(Vec::with_capacity(16));
181     abbrev.write_all(b"#");
182     {
183         let start_position = abbrev.position() as usize;
184         let bytes_written = leb128::write_unsigned_leb128(abbrev.get_mut(),
185                                                           start_position,
186                                                           pos);
187         abbrev.set_position((start_position + bytes_written) as u64);
188     }
189
190     cx.abbrevs.borrow_mut().insert(t, ty_abbrev {
191         s: if abbrev.position() < len {
192             abbrev.get_ref()[..abbrev.position() as usize].to_owned()
193         } else {
194             // if the abbreviation is longer than the real type,
195             // don't use #-notation. However, insert it here so
196             // other won't have to `mark_stable_position`
197             w.get_ref()[pos as usize .. end as usize].to_owned()
198         }
199     });
200 }
201
202 fn enc_mutability(w: &mut Cursor<Vec<u8>>, mt: hir::Mutability) {
203     match mt {
204         hir::MutImmutable => (),
205         hir::MutMutable => {
206             write!(w, "m");
207         }
208     };
209 }
210
211 fn enc_mt<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
212                     mt: ty::TypeAndMut<'tcx>) {
213     enc_mutability(w, mt.mutbl);
214     enc_ty(w, cx, mt.ty);
215 }
216
217 fn enc_opt<T, F>(w: &mut Cursor<Vec<u8>>, t: Option<T>, enc_f: F) where
218     F: FnOnce(&mut Cursor<Vec<u8>>, T),
219 {
220     match t {
221         None => {
222             write!(w, "n");
223         }
224         Some(v) => {
225             write!(w, "s");
226             enc_f(w, v);
227         }
228     }
229 }
230
231 fn enc_vec_per_param_space<'a, 'tcx, T, F>(w: &mut Cursor<Vec<u8>>,
232                                            cx: &ctxt<'a, 'tcx>,
233                                            v: &VecPerParamSpace<T>,
234                                            mut op: F) where
235     F: FnMut(&mut Cursor<Vec<u8>>, &ctxt<'a, 'tcx>, &T),
236 {
237     for &space in &subst::ParamSpace::all() {
238         write!(w, "[");
239         for t in v.get_slice(space) {
240             op(w, cx, t);
241         }
242         write!(w, "]");
243     }
244 }
245
246 pub fn enc_substs<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
247                             substs: &subst::Substs<'tcx>) {
248     enc_region_substs(w, cx, &substs.regions);
249     enc_vec_per_param_space(w, cx, &substs.types,
250                             |w, cx, &ty| enc_ty(w, cx, ty));
251 }
252
253 fn enc_region_substs(w: &mut Cursor<Vec<u8>>, cx: &ctxt, substs: &subst::RegionSubsts) {
254     match *substs {
255         subst::ErasedRegions => {
256             write!(w, "e");
257         }
258         subst::NonerasedRegions(ref regions) => {
259             write!(w, "n");
260             enc_vec_per_param_space(w, cx, regions,
261                                     |w, cx, &r| enc_region(w, cx, r));
262         }
263     }
264 }
265
266 pub fn enc_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, r: ty::Region) {
267     match r {
268         ty::ReLateBound(id, br) => {
269             write!(w, "b[{}|", id.depth);
270             enc_bound_region(w, cx, br);
271             write!(w, "]");
272         }
273         ty::ReEarlyBound(ref data) => {
274             write!(w, "B[{}|{}|{}]",
275                    data.space.to_uint(),
276                    data.index,
277                    data.name);
278         }
279         ty::ReFree(ref fr) => {
280             write!(w, "f[");
281             enc_scope(w, cx, fr.scope);
282             write!(w, "|");
283             enc_bound_region(w, cx, fr.bound_region);
284             write!(w, "]");
285         }
286         ty::ReScope(scope) => {
287             write!(w, "s");
288             enc_scope(w, cx, scope);
289             write!(w, "|");
290         }
291         ty::ReStatic => {
292             write!(w, "t");
293         }
294         ty::ReEmpty => {
295             write!(w, "e");
296         }
297         ty::ReVar(_) | ty::ReSkolemized(..) => {
298             // these should not crop up after typeck
299             cx.diag.bug("cannot encode region variables");
300         }
301     }
302 }
303
304 fn enc_scope(w: &mut Cursor<Vec<u8>>, cx: &ctxt, scope: region::CodeExtent) {
305     match cx.tcx.region_maps.code_extent_data(scope) {
306         region::CodeExtentData::CallSiteScope {
307             fn_id, body_id } => write!(w, "C[{}|{}]", fn_id, body_id),
308         region::CodeExtentData::ParameterScope {
309             fn_id, body_id } => write!(w, "P[{}|{}]", fn_id, body_id),
310         region::CodeExtentData::Misc(node_id) => write!(w, "M{}", node_id),
311         region::CodeExtentData::Remainder(region::BlockRemainder {
312             block: b, first_statement_index: i }) => write!(w, "B[{}|{}]", b, i),
313         region::CodeExtentData::DestructionScope(node_id) => write!(w, "D{}", node_id),
314     };
315 }
316
317 fn enc_bound_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, br: ty::BoundRegion) {
318     match br {
319         ty::BrAnon(idx) => {
320             write!(w, "a{}|", idx);
321         }
322         ty::BrNamed(d, name) => {
323             write!(w, "[{}|{}]",
324                      (cx.ds)(d),
325                      name);
326         }
327         ty::BrFresh(id) => {
328             write!(w, "f{}|", id);
329         }
330         ty::BrEnv => {
331             write!(w, "e|");
332         }
333     }
334 }
335
336 pub fn enc_trait_ref<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
337                                s: ty::TraitRef<'tcx>) {
338     write!(w, "{}|", (cx.ds)(s.def_id));
339     enc_substs(w, cx, s.substs);
340 }
341
342 fn enc_unsafety(w: &mut Cursor<Vec<u8>>, p: hir::Unsafety) {
343     match p {
344         hir::Unsafety::Normal => write!(w, "n"),
345         hir::Unsafety::Unsafe => write!(w, "u"),
346     };
347 }
348
349 fn enc_abi(w: &mut Cursor<Vec<u8>>, abi: Abi) {
350     write!(w, "[");
351     write!(w, "{}", abi.name());
352     write!(w, "]");
353 }
354
355 pub fn enc_bare_fn_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
356                                 ft: &ty::BareFnTy<'tcx>) {
357     enc_unsafety(w, ft.unsafety);
358     enc_abi(w, ft.abi);
359     enc_fn_sig(w, cx, &ft.sig);
360 }
361
362 pub fn enc_closure_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
363                                 ft: &ty::ClosureTy<'tcx>) {
364     enc_unsafety(w, ft.unsafety);
365     enc_fn_sig(w, cx, &ft.sig);
366     enc_abi(w, ft.abi);
367 }
368
369 fn enc_fn_sig<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
370                         fsig: &ty::PolyFnSig<'tcx>) {
371     write!(w, "[");
372     for ty in &fsig.0.inputs {
373         enc_ty(w, cx, *ty);
374     }
375     write!(w, "]");
376     if fsig.0.variadic {
377         write!(w, "V");
378     } else {
379         write!(w, "N");
380     }
381     match fsig.0.output {
382         ty::FnConverging(result_type) => {
383             enc_ty(w, cx, result_type);
384         }
385         ty::FnDiverging => {
386             write!(w, "z");
387         }
388     }
389 }
390
391 pub fn enc_builtin_bounds(w: &mut Cursor<Vec<u8>>, _cx: &ctxt, bs: &ty::BuiltinBounds) {
392     for bound in bs {
393         match bound {
394             ty::BoundSend => write!(w, "S"),
395             ty::BoundSized => write!(w, "Z"),
396             ty::BoundCopy => write!(w, "P"),
397             ty::BoundSync => write!(w, "T"),
398         };
399     }
400
401     write!(w, ".");
402 }
403
404 pub fn enc_existential_bounds<'a,'tcx>(w: &mut Cursor<Vec<u8>>,
405                                        cx: &ctxt<'a,'tcx>,
406                                        bs: &ty::ExistentialBounds<'tcx>) {
407     enc_builtin_bounds(w, cx, &bs.builtin_bounds);
408
409     enc_region(w, cx, bs.region_bound);
410
411     for tp in &bs.projection_bounds {
412         write!(w, "P");
413         enc_projection_predicate(w, cx, &tp.0);
414     }
415
416     write!(w, ".");
417 }
418
419 pub fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
420                                     v: &ty::TypeParameterDef<'tcx>) {
421     write!(w, "{}:{}|{}|{}|{}|",
422              v.name, (cx.ds)(v.def_id),
423              v.space.to_uint(), v.index, (cx.ds)(v.default_def_id));
424     enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
425     enc_object_lifetime_default(w, cx, v.object_lifetime_default);
426 }
427
428 pub fn enc_region_param_def(w: &mut Cursor<Vec<u8>>, cx: &ctxt,
429                             v: &ty::RegionParameterDef) {
430     write!(w, "{}:{}|{}|{}|",
431              v.name, (cx.ds)(v.def_id),
432              v.space.to_uint(), v.index);
433     for &r in &v.bounds {
434         write!(w, "R");
435         enc_region(w, cx, r);
436     }
437     write!(w, ".");
438 }
439
440 fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Cursor<Vec<u8>>,
441                                          cx: &ctxt<'a, 'tcx>,
442                                          default: ty::ObjectLifetimeDefault)
443 {
444     match default {
445         ty::ObjectLifetimeDefault::Ambiguous => {
446             write!(w, "a");
447         }
448         ty::ObjectLifetimeDefault::BaseDefault => {
449             write!(w, "b");
450         }
451         ty::ObjectLifetimeDefault::Specific(r) => {
452             write!(w, "s");
453             enc_region(w, cx, r);
454         }
455     }
456 }
457
458 pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor<Vec<u8>>,
459                                cx: &ctxt<'a, 'tcx>,
460                                p: &ty::Predicate<'tcx>)
461 {
462     match *p {
463         ty::Predicate::Trait(ref trait_ref) => {
464             write!(w, "t");
465             enc_trait_ref(w, cx, trait_ref.0.trait_ref);
466         }
467         ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => {
468             write!(w, "e");
469             enc_ty(w, cx, a);
470             enc_ty(w, cx, b);
471         }
472         ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => {
473             write!(w, "r");
474             enc_region(w, cx, a);
475             enc_region(w, cx, b);
476         }
477         ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => {
478             write!(w, "o");
479             enc_ty(w, cx, a);
480             enc_region(w, cx, b);
481         }
482         ty::Predicate::Projection(ty::Binder(ref data)) => {
483             write!(w, "p");
484             enc_projection_predicate(w, cx, data);
485         }
486         ty::Predicate::WellFormed(data) => {
487             write!(w, "w");
488             enc_ty(w, cx, data);
489         }
490         ty::Predicate::ObjectSafe(trait_def_id) => {
491             write!(w, "O{}|", (cx.ds)(trait_def_id));
492         }
493     }
494 }
495
496 fn enc_projection_predicate<'a, 'tcx>(w: &mut Cursor<Vec<u8>>,
497                                       cx: &ctxt<'a, 'tcx>,
498                                       data: &ty::ProjectionPredicate<'tcx>) {
499     enc_trait_ref(w, cx, data.projection_ty.trait_ref);
500     write!(w, "{}|", data.projection_ty.item_name);
501     enc_ty(w, cx, data.ty);
502 }