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.
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.
13 #![allow(unused_must_use)] // as with encoding, everything is a no-fail MemWriter
14 #![allow(non_camel_case_types)]
16 use std::cell::RefCell;
18 use std::io::prelude::*;
20 use middle::def_id::DefId;
23 use middle::subst::VecPerParamSpace;
24 use middle::ty::ParamTy;
25 use middle::ty::{self, Ty};
26 use util::nodemap::FnvHashMap;
32 use syntax::diagnostic::SpanHandler;
34 use rbml::writer::{self, Encoder};
36 macro_rules! mywrite { ($w:expr, $($arg:tt)*) => ({ write!($w.writer, $($arg)*); }) }
38 pub struct ctxt<'a, 'tcx: 'a> {
39 pub diag: &'a SpanHandler,
40 // Def -> str Callback:
41 pub ds: fn(DefId) -> String,
43 pub tcx: &'a ty::ctxt<'tcx>,
44 pub abbrevs: &'a abbrev_map<'tcx>
47 // Compact string representation for Ty values. API TyStr & parse_from_str.
48 // Extra parameters are for converting to/from def_ids in the string rep.
49 // Whatever format you choose should not contain pipe characters.
50 pub struct ty_abbrev {
54 pub type abbrev_map<'tcx> = RefCell<FnvHashMap<Ty<'tcx>, ty_abbrev>>;
56 pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) {
57 match cx.abbrevs.borrow_mut().get(&t) {
58 Some(a) => { w.writer.write_all(&a.s); return; }
62 // type abbreviations needs a stable position
63 let pos = w.mark_stable_position();
66 ty::TyBool => mywrite!(w, "b"),
67 ty::TyChar => mywrite!(w, "c"),
70 ast::TyIs => mywrite!(w, "is"),
71 ast::TyI8 => mywrite!(w, "MB"),
72 ast::TyI16 => mywrite!(w, "MW"),
73 ast::TyI32 => mywrite!(w, "ML"),
74 ast::TyI64 => mywrite!(w, "MD")
79 ast::TyUs => mywrite!(w, "us"),
80 ast::TyU8 => mywrite!(w, "Mb"),
81 ast::TyU16 => mywrite!(w, "Mw"),
82 ast::TyU32 => mywrite!(w, "Ml"),
83 ast::TyU64 => mywrite!(w, "Md")
88 ast::TyF32 => mywrite!(w, "Mf"),
89 ast::TyF64 => mywrite!(w, "MF"),
92 ty::TyEnum(def, substs) => {
93 mywrite!(w, "t[{}|", (cx.ds)(def.did));
94 enc_substs(w, cx, substs);
97 ty::TyTrait(box ty::TraitTy { ref principal,
100 enc_trait_ref(w, cx, principal.0);
101 enc_existential_bounds(w, cx, bounds);
104 ty::TyTuple(ref ts) => {
106 for t in ts { enc_ty(w, cx, *t); }
109 ty::TyBox(typ) => { mywrite!(w, "~"); enc_ty(w, cx, typ); }
110 ty::TyRawPtr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); }
111 ty::TyRef(r, mt) => {
113 enc_region(w, cx, *r);
116 ty::TyArray(t, sz) => {
119 mywrite!(w, "/{}|", sz);
129 ty::TyBareFn(Some(def_id), f) => {
131 mywrite!(w, "{}|", (cx.ds)(def_id));
132 enc_bare_fn_ty(w, cx, f);
134 ty::TyBareFn(None, f) => {
136 enc_bare_fn_ty(w, cx, f);
139 cx.diag.handler().bug("cannot encode inference variable types");
141 ty::TyParam(ParamTy {space, idx, name}) => {
142 mywrite!(w, "p[{}|{}|{}]", idx, space.to_uint(), name)
144 ty::TyStruct(def, substs) => {
145 mywrite!(w, "a[{}|", (cx.ds)(def.did));
146 enc_substs(w, cx, substs);
149 ty::TyClosure(def, ref substs) => {
150 mywrite!(w, "k[{}|", (cx.ds)(def));
151 enc_substs(w, cx, &substs.func_substs);
152 for ty in &substs.upvar_tys {
158 ty::TyProjection(ref data) => {
160 enc_trait_ref(w, cx, data.trait_ref);
161 mywrite!(w, "{}]", data.item_name);
168 let end = w.mark_stable_position();
171 let buf: &mut [u8] = &mut [0; 16]; // vuint < 15 bytes
172 let mut abbrev = Cursor::new(buf);
173 abbrev.write_all(b"#");
174 writer::write_vuint(&mut abbrev, pos as usize);
176 cx.abbrevs.borrow_mut().insert(t, ty_abbrev {
177 s: if abbrev.position() < len {
178 abbrev.get_ref()[..abbrev.position() as usize].to_owned()
180 // if the abbreviation is longer than the real type,
181 // don't use #-notation. However, insert it here so
182 // other won't have to `mark_stable_position`
183 w.writer.get_ref()[pos as usize..end as usize].to_owned()
188 fn enc_mutability(w: &mut Encoder, mt: hir::Mutability) {
190 hir::MutImmutable => (),
191 hir::MutMutable => mywrite!(w, "m"),
195 fn enc_mt<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
196 mt: ty::TypeAndMut<'tcx>) {
197 enc_mutability(w, mt.mutbl);
198 enc_ty(w, cx, mt.ty);
201 fn enc_opt<T, F>(w: &mut Encoder, t: Option<T>, enc_f: F) where
202 F: FnOnce(&mut Encoder, T),
205 None => mywrite!(w, "n"),
213 fn enc_vec_per_param_space<'a, 'tcx, T, F>(w: &mut Encoder,
215 v: &VecPerParamSpace<T>,
217 F: FnMut(&mut Encoder, &ctxt<'a, 'tcx>, &T),
219 for &space in &subst::ParamSpace::all() {
221 for t in v.get_slice(space) {
228 pub fn enc_substs<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
229 substs: &subst::Substs<'tcx>) {
230 enc_region_substs(w, cx, &substs.regions);
231 enc_vec_per_param_space(w, cx, &substs.types,
232 |w, cx, &ty| enc_ty(w, cx, ty));
235 fn enc_region_substs(w: &mut Encoder, cx: &ctxt, substs: &subst::RegionSubsts) {
237 subst::ErasedRegions => {
240 subst::NonerasedRegions(ref regions) => {
242 enc_vec_per_param_space(w, cx, regions,
243 |w, cx, &r| enc_region(w, cx, r));
248 pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) {
250 ty::ReLateBound(id, br) => {
251 mywrite!(w, "b[{}|", id.depth);
252 enc_bound_region(w, cx, br);
255 ty::ReEarlyBound(ref data) => {
256 mywrite!(w, "B[{}|{}|{}|{}]",
257 (cx.ds)(data.def_id),
258 data.space.to_uint(),
262 ty::ReFree(ref fr) => {
264 enc_scope(w, cx, fr.scope);
266 enc_bound_region(w, cx, fr.bound_region);
269 ty::ReScope(scope) => {
271 enc_scope(w, cx, scope);
280 ty::ReVar(_) | ty::ReSkolemized(..) => {
281 // these should not crop up after typeck
282 cx.diag.handler().bug("cannot encode region variables");
287 fn enc_scope(w: &mut Encoder, cx: &ctxt, scope: region::CodeExtent) {
288 match cx.tcx.region_maps.code_extent_data(scope) {
289 region::CodeExtentData::ParameterScope {
290 fn_id, body_id } => mywrite!(w, "P[{}|{}]", fn_id, body_id),
291 region::CodeExtentData::Misc(node_id) => mywrite!(w, "M{}", node_id),
292 region::CodeExtentData::Remainder(region::BlockRemainder {
293 block: b, first_statement_index: i }) => mywrite!(w, "B[{}|{}]", b, i),
294 region::CodeExtentData::DestructionScope(node_id) => mywrite!(w, "D{}", node_id),
298 fn enc_bound_region(w: &mut Encoder, cx: &ctxt, br: ty::BoundRegion) {
301 mywrite!(w, "a{}|", idx);
303 ty::BrNamed(d, name) => {
304 mywrite!(w, "[{}|{}]",
309 mywrite!(w, "f{}|", id);
317 pub fn enc_trait_ref<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
318 s: ty::TraitRef<'tcx>) {
319 mywrite!(w, "{}|", (cx.ds)(s.def_id));
320 enc_substs(w, cx, s.substs);
323 fn enc_unsafety(w: &mut Encoder, p: hir::Unsafety) {
325 hir::Unsafety::Normal => mywrite!(w, "n"),
326 hir::Unsafety::Unsafe => mywrite!(w, "u"),
330 fn enc_abi(w: &mut Encoder, abi: Abi) {
332 mywrite!(w, "{}", abi.name());
336 pub fn enc_bare_fn_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
337 ft: &ty::BareFnTy<'tcx>) {
338 enc_unsafety(w, ft.unsafety);
340 enc_fn_sig(w, cx, &ft.sig);
343 pub fn enc_closure_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
344 ft: &ty::ClosureTy<'tcx>) {
345 enc_unsafety(w, ft.unsafety);
346 enc_fn_sig(w, cx, &ft.sig);
350 fn enc_fn_sig<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
351 fsig: &ty::PolyFnSig<'tcx>) {
353 for ty in &fsig.0.inputs {
362 match fsig.0.output {
363 ty::FnConverging(result_type) => {
364 enc_ty(w, cx, result_type);
372 pub fn enc_builtin_bounds(w: &mut Encoder, _cx: &ctxt, bs: &ty::BuiltinBounds) {
375 ty::BoundSend => mywrite!(w, "S"),
376 ty::BoundSized => mywrite!(w, "Z"),
377 ty::BoundCopy => mywrite!(w, "P"),
378 ty::BoundSync => mywrite!(w, "T"),
385 pub fn enc_existential_bounds<'a,'tcx>(w: &mut Encoder,
387 bs: &ty::ExistentialBounds<'tcx>) {
388 enc_builtin_bounds(w, cx, &bs.builtin_bounds);
390 enc_region(w, cx, bs.region_bound);
392 for tp in &bs.projection_bounds {
394 enc_projection_predicate(w, cx, &tp.0);
400 pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
401 v: &ty::TypeParameterDef<'tcx>) {
402 mywrite!(w, "{}:{}|{}|{}|{}|",
403 v.name, (cx.ds)(v.def_id),
404 v.space.to_uint(), v.index, (cx.ds)(v.default_def_id));
405 enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
406 enc_object_lifetime_default(w, cx, v.object_lifetime_default);
409 pub fn enc_region_param_def(w: &mut Encoder, cx: &ctxt,
410 v: &ty::RegionParameterDef) {
411 mywrite!(w, "{}:{}|{}|{}|",
412 v.name, (cx.ds)(v.def_id),
413 v.space.to_uint(), v.index);
414 for &r in &v.bounds {
416 enc_region(w, cx, r);
421 fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Encoder,
423 default: ty::ObjectLifetimeDefault)
426 ty::ObjectLifetimeDefault::Ambiguous => mywrite!(w, "a"),
427 ty::ObjectLifetimeDefault::BaseDefault => mywrite!(w, "b"),
428 ty::ObjectLifetimeDefault::Specific(r) => {
430 enc_region(w, cx, r);
435 pub fn enc_predicate<'a, 'tcx>(w: &mut Encoder,
437 p: &ty::Predicate<'tcx>)
440 ty::Predicate::Trait(ref trait_ref) => {
442 enc_trait_ref(w, cx, trait_ref.0.trait_ref);
444 ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => {
449 ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => {
451 enc_region(w, cx, a);
452 enc_region(w, cx, b);
454 ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => {
457 enc_region(w, cx, b);
459 ty::Predicate::Projection(ty::Binder(ref data)) => {
461 enc_projection_predicate(w, cx, data)
463 ty::Predicate::WellFormed(data) => {
467 ty::Predicate::ObjectSafe(trait_def_id) => {
468 mywrite!(w, "O{}|", (cx.ds)(trait_def_id));
473 fn enc_projection_predicate<'a, 'tcx>(w: &mut Encoder,
475 data: &ty::ProjectionPredicate<'tcx>) {
476 enc_trait_ref(w, cx, data.projection_ty.trait_ref);
477 mywrite!(w, "{}|", data.projection_ty.item_name);
478 enc_ty(w, cx, data.ty);