]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/reflect.rs
librustc: Implement associated types behind a feature gate.
[rust.git] / src / librustc / middle / trans / reflect.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 use back::link::mangle_internal_name_by_path_and_seq;
12 use llvm::{ValueRef, get_param};
13 use middle::trans::adt;
14 use middle::trans::base::*;
15 use middle::trans::build::*;
16 use middle::trans::callee::ArgVals;
17 use middle::trans::callee;
18 use middle::trans::common::*;
19 use middle::trans::datum::*;
20 use middle::trans::glue;
21 use middle::trans::machine;
22 use middle::trans::meth;
23 use middle::trans::type_::Type;
24 use middle::trans::type_of::*;
25 use middle::ty;
26 use util::ppaux::ty_to_string;
27
28 use arena::TypedArena;
29 use libc::c_uint;
30 use syntax::ast::DefId;
31 use syntax::ast;
32 use syntax::ast_map;
33 use syntax::parse::token::{InternedString, special_idents};
34 use syntax::parse::token;
35
36 pub struct Reflector<'a, 'blk, 'tcx: 'blk> {
37     visitor_val: ValueRef,
38     visitor_items: &'a [ty::ImplOrTraitItem],
39     final_bcx: Block<'blk, 'tcx>,
40     tydesc_ty: Type,
41     bcx: Block<'blk, 'tcx>
42 }
43
44 impl<'a, 'blk, 'tcx> Reflector<'a, 'blk, 'tcx> {
45     pub fn c_uint(&mut self, u: uint) -> ValueRef {
46         C_uint(self.bcx.ccx(), u)
47     }
48
49     pub fn c_bool(&mut self, b: bool) -> ValueRef {
50         C_bool(self.bcx.ccx(), b)
51     }
52
53     pub fn c_slice(&mut self, s: InternedString) -> ValueRef {
54         // We're careful to not use first class aggregates here because that
55         // will kick us off fast isel. (Issue #4352.)
56         let bcx = self.bcx;
57         let str_ty = ty::mk_str_slice(bcx.tcx(), ty::ReStatic, ast::MutImmutable);
58         let scratch = rvalue_scratch_datum(bcx, str_ty, "");
59         let len = C_uint(bcx.ccx(), s.get().len());
60         let c_str = PointerCast(bcx, C_cstr(bcx.ccx(), s, false), Type::i8p(bcx.ccx()));
61         Store(bcx, c_str, GEPi(bcx, scratch.val, [ 0, 0 ]));
62         Store(bcx, len, GEPi(bcx, scratch.val, [ 0, 1 ]));
63         scratch.val
64     }
65
66     pub fn c_size_and_align(&mut self, t: ty::t) -> Vec<ValueRef> {
67         let tr = type_of(self.bcx.ccx(), t);
68         let s = machine::llsize_of_real(self.bcx.ccx(), tr);
69         let a = align_of(self.bcx.ccx(), t);
70         return vec!(self.c_uint(s as uint),
71              self.c_uint(a as uint));
72     }
73
74     pub fn c_tydesc(&mut self, t: ty::t) -> ValueRef {
75         let bcx = self.bcx;
76         let static_ti = get_tydesc(bcx.ccx(), t);
77         glue::lazily_emit_visit_glue(bcx.ccx(), &*static_ti);
78         PointerCast(bcx, static_ti.tydesc, self.tydesc_ty.ptr_to())
79     }
80
81     pub fn c_mt(&mut self, mt: &ty::mt) -> Vec<ValueRef> {
82         vec!(self.c_uint(mt.mutbl as uint),
83           self.c_tydesc(mt.ty))
84     }
85
86     pub fn visit(&mut self, ty_name: &str, args: &[ValueRef]) {
87         let fcx = self.bcx.fcx;
88         let tcx = self.bcx.tcx();
89         let mth_idx = ty::impl_or_trait_item_idx(token::str_to_ident(format!(
90                         "visit_{}", ty_name).as_slice()),
91                                      self.visitor_items.as_slice()).expect(
92                 format!("couldn't find visit method for {}", ty_name).as_slice());
93         let method = match self.visitor_items[mth_idx] {
94             ty::MethodTraitItem(ref method) => (*method).clone(),
95             ty::TypeTraitItem(_) => return,
96         };
97         let mth_ty = ty::mk_bare_fn(tcx, method.fty.clone());
98         debug!("Emit call visit method: visit_{}: {}", ty_name, ty_to_string(tcx, mth_ty));
99         let v = self.visitor_val;
100         debug!("passing {} args:", args.len());
101         let mut bcx = self.bcx;
102         for (i, a) in args.iter().enumerate() {
103             debug!("arg {}: {}", i, bcx.val_to_string(*a));
104         }
105         let result = unpack_result!(bcx, callee::trans_call_inner(
106             self.bcx, None, mth_ty,
107             |bcx, _| meth::trans_trait_callee_from_llval(bcx,
108                                                          mth_ty,
109                                                          mth_idx,
110                                                          v),
111             ArgVals(args), None));
112         let next_bcx = fcx.new_temp_block("next");
113         CondBr(bcx, result, next_bcx.llbb, self.final_bcx.llbb);
114         self.bcx = next_bcx
115     }
116
117     pub fn bracketed(&mut self,
118                      bracket_name: &str,
119                      extra: &[ValueRef],
120                      inner: |&mut Reflector|) {
121         self.visit(format!("enter_{}", bracket_name).as_slice(), extra);
122         inner(self);
123         self.visit(format!("leave_{}", bracket_name).as_slice(), extra);
124     }
125
126     pub fn leaf(&mut self, name: &str) {
127         self.visit(name, []);
128     }
129
130     // Entrypoint
131     pub fn visit_ty(&mut self, t: ty::t) {
132         let bcx = self.bcx;
133         let tcx = bcx.tcx();
134         debug!("reflect::visit_ty {}", ty_to_string(bcx.tcx(), t));
135
136         match ty::get(t).sty {
137           ty::ty_bot => self.leaf("bot"),
138           ty::ty_nil => self.leaf("nil"),
139           ty::ty_bool => self.leaf("bool"),
140           ty::ty_char => self.leaf("char"),
141           ty::ty_int(ast::TyI) => self.leaf("int"),
142           ty::ty_int(ast::TyI8) => self.leaf("i8"),
143           ty::ty_int(ast::TyI16) => self.leaf("i16"),
144           ty::ty_int(ast::TyI32) => self.leaf("i32"),
145           ty::ty_int(ast::TyI64) => self.leaf("i64"),
146           ty::ty_uint(ast::TyU) => self.leaf("uint"),
147           ty::ty_uint(ast::TyU8) => self.leaf("u8"),
148           ty::ty_uint(ast::TyU16) => self.leaf("u16"),
149           ty::ty_uint(ast::TyU32) => self.leaf("u32"),
150           ty::ty_uint(ast::TyU64) => self.leaf("u64"),
151           ty::ty_float(ast::TyF32) => self.leaf("f32"),
152           ty::ty_float(ast::TyF64) => self.leaf("f64"),
153
154           ty::ty_open(_) | ty::ty_str | ty::ty_vec(_, None) | ty::ty_trait(..) => {
155               // Unfortunately we can't do anything here because at runtime we
156               // pass around the value by pointer (*u8). But unsized pointers are
157               // fat and so we can't just cast them to *u8 and back. So we have
158               // to work with the pointer directly (see ty_ptr/ty_rptr/ty_uniq).
159               fail!("Can't reflect unsized type")
160           }
161           // FIXME(15049) Reflection for unsized structs.
162           ty::ty_struct(..) if !ty::type_is_sized(bcx.tcx(), t) => {
163               fail!("Can't reflect unsized type")
164           }
165
166           // Should rename to vec_*.
167           ty::ty_vec(ty, Some(sz)) => {
168               let mut extra = (vec!(self.c_uint(sz))).append(self.c_size_and_align(t).as_slice());
169               extra.push(self.c_tydesc(ty));
170               self.visit("evec_fixed", extra.as_slice())
171           }
172           // Should remove mt from box and uniq.
173           ty::ty_box(typ) => {
174               let extra = self.c_mt(&ty::mt {
175                   ty: typ,
176                   mutbl: ast::MutImmutable,
177               });
178               self.visit("box", extra.as_slice())
179           }
180           ty::ty_ptr(ref mt) => {
181               match ty::get(mt.ty).sty {
182                   ty::ty_vec(ty, None) => {
183                       let extra = self.c_mt(&ty::mt{ty: ty, mutbl: mt.mutbl});
184                       self.visit("evec_slice", extra.as_slice())
185                   }
186                   ty::ty_str => self.visit("estr_slice", &[]),
187                   ty::ty_trait(..) => {
188                       let extra = [
189                           self.c_slice(token::intern_and_get_ident(
190                                   ty_to_string(tcx, t).as_slice()))
191                       ];
192                       self.visit("trait", extra);
193                   }
194                   _ => {
195                       let extra = self.c_mt(mt);
196                       self.visit("ptr", extra.as_slice())
197                   }
198               }
199           }
200           ty::ty_uniq(typ) => {
201               match ty::get(typ).sty {
202                   ty::ty_trait(..) => {
203                       let extra = [
204                           self.c_slice(token::intern_and_get_ident(
205                                   ty_to_string(tcx, t).as_slice()))
206                       ];
207                       self.visit("trait", extra);
208                   }
209                   // FIXME(15049) allow reflection of Box<[T]>. You'll need to
210                   // restore visit_evec_uniq.
211                   ty::ty_vec(_, None) => {
212                       fail!("Box<[T]> theoretically doesn't exist, so don't try to reflect it")
213                   }
214                   ty::ty_str => fail!("Can't reflect Box<str> which shouldn't be used anyway"),
215                   _ => {
216                       let extra = self.c_mt(&ty::mt {
217                           ty: typ,
218                           mutbl: ast::MutImmutable,
219                       });
220                       self.visit("uniq", extra.as_slice())
221                   }
222               }
223           }
224           ty::ty_rptr(_, ref mt) => {
225               match ty::get(mt.ty).sty {
226                   ty::ty_vec(ty, None) => {
227                       let extra = self.c_mt(&ty::mt{ty: ty, mutbl: mt.mutbl});
228                       self.visit("evec_slice", extra.as_slice())
229                   }
230                   ty::ty_str => self.visit("estr_slice", &[]),
231                   ty::ty_trait(..) => {
232                       let extra = [
233                           self.c_slice(token::intern_and_get_ident(
234                                   ty_to_string(tcx, t).as_slice()))
235                       ];
236                       self.visit("trait", extra);
237                   }
238                   _ => {
239                       let extra = self.c_mt(mt);
240                       self.visit("rptr", extra.as_slice())
241                   }
242               }
243           }
244
245           ty::ty_tup(ref tys) => {
246               let extra = (vec!(self.c_uint(tys.len())))
247                           .append(self.c_size_and_align(t).as_slice());
248               self.bracketed("tup", extra.as_slice(), |this| {
249                   for (i, t) in tys.iter().enumerate() {
250                       let extra = vec!(this.c_uint(i), this.c_tydesc(*t));
251                       this.visit("tup_field", extra.as_slice());
252                   }
253               })
254           }
255
256           // FIXME (#2594): fetch constants out of intrinsic
257           // FIXME (#4809): visitor should break out bare fns from other fns
258           ty::ty_closure(ref fty) => {
259             let pureval = ast_fn_style_constant(fty.fn_style);
260             let sigilval = match fty.store {
261                 ty::UniqTraitStore => 2u,
262                 ty::RegionTraitStore(..) => 4u,
263             };
264             let retval = if ty::type_is_bot(fty.sig.output) {0u} else {1u};
265             let extra = vec!(self.c_uint(pureval),
266                           self.c_uint(sigilval),
267                           self.c_uint(fty.sig.inputs.len()),
268                           self.c_uint(retval));
269             self.visit("enter_fn", extra.as_slice());
270             self.visit_sig(retval, &fty.sig);
271             self.visit("leave_fn", extra.as_slice());
272           }
273
274           // FIXME (#2594): fetch constants out of intrinsic:: for the
275           // numbers.
276           ty::ty_bare_fn(ref fty) => {
277             let pureval = ast_fn_style_constant(fty.fn_style);
278             let sigilval = 0u;
279             let retval = if ty::type_is_bot(fty.sig.output) {0u} else {1u};
280             let extra = vec!(self.c_uint(pureval),
281                           self.c_uint(sigilval),
282                           self.c_uint(fty.sig.inputs.len()),
283                           self.c_uint(retval));
284             self.visit("enter_fn", extra.as_slice());
285             self.visit_sig(retval, &fty.sig);
286             self.visit("leave_fn", extra.as_slice());
287           }
288
289           ty::ty_struct(did, ref substs) => {
290               let fields = ty::struct_fields(tcx, did, substs);
291               let mut named_fields = false;
292               if !fields.is_empty() {
293                   named_fields = fields.get(0).ident.name !=
294                       special_idents::unnamed_field.name;
295               }
296
297               // This and the type_is_sized check on individual field types are
298               // because we cannot reflect unsized types (see note above). We
299               // just pretend the unsized field does not exist and print nothing.
300               // This is sub-optimal.
301               let len = fields.len();
302
303               let extra = (vec!(
304                   self.c_slice(
305                       token::intern_and_get_ident(ty_to_string(tcx,
306                                                             t).as_slice())),
307                   self.c_bool(named_fields),
308                   self.c_uint(len)
309               )).append(self.c_size_and_align(t).as_slice());
310               self.bracketed("class", extra.as_slice(), |this| {
311                   for (i, field) in fields.iter().enumerate() {
312                       let extra = (vec!(
313                         this.c_uint(i),
314                         this.c_slice(token::get_ident(field.ident)),
315                         this.c_bool(named_fields)
316                       )).append(this.c_mt(&field.mt).as_slice());
317                       this.visit("class_field", extra.as_slice());
318                   }
319               })
320           }
321
322           // FIXME (#2595): visiting all the variants in turn is probably
323           // not ideal. It'll work but will get costly on big enums. Maybe
324           // let the visitor tell us if it wants to visit only a particular
325           // variant?
326           ty::ty_enum(did, ref substs) => {
327             let ccx = bcx.ccx();
328             let repr = adt::represent_type(bcx.ccx(), t);
329             let variants = ty::substd_enum_variants(ccx.tcx(), did, substs);
330             let llptrty = type_of(ccx, t).ptr_to();
331             let opaquety = ty::get_opaque_ty(ccx.tcx()).unwrap();
332             let opaqueptrty = ty::mk_ptr(ccx.tcx(), ty::mt { ty: opaquety,
333                                                            mutbl: ast::MutImmutable });
334
335             let make_get_disr = || {
336                 let sym = mangle_internal_name_by_path_and_seq(
337                     ast_map::Values([].iter()).chain(None), "get_disr");
338
339                 let fn_ty = ty::mk_ctor_fn(ccx.tcx(), ast::DUMMY_NODE_ID,
340                                            [opaqueptrty], ty::mk_u64());
341                 let llfdecl = decl_internal_rust_fn(ccx,
342                                                     fn_ty,
343                                                     sym.as_slice());
344                 let arena = TypedArena::new();
345                 let empty_param_substs = param_substs::empty();
346                 let fcx = new_fn_ctxt(ccx, llfdecl, ast::DUMMY_NODE_ID, false,
347                                       ty::mk_u64(), &empty_param_substs,
348                                       None, &arena);
349                 let bcx = init_function(&fcx, false, ty::mk_u64());
350
351                 // we know the return type of llfdecl is an int here, so
352                 // no need for a special check to see if the return type
353                 // is immediate.
354                 let arg = get_param(llfdecl, fcx.arg_pos(0u) as c_uint);
355                 let arg = BitCast(bcx, arg, llptrty);
356                 let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx)));
357                 assert!(!fcx.needs_ret_allocas);
358                 let ret_slot = fcx.get_ret_slot(bcx, ty::mk_u64(), "ret_slot");
359                 Store(bcx, ret, ret_slot);
360                 match fcx.llreturn.get() {
361                     Some(llreturn) => Br(bcx, llreturn),
362                     None => {}
363                 };
364                 finish_fn(&fcx, bcx, ty::mk_u64());
365                 llfdecl
366             };
367
368             let enum_args = (vec!(self.c_uint(variants.len()), make_get_disr()))
369                             .append(self.c_size_and_align(t).as_slice());
370             self.bracketed("enum", enum_args.as_slice(), |this| {
371                 for (i, v) in variants.iter().enumerate() {
372                     let name = token::get_ident(v.name);
373                     let variant_args = [this.c_uint(i),
374                                          C_u64(ccx, v.disr_val),
375                                          this.c_uint(v.args.len()),
376                                          this.c_slice(name)];
377                     this.bracketed("enum_variant",
378                                    variant_args,
379                                    |this| {
380                         for (j, a) in v.args.iter().enumerate() {
381                             let bcx = this.bcx;
382                             let null = C_null(llptrty);
383                             let ptr = adt::trans_field_ptr(bcx, &*repr, null, v.disr_val, j);
384                             let offset = p2i(ccx, ptr);
385                             let field_args = [this.c_uint(j),
386                                                offset,
387                                                this.c_tydesc(*a)];
388                             this.visit("enum_variant_field",
389                                        field_args);
390                         }
391                     })
392                 }
393             })
394           }
395
396           // Miscellaneous extra types
397           ty::ty_infer(_) => self.leaf("infer"),
398           ty::ty_err => self.leaf("err"),
399           ty::ty_unboxed_closure(..) => self.leaf("err"),
400           ty::ty_param(ref p) => {
401               let extra = vec!(self.c_uint(p.idx));
402               self.visit("param", extra.as_slice())
403           }
404         }
405     }
406
407     pub fn visit_sig(&mut self, retval: uint, sig: &ty::FnSig) {
408         for (i, arg) in sig.inputs.iter().enumerate() {
409             let modeval = 5u;   // "by copy"
410             let extra = vec!(self.c_uint(i),
411                          self.c_uint(modeval),
412                          self.c_tydesc(*arg));
413             self.visit("fn_input", extra.as_slice());
414         }
415         let extra = vec!(self.c_uint(retval),
416                       self.c_bool(sig.variadic),
417                       self.c_tydesc(sig.output));
418         self.visit("fn_output", extra.as_slice());
419     }
420 }
421
422 // Emit a sequence of calls to visit_ty::visit_foo
423 pub fn emit_calls_to_trait_visit_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
424                                                 t: ty::t,
425                                                 visitor_val: ValueRef,
426                                                 visitor_trait_id: DefId)
427                                                 -> Block<'blk, 'tcx> {
428     let fcx = bcx.fcx;
429     let final = fcx.new_temp_block("final");
430     let tydesc_ty = ty::get_tydesc_ty(bcx.tcx()).unwrap();
431     let tydesc_ty = type_of(bcx.ccx(), tydesc_ty);
432     let visitor_items = ty::trait_items(bcx.tcx(), visitor_trait_id);
433     let mut r = Reflector {
434         visitor_val: visitor_val,
435         visitor_items: visitor_items.as_slice(),
436         final_bcx: final,
437         tydesc_ty: tydesc_ty,
438         bcx: bcx
439     };
440     r.visit_ty(t);
441     Br(r.bcx, final.llbb);
442     return final;
443 }
444
445 pub fn ast_fn_style_constant(fn_style: ast::FnStyle) -> uint {
446     match fn_style {
447         ast::UnsafeFn => 1u,
448         ast::NormalFn => 2u,
449     }
450 }