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