]> git.lizzy.rs Git - rust.git/blob - src/librustc/metadata/tyencode.rs
auto merge of #11598 : alexcrichton/rust/io-export, r=brson
[rust.git] / src / librustc / metadata / tyencode.rs
1 // Copyright 2012 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 use std::cell::RefCell;
14 use std::hashmap::HashMap;
15 use std::io;
16 use std::io::MemWriter;
17 use std::str;
18 use std::fmt;
19
20 use middle::ty::param_ty;
21 use middle::ty;
22
23 use syntax::abi::AbiSet;
24 use syntax::ast;
25 use syntax::ast::*;
26 use syntax::diagnostic::SpanHandler;
27 use syntax::print::pprust::*;
28
29 macro_rules! mywrite( ($wr:expr, $($arg:tt)*) => (
30     format_args!(|a| { mywrite($wr, a) }, $($arg)*)
31 ) )
32
33 pub struct ctxt {
34     diag: @SpanHandler,
35     // Def -> str Callback:
36     ds: extern "Rust" fn(DefId) -> ~str,
37     // The type context.
38     tcx: ty::ctxt,
39     abbrevs: abbrev_ctxt
40 }
41
42 // Compact string representation for ty.t values. API ty_str & parse_from_str.
43 // Extra parameters are for converting to/from def_ids in the string rep.
44 // Whatever format you choose should not contain pipe characters.
45 pub struct ty_abbrev {
46     pos: uint,
47     len: uint,
48     s: @str
49 }
50
51 pub enum abbrev_ctxt {
52     ac_no_abbrevs,
53     ac_use_abbrevs(@RefCell<HashMap<ty::t, ty_abbrev>>),
54 }
55
56 fn mywrite(w: &mut MemWriter, fmt: &fmt::Arguments) {
57     fmt::write(&mut *w as &mut io::Writer, fmt);
58 }
59
60 pub fn enc_ty(w: &mut MemWriter, cx: @ctxt, t: ty::t) {
61     match cx.abbrevs {
62       ac_no_abbrevs => {
63           let result_str_opt;
64           {
65               let short_names_cache = cx.tcx.short_names_cache.borrow();
66               result_str_opt = short_names_cache.get()
67                                                 .find(&t)
68                                                 .map(|result| *result);
69           }
70           let result_str = match result_str_opt {
71             Some(s) => s,
72             None => {
73                 let wr = &mut MemWriter::new();
74                 enc_sty(wr, cx, &ty::get(t).sty);
75                 let s = str::from_utf8(wr.get_ref()).to_managed();
76                 let mut short_names_cache = cx.tcx
77                                               .short_names_cache
78                                               .borrow_mut();
79                 short_names_cache.get().insert(t, s);
80                 s
81             }
82           };
83           w.write(result_str.as_bytes());
84       }
85       ac_use_abbrevs(abbrevs) => {
86           {
87               let mut abbrevs = abbrevs.borrow_mut();
88               match abbrevs.get().find(&t) {
89                   Some(a) => { w.write(a.s.as_bytes()); return; }
90                   None => {}
91               }
92           }
93           let pos = w.tell();
94           enc_sty(w, cx, &ty::get(t).sty);
95           let end = w.tell();
96           let len = end - pos;
97           fn estimate_sz(u: u64) -> u64 {
98               let mut n = u;
99               let mut len = 0;
100               while n != 0 { len += 1; n = n >> 4; }
101               return len;
102           }
103           let abbrev_len = 3 + estimate_sz(pos) + estimate_sz(len);
104           if abbrev_len < len {
105               // I.e. it's actually an abbreviation.
106               let s = format!("\\#{:x}:{:x}\\#", pos, len).to_managed();
107               let a = ty_abbrev { pos: pos as uint,
108                                   len: len as uint,
109                                   s: s };
110               {
111                   let mut abbrevs = abbrevs.borrow_mut();
112                   abbrevs.get().insert(t, a);
113               }
114           }
115           return;
116       }
117     }
118 }
119
120 fn enc_mutability(w: &mut MemWriter, mt: ast::Mutability) {
121     match mt {
122         MutImmutable => (),
123         MutMutable => mywrite!(w, "m"),
124     }
125 }
126
127 fn enc_mt(w: &mut MemWriter, cx: @ctxt, mt: ty::mt) {
128     enc_mutability(w, mt.mutbl);
129     enc_ty(w, cx, mt.ty);
130 }
131
132 fn enc_opt<T>(w: &mut MemWriter, t: Option<T>, enc_f: |&mut MemWriter, T|) {
133     match t {
134         None => mywrite!(w, "n"),
135         Some(v) => {
136             mywrite!(w, "s");
137             enc_f(w, v);
138         }
139     }
140 }
141
142 pub fn enc_substs(w: &mut MemWriter, cx: @ctxt, substs: &ty::substs) {
143     enc_region_substs(w, cx, &substs.regions);
144     enc_opt(w, substs.self_ty, |w, t| enc_ty(w, cx, t));
145     mywrite!(w, "[");
146     for t in substs.tps.iter() { enc_ty(w, cx, *t); }
147     mywrite!(w, "]");
148 }
149
150 fn enc_region_substs(w: &mut MemWriter, cx: @ctxt, substs: &ty::RegionSubsts) {
151     match *substs {
152         ty::ErasedRegions => {
153             mywrite!(w, "e");
154         }
155         ty::NonerasedRegions(ref regions) => {
156             mywrite!(w, "n");
157             for &r in regions.iter() {
158                 enc_region(w, cx, r);
159             }
160             mywrite!(w, ".");
161         }
162     }
163 }
164
165 fn enc_region(w: &mut MemWriter, cx: @ctxt, r: ty::Region) {
166     match r {
167         ty::ReLateBound(id, br) => {
168             mywrite!(w, "b[{}|", id);
169             enc_bound_region(w, cx, br);
170             mywrite!(w, "]");
171         }
172         ty::ReEarlyBound(node_id, index, ident) => {
173             mywrite!(w, "B[{}|{}|{}]",
174                      node_id,
175                      index,
176                      cx.tcx.sess.str_of(ident));
177         }
178         ty::ReFree(ref fr) => {
179             mywrite!(w, "f[{}|", fr.scope_id);
180             enc_bound_region(w, cx, fr.bound_region);
181             mywrite!(w, "]");
182         }
183         ty::ReScope(nid) => {
184             mywrite!(w, "s{}|", nid);
185         }
186         ty::ReStatic => {
187             mywrite!(w, "t");
188         }
189         ty::ReEmpty => {
190             mywrite!(w, "e");
191         }
192         ty::ReInfer(_) => {
193             // these should not crop up after typeck
194             cx.diag.handler().bug("Cannot encode region variables");
195         }
196     }
197 }
198
199 fn enc_bound_region(w: &mut MemWriter, cx: @ctxt, br: ty::BoundRegion) {
200     match br {
201         ty::BrAnon(idx) => {
202             mywrite!(w, "a{}|", idx);
203         }
204         ty::BrNamed(d, s) => {
205             mywrite!(w, "[{}|{}]",
206                      (cx.ds)(d),
207                      cx.tcx.sess.str_of(s));
208         }
209         ty::BrFresh(id) => {
210             mywrite!(w, "f{}|", id);
211         }
212     }
213 }
214
215 pub fn enc_vstore(w: &mut MemWriter, cx: @ctxt, v: ty::vstore) {
216     mywrite!(w, "/");
217     match v {
218         ty::vstore_fixed(u) => mywrite!(w, "{}|", u),
219         ty::vstore_uniq => mywrite!(w, "~"),
220         ty::vstore_box => mywrite!(w, "@"),
221         ty::vstore_slice(r) => {
222             mywrite!(w, "&");
223             enc_region(w, cx, r);
224         }
225     }
226 }
227
228 pub fn enc_trait_ref(w: &mut MemWriter, cx: @ctxt, s: &ty::TraitRef) {
229     mywrite!(w, "{}|", (cx.ds)(s.def_id));
230     enc_substs(w, cx, &s.substs);
231 }
232
233 pub fn enc_trait_store(w: &mut MemWriter, cx: @ctxt, s: ty::TraitStore) {
234     match s {
235         ty::UniqTraitStore => mywrite!(w, "~"),
236         ty::BoxTraitStore => mywrite!(w, "@"),
237         ty::RegionTraitStore(re) => {
238             mywrite!(w, "&");
239             enc_region(w, cx, re);
240         }
241     }
242 }
243
244 fn enc_sty(w: &mut MemWriter, cx: @ctxt, st: &ty::sty) {
245     match *st {
246         ty::ty_nil => mywrite!(w, "n"),
247         ty::ty_bot => mywrite!(w, "z"),
248         ty::ty_bool => mywrite!(w, "b"),
249         ty::ty_char => mywrite!(w, "c"),
250         ty::ty_int(t) => {
251             match t {
252                 TyI => mywrite!(w, "i"),
253                 TyI8 => mywrite!(w, "MB"),
254                 TyI16 => mywrite!(w, "MW"),
255                 TyI32 => mywrite!(w, "ML"),
256                 TyI64 => mywrite!(w, "MD")
257             }
258         }
259         ty::ty_uint(t) => {
260             match t {
261                 TyU => mywrite!(w, "u"),
262                 TyU8 => mywrite!(w, "Mb"),
263                 TyU16 => mywrite!(w, "Mw"),
264                 TyU32 => mywrite!(w, "Ml"),
265                 TyU64 => mywrite!(w, "Md")
266             }
267         }
268         ty::ty_float(t) => {
269             match t {
270                 TyF32 => mywrite!(w, "Mf"),
271                 TyF64 => mywrite!(w, "MF"),
272             }
273         }
274         ty::ty_enum(def, ref substs) => {
275             mywrite!(w, "t[{}|", (cx.ds)(def));
276             enc_substs(w, cx, substs);
277             mywrite!(w, "]");
278         }
279         ty::ty_trait(def, ref substs, store, mt, bounds) => {
280             mywrite!(w, "x[{}|", (cx.ds)(def));
281             enc_substs(w, cx, substs);
282             enc_trait_store(w, cx, store);
283             enc_mutability(w, mt);
284             let bounds = ty::ParamBounds {builtin_bounds: bounds,
285                                           trait_bounds: ~[]};
286             enc_bounds(w, cx, &bounds);
287             mywrite!(w, "]");
288         }
289         ty::ty_tup(ref ts) => {
290             mywrite!(w, "T[");
291             for t in ts.iter() { enc_ty(w, cx, *t); }
292             mywrite!(w, "]");
293         }
294         ty::ty_box(typ) => { mywrite!(w, "@"); enc_ty(w, cx, typ); }
295         ty::ty_uniq(typ) => { mywrite!(w, "~"); enc_ty(w, cx, typ); }
296         ty::ty_ptr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); }
297         ty::ty_rptr(r, mt) => {
298             mywrite!(w, "&");
299             enc_region(w, cx, r);
300             enc_mt(w, cx, mt);
301         }
302         ty::ty_vec(mt, v) => {
303             mywrite!(w, "V");
304             enc_mt(w, cx, mt);
305             enc_vstore(w, cx, v);
306         }
307         ty::ty_str(v) => {
308             mywrite!(w, "v");
309             enc_vstore(w, cx, v);
310         }
311         ty::ty_unboxed_vec(mt) => { mywrite!(w, "U"); enc_mt(w, cx, mt); }
312         ty::ty_closure(ref f) => {
313             mywrite!(w, "f");
314             enc_closure_ty(w, cx, f);
315         }
316         ty::ty_bare_fn(ref f) => {
317             mywrite!(w, "F");
318             enc_bare_fn_ty(w, cx, f);
319         }
320         ty::ty_infer(_) => {
321             cx.diag.handler().bug("Cannot encode inference variable types");
322         }
323         ty::ty_param(param_ty {idx: id, def_id: did}) => {
324             mywrite!(w, "p{}|{}", (cx.ds)(did), id);
325         }
326         ty::ty_self(did) => {
327             mywrite!(w, "s{}|", (cx.ds)(did));
328         }
329         ty::ty_type => mywrite!(w, "Y"),
330         ty::ty_opaque_closure_ptr(p) => {
331             mywrite!(w, "C&");
332             enc_sigil(w, p);
333         }
334         ty::ty_struct(def, ref substs) => {
335             mywrite!(w, "a[{}|", (cx.ds)(def));
336             enc_substs(w, cx, substs);
337             mywrite!(w, "]");
338         }
339         ty::ty_err => fail!("Shouldn't encode error type")
340     }
341 }
342
343 fn enc_sigil(w: &mut MemWriter, sigil: Sigil) {
344     match sigil {
345         ManagedSigil => mywrite!(w, "@"),
346         OwnedSigil => mywrite!(w, "~"),
347         BorrowedSigil => mywrite!(w, "&"),
348     }
349 }
350
351 fn enc_purity(w: &mut MemWriter, p: Purity) {
352     match p {
353         ImpureFn => mywrite!(w, "i"),
354         UnsafeFn => mywrite!(w, "u"),
355         ExternFn => mywrite!(w, "c")
356     }
357 }
358
359 fn enc_abi_set(w: &mut MemWriter, abis: AbiSet) {
360     mywrite!(w, "[");
361     abis.each(|abi| {
362         mywrite!(w, "{},", abi.name());
363         true
364     });
365     mywrite!(w, "]")
366 }
367
368 fn enc_onceness(w: &mut MemWriter, o: Onceness) {
369     match o {
370         Once => mywrite!(w, "o"),
371         Many => mywrite!(w, "m")
372     }
373 }
374
375 pub fn enc_bare_fn_ty(w: &mut MemWriter, cx: @ctxt, ft: &ty::BareFnTy) {
376     enc_purity(w, ft.purity);
377     enc_abi_set(w, ft.abis);
378     enc_fn_sig(w, cx, &ft.sig);
379 }
380
381 fn enc_closure_ty(w: &mut MemWriter, cx: @ctxt, ft: &ty::ClosureTy) {
382     enc_sigil(w, ft.sigil);
383     enc_purity(w, ft.purity);
384     enc_onceness(w, ft.onceness);
385     enc_region(w, cx, ft.region);
386     let bounds = ty::ParamBounds {builtin_bounds: ft.bounds,
387                                   trait_bounds: ~[]};
388     enc_bounds(w, cx, &bounds);
389     enc_fn_sig(w, cx, &ft.sig);
390 }
391
392 fn enc_fn_sig(w: &mut MemWriter, cx: @ctxt, fsig: &ty::FnSig) {
393     mywrite!(w, "[{}|", fsig.binder_id);
394     for ty in fsig.inputs.iter() {
395         enc_ty(w, cx, *ty);
396     }
397     mywrite!(w, "]");
398     if fsig.variadic {
399         mywrite!(w, "V");
400     } else {
401         mywrite!(w, "N");
402     }
403     enc_ty(w, cx, fsig.output);
404 }
405
406 fn enc_bounds(w: &mut MemWriter, cx: @ctxt, bs: &ty::ParamBounds) {
407     for bound in bs.builtin_bounds.iter() {
408         match bound {
409             ty::BoundSend => mywrite!(w, "S"),
410             ty::BoundFreeze => mywrite!(w, "K"),
411             ty::BoundStatic => mywrite!(w, "O"),
412             ty::BoundSized => mywrite!(w, "Z"),
413             ty::BoundPod => mywrite!(w, "P"),
414         }
415     }
416
417     for &tp in bs.trait_bounds.iter() {
418         mywrite!(w, "I");
419         enc_trait_ref(w, cx, tp);
420     }
421
422     mywrite!(w, ".");
423 }
424
425 pub fn enc_type_param_def(w: &mut MemWriter, cx: @ctxt, v: &ty::TypeParameterDef) {
426     mywrite!(w, "{}:{}|", cx.tcx.sess.str_of(v.ident), (cx.ds)(v.def_id));
427     enc_bounds(w, cx, v.bounds);
428 }