]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/type_of.rs
Convert most code to new inner attribute syntax.
[rust.git] / src / librustc / middle / trans / type_of.rs
1 // Copyright 2012-2013 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 #![allow(non_camel_case_types)]
12
13 use middle::trans::adt;
14 use middle::trans::common::*;
15 use middle::trans::foreign;
16 use middle::ty;
17 use util::ppaux;
18 use util::ppaux::Repr;
19
20 use middle::trans::type_::Type;
21
22 use syntax::ast;
23 use syntax::owned_slice::OwnedSlice;
24
25 pub fn arg_is_indirect(ccx: &CrateContext, arg_ty: ty::t) -> bool {
26     !type_is_immediate(ccx, arg_ty)
27 }
28
29 pub fn return_uses_outptr(ccx: &CrateContext, ty: ty::t) -> bool {
30     !type_is_immediate(ccx, ty)
31 }
32
33 pub fn type_of_explicit_arg(ccx: &CrateContext, arg_ty: ty::t) -> Type {
34     let llty = type_of(ccx, arg_ty);
35     if arg_is_indirect(ccx, arg_ty) {
36         llty.ptr_to()
37     } else {
38         llty
39     }
40 }
41
42 pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
43                        inputs: &[ty::t], output: ty::t) -> Type {
44     let mut atys: Vec<Type> = Vec::new();
45
46     // Arg 0: Output pointer.
47     // (if the output type is non-immediate)
48     let use_out_pointer = return_uses_outptr(cx, output);
49     let lloutputtype = type_of(cx, output);
50     if use_out_pointer {
51         atys.push(lloutputtype.ptr_to());
52     }
53
54     // Arg 1: Environment
55     if has_env {
56         atys.push(Type::i8p(cx));
57     }
58
59     // ... then explicit args.
60     let input_tys = inputs.iter().map(|&arg_ty| type_of_explicit_arg(cx, arg_ty));
61     atys.extend(input_tys);
62
63     // Use the output as the actual return value if it's immediate.
64     if use_out_pointer || return_type_is_void(cx, output) {
65         Type::func(atys.as_slice(), &Type::void(cx))
66     } else {
67         Type::func(atys.as_slice(), &lloutputtype)
68     }
69 }
70
71 // Given a function type and a count of ty params, construct an llvm type
72 pub fn type_of_fn_from_ty(cx: &CrateContext, fty: ty::t) -> Type {
73     match ty::get(fty).sty {
74         ty::ty_closure(ref f) => {
75             type_of_rust_fn(cx, true, f.sig.inputs.as_slice(), f.sig.output)
76         }
77         ty::ty_bare_fn(ref f) => {
78             if f.abis.is_rust() || f.abis.is_intrinsic() {
79                 type_of_rust_fn(cx,
80                                 false,
81                                 f.sig.inputs.as_slice(),
82                                 f.sig.output)
83             } else {
84                 foreign::lltype_for_foreign_fn(cx, fty)
85             }
86         }
87         _ => {
88             cx.sess().bug("type_of_fn_from_ty given non-closure, non-bare-fn")
89         }
90     }
91 }
92
93 // A "sizing type" is an LLVM type, the size and alignment of which are
94 // guaranteed to be equivalent to what you would get out of `type_of()`. It's
95 // useful because:
96 //
97 // (1) It may be cheaper to compute the sizing type than the full type if all
98 //     you're interested in is the size and/or alignment;
99 //
100 // (2) It won't make any recursive calls to determine the structure of the
101 //     type behind pointers. This can help prevent infinite loops for
102 //     recursive types. For example, enum types rely on this behavior.
103
104 pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
105     match cx.llsizingtypes.borrow().find_copy(&t) {
106         Some(t) => return t,
107         None => ()
108     }
109
110     let llsizingty = match ty::get(t).sty {
111         ty::ty_nil | ty::ty_bot => Type::nil(cx),
112         ty::ty_bool => Type::bool(cx),
113         ty::ty_char => Type::char(cx),
114         ty::ty_int(t) => Type::int_from_ty(cx, t),
115         ty::ty_uint(t) => Type::uint_from_ty(cx, t),
116         ty::ty_float(t) => Type::float_from_ty(cx, t),
117
118         ty::ty_str(ty::vstore_uniq) |
119         ty::ty_vec(_, ty::vstore_uniq) |
120         ty::ty_box(..) |
121         ty::ty_uniq(..) |
122         ty::ty_ptr(..) |
123         ty::ty_rptr(..) => Type::i8p(cx),
124
125         ty::ty_str(ty::vstore_slice(..)) |
126         ty::ty_vec(_, ty::vstore_slice(..)) => {
127             Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false)
128         }
129
130         ty::ty_bare_fn(..) => Type::i8p(cx),
131         ty::ty_closure(..) => Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false),
132         ty::ty_trait(..) => Type::opaque_trait(cx),
133
134         ty::ty_str(ty::vstore_fixed(size)) => Type::array(&Type::i8(cx), size as u64),
135         ty::ty_vec(mt, ty::vstore_fixed(size)) => {
136             Type::array(&sizing_type_of(cx, mt.ty), size as u64)
137         }
138
139         ty::ty_unboxed_vec(mt) => {
140             Type::vec(cx, &sizing_type_of(cx, mt.ty))
141         }
142
143         ty::ty_tup(..) | ty::ty_enum(..) => {
144             let repr = adt::represent_type(cx, t);
145             adt::sizing_type_of(cx, repr)
146         }
147
148         ty::ty_struct(..) => {
149             if ty::type_is_simd(cx.tcx(), t) {
150                 let et = ty::simd_type(cx.tcx(), t);
151                 let n = ty::simd_size(cx.tcx(), t);
152                 Type::vector(&type_of(cx, et), n as u64)
153             } else {
154                 let repr = adt::represent_type(cx, t);
155                 adt::sizing_type_of(cx, repr)
156             }
157         }
158
159         ty::ty_self(_) | ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => {
160             cx.sess().bug(format!("fictitious type {:?} in sizing_type_of()",
161                                   ty::get(t).sty))
162         }
163     };
164
165     cx.llsizingtypes.borrow_mut().insert(t, llsizingty);
166     llsizingty
167 }
168
169 // NB: If you update this, be sure to update `sizing_type_of()` as well.
170 pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
171     // Check the cache.
172     match cx.lltypes.borrow().find(&t) {
173         Some(&llty) => return llty,
174         None => ()
175     }
176
177     debug!("type_of {} {:?}", t.repr(cx.tcx()), t);
178
179     // Replace any typedef'd types with their equivalent non-typedef
180     // type. This ensures that all LLVM nominal types that contain
181     // Rust types are defined as the same LLVM types.  If we don't do
182     // this then, e.g. `Option<{myfield: bool}>` would be a different
183     // type than `Option<myrec>`.
184     let t_norm = ty::normalize_ty(cx.tcx(), t);
185
186     if t != t_norm {
187         let llty = type_of(cx, t_norm);
188         debug!("--> normalized {} {:?} to {} {:?} llty={}",
189                 t.repr(cx.tcx()),
190                 t,
191                 t_norm.repr(cx.tcx()),
192                 t_norm,
193                 cx.tn.type_to_str(llty));
194         cx.lltypes.borrow_mut().insert(t, llty);
195         return llty;
196     }
197
198     let mut llty = match ty::get(t).sty {
199       ty::ty_nil | ty::ty_bot => Type::nil(cx),
200       ty::ty_bool => Type::bool(cx),
201       ty::ty_char => Type::char(cx),
202       ty::ty_int(t) => Type::int_from_ty(cx, t),
203       ty::ty_uint(t) => Type::uint_from_ty(cx, t),
204       ty::ty_float(t) => Type::float_from_ty(cx, t),
205       ty::ty_str(ty::vstore_uniq) => {
206         Type::vec(cx, &Type::i8(cx)).ptr_to()
207       }
208       ty::ty_enum(did, ref substs) => {
209         // Only create the named struct, but don't fill it in. We
210         // fill it in *after* placing it into the type cache. This
211         // avoids creating more than one copy of the enum when one
212         // of the enum's variants refers to the enum itself.
213         let repr = adt::represent_type(cx, t);
214         let name = llvm_type_name(cx, an_enum, did, substs.tps.as_slice());
215         adt::incomplete_type_of(cx, repr, name)
216       }
217       ty::ty_box(typ) => {
218           Type::at_box(cx, type_of(cx, typ)).ptr_to()
219       }
220       ty::ty_uniq(typ) => {
221           type_of(cx, typ).ptr_to()
222       }
223       ty::ty_vec(ref mt, ty::vstore_uniq) => {
224           Type::vec(cx, &type_of(cx, mt.ty)).ptr_to()
225       }
226       ty::ty_unboxed_vec(ref mt) => {
227           Type::vec(cx, &type_of(cx, mt.ty))
228       }
229       ty::ty_ptr(ref mt) => type_of(cx, mt.ty).ptr_to(),
230       ty::ty_rptr(_, ref mt) => type_of(cx, mt.ty).ptr_to(),
231
232       ty::ty_vec(ref mt, ty::vstore_slice(_)) => {
233           let p_ty = type_of(cx, mt.ty).ptr_to();
234           let u_ty = Type::uint_from_ty(cx, ast::TyU);
235           Type::struct_(cx, [p_ty, u_ty], false)
236       }
237
238       ty::ty_str(ty::vstore_slice(_)) => {
239           // This means we get a nicer name in the output
240           cx.tn.find_type("str_slice").unwrap()
241       }
242
243       ty::ty_str(ty::vstore_fixed(n)) => {
244           Type::array(&Type::i8(cx), (n + 1u) as u64)
245       }
246
247       ty::ty_vec(ref mt, ty::vstore_fixed(n)) => {
248           Type::array(&type_of(cx, mt.ty), n as u64)
249       }
250
251       ty::ty_bare_fn(_) => {
252           type_of_fn_from_ty(cx, t).ptr_to()
253       }
254       ty::ty_closure(_) => {
255           let fn_ty = type_of_fn_from_ty(cx, t).ptr_to();
256           Type::struct_(cx, [fn_ty, Type::i8p(cx)], false)
257       }
258       ty::ty_trait(..) => Type::opaque_trait(cx),
259       ty::ty_tup(..) => {
260           let repr = adt::represent_type(cx, t);
261           adt::type_of(cx, repr)
262       }
263       ty::ty_struct(did, ref substs) => {
264           if ty::type_is_simd(cx.tcx(), t) {
265               let et = ty::simd_type(cx.tcx(), t);
266               let n = ty::simd_size(cx.tcx(), t);
267               Type::vector(&type_of(cx, et), n as u64)
268           } else {
269               // Only create the named struct, but don't fill it in. We fill it
270               // in *after* placing it into the type cache. This prevents
271               // infinite recursion with recursive struct types.
272               let repr = adt::represent_type(cx, t);
273               let name = llvm_type_name(cx,
274                                         a_struct,
275                                         did,
276                                         substs.tps.as_slice());
277               adt::incomplete_type_of(cx, repr, name)
278           }
279       }
280       ty::ty_self(..) => cx.sess().unimpl("type_of: ty_self"),
281       ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"),
282       ty::ty_param(..) => cx.sess().bug("type_of with ty_param"),
283       ty::ty_err(..) => cx.sess().bug("type_of with ty_err")
284     };
285
286     debug!("--> mapped t={} {:?} to llty={}",
287             t.repr(cx.tcx()),
288             t,
289             cx.tn.type_to_str(llty));
290
291     cx.lltypes.borrow_mut().insert(t, llty);
292
293     // If this was an enum or struct, fill in the type now.
294     match ty::get(t).sty {
295         ty::ty_enum(..) | ty::ty_struct(..) if !ty::type_is_simd(cx.tcx(), t) => {
296             let repr = adt::represent_type(cx, t);
297             adt::finish_type_of(cx, repr, &mut llty);
298         }
299         _ => ()
300     }
301
302     return llty;
303 }
304
305 // Want refinements! (Or case classes, I guess
306 pub enum named_ty { a_struct, an_enum }
307
308 pub fn llvm_type_name(cx: &CrateContext,
309                       what: named_ty,
310                       did: ast::DefId,
311                       tps: &[ty::t]) -> ~str {
312     let name = match what {
313         a_struct => { "struct" }
314         an_enum => { "enum" }
315     };
316     let tstr = ppaux::parameterized(cx.tcx(), ty::item_path_str(cx.tcx(), did),
317                                     &ty::NonerasedRegions(OwnedSlice::empty()),
318                                     tps, did, false);
319     if did.krate == 0 {
320         format!("{}.{}", name, tstr)
321     } else {
322         format!("{}.{}[\\#{}]", name, tstr, did.krate)
323     }
324 }
325
326 pub fn type_of_dtor(ccx: &CrateContext, self_ty: ty::t) -> Type {
327     let self_ty = type_of(ccx, self_ty).ptr_to();
328     Type::func([self_ty], &Type::void(ccx))
329 }