]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/common.rs
auto merge of #15374 : steveklabnik/rust/comments, r=brson
[rust.git] / src / librustc / middle / trans / common.rs
1 // Copyright 2012-2014 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, non_snake_case_functions)]
12
13 //! Code that is useful in various trans modules.
14
15 use driver::session::Session;
16 use lib::llvm::{ValueRef, BasicBlockRef, BuilderRef};
17 use lib::llvm::{True, False, Bool};
18 use lib::llvm::llvm;
19 use lib;
20 use middle::def;
21 use middle::lang_items::LangItem;
22 use middle::subst;
23 use middle::subst::Subst;
24 use middle::trans::build;
25 use middle::trans::cleanup;
26 use middle::trans::datum;
27 use middle::trans::debuginfo;
28 use middle::trans::type_::Type;
29 use middle::ty;
30 use middle::typeck;
31 use util::ppaux::Repr;
32 use util::nodemap::NodeMap;
33
34 use arena::TypedArena;
35 use std::collections::HashMap;
36 use libc::{c_uint, c_longlong, c_ulonglong, c_char};
37 use std::c_str::ToCStr;
38 use std::cell::{Cell, RefCell};
39 use std::vec::Vec;
40 use syntax::ast::Ident;
41 use syntax::ast;
42 use syntax::ast_map::{PathElem, PathName};
43 use syntax::codemap::Span;
44 use syntax::parse::token::InternedString;
45 use syntax::parse::token;
46
47 pub use middle::trans::context::CrateContext;
48
49 fn type_is_newtype_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
50     match ty::get(ty).sty {
51         ty::ty_struct(def_id, ref substs) => {
52             let fields = ty::struct_fields(ccx.tcx(), def_id, substs);
53             fields.len() == 1 &&
54                 fields.get(0).ident.name ==
55                     token::special_idents::unnamed_field.name &&
56                 type_is_immediate(ccx, fields.get(0).mt.ty)
57         }
58         _ => false
59     }
60 }
61
62 pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
63     use middle::trans::machine::llsize_of_alloc;
64     use middle::trans::type_of::sizing_type_of;
65     let tcx = ccx.tcx();
66     let simple = ty::type_is_scalar(ty) || ty::type_is_boxed(ty) ||
67         ty::type_is_unique(ty) || ty::type_is_region_ptr(ty) ||
68         type_is_newtype_immediate(ccx, ty) || ty::type_is_bot(ty) ||
69         ty::type_is_simd(tcx, ty);
70     if simple && !ty::type_is_trait(ty) {
71         return true;
72     }
73     match ty::get(ty).sty {
74         ty::ty_bot => true,
75         ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) => {
76             let llty = sizing_type_of(ccx, ty);
77             llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type)
78         }
79         _ => type_is_zero_size(ccx, ty)
80     }
81 }
82
83 pub fn type_is_zero_size(ccx: &CrateContext, ty: ty::t) -> bool {
84     /*!
85      * Identify types which have size zero at runtime.
86      */
87
88     use middle::trans::machine::llsize_of_alloc;
89     use middle::trans::type_of::sizing_type_of;
90     let llty = sizing_type_of(ccx, ty);
91     llsize_of_alloc(ccx, llty) == 0
92 }
93
94 pub fn return_type_is_void(ccx: &CrateContext, ty: ty::t) -> bool {
95     /*!
96      * Identifies types which we declare to be equivalent to `void`
97      * in C for the purpose of function return types. These are
98      * `()`, bot, and uninhabited enums. Note that all such types
99      * are also zero-size, but not all zero-size types use a `void`
100      * return type (in order to aid with C ABI compatibility).
101      */
102
103     ty::type_is_nil(ty) || ty::type_is_bot(ty) || ty::type_is_empty(ccx.tcx(), ty)
104 }
105
106 /// Generates a unique symbol based off the name given. This is used to create
107 /// unique symbols for things like closures.
108 pub fn gensym_name(name: &str) -> PathElem {
109     let num = token::gensym(name);
110     // use one colon which will get translated to a period by the mangler, and
111     // we're guaranteed that `num` is globally unique for this crate.
112     PathName(token::gensym(format!("{}:{}", name, num).as_slice()))
113 }
114
115 pub struct tydesc_info {
116     pub ty: ty::t,
117     pub tydesc: ValueRef,
118     pub size: ValueRef,
119     pub align: ValueRef,
120     pub name: ValueRef,
121     pub visit_glue: Cell<Option<ValueRef>>,
122 }
123
124 /*
125  * A note on nomenclature of linking: "extern", "foreign", and "upcall".
126  *
127  * An "extern" is an LLVM symbol we wind up emitting an undefined external
128  * reference to. This means "we don't have the thing in this compilation unit,
129  * please make sure you link it in at runtime". This could be a reference to
130  * C code found in a C library, or rust code found in a rust crate.
131  *
132  * Most "externs" are implicitly declared (automatically) as a result of a
133  * user declaring an extern _module_ dependency; this causes the rust driver
134  * to locate an extern crate, scan its compilation metadata, and emit extern
135  * declarations for any symbols used by the declaring crate.
136  *
137  * A "foreign" is an extern that references C (or other non-rust ABI) code.
138  * There is no metadata to scan for extern references so in these cases either
139  * a header-digester like bindgen, or manual function prototypes, have to
140  * serve as declarators. So these are usually given explicitly as prototype
141  * declarations, in rust code, with ABI attributes on them noting which ABI to
142  * link via.
143  *
144  * An "upcall" is a foreign call generated by the compiler (not corresponding
145  * to any user-written call in the code) into the runtime library, to perform
146  * some helper task such as bringing a task to life, allocating memory, etc.
147  *
148  */
149
150 pub struct NodeInfo {
151     pub id: ast::NodeId,
152     pub span: Span,
153 }
154
155 pub fn expr_info(expr: &ast::Expr) -> NodeInfo {
156     NodeInfo { id: expr.id, span: expr.span }
157 }
158
159 pub struct BuilderRef_res {
160     pub b: BuilderRef,
161 }
162
163 impl Drop for BuilderRef_res {
164     fn drop(&mut self) {
165         unsafe {
166             llvm::LLVMDisposeBuilder(self.b);
167         }
168     }
169 }
170
171 pub fn BuilderRef_res(b: BuilderRef) -> BuilderRef_res {
172     BuilderRef_res {
173         b: b
174     }
175 }
176
177 pub type ExternMap = HashMap<String, ValueRef>;
178
179 // Here `self_ty` is the real type of the self parameter to this method. It
180 // will only be set in the case of default methods.
181 pub struct param_substs {
182     pub substs: subst::Substs,
183     pub vtables: typeck::vtable_res,
184 }
185
186 impl param_substs {
187     pub fn empty() -> param_substs {
188         param_substs {
189             substs: subst::Substs::trans_empty(),
190             vtables: subst::VecPerParamSpace::empty(),
191         }
192     }
193
194     pub fn validate(&self) {
195         assert!(self.substs.types.all(|t| !ty::type_needs_infer(*t)));
196     }
197 }
198
199 fn param_substs_to_string(this: &param_substs, tcx: &ty::ctxt) -> String {
200     format!("param_substs({})", this.substs.repr(tcx))
201 }
202
203 impl Repr for param_substs {
204     fn repr(&self, tcx: &ty::ctxt) -> String {
205         param_substs_to_string(self, tcx)
206     }
207 }
208
209 pub trait SubstP {
210     fn substp(&self, tcx: &ty::ctxt, param_substs: &param_substs)
211               -> Self;
212 }
213
214 impl<T:Subst+Clone> SubstP for T {
215     fn substp(&self, tcx: &ty::ctxt, substs: &param_substs) -> T {
216         self.subst(tcx, &substs.substs)
217     }
218 }
219
220 // work around bizarre resolve errors
221 pub type RvalueDatum = datum::Datum<datum::Rvalue>;
222 pub type LvalueDatum = datum::Datum<datum::Lvalue>;
223
224 // Function context.  Every LLVM function we create will have one of
225 // these.
226 pub struct FunctionContext<'a> {
227     // The ValueRef returned from a call to llvm::LLVMAddFunction; the
228     // address of the first instruction in the sequence of
229     // instructions for this function that will go in the .text
230     // section of the executable we're generating.
231     pub llfn: ValueRef,
232
233     // The environment argument in a closure.
234     pub llenv: Option<ValueRef>,
235
236     // The place to store the return value. If the return type is immediate,
237     // this is an alloca in the function. Otherwise, it's the hidden first
238     // parameter to the function. After function construction, this should
239     // always be Some.
240     pub llretptr: Cell<Option<ValueRef>>,
241
242     // These pub elements: "hoisted basic blocks" containing
243     // administrative activities that have to happen in only one place in
244     // the function, due to LLVM's quirks.
245     // A marker for the place where we want to insert the function's static
246     // allocas, so that LLVM will coalesce them into a single alloca call.
247     pub alloca_insert_pt: Cell<Option<ValueRef>>,
248     pub llreturn: Cell<Option<BasicBlockRef>>,
249
250     // The a value alloca'd for calls to upcalls.rust_personality. Used when
251     // outputting the resume instruction.
252     pub personality: Cell<Option<ValueRef>>,
253
254     // True if the caller expects this fn to use the out pointer to
255     // return. Either way, your code should write into llretptr, but if
256     // this value is false, llretptr will be a local alloca.
257     pub caller_expects_out_pointer: bool,
258
259     // Maps arguments to allocas created for them in llallocas.
260     pub llargs: RefCell<NodeMap<LvalueDatum>>,
261
262     // Maps the def_ids for local variables to the allocas created for
263     // them in llallocas.
264     pub lllocals: RefCell<NodeMap<LvalueDatum>>,
265
266     // Same as above, but for closure upvars
267     pub llupvars: RefCell<NodeMap<ValueRef>>,
268
269     // The NodeId of the function, or -1 if it doesn't correspond to
270     // a user-defined function.
271     pub id: ast::NodeId,
272
273     // If this function is being monomorphized, this contains the type
274     // substitutions used.
275     pub param_substs: &'a param_substs,
276
277     // The source span and nesting context where this function comes from, for
278     // error reporting and symbol generation.
279     pub span: Option<Span>,
280
281     // The arena that blocks are allocated from.
282     pub block_arena: &'a TypedArena<Block<'a>>,
283
284     // This function's enclosing crate context.
285     pub ccx: &'a CrateContext,
286
287     // Used and maintained by the debuginfo module.
288     pub debug_context: debuginfo::FunctionDebugContext,
289
290     // Cleanup scopes.
291     pub scopes: RefCell<Vec<cleanup::CleanupScope<'a>> >,
292 }
293
294 impl<'a> FunctionContext<'a> {
295     pub fn arg_pos(&self, arg: uint) -> uint {
296         let arg = self.env_arg_pos() + arg;
297         if self.llenv.is_some() {
298             arg + 1
299         } else {
300             arg
301         }
302     }
303
304     pub fn out_arg_pos(&self) -> uint {
305         assert!(self.caller_expects_out_pointer);
306         0u
307     }
308
309     pub fn env_arg_pos(&self) -> uint {
310         if self.caller_expects_out_pointer {
311             1u
312         } else {
313             0u
314         }
315     }
316
317     pub fn cleanup(&self) {
318         unsafe {
319             llvm::LLVMInstructionEraseFromParent(self.alloca_insert_pt
320                                                      .get()
321                                                      .unwrap());
322         }
323     }
324
325     pub fn get_llreturn(&self) -> BasicBlockRef {
326         if self.llreturn.get().is_none() {
327
328             self.llreturn.set(Some(unsafe {
329                 "return".with_c_str(|buf| {
330                     llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx, self.llfn, buf)
331                 })
332             }))
333         }
334
335         self.llreturn.get().unwrap()
336     }
337
338     pub fn new_block(&'a self,
339                      is_lpad: bool,
340                      name: &str,
341                      opt_node_id: Option<ast::NodeId>)
342                      -> &'a Block<'a> {
343         unsafe {
344             let llbb = name.with_c_str(|buf| {
345                     llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx,
346                                                         self.llfn,
347                                                         buf)
348                 });
349             Block::new(llbb, is_lpad, opt_node_id, self)
350         }
351     }
352
353     pub fn new_id_block(&'a self,
354                         name: &str,
355                         node_id: ast::NodeId)
356                         -> &'a Block<'a> {
357         self.new_block(false, name, Some(node_id))
358     }
359
360     pub fn new_temp_block(&'a self,
361                           name: &str)
362                           -> &'a Block<'a> {
363         self.new_block(false, name, None)
364     }
365
366     pub fn join_blocks(&'a self,
367                        id: ast::NodeId,
368                        in_cxs: &[&'a Block<'a>])
369                        -> &'a Block<'a> {
370         let out = self.new_id_block("join", id);
371         let mut reachable = false;
372         for bcx in in_cxs.iter() {
373             if !bcx.unreachable.get() {
374                 build::Br(*bcx, out.llbb);
375                 reachable = true;
376             }
377         }
378         if !reachable {
379             build::Unreachable(out);
380         }
381         return out;
382     }
383 }
384
385 // Basic block context.  We create a block context for each basic block
386 // (single-entry, single-exit sequence of instructions) we generate from Rust
387 // code.  Each basic block we generate is attached to a function, typically
388 // with many basic blocks per function.  All the basic blocks attached to a
389 // function are organized as a directed graph.
390 pub struct Block<'a> {
391     // The BasicBlockRef returned from a call to
392     // llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic
393     // block to the function pointed to by llfn.  We insert
394     // instructions into that block by way of this block context.
395     // The block pointing to this one in the function's digraph.
396     pub llbb: BasicBlockRef,
397     pub terminated: Cell<bool>,
398     pub unreachable: Cell<bool>,
399
400     // Is this block part of a landing pad?
401     pub is_lpad: bool,
402
403     // AST node-id associated with this block, if any. Used for
404     // debugging purposes only.
405     pub opt_node_id: Option<ast::NodeId>,
406
407     // The function context for the function to which this block is
408     // attached.
409     pub fcx: &'a FunctionContext<'a>,
410 }
411
412 impl<'a> Block<'a> {
413     pub fn new<'a>(
414                llbb: BasicBlockRef,
415                is_lpad: bool,
416                opt_node_id: Option<ast::NodeId>,
417                fcx: &'a FunctionContext<'a>)
418                -> &'a Block<'a> {
419         fcx.block_arena.alloc(Block {
420             llbb: llbb,
421             terminated: Cell::new(false),
422             unreachable: Cell::new(false),
423             is_lpad: is_lpad,
424             opt_node_id: opt_node_id,
425             fcx: fcx
426         })
427     }
428
429     pub fn ccx(&self) -> &'a CrateContext { self.fcx.ccx }
430     pub fn tcx(&self) -> &'a ty::ctxt {
431         &self.fcx.ccx.tcx
432     }
433     pub fn sess(&self) -> &'a Session { self.fcx.ccx.sess() }
434
435     pub fn ident(&self, ident: Ident) -> String {
436         token::get_ident(ident).get().to_string()
437     }
438
439     pub fn node_id_to_string(&self, id: ast::NodeId) -> String {
440         self.tcx().map.node_to_string(id).to_string()
441     }
442
443     pub fn expr_to_string(&self, e: &ast::Expr) -> String {
444         e.repr(self.tcx())
445     }
446
447     pub fn def(&self, nid: ast::NodeId) -> def::Def {
448         match self.tcx().def_map.borrow().find(&nid) {
449             Some(&v) => v,
450             None => {
451                 self.tcx().sess.bug(format!(
452                     "no def associated with node id {:?}", nid).as_slice());
453             }
454         }
455     }
456
457     pub fn val_to_string(&self, val: ValueRef) -> String {
458         self.ccx().tn.val_to_string(val)
459     }
460
461     pub fn llty_str(&self, ty: Type) -> String {
462         self.ccx().tn.type_to_string(ty)
463     }
464
465     pub fn ty_to_string(&self, t: ty::t) -> String {
466         t.repr(self.tcx())
467     }
468
469     pub fn to_str(&self) -> String {
470         let blk: *const Block = self;
471         format!("[block {}]", blk)
472     }
473 }
474
475 pub struct Result<'a> {
476     pub bcx: &'a Block<'a>,
477     pub val: ValueRef
478 }
479
480 impl<'a> Result<'a> {
481     pub fn new(bcx: &'a Block<'a>, val: ValueRef) -> Result<'a> {
482         Result {
483             bcx: bcx,
484             val: val,
485         }
486     }
487 }
488
489 pub fn val_ty(v: ValueRef) -> Type {
490     unsafe {
491         Type::from_ref(llvm::LLVMTypeOf(v))
492     }
493 }
494
495 // LLVM constant constructors.
496 pub fn C_null(t: Type) -> ValueRef {
497     unsafe {
498         llvm::LLVMConstNull(t.to_ref())
499     }
500 }
501
502 pub fn C_undef(t: Type) -> ValueRef {
503     unsafe {
504         llvm::LLVMGetUndef(t.to_ref())
505     }
506 }
507
508 pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef {
509     unsafe {
510         llvm::LLVMConstInt(t.to_ref(), u, sign_extend as Bool)
511     }
512 }
513
514 pub fn C_floating(s: &str, t: Type) -> ValueRef {
515     unsafe {
516         s.with_c_str(|buf| llvm::LLVMConstRealOfString(t.to_ref(), buf))
517     }
518 }
519
520 pub fn C_nil(ccx: &CrateContext) -> ValueRef {
521     C_struct(ccx, [], false)
522 }
523
524 pub fn C_bool(ccx: &CrateContext, val: bool) -> ValueRef {
525     C_integral(Type::i1(ccx), val as u64, false)
526 }
527
528 pub fn C_i32(ccx: &CrateContext, i: i32) -> ValueRef {
529     C_integral(Type::i32(ccx), i as u64, true)
530 }
531
532 pub fn C_i64(ccx: &CrateContext, i: i64) -> ValueRef {
533     C_integral(Type::i64(ccx), i as u64, true)
534 }
535
536 pub fn C_u64(ccx: &CrateContext, i: u64) -> ValueRef {
537     C_integral(Type::i64(ccx), i, false)
538 }
539
540 pub fn C_int(ccx: &CrateContext, i: int) -> ValueRef {
541     C_integral(ccx.int_type, i as u64, true)
542 }
543
544 pub fn C_uint(ccx: &CrateContext, i: uint) -> ValueRef {
545     C_integral(ccx.int_type, i as u64, false)
546 }
547
548 pub fn C_u8(ccx: &CrateContext, i: uint) -> ValueRef {
549     C_integral(Type::i8(ccx), i as u64, false)
550 }
551
552
553 // This is a 'c-like' raw string, which differs from
554 // our boxed-and-length-annotated strings.
555 pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> ValueRef {
556     unsafe {
557         match cx.const_cstr_cache.borrow().find(&s) {
558             Some(&llval) => return llval,
559             None => ()
560         }
561
562         let sc = llvm::LLVMConstStringInContext(cx.llcx,
563                                                 s.get().as_ptr() as *const c_char,
564                                                 s.get().len() as c_uint,
565                                                 !null_terminated as Bool);
566
567         let gsym = token::gensym("str");
568         let g = format!("str{}", gsym).with_c_str(|buf| {
569             llvm::LLVMAddGlobal(cx.llmod, val_ty(sc).to_ref(), buf)
570         });
571         llvm::LLVMSetInitializer(g, sc);
572         llvm::LLVMSetGlobalConstant(g, True);
573         lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage);
574
575         cx.const_cstr_cache.borrow_mut().insert(s, g);
576         g
577     }
578 }
579
580 // NB: Do not use `do_spill_noroot` to make this into a constant string, or
581 // you will be kicked off fast isel. See issue #4352 for an example of this.
582 pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef {
583     unsafe {
584         let len = s.get().len();
585         let cs = llvm::LLVMConstPointerCast(C_cstr(cx, s, false),
586                                             Type::i8p(cx).to_ref());
587         C_named_struct(cx.tn.find_type("str_slice").unwrap(), [cs, C_uint(cx, len)])
588     }
589 }
590
591 pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef {
592     unsafe {
593         let len = data.len();
594         let lldata = C_bytes(cx, data);
595
596         let gsym = token::gensym("binary");
597         let g = format!("binary{}", gsym).with_c_str(|buf| {
598             llvm::LLVMAddGlobal(cx.llmod, val_ty(lldata).to_ref(), buf)
599         });
600         llvm::LLVMSetInitializer(g, lldata);
601         llvm::LLVMSetGlobalConstant(g, True);
602         lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage);
603
604         let cs = llvm::LLVMConstPointerCast(g, Type::i8p(cx).to_ref());
605         C_struct(cx, [cs, C_uint(cx, len)], false)
606     }
607 }
608
609 pub fn C_struct(ccx: &CrateContext, elts: &[ValueRef], packed: bool) -> ValueRef {
610     unsafe {
611         llvm::LLVMConstStructInContext(ccx.llcx,
612                                        elts.as_ptr(), elts.len() as c_uint,
613                                        packed as Bool)
614     }
615 }
616
617 pub fn C_named_struct(t: Type, elts: &[ValueRef]) -> ValueRef {
618     unsafe {
619         llvm::LLVMConstNamedStruct(t.to_ref(), elts.as_ptr(), elts.len() as c_uint)
620     }
621 }
622
623 pub fn C_array(ty: Type, elts: &[ValueRef]) -> ValueRef {
624     unsafe {
625         return llvm::LLVMConstArray(ty.to_ref(), elts.as_ptr(), elts.len() as c_uint);
626     }
627 }
628
629 pub fn C_bytes(ccx: &CrateContext, bytes: &[u8]) -> ValueRef {
630     unsafe {
631         let ptr = bytes.as_ptr() as *const c_char;
632         return llvm::LLVMConstStringInContext(ccx.llcx, ptr, bytes.len() as c_uint, True);
633     }
634 }
635
636 pub fn get_param(fndecl: ValueRef, param: uint) -> ValueRef {
637     unsafe {
638         llvm::LLVMGetParam(fndecl, param as c_uint)
639     }
640 }
641
642 pub fn const_get_elt(cx: &CrateContext, v: ValueRef, us: &[c_uint])
643                   -> ValueRef {
644     unsafe {
645         let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint);
646
647         debug!("const_get_elt(v={}, us={:?}, r={})",
648                cx.tn.val_to_string(v), us, cx.tn.val_to_string(r));
649
650         return r;
651     }
652 }
653
654 pub fn is_const(v: ValueRef) -> bool {
655     unsafe {
656         llvm::LLVMIsConstant(v) == True
657     }
658 }
659
660 pub fn const_to_int(v: ValueRef) -> c_longlong {
661     unsafe {
662         llvm::LLVMConstIntGetSExtValue(v)
663     }
664 }
665
666 pub fn const_to_uint(v: ValueRef) -> c_ulonglong {
667     unsafe {
668         llvm::LLVMConstIntGetZExtValue(v)
669     }
670 }
671
672 pub fn is_undef(val: ValueRef) -> bool {
673     unsafe {
674         llvm::LLVMIsUndef(val) != False
675     }
676 }
677
678 pub fn is_null(val: ValueRef) -> bool {
679     unsafe {
680         llvm::LLVMIsNull(val) != False
681     }
682 }
683
684 pub fn monomorphize_type(bcx: &Block, t: ty::t) -> ty::t {
685     t.subst(bcx.tcx(), &bcx.fcx.param_substs.substs)
686 }
687
688 pub fn node_id_type(bcx: &Block, id: ast::NodeId) -> ty::t {
689     let tcx = bcx.tcx();
690     let t = ty::node_id_to_type(tcx, id);
691     monomorphize_type(bcx, t)
692 }
693
694 pub fn expr_ty(bcx: &Block, ex: &ast::Expr) -> ty::t {
695     node_id_type(bcx, ex.id)
696 }
697
698 pub fn expr_ty_adjusted(bcx: &Block, ex: &ast::Expr) -> ty::t {
699     monomorphize_type(bcx, ty::expr_ty_adjusted(bcx.tcx(), ex))
700 }
701
702 // Key used to lookup values supplied for type parameters in an expr.
703 #[deriving(PartialEq)]
704 pub enum ExprOrMethodCall {
705     // Type parameters for a path like `None::<int>`
706     ExprId(ast::NodeId),
707
708     // Type parameters for a method call like `a.foo::<int>()`
709     MethodCall(typeck::MethodCall)
710 }
711
712 pub fn node_id_substs(bcx: &Block,
713                       node: ExprOrMethodCall)
714                       -> subst::Substs {
715     let tcx = bcx.tcx();
716
717     let substs = match node {
718         ExprId(id) => {
719             ty::node_id_item_substs(tcx, id).substs
720         }
721         MethodCall(method_call) => {
722             tcx.method_map.borrow().get(&method_call).substs.clone()
723         }
724     };
725
726     if substs.types.any(|t| ty::type_needs_infer(*t)) {
727         bcx.sess().bug(
728             format!("type parameters for node {:?} include inference types: \
729                      {}",
730                     node,
731                     substs.repr(bcx.tcx())).as_slice());
732     }
733
734     substs.substp(tcx, bcx.fcx.param_substs)
735 }
736
737 pub fn node_vtables(bcx: &Block, id: typeck::MethodCall)
738                  -> typeck::vtable_res {
739     bcx.tcx().vtable_map.borrow().find(&id).map(|vts| {
740         resolve_vtables_in_fn_ctxt(bcx.fcx, vts)
741     }).unwrap_or_else(|| subst::VecPerParamSpace::empty())
742 }
743
744 // Apply the typaram substitutions in the FunctionContext to some
745 // vtables. This should eliminate any vtable_params.
746 pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext,
747                                   vts: &typeck::vtable_res)
748                                   -> typeck::vtable_res {
749     resolve_vtables_under_param_substs(fcx.ccx.tcx(),
750                                        fcx.param_substs,
751                                        vts)
752 }
753
754 pub fn resolve_vtables_under_param_substs(tcx: &ty::ctxt,
755                                           param_substs: &param_substs,
756                                           vts: &typeck::vtable_res)
757                                           -> typeck::vtable_res
758 {
759     vts.map(|ds| {
760         resolve_param_vtables_under_param_substs(tcx,
761                                                  param_substs,
762                                                  ds)
763     })
764 }
765
766 pub fn resolve_param_vtables_under_param_substs(tcx: &ty::ctxt,
767                                                 param_substs: &param_substs,
768                                                 ds: &typeck::vtable_param_res)
769                                                 -> typeck::vtable_param_res
770 {
771     ds.iter().map(|d| {
772         resolve_vtable_under_param_substs(tcx,
773                                           param_substs,
774                                           d)
775     }).collect()
776 }
777
778
779
780 pub fn resolve_vtable_under_param_substs(tcx: &ty::ctxt,
781                                          param_substs: &param_substs,
782                                          vt: &typeck::vtable_origin)
783                                          -> typeck::vtable_origin
784 {
785     match *vt {
786         typeck::vtable_static(trait_id, ref vtable_substs, ref sub) => {
787             let vtable_substs = vtable_substs.substp(tcx, param_substs);
788             typeck::vtable_static(
789                 trait_id,
790                 vtable_substs,
791                 resolve_vtables_under_param_substs(tcx, param_substs, sub))
792         }
793         typeck::vtable_param(n_param, n_bound) => {
794             find_vtable(tcx, param_substs, n_param, n_bound)
795         }
796         typeck::vtable_error => typeck::vtable_error
797     }
798 }
799
800 pub fn find_vtable(tcx: &ty::ctxt,
801                    ps: &param_substs,
802                    n_param: typeck::param_index,
803                    n_bound: uint)
804                    -> typeck::vtable_origin {
805     debug!("find_vtable(n_param={:?}, n_bound={}, ps={})",
806            n_param, n_bound, ps.repr(tcx));
807
808     let param_bounds = ps.vtables.get(n_param.space,
809                                       n_param.index);
810     param_bounds.get(n_bound).clone()
811 }
812
813 pub fn langcall(bcx: &Block,
814                 span: Option<Span>,
815                 msg: &str,
816                 li: LangItem)
817                 -> ast::DefId {
818     match bcx.tcx().lang_items.require(li) {
819         Ok(id) => id,
820         Err(s) => {
821             let msg = format!("{} {}", msg, s);
822             match span {
823                 Some(span) => bcx.tcx().sess.span_fatal(span, msg.as_slice()),
824                 None => bcx.tcx().sess.fatal(msg.as_slice()),
825             }
826         }
827     }
828 }