(index<- )        ./librustc/middle/trans/type_of.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   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_tyty::t) -> bool {
  27      !type_is_immediate(ccx, arg_ty)
  28  }
  29  
  30  pub fn return_uses_outptr(ccx: &CrateContext, tyty::t) -> bool {
  31      !type_is_immediate(ccx, ty)
  32  }
  33  
  34  pub fn type_of_explicit_arg(ccx: &CrateContext, arg_tyty::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], outputty::t) -> Type {
  45      let mut atysVec<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, ftyty::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, tty::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))
 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, tty::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)
 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)
 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                        whatnamed_ty,
 303                        didast::DefId,
 304                        tps: &[ty::t]) -> ~str {
 305      let name = match what {
 306          a_struct => { "struct}
 307          an_enum => { "enum}
 308      };
 309      let tstr = ppaux::parameterized(cx.tcx(), ty::item_path_str(cx.tcx(), did),
 310                                      &ty::NonerasedRegions(OwnedSlice::empty()),
 311                                      tps, did, false);
 312      if did.krate == 0 {
 313          format!("{}.{}", name, tstr)
 314      } else {
 315          format!("{}.{}[\\#{}]", name, tstr, did.krate)
 316      }
 317  }
 318  
 319  pub fn type_of_dtor(ccx: &CrateContext, self_tyty::t) -> Type {
 320      let self_ty = type_of(ccx, self_ty).ptr_to();
 321      Type::func([self_ty], &Type::void(ccx))
 322  }


librustc/middle/trans/type_of.rs:25:1-25:1 -fn- definition:
pub fn arg_is_indirect(ccx: &CrateContext, arg_ty: ty::t) -> bool {
    !type_is_immediate(ccx, arg_ty)
}
references:- 5
35:     let llty = type_of(ccx, arg_ty);
36:     if arg_is_indirect(ccx, arg_ty) {
37:         llty.ptr_to()
librustc/middle/trans/base.rs:
1248:     datum::Rvalue {
1249:         mode: if arg_is_indirect(cx.ccx, t) { ByRef } else { ByValue }
1250:     }
librustc/middle/trans/_match.rs:
2066:             let arg_ty = node_id_type(bcx, pat.id);
2067:             if type_of::arg_is_indirect(bcx.ccx(), arg_ty)
2068:                 && bcx.sess().opts.debuginfo != FullDebugInfo {
librustc/middle/trans/foreign.rs:
670:             let llrust_ty = *tys.llsig.llarg_tys.get(i);
671:             let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
672:             let llforeign_arg_ty = *tys.fn_ty.arg_tys.get(i);


librustc/middle/trans/type_of.rs:33:1-33:1 -fn- definition:
pub fn type_of_explicit_arg(ccx: &CrateContext, arg_ty: ty::t) -> Type {
    let llty = type_of(ccx, arg_ty);
    if arg_is_indirect(ccx, arg_ty) {
references:- 2
librustc/middle/trans/callee.rs:
898:             // this could happen due to e.g. subtyping
899:             let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
900:             debug!("casting actual type ({}) to match formal ({})",
librustc/middle/trans/type_of.rs:
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);


librustc/middle/trans/type_of.rs:166:73-166:73 -fn- definition:
// NB: If you update this, be sure to update `sizing_type_of()` as well.
pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
    // Check the cache.
references:- 93
librustc/middle/trans/base.rs:
librustc/middle/trans/_match.rs:
librustc/middle/trans/closure.rs:
librustc/middle/trans/tvec.rs:
librustc/middle/trans/meth.rs:
librustc/middle/trans/foreign.rs:
librustc/middle/trans/intrinsic.rs:
librustc/middle/trans/reflect.rs:
librustc/middle/trans/debuginfo.rs:
librustc/middle/trans/adt.rs:
librustc/middle/trans/asm.rs:
librustc/middle/trans/glue.rs:
librustc/middle/trans/datum.rs:
librustc/middle/trans/callee.rs:
librustc/middle/trans/expr.rs:
librustc/middle/trans/consts.rs:
librustc/middle/trans/debuginfo.rs:


librustc/middle/trans/type_of.rs:104:1-104:1 -fn- definition:
pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
    match cx.llsizingtypes.borrow().find_copy(&t) {
        Some(t) => return t,
references:- 9
135:         ty::ty_vec(mt, Some(size)) => {
136:             Type::array(&sizing_type_of(cx, mt.ty), size as u64)
137:         }
librustc/middle/trans/adt.rs:
298: fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool) -> Struct {
299:     let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>();
300:     let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
--
790:     for &ty in st.fields.iter() {
791:         let llty = type_of::sizing_type_of(ccx, ty);
792:         if !st.packed {
librustc/middle/trans/glue.rs:
88:                 _ => {
89:                     let llty = sizing_type_of(ccx, typ);
90:                     // Unique boxes do not allocate for zero-size types. The standard
librustc/middle/trans/common.rs:
73:         ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) => {
74:             let llty = sizing_type_of(ccx, ty);
75:             llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type)
--
87:     use middle::trans::type_of::sizing_type_of;
88:     let llty = sizing_type_of(ccx, ty);
89:     llsize_of_alloc(ccx, llty) == 0
librustc/middle/trans/consts.rs:
273:     let llty = type_of::sizing_type_of(cx, ety_adjusted);
274:     let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
librustc/middle/trans/adt.rs:
771:                     // field; see #8506.
772:                     C_null(type_of::sizing_type_of(ccx, ty))
773:                 }).collect::<Vec<ValueRef>>();


librustc/middle/trans/type_of.rs:72:74-72:74 -fn- definition:
// Given a function type and a count of ty params, construct an llvm type
pub fn type_of_fn_from_ty(cx: &CrateContext, fty: ty::t) -> Type {
    match ty::get(fty).sty {
references:- 6
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)
librustc/middle/trans/meth.rs:
213:             let callee_ty = node_id_type(bcx, expr_id);
214:             let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to();
215:             PointerCast(bcx, llfn, llty)
librustc/middle/trans/callee.rs:
444:     // other weird situations. Annoying.
445:     let llty = type_of::type_of_fn_from_ty(ccx, fn_tpt.ty);
446:     let llptrty = llty.ptr_to();
librustc/middle/trans/base.rs:
860:                     let cconv = c.unwrap_or(lib::llvm::CCallConv);
861:                     let llty = type_of_fn_from_ty(ccx, t);
862:                     get_extern_fn(&mut *ccx.externs.borrow_mut(), ccx.llmod,


librustc/middle/trans/type_of.rs:29:1-29:1 -fn- definition:
pub fn return_uses_outptr(ccx: &CrateContext, ty: ty::t) -> bool {
    !type_is_immediate(ccx, ty)
}
references:- 11
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);
librustc/middle/trans/base.rs:
245:     let uses_outptr = type_of::return_uses_outptr(ccx, output);
246:     let offset = if uses_outptr { 1 } else { 0 };
--
1117:     unsafe {
1118:         if type_of::return_uses_outptr(fcx.ccx, output_type) {
1119:             llvm::LLVMGetParam(fcx.llfn, 0)
--
1164:     };
1165:     let uses_outptr = type_of::return_uses_outptr(ccx, substd_output_type);
1166:     let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl);
librustc/middle/trans/foreign.rs:
614:         let rust_uses_outptr =
615:             type_of::return_uses_outptr(ccx, tys.fn_sig.output);
616:         let return_alloca: Option<ValueRef>;
--
824:         llret_ty: llret_ty,
825:         sret: type_of::return_uses_outptr(ccx, fn_sig.output),
826:     }
librustc/middle/trans/callee.rs:
618:         // return type, otherwise push "undef".
619:         if type_of::return_uses_outptr(ccx, ret_ty) {
620:             llargs.push(opt_llretslot.unwrap());
--
735:         None => {
736:             assert!(!type_of::return_uses_outptr(bcx.ccx(), ret_ty));
737:         }


librustc/middle/trans/type_of.rs:42:1-42:1 -fn- definition:
pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
                       inputs: &[ty::t], output: ty::t) -> Type {
    let mut atys: Vec<Type> = Vec::new();
references:- 4
75:         ty::ty_closure(ref f) => {
76:             type_of_rust_fn(cx, true, f.sig.inputs.as_slice(), f.sig.output)
77:         }
librustc/middle/trans/base.rs:
242:     let llfty = type_of_rust_fn(ccx, has_env, inputs, output);
243:     let llfn = decl_cdecl_fn(ccx.llmod, name, llfty, output);
librustc/middle/trans/meth.rs:
406:         ty::ty_bare_fn(ref f) if f.abi == Rust => {
407:             type_of_rust_fn(ccx, true, f.sig.inputs.slice_from(1), f.sig.output)
408:         }
librustc/middle/trans/type_of.rs:
79:             if f.abi == abi::Rust || f.abi == abi::RustIntrinsic {
80:                 type_of_rust_fn(cx,
81:                                 false,


librustc/middle/trans/type_of.rs:300:1-300:1 -fn- definition:
pub fn llvm_type_name(cx: &CrateContext,
                      what: named_ty,
                      did: ast::DefId,
references:- 2
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)
--
262:               let repr = adt::represent_type(cx, t);
263:               let name = llvm_type_name(cx,
264:                                         a_struct,