]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/check/mod.rs
Register new snapshots
[rust.git] / src / librustc / middle / typeck / check / mod.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 /*
12
13 # check.rs
14
15 Within the check phase of type check, we check each item one at a time
16 (bodies of function expressions are checked as part of the containing
17 function).  Inference is used to supply types wherever they are
18 unknown.
19
20 By far the most complex case is checking the body of a function. This
21 can be broken down into several distinct phases:
22
23 - gather: creates type variables to represent the type of each local
24   variable and pattern binding.
25
26 - main: the main pass does the lion's share of the work: it
27   determines the types of all expressions, resolves
28   methods, checks for most invalid conditions, and so forth.  In
29   some cases, where a type is unknown, it may create a type or region
30   variable and use that as the type of an expression.
31
32   In the process of checking, various constraints will be placed on
33   these type variables through the subtyping relationships requested
34   through the `demand` module.  The `typeck::infer` module is in charge
35   of resolving those constraints.
36
37 - regionck: after main is complete, the regionck pass goes over all
38   types looking for regions and making sure that they did not escape
39   into places they are not in scope.  This may also influence the
40   final assignments of the various region variables if there is some
41   flexibility.
42
43 - vtable: find and records the impls to use for each trait bound that
44   appears on a type parameter.
45
46 - writeback: writes the final types within a function body, replacing
47   type variables with their final inferred types.  These final types
48   are written into the `tcx.node_types` table, which should *never* contain
49   any reference to a type variable.
50
51 ## Intermediate types
52
53 While type checking a function, the intermediate types for the
54 expressions, blocks, and so forth contained within the function are
55 stored in `fcx.node_types` and `fcx.node_type_substs`.  These types
56 may contain unresolved type variables.  After type checking is
57 complete, the functions in the writeback module are used to take the
58 types from this table, resolve them, and then write them into their
59 permanent home in the type context `ccx.tcx`.
60
61 This means that during inferencing you should use `fcx.write_ty()`
62 and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of
63 nodes within the function.
64
65 The types of top-level items, which never contain unbound type
66 variables, are stored directly into the `tcx` tables.
67
68 n.b.: A type variable is not the same thing as a type parameter.  A
69 type variable is rather an "instance" of a type parameter: that is,
70 given a generic function `fn foo<T>(t: T)`: while checking the
71 function `foo`, the type `ty_param(0)` refers to the type `T`, which
72 is treated in abstract.  When `foo()` is called, however, `T` will be
73 substituted for a fresh type variable `N`.  This variable will
74 eventually be resolved to some concrete type (which might itself be
75 type parameter).
76
77 */
78
79
80 use middle::const_eval;
81 use middle::lang_items::{ExchangeHeapLangItem, GcLangItem};
82 use middle::lang_items::{ManagedHeapLangItem};
83 use middle::lint::UnreachableCode;
84 use middle::pat_util::pat_id_map;
85 use middle::pat_util;
86 use middle::subst::Subst;
87 use middle::ty::{FnSig, VariantInfo};
88 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
89 use middle::ty::{substs, param_ty, Disr, ExprTyProvider};
90 use middle::ty;
91 use middle::ty_fold::TypeFolder;
92 use middle::typeck::astconv::AstConv;
93 use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
94 use middle::typeck::astconv;
95 use middle::typeck::check::_match::pat_ctxt;
96 use middle::typeck::check::method::{AutoderefReceiver};
97 use middle::typeck::check::method::{AutoderefReceiverFlag};
98 use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
99 use middle::typeck::check::method::{DontAutoderefReceiver};
100 use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
101 use middle::typeck::check::regionmanip::relate_free_regions;
102 use middle::typeck::check::vtable::VtableContext;
103 use middle::typeck::CrateCtxt;
104 use middle::typeck::infer::{resolve_type, force_tvar};
105 use middle::typeck::infer;
106 use middle::typeck::rscope::RegionScope;
107 use middle::typeck::{lookup_def_ccx};
108 use middle::typeck::no_params;
109 use middle::typeck::{require_same_types, vtable_map};
110 use middle::typeck::{MethodCall, MethodMap};
111 use middle::lang_items::TypeIdLangItem;
112 use util::common::{block_query, indenter, loop_query};
113 use util::ppaux;
114 use util::ppaux::{UserString, Repr};
115 use util::nodemap::{FnvHashMap, NodeMap};
116
117 use std::cell::{Cell, RefCell};
118 use collections::HashMap;
119 use std::mem::replace;
120 use std::rc::Rc;
121 use std::vec::Vec;
122 use syntax::abi;
123 use syntax::ast::{Provided, Required};
124 use syntax::ast;
125 use syntax::ast_map;
126 use syntax::ast_util::local_def;
127 use syntax::ast_util;
128 use syntax::attr;
129 use syntax::codemap::Span;
130 use syntax::codemap;
131 use syntax::owned_slice::OwnedSlice;
132 use syntax::parse::token;
133 use syntax::print::pprust;
134 use syntax::visit;
135 use syntax::visit::Visitor;
136 use syntax;
137
138 pub mod _match;
139 pub mod vtable;
140 pub mod writeback;
141 pub mod regionmanip;
142 pub mod regionck;
143 pub mod demand;
144 pub mod method;
145
146 /// Fields that are part of a `FnCtxt` which are inherited by
147 /// closures defined within the function.  For example:
148 ///
149 ///     fn foo() {
150 ///         bar(proc() { ... })
151 ///     }
152 ///
153 /// Here, the function `foo()` and the closure passed to
154 /// `bar()` will each have their own `FnCtxt`, but they will
155 /// share the inherited fields.
156 pub struct Inherited<'a> {
157     infcx: infer::InferCtxt<'a>,
158     locals: RefCell<NodeMap<ty::t>>,
159     param_env: ty::ParameterEnvironment,
160
161     // Temporary tables:
162     node_types: RefCell<NodeMap<ty::t>>,
163     node_type_substs: RefCell<NodeMap<ty::substs>>,
164     adjustments: RefCell<NodeMap<ty::AutoAdjustment>>,
165     method_map: MethodMap,
166     vtable_map: vtable_map,
167     upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
168 }
169
170 #[deriving(Clone)]
171 pub enum FnKind {
172     // A do-closure.
173     DoBlock,
174
175     // A normal closure or fn item.
176     Vanilla
177 }
178
179 #[deriving(Clone)]
180 pub struct FnStyleState {
181     pub def: ast::NodeId,
182     pub fn_style: ast::FnStyle,
183     from_fn: bool
184 }
185
186 impl FnStyleState {
187     pub fn function(fn_style: ast::FnStyle, def: ast::NodeId) -> FnStyleState {
188         FnStyleState { def: def, fn_style: fn_style, from_fn: true }
189     }
190
191     pub fn recurse(&mut self, blk: &ast::Block) -> FnStyleState {
192         match self.fn_style {
193             // If this unsafe, then if the outer function was already marked as
194             // unsafe we shouldn't attribute the unsafe'ness to the block. This
195             // way the block can be warned about instead of ignoring this
196             // extraneous block (functions are never warned about).
197             ast::UnsafeFn if self.from_fn => *self,
198
199             fn_style => {
200                 let (fn_style, def) = match blk.rules {
201                     ast::UnsafeBlock(..) => (ast::UnsafeFn, blk.id),
202                     ast::DefaultBlock => (fn_style, self.def),
203                 };
204                 FnStyleState{ def: def,
205                              fn_style: fn_style,
206                              from_fn: false }
207             }
208         }
209     }
210 }
211
212 /// Whether `check_binop` is part of an assignment or not.
213 /// Used to know wether we allow user overloads and to print
214 /// better messages on error.
215 #[deriving(Eq)]
216 enum IsBinopAssignment{
217     SimpleBinop,
218     BinopAssignment,
219 }
220
221 #[deriving(Clone)]
222 pub struct FnCtxt<'a> {
223     // Number of errors that had been reported when we started
224     // checking this function. On exit, if we find that *more* errors
225     // have been reported, we will skip regionck and other work that
226     // expects the types within the function to be consistent.
227     err_count_on_creation: uint,
228
229     ret_ty: ty::t,
230     ps: RefCell<FnStyleState>,
231
232     // Sometimes we generate region pointers where the precise region
233     // to use is not known. For example, an expression like `&x.f`
234     // where `x` is of type `@T`: in this case, we will be rooting
235     // `x` onto the stack frame, and we could choose to root it until
236     // the end of (almost) any enclosing block or expression.  We
237     // want to pick the narrowest block that encompasses all uses.
238     //
239     // What we do in such cases is to generate a region variable with
240     // `region_lb` as a lower bound.  The regionck pass then adds
241     // other constraints based on how the variable is used and region
242     // inference selects the ultimate value.  Finally, borrowck is
243     // charged with guaranteeing that the value whose address was taken
244     // can actually be made to live as long as it needs to live.
245     region_lb: Cell<ast::NodeId>,
246
247     // Says whether we're inside a for loop, in a do block
248     // or neither. Helps with error messages involving the
249     // function return type.
250     fn_kind: FnKind,
251
252     inh: &'a Inherited<'a>,
253
254     ccx: &'a CrateCtxt<'a>,
255 }
256
257 impl<'a> Inherited<'a> {
258     fn new(tcx: &'a ty::ctxt,
259            param_env: ty::ParameterEnvironment)
260            -> Inherited<'a> {
261         Inherited {
262             infcx: infer::new_infer_ctxt(tcx),
263             locals: RefCell::new(NodeMap::new()),
264             param_env: param_env,
265             node_types: RefCell::new(NodeMap::new()),
266             node_type_substs: RefCell::new(NodeMap::new()),
267             adjustments: RefCell::new(NodeMap::new()),
268             method_map: RefCell::new(FnvHashMap::new()),
269             vtable_map: RefCell::new(FnvHashMap::new()),
270             upvar_borrow_map: RefCell::new(HashMap::new()),
271         }
272     }
273 }
274
275 // Used by check_const and check_enum_variants
276 fn blank_fn_ctxt<'a>(ccx: &'a CrateCtxt<'a>,
277                      inh: &'a Inherited<'a>,
278                      rty: ty::t,
279                      region_bnd: ast::NodeId)
280                      -> FnCtxt<'a> {
281     FnCtxt {
282         err_count_on_creation: ccx.tcx.sess.err_count(),
283         ret_ty: rty,
284         ps: RefCell::new(FnStyleState::function(ast::NormalFn, 0)),
285         region_lb: Cell::new(region_bnd),
286         fn_kind: Vanilla,
287         inh: inh,
288         ccx: ccx
289     }
290 }
291
292 fn blank_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> {
293     // It's kind of a kludge to manufacture a fake function context
294     // and statement context, but we might as well do write the code only once
295     let param_env = ty::ParameterEnvironment { free_substs: substs::empty(),
296                                                self_param_bound: None,
297                                                type_param_bounds: Vec::new() };
298     Inherited::new(ccx.tcx, param_env)
299 }
300
301 impl<'a> ExprTyProvider for FnCtxt<'a> {
302     fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
303         self.expr_ty(ex)
304     }
305
306     fn ty_ctxt<'a>(&'a self) -> &'a ty::ctxt {
307         self.ccx.tcx
308     }
309 }
310
311 struct CheckItemTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
312
313 impl<'a> Visitor<()> for CheckItemTypesVisitor<'a> {
314     fn visit_item(&mut self, i: &ast::Item, _: ()) {
315         check_item(self.ccx, i);
316         visit::walk_item(self, i, ());
317     }
318 }
319
320 struct CheckItemSizedTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
321
322 impl<'a> Visitor<()> for CheckItemSizedTypesVisitor<'a> {
323     fn visit_item(&mut self, i: &ast::Item, _: ()) {
324         check_item_sized(self.ccx, i);
325         visit::walk_item(self, i, ());
326     }
327 }
328
329 pub fn check_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
330     let mut visit = CheckItemTypesVisitor { ccx: ccx };
331     visit::walk_crate(&mut visit, krate, ());
332
333     ccx.tcx.sess.abort_if_errors();
334
335     let mut visit = CheckItemSizedTypesVisitor { ccx: ccx };
336     visit::walk_crate(&mut visit, krate, ());
337 }
338
339 fn check_bare_fn(ccx: &CrateCtxt,
340                  decl: &ast::FnDecl,
341                  body: &ast::Block,
342                  id: ast::NodeId,
343                  fty: ty::t,
344                  param_env: ty::ParameterEnvironment) {
345     // Compute the fty from point of view of inside fn
346     // (replace any type-scheme with a type)
347     let fty = fty.subst(ccx.tcx, &param_env.free_substs);
348
349     match ty::get(fty).sty {
350         ty::ty_bare_fn(ref fn_ty) => {
351             let inh = Inherited::new(ccx.tcx, param_env);
352             let fcx = check_fn(ccx, fn_ty.fn_style, &fn_ty.sig,
353                                decl, id, body, Vanilla, &inh);
354
355             vtable::resolve_in_block(&fcx, body);
356             regionck::regionck_fn(&fcx, body);
357             writeback::resolve_type_vars_in_fn(&fcx, decl, body);
358         }
359         _ => ccx.tcx.sess.impossible_case(body.span,
360                                  "check_bare_fn: function type expected")
361     }
362 }
363
364 struct GatherLocalsVisitor<'a> {
365     fcx: &'a FnCtxt<'a>
366 }
367
368 impl<'a> GatherLocalsVisitor<'a> {
369     fn assign(&mut self, nid: ast::NodeId, ty_opt: Option<ty::t>) {
370             match ty_opt {
371                 None => {
372                     // infer the variable's type
373                     let var_id = self.fcx.infcx().next_ty_var_id();
374                     let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
375                     self.fcx.inh.locals.borrow_mut().insert(nid, var_ty);
376                 }
377                 Some(typ) => {
378                     // take type that the user specified
379                     self.fcx.inh.locals.borrow_mut().insert(nid, typ);
380                 }
381             }
382     }
383 }
384
385 impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
386     // Add explicitly-declared locals.
387     fn visit_local(&mut self, local: &ast::Local, _: ()) {
388         let o_ty = match local.ty.node {
389             ast::TyInfer => None,
390             _ => Some(self.fcx.to_ty(local.ty))
391         };
392         self.assign(local.id, o_ty);
393         debug!("Local variable {} is assigned type {}",
394                self.fcx.pat_to_str(local.pat),
395                self.fcx.infcx().ty_to_str(
396                    self.fcx.inh.locals.borrow().get_copy(&local.id)));
397         visit::walk_local(self, local, ());
398     }
399
400     // Add pattern bindings.
401     fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
402             match p.node {
403               ast::PatIdent(_, ref path, _)
404                   if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) => {
405                 self.assign(p.id, None);
406                 debug!("Pattern binding {} is assigned to {}",
407                        token::get_ident(path.segments.get(0).identifier),
408                        self.fcx.infcx().ty_to_str(
409                            self.fcx.inh.locals.borrow().get_copy(&p.id)));
410               }
411               _ => {}
412             }
413             visit::walk_pat(self, p, ());
414
415     }
416
417     fn visit_block(&mut self, b: &ast::Block, _: ()) {
418         // non-obvious: the `blk` variable maps to region lb, so
419         // we have to keep this up-to-date.  This
420         // is... unfortunate.  It'd be nice to not need this.
421         self.fcx.with_region_lb(b.id, || visit::walk_block(self, b, ()));
422     }
423
424     // Don't descend into fns and items
425     fn visit_fn(&mut self, _: &visit::FnKind, _: &ast::FnDecl,
426                 _: &ast::Block, _: Span, _: ast::NodeId, _: ()) { }
427     fn visit_item(&mut self, _: &ast::Item, _: ()) { }
428
429 }
430
431 fn check_fn<'a>(ccx: &'a CrateCtxt<'a>,
432                 fn_style: ast::FnStyle,
433                 fn_sig: &ty::FnSig,
434                 decl: &ast::FnDecl,
435                 id: ast::NodeId,
436                 body: &ast::Block,
437                 fn_kind: FnKind,
438                 inherited: &'a Inherited<'a>) -> FnCtxt<'a>
439 {
440     /*!
441      * Helper used by check_bare_fn and check_expr_fn.  Does the
442      * grungy work of checking a function body and returns the
443      * function context used for that purpose, since in the case of a
444      * fn item there is still a bit more to do.
445      *
446      * - ...
447      * - inherited: other fields inherited from the enclosing fn (if any)
448      */
449
450     let tcx = ccx.tcx;
451     let err_count_on_creation = tcx.sess.err_count();
452
453     // First, we have to replace any bound regions in the fn type with free ones.
454     // The free region references will be bound the node_id of the body block.
455     let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(tcx, fn_sig, |br| {
456         ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
457     });
458
459     relate_free_regions(tcx, &fn_sig);
460
461     let arg_tys = fn_sig.inputs.as_slice();
462     let ret_ty = fn_sig.output;
463
464     debug!("check_fn(arg_tys={:?}, ret_ty={:?})",
465            arg_tys.iter().map(|&a| ppaux::ty_to_str(tcx, a)).collect::<Vec<~str>>(),
466            ppaux::ty_to_str(tcx, ret_ty));
467
468     // Create the function context.  This is either derived from scratch or,
469     // in the case of function expressions, based on the outer context.
470     let fcx = FnCtxt {
471         err_count_on_creation: err_count_on_creation,
472         ret_ty: ret_ty,
473         ps: RefCell::new(FnStyleState::function(fn_style, id)),
474         region_lb: Cell::new(body.id),
475         fn_kind: fn_kind,
476         inh: inherited,
477         ccx: ccx
478     };
479
480     {
481
482         let mut visit = GatherLocalsVisitor { fcx: &fcx, };
483         // Add formal parameters.
484         for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
485             // Create type variables for each argument.
486             pat_util::pat_bindings(&tcx.def_map,
487                                    input.pat,
488                                    |_bm, pat_id, _sp, _path| {
489                                        visit.assign(pat_id, None);
490                                    });
491
492             // Check the pattern.
493             let pcx = pat_ctxt {
494                 fcx: &fcx,
495                 map: pat_id_map(&tcx.def_map, input.pat),
496             };
497             _match::check_pat(&pcx, input.pat, *arg_ty);
498         }
499
500         visit.visit_block(body, ());
501     }
502
503     check_block_with_expected(&fcx, body, Some(ret_ty));
504
505     // We unify the tail expr's type with the
506     // function result type, if there is a tail expr.
507     match body.expr {
508         Some(tail_expr) => {
509             // Special case: we print a special error if there appears
510             // to be do-block/for-loop confusion
511             demand::suptype_with_fn(&fcx, tail_expr.span, false,
512                 fcx.ret_ty, fcx.expr_ty(tail_expr),
513                 |sp, e, a, s| {
514                     fcx.report_mismatched_return_types(sp, e, a, s);
515                 });
516         }
517         None => {}
518     }
519
520     for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
521         fcx.write_ty(input.id, *arg);
522     }
523
524     fcx
525 }
526
527 fn span_for_field(tcx: &ty::ctxt, field: &ty::field_ty, struct_id: ast::DefId) -> Span {
528     assert!(field.id.krate == ast::LOCAL_CRATE);
529     let item = match tcx.map.find(struct_id.node) {
530         Some(ast_map::NodeItem(item)) => item,
531         None => fail!("node not in ast map: {}", struct_id.node),
532         _ => fail!("expected item, found {}", tcx.map.node_to_str(struct_id.node))
533     };
534
535     match item.node {
536         ast::ItemStruct(struct_def, _) => {
537             match struct_def.fields.iter().find(|f| match f.node.kind {
538                 ast::NamedField(ident, _) => ident.name == field.name,
539                 _ => false,
540             }) {
541                 Some(f) => f.span,
542                 None => tcx.sess.bug(format!("Could not find field {}",
543                                              token::get_name(field.name))),
544             }
545         },
546         _ => tcx.sess.bug("Field found outside of a struct?"),
547     }
548 }
549
550 // Check struct fields are uniquely named wrt parents.
551 fn check_for_field_shadowing(tcx: &ty::ctxt,
552                              id: ast::DefId) {
553     let struct_fields = tcx.struct_fields.borrow();
554     let fields = struct_fields.get(&id);
555
556     let superstructs = tcx.superstructs.borrow();
557     let super_struct = superstructs.get(&id);
558     match *super_struct {
559         Some(parent_id) => {
560             let super_fields = ty::lookup_struct_fields(tcx, parent_id);
561             for f in fields.iter() {
562                 match super_fields.iter().find(|sf| f.name == sf.name) {
563                     Some(prev_field) => {
564                         tcx.sess.span_err(span_for_field(tcx, f, id),
565                             format!("field `{}` hides field declared in super-struct",
566                                     token::get_name(f.name)));
567                         tcx.sess.span_note(span_for_field(tcx, prev_field, parent_id),
568                             "previously declared here");
569                     },
570                     None => {}
571                 }
572             }
573         },
574         None => {}
575     }
576 }
577
578 fn check_fields_sized(tcx: &ty::ctxt,
579                       struct_def: &ast::StructDef) {
580     let len = struct_def.fields.len();
581     if len == 0 {
582         return;
583     }
584     for f in struct_def.fields.slice_to(len - 1).iter() {
585         let t = ty::node_id_to_type(tcx, f.node.id);
586         if !ty::type_is_sized(tcx, t) {
587             match f.node.kind {
588                 ast::NamedField(ident, _) => {
589                     tcx.sess.span_err(f.span, format!("type `{}` is dynamically sized. \
590                                                        dynamically sized types may only \
591                                                        appear as the type of the final \
592                                                        field in a struct",
593                                                       token::get_ident(ident)));
594                 }
595                 ast::UnnamedField(_) => {
596                     tcx.sess.span_err(f.span, "dynamically sized type in field");
597                 }
598             }
599         }
600     }
601 }
602
603 pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
604     let tcx = ccx.tcx;
605
606     check_representable(tcx, span, id, "struct");
607     check_instantiable(tcx, span, id);
608
609     // Check there are no overlapping fields in super-structs
610     check_for_field_shadowing(tcx, local_def(id));
611
612     if ty::lookup_simd(tcx, local_def(id)) {
613         check_simd(tcx, span, id);
614     }
615 }
616
617 pub fn check_item_sized(ccx: &CrateCtxt, it: &ast::Item) {
618     debug!("check_item(it.id={}, it.ident={})",
619            it.id,
620            ty::item_path_str(ccx.tcx, local_def(it.id)));
621     let _indenter = indenter();
622
623     match it.node {
624         ast::ItemEnum(ref enum_definition, _) => {
625             check_enum_variants_sized(ccx,
626                                       enum_definition.variants.as_slice());
627         }
628         ast::ItemStruct(..) => {
629             check_fields_sized(ccx.tcx, ccx.tcx.map.expect_struct(it.id));
630         }
631         _ => {}
632     }
633 }
634
635 pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
636     debug!("check_item(it.id={}, it.ident={})",
637            it.id,
638            ty::item_path_str(ccx.tcx, local_def(it.id)));
639     let _indenter = indenter();
640
641     match it.node {
642       ast::ItemStatic(_, _, e) => check_const(ccx, it.span, e, it.id),
643       ast::ItemEnum(ref enum_definition, _) => {
644         check_enum_variants(ccx,
645                             it.span,
646                             enum_definition.variants.as_slice(),
647                             it.id);
648       }
649       ast::ItemFn(decl, _, _, _, body) => {
650         let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
651
652         let param_env = ty::construct_parameter_environment(
653                 ccx.tcx,
654                 None,
655                 fn_tpt.generics.type_param_defs(),
656                 [],
657                 [],
658                 fn_tpt.generics.region_param_defs.as_slice(),
659                 body.id);
660
661         check_bare_fn(ccx, decl, body, it.id, fn_tpt.ty, param_env);
662       }
663       ast::ItemImpl(_, ref opt_trait_ref, _, ref ms) => {
664         debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
665
666         let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
667         for m in ms.iter() {
668             check_method_body(ccx, &impl_tpt.generics, None, *m);
669         }
670
671         match *opt_trait_ref {
672             Some(ref ast_trait_ref) => {
673                 let impl_trait_ref =
674                     ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id);
675                 check_impl_methods_against_trait(ccx,
676                                              it.span,
677                                              &impl_tpt.generics,
678                                              ast_trait_ref,
679                                              &*impl_trait_ref,
680                                              ms.as_slice());
681                 vtable::resolve_impl(ccx.tcx, it, &impl_tpt.generics, &*impl_trait_ref);
682             }
683             None => { }
684         }
685
686       }
687       ast::ItemTrait(_, _, _, ref trait_methods) => {
688         let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
689         for trait_method in (*trait_methods).iter() {
690             match *trait_method {
691                 Required(..) => {
692                     // Nothing to do, since required methods don't have
693                     // bodies to check.
694                 }
695                 Provided(m) => {
696                     check_method_body(ccx, &trait_def.generics,
697                                       Some(trait_def.trait_ref.clone()), m);
698                 }
699             }
700         }
701       }
702       ast::ItemStruct(..) => {
703         check_struct(ccx, it.id, it.span);
704       }
705       ast::ItemTy(ref t, ref generics) => {
706         let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id);
707         check_bounds_are_used(ccx, t.span, &generics.ty_params, tpt_ty);
708       }
709       ast::ItemForeignMod(ref m) => {
710         if m.abi == abi::RustIntrinsic {
711             for item in m.items.iter() {
712                 check_intrinsic_type(ccx, *item);
713             }
714         } else {
715             for item in m.items.iter() {
716                 let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id));
717                 if tpt.generics.has_type_params() {
718                     ccx.tcx.sess.span_err(item.span, "foreign items may not have type parameters");
719                 }
720
721                 match item.node {
722                     ast::ForeignItemFn(ref fn_decl, _) => {
723                         if fn_decl.variadic && m.abi != abi::C {
724                             ccx.tcx.sess.span_err(
725                                 item.span, "variadic function must have C calling convention");
726                         }
727                     }
728                     _ => {}
729                 }
730             }
731         }
732       }
733       _ => {/* nothing to do */ }
734     }
735 }
736
737 fn check_method_body(ccx: &CrateCtxt,
738                      item_generics: &ty::Generics,
739                      self_bound: Option<Rc<ty::TraitRef>>,
740                      method: &ast::Method) {
741     /*!
742      * Type checks a method body.
743      *
744      * # Parameters
745      * - `item_generics`: generics defined on the impl/trait that contains
746      *   the method
747      * - `self_bound`: bound for the `Self` type parameter, if any
748      * - `method`: the method definition
749      */
750
751     debug!("check_method_body(item_generics={}, \
752             self_bound={}, \
753             method.id={})",
754             item_generics.repr(ccx.tcx),
755             self_bound.repr(ccx.tcx),
756             method.id);
757     let method_def_id = local_def(method.id);
758     let method_ty = ty::method(ccx.tcx, method_def_id);
759     let method_generics = &method_ty.generics;
760
761     let param_env =
762         ty::construct_parameter_environment(
763             ccx.tcx,
764             self_bound,
765             item_generics.type_param_defs(),
766             method_generics.type_param_defs(),
767             item_generics.region_param_defs(),
768             method_generics.region_param_defs(),
769             method.body.id);
770
771     let fty = ty::node_id_to_type(ccx.tcx, method.id);
772
773     check_bare_fn(ccx, method.decl, method.body, method.id, fty, param_env);
774 }
775
776 fn check_impl_methods_against_trait(ccx: &CrateCtxt,
777                                     impl_span: Span,
778                                     impl_generics: &ty::Generics,
779                                     ast_trait_ref: &ast::TraitRef,
780                                     impl_trait_ref: &ty::TraitRef,
781                                     impl_methods: &[@ast::Method]) {
782     // Locate trait methods
783     let tcx = ccx.tcx;
784     let trait_methods = ty::trait_methods(tcx, impl_trait_ref.def_id);
785
786     // Check existing impl methods to see if they are both present in trait
787     // and compatible with trait signature
788     for impl_method in impl_methods.iter() {
789         let impl_method_def_id = local_def(impl_method.id);
790         let impl_method_ty = ty::method(ccx.tcx, impl_method_def_id);
791
792         // If this is an impl of a trait method, find the corresponding
793         // method definition in the trait.
794         let opt_trait_method_ty =
795             trait_methods.iter().
796             find(|tm| tm.ident.name == impl_method_ty.ident.name);
797         match opt_trait_method_ty {
798             Some(trait_method_ty) => {
799                 compare_impl_method(ccx.tcx,
800                                     impl_generics,
801                                     &*impl_method_ty,
802                                     impl_method.span,
803                                     impl_method.body.id,
804                                     &**trait_method_ty,
805                                     &impl_trait_ref.substs);
806             }
807             None => {
808                 tcx.sess.span_err(
809                     impl_method.span,
810                     format!("method `{}` is not a member of trait `{}`",
811                             token::get_ident(impl_method_ty.ident),
812                             pprust::path_to_str(&ast_trait_ref.path)));
813             }
814         }
815     }
816
817     // Check for missing methods from trait
818     let provided_methods = ty::provided_trait_methods(tcx,
819                                                       impl_trait_ref.def_id);
820     let mut missing_methods = Vec::new();
821     for trait_method in trait_methods.iter() {
822         let is_implemented =
823             impl_methods.iter().any(
824                 |m| m.ident.name == trait_method.ident.name);
825         let is_provided =
826             provided_methods.iter().any(
827                 |m| m.ident.name == trait_method.ident.name);
828         if !is_implemented && !is_provided {
829             missing_methods.push(
830                 format!("`{}`", token::get_ident(trait_method.ident)));
831         }
832     }
833
834     if !missing_methods.is_empty() {
835         tcx.sess.span_err(
836             impl_span,
837             format!("not all trait methods implemented, missing: {}",
838                     missing_methods.connect(", ")));
839     }
840 }
841
842 /**
843  * Checks that a method from an impl/class conforms to the signature of
844  * the same method as declared in the trait.
845  *
846  * # Parameters
847  *
848  * - impl_generics: the generics declared on the impl itself (not the method!)
849  * - impl_m: type of the method we are checking
850  * - impl_m_span: span to use for reporting errors
851  * - impl_m_body_id: id of the method body
852  * - trait_m: the method in the trait
853  * - trait_substs: the substitutions used on the type of the trait
854  */
855 fn compare_impl_method(tcx: &ty::ctxt,
856                        impl_generics: &ty::Generics,
857                        impl_m: &ty::Method,
858                        impl_m_span: Span,
859                        impl_m_body_id: ast::NodeId,
860                        trait_m: &ty::Method,
861                        trait_substs: &ty::substs) {
862     debug!("compare_impl_method()");
863     let infcx = infer::new_infer_ctxt(tcx);
864
865     let impl_tps = impl_generics.type_param_defs().len();
866
867     // Try to give more informative error messages about self typing
868     // mismatches.  Note that any mismatch will also be detected
869     // below, where we construct a canonical function type that
870     // includes the self parameter as a normal parameter.  It's just
871     // that the error messages you get out of this code are a bit more
872     // inscrutable, particularly for cases where one method has no
873     // self.
874     match (&trait_m.explicit_self, &impl_m.explicit_self) {
875         (&ast::SelfStatic, &ast::SelfStatic) => {}
876         (&ast::SelfStatic, _) => {
877             tcx.sess.span_err(
878                 impl_m_span,
879                 format!("method `{}` has a `{}` declaration in the impl, \
880                         but not in the trait",
881                         token::get_ident(trait_m.ident),
882                         pprust::explicit_self_to_str(impl_m.explicit_self)));
883             return;
884         }
885         (_, &ast::SelfStatic) => {
886             tcx.sess.span_err(
887                 impl_m_span,
888                 format!("method `{}` has a `{}` declaration in the trait, \
889                         but not in the impl",
890                         token::get_ident(trait_m.ident),
891                         pprust::explicit_self_to_str(trait_m.explicit_self)));
892             return;
893         }
894         _ => {
895             // Let the type checker catch other errors below
896         }
897     }
898
899     let num_impl_m_type_params = impl_m.generics.type_param_defs().len();
900     let num_trait_m_type_params = trait_m.generics.type_param_defs().len();
901     if num_impl_m_type_params != num_trait_m_type_params {
902         tcx.sess.span_err(
903             impl_m_span,
904             format!("method `{method}` has {nimpl, plural, =1{# type parameter} \
905                                                         other{# type parameters}}, \
906                      but its trait declaration has {ntrait, plural, =1{# type parameter} \
907                                                                  other{# type parameters}}",
908                     method = token::get_ident(trait_m.ident),
909                     nimpl = num_impl_m_type_params,
910                     ntrait = num_trait_m_type_params));
911         return;
912     }
913
914     if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() {
915         tcx.sess.span_err(
916             impl_m_span,
917             format!("method `{method}` has {nimpl, plural, =1{# parameter} \
918                                                         other{# parameters}} \
919                      but the declaration in trait `{trait}` has {ntrait}",
920                  method = token::get_ident(trait_m.ident),
921                  nimpl = impl_m.fty.sig.inputs.len(),
922                  trait = ty::item_path_str(tcx, trait_m.def_id),
923                  ntrait = trait_m.fty.sig.inputs.len()));
924         return;
925     }
926
927     let it = trait_m.generics.type_param_defs().iter()
928         .zip(impl_m.generics.type_param_defs().iter());
929
930     for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
931         // Check that the impl does not require any builtin-bounds
932         // that the trait does not guarantee:
933         let extra_bounds =
934             impl_param_def.bounds.builtin_bounds -
935             trait_param_def.bounds.builtin_bounds;
936         if !extra_bounds.is_empty() {
937            tcx.sess.span_err(
938                impl_m_span,
939                format!("in method `{}`, \
940                        type parameter {} requires `{}`, \
941                        which is not required by \
942                        the corresponding type parameter \
943                        in the trait declaration",
944                        token::get_ident(trait_m.ident),
945                        i,
946                        extra_bounds.user_string(tcx)));
947            return;
948         }
949
950         // FIXME(#2687)---we should be checking that the bounds of the
951         // trait imply the bounds of the subtype, but it appears we
952         // are...not checking this.
953         if impl_param_def.bounds.trait_bounds.len() !=
954             trait_param_def.bounds.trait_bounds.len()
955         {
956             tcx.sess.span_err(
957                 impl_m_span,
958                 format!("in method `{method}`, \
959                         type parameter {typaram} has \
960                         {nimpl, plural, =1{# trait bound} other{# trait bounds}}, \
961                         but the corresponding type parameter in \
962                         the trait declaration has \
963                         {ntrait, plural, =1{# trait bound} other{# trait bounds}}",
964                         method = token::get_ident(trait_m.ident),
965                         typaram = i,
966                         nimpl = impl_param_def.bounds.trait_bounds.len(),
967                         ntrait = trait_param_def.bounds.trait_bounds.len()));
968             return;
969         }
970     }
971
972     // Create a substitution that maps the type parameters on the impl
973     // to themselves and which replace any references to bound regions
974     // in the self type with free regions.  So, for example, if the
975     // impl type is "&'a str", then this would replace the self
976     // type with a free region `self`.
977     let dummy_impl_tps: Vec<ty::t> =
978         impl_generics.type_param_defs().iter().enumerate().
979         map(|(i,t)| ty::mk_param(tcx, i, t.def_id)).
980         collect();
981     let dummy_method_tps: Vec<ty::t> =
982         impl_m.generics.type_param_defs().iter().enumerate().
983         map(|(i,t)| ty::mk_param(tcx, i + impl_tps, t.def_id)).
984         collect();
985     let dummy_impl_regions: OwnedSlice<ty::Region> =
986         impl_generics.region_param_defs().iter().
987         map(|l| ty::ReFree(ty::FreeRegion {
988                 scope_id: impl_m_body_id,
989                 bound_region: ty::BrNamed(l.def_id, l.name)})).
990         collect();
991     let dummy_substs = ty::substs {
992         tps: dummy_impl_tps.append(dummy_method_tps.as_slice()),
993         regions: ty::NonerasedRegions(dummy_impl_regions),
994         self_ty: None };
995
996     // Create a bare fn type for trait/impl
997     // It'd be nice to refactor so as to provide the bare fn types instead.
998     let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
999     let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
1000
1001     // Perform substitutions so that the trait/impl methods are expressed
1002     // in terms of the same set of type/region parameters:
1003     // - replace trait type parameters with those from `trait_substs`,
1004     //   except with any reference to bound self replaced with `dummy_self_r`
1005     // - replace method parameters on the trait with fresh, dummy parameters
1006     //   that correspond to the parameters we will find on the impl
1007     // - replace self region with a fresh, dummy region
1008     let impl_fty = {
1009         debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
1010         impl_fty.subst(tcx, &dummy_substs)
1011     };
1012     debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
1013     let trait_fty = {
1014         let substs { regions: trait_regions,
1015                      tps: trait_tps,
1016                      self_ty: self_ty } = trait_substs.subst(tcx, &dummy_substs);
1017         let substs = substs {
1018             regions: trait_regions,
1019             tps: trait_tps.append(dummy_method_tps.as_slice()),
1020             self_ty: self_ty,
1021         };
1022         debug!("trait_fty (pre-subst): {} substs={}",
1023                trait_fty.repr(tcx), substs.repr(tcx));
1024         trait_fty.subst(tcx, &substs)
1025     };
1026     debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx));
1027
1028     match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span),
1029                           impl_fty, trait_fty) {
1030         Ok(()) => {}
1031         Err(ref terr) => {
1032             tcx.sess.span_err(
1033                 impl_m_span,
1034                 format!("method `{}` has an incompatible type for trait: {}",
1035                         token::get_ident(trait_m.ident),
1036                         ty::type_err_to_str(tcx, terr)));
1037             ty::note_and_explain_type_err(tcx, terr);
1038         }
1039     }
1040 }
1041
1042 impl<'a> AstConv for FnCtxt<'a> {
1043     fn tcx<'a>(&'a self) -> &'a ty::ctxt { self.ccx.tcx }
1044
1045     fn get_item_ty(&self, id: ast::DefId) -> ty::ty_param_bounds_and_ty {
1046         ty::lookup_item_type(self.tcx(), id)
1047     }
1048
1049     fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef> {
1050         ty::lookup_trait_def(self.tcx(), id)
1051     }
1052
1053     fn ty_infer(&self, _span: Span) -> ty::t {
1054         self.infcx().next_ty_var()
1055     }
1056 }
1057
1058 impl<'a> FnCtxt<'a> {
1059     pub fn infcx<'b>(&'b self) -> &'b infer::InferCtxt<'a> {
1060         &self.inh.infcx
1061     }
1062
1063     pub fn err_count_since_creation(&self) -> uint {
1064         self.ccx.tcx.sess.err_count() - self.err_count_on_creation
1065     }
1066
1067     pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
1068         VtableContext {
1069             infcx: self.infcx(),
1070             param_env: &self.inh.param_env
1071         }
1072     }
1073 }
1074
1075 impl<'a> RegionScope for infer::InferCtxt<'a> {
1076     fn anon_regions(&self, span: Span, count: uint)
1077                     -> Result<Vec<ty::Region> , ()> {
1078         Ok(Vec::from_fn(count, |_| {
1079             self.next_region_var(infer::MiscVariable(span))
1080         }))
1081     }
1082 }
1083
1084 impl<'a> FnCtxt<'a> {
1085     pub fn tag(&self) -> ~str {
1086         format!("{}", self as *FnCtxt)
1087     }
1088
1089     pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t {
1090         match self.inh.locals.borrow().find(&nid) {
1091             Some(&t) => t,
1092             None => {
1093                 self.tcx().sess.span_bug(
1094                     span,
1095                     format!("no type for local variable {:?}", nid));
1096             }
1097         }
1098     }
1099
1100     #[inline]
1101     pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
1102         debug!("write_ty({}, {}) in fcx {}",
1103                node_id, ppaux::ty_to_str(self.tcx(), ty), self.tag());
1104         self.inh.node_types.borrow_mut().insert(node_id, ty);
1105     }
1106
1107     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::substs) {
1108         if !ty::substs_is_noop(&substs) {
1109             debug!("write_substs({}, {}) in fcx {}",
1110                    node_id,
1111                    ty::substs_to_str(self.tcx(), &substs),
1112                    self.tag());
1113
1114             self.inh.node_type_substs.borrow_mut().insert(node_id, substs);
1115         }
1116     }
1117
1118     pub fn write_ty_substs(&self,
1119                            node_id: ast::NodeId,
1120                            ty: ty::t,
1121                            substs: ty::substs) {
1122         let ty = ty::subst(self.tcx(), &substs, ty);
1123         self.write_ty(node_id, ty);
1124         self.write_substs(node_id, substs);
1125     }
1126
1127     pub fn write_autoderef_adjustment(&self,
1128                                       node_id: ast::NodeId,
1129                                       derefs: uint) {
1130         if derefs == 0 { return; }
1131         self.write_adjustment(
1132             node_id,
1133             ty::AutoDerefRef(ty::AutoDerefRef {
1134                 autoderefs: derefs,
1135                 autoref: None })
1136         );
1137     }
1138
1139     pub fn write_adjustment(&self,
1140                             node_id: ast::NodeId,
1141                             adj: ty::AutoAdjustment) {
1142         debug!("write_adjustment(node_id={:?}, adj={:?})", node_id, adj);
1143         self.inh.adjustments.borrow_mut().insert(node_id, adj);
1144     }
1145
1146     pub fn write_nil(&self, node_id: ast::NodeId) {
1147         self.write_ty(node_id, ty::mk_nil());
1148     }
1149     pub fn write_bot(&self, node_id: ast::NodeId) {
1150         self.write_ty(node_id, ty::mk_bot());
1151     }
1152     pub fn write_error(&self, node_id: ast::NodeId) {
1153         self.write_ty(node_id, ty::mk_err());
1154     }
1155
1156     pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
1157         ast_ty_to_ty(self, self.infcx(), ast_t)
1158     }
1159
1160     pub fn pat_to_str(&self, pat: &ast::Pat) -> ~str {
1161         pat.repr(self.tcx())
1162     }
1163
1164     pub fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
1165         match self.inh.node_types.borrow().find(&ex.id) {
1166             Some(&t) => t,
1167             None => {
1168                 self.tcx().sess.bug(format!("no type for expr in fcx {}",
1169                                             self.tag()));
1170             }
1171         }
1172     }
1173
1174     pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
1175         match self.inh.node_types.borrow().find(&id) {
1176             Some(&t) => t,
1177             None => {
1178                 self.tcx().sess.bug(
1179                     format!("no type for node {}: {} in fcx {}",
1180                             id, self.tcx().map.node_to_str(id),
1181                             self.tag()));
1182             }
1183         }
1184     }
1185
1186     pub fn method_ty_substs(&self, id: ast::NodeId) -> ty::substs {
1187         match self.inh.method_map.borrow().find(&MethodCall::expr(id)) {
1188             Some(method) => method.substs.clone(),
1189             None => {
1190                 self.tcx().sess.bug(
1191                     format!("no method entry for node {}: {} in fcx {}",
1192                             id, self.tcx().map.node_to_str(id),
1193                             self.tag()));
1194             }
1195         }
1196     }
1197
1198     pub fn opt_node_ty_substs(&self,
1199                               id: ast::NodeId,
1200                               f: |&ty::substs| -> bool)
1201                               -> bool {
1202         match self.inh.node_type_substs.borrow().find(&id) {
1203             Some(s) => f(s),
1204             None => true
1205         }
1206     }
1207
1208     pub fn mk_subty(&self,
1209                     a_is_expected: bool,
1210                     origin: infer::TypeOrigin,
1211                     sub: ty::t,
1212                     sup: ty::t)
1213                     -> Result<(), ty::type_err> {
1214         infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
1215     }
1216
1217     pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t)
1218                         -> Result<(), ty::type_err> {
1219         infer::can_mk_subty(self.infcx(), sub, sup)
1220     }
1221
1222     pub fn mk_assignty(&self,
1223                        expr: &ast::Expr,
1224                        sub: ty::t,
1225                        sup: ty::t)
1226                        -> Result<(), ty::type_err> {
1227         match infer::mk_coercety(self.infcx(),
1228                                  false,
1229                                  infer::ExprAssignable(expr.span),
1230                                  sub,
1231                                  sup) {
1232             Ok(None) => Ok(()),
1233             Err(ref e) => Err((*e)),
1234             Ok(Some(adjustment)) => {
1235                 self.write_adjustment(expr.id, adjustment);
1236                 Ok(())
1237             }
1238         }
1239     }
1240
1241     pub fn mk_eqty(&self,
1242                    a_is_expected: bool,
1243                    origin: infer::TypeOrigin,
1244                    sub: ty::t,
1245                    sup: ty::t)
1246                    -> Result<(), ty::type_err> {
1247         infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
1248     }
1249
1250     pub fn mk_subr(&self,
1251                    a_is_expected: bool,
1252                    origin: infer::SubregionOrigin,
1253                    sub: ty::Region,
1254                    sup: ty::Region) {
1255         infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
1256     }
1257
1258     pub fn with_region_lb<R>(&self, lb: ast::NodeId, f: || -> R) -> R {
1259         let old_region_lb = self.region_lb.get();
1260         self.region_lb.set(lb);
1261         let v = f();
1262         self.region_lb.set(old_region_lb);
1263         v
1264     }
1265
1266     pub fn type_error_message(&self,
1267                               sp: Span,
1268                               mk_msg: |~str| -> ~str,
1269                               actual_ty: ty::t,
1270                               err: Option<&ty::type_err>) {
1271         self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
1272     }
1273
1274     pub fn report_mismatched_return_types(&self,
1275                                           sp: Span,
1276                                           e: ty::t,
1277                                           a: ty::t,
1278                                           err: &ty::type_err) {
1279         // Derived error
1280         if ty::type_is_error(e) || ty::type_is_error(a) {
1281             return;
1282         }
1283         self.infcx().report_mismatched_types(sp, e, a, err)
1284     }
1285
1286     pub fn report_mismatched_types(&self,
1287                                    sp: Span,
1288                                    e: ty::t,
1289                                    a: ty::t,
1290                                    err: &ty::type_err) {
1291         self.infcx().report_mismatched_types(sp, e, a, err)
1292     }
1293 }
1294
1295 pub enum LvaluePreference {
1296     PreferMutLvalue,
1297     NoPreference
1298 }
1299
1300 pub fn autoderef<T>(fcx: &FnCtxt, sp: Span, base_ty: ty::t,
1301                     expr_id: Option<ast::NodeId>,
1302                     mut lvalue_pref: LvaluePreference,
1303                     should_stop: |ty::t, uint| -> Option<T>)
1304                     -> (ty::t, uint, Option<T>) {
1305     /*!
1306      * Executes an autoderef loop for the type `t`. At each step, invokes
1307      * `should_stop` to decide whether to terminate the loop. Returns
1308      * the final type and number of derefs that it performed.
1309      *
1310      * Note: this method does not modify the adjustments table. The caller is
1311      * responsible for inserting an AutoAdjustment record into the `fcx`
1312      * using one of the suitable methods.
1313      */
1314
1315     let mut t = base_ty;
1316     for autoderefs in range(0, fcx.tcx().sess.recursion_limit.get()) {
1317         let resolved_t = structurally_resolved_type(fcx, sp, t);
1318
1319         match should_stop(resolved_t, autoderefs) {
1320             Some(x) => return (resolved_t, autoderefs, Some(x)),
1321             None => {}
1322         }
1323
1324         // Otherwise, deref if type is derefable:
1325         let mt = match ty::deref(resolved_t, false) {
1326             Some(mt) => Some(mt),
1327             None => {
1328                 let method_call =
1329                     expr_id.map(|id| MethodCall::autoderef(id, autoderefs as u32));
1330                 try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
1331             }
1332         };
1333         match mt {
1334             Some(mt) => {
1335                 t = mt.ty;
1336                 if mt.mutbl == ast::MutImmutable {
1337                     lvalue_pref = NoPreference;
1338                 }
1339             }
1340             None => return (resolved_t, autoderefs, None)
1341         }
1342     }
1343
1344     // We've reached the recursion limit, error gracefully.
1345     fcx.tcx().sess.span_err(sp,
1346         format!("reached the recursion limit while auto-dereferencing {}",
1347                 base_ty.repr(fcx.tcx())));
1348     (ty::mk_err(), 0, None)
1349 }
1350
1351 fn try_overloaded_deref(fcx: &FnCtxt,
1352                         span: Span,
1353                         method_call: Option<MethodCall>,
1354                         base_expr: Option<&ast::Expr>,
1355                         base_ty: ty::t,
1356                         lvalue_pref: LvaluePreference)
1357                         -> Option<ty::mt> {
1358     // Try DerefMut first, if preferred.
1359     let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
1360         (PreferMutLvalue, Some(trait_did)) => {
1361             method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
1362                                     token::intern("deref_mut"), trait_did,
1363                                     base_ty, [], DontAutoderefReceiver)
1364         }
1365         _ => None
1366     };
1367
1368     // Otherwise, fall back to Deref.
1369     let method = match (method, fcx.tcx().lang_items.deref_trait()) {
1370         (None, Some(trait_did)) => {
1371             method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
1372                                     token::intern("deref"), trait_did,
1373                                     base_ty, [], DontAutoderefReceiver)
1374         }
1375         (method, _) => method
1376     };
1377
1378     match method {
1379         Some(method) => {
1380             let ref_ty = ty::ty_fn_ret(method.ty);
1381             match method_call {
1382                 Some(method_call) => {
1383                     fcx.inh.method_map.borrow_mut().insert(method_call, method);
1384                 }
1385                 None => {}
1386             }
1387             ty::deref(ref_ty, true)
1388         }
1389         None => None
1390     }
1391 }
1392
1393 // AST fragment checking
1394 pub fn check_lit(fcx: &FnCtxt, lit: &ast::Lit) -> ty::t {
1395     let tcx = fcx.ccx.tcx;
1396
1397     match lit.node {
1398         ast::LitStr(..) => ty::mk_str(tcx, ty::VstoreSlice(ty::ReStatic)),
1399         ast::LitBinary(..) => {
1400             ty::mk_slice(tcx, ty::ReStatic, ty::mt{ ty: ty::mk_u8(), mutbl: ast::MutImmutable })
1401         }
1402         ast::LitChar(_) => ty::mk_char(),
1403         ast::LitInt(_, t) => ty::mk_mach_int(t),
1404         ast::LitUint(_, t) => ty::mk_mach_uint(t),
1405         ast::LitIntUnsuffixed(_) => {
1406             // An unsuffixed integer literal could have any integral type,
1407             // so we create an integral type variable for it.
1408             ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
1409         }
1410         ast::LitFloat(_, t) => ty::mk_mach_float(t),
1411         ast::LitFloatUnsuffixed(_) => {
1412             // An unsuffixed floating point literal could have any floating point
1413             // type, so we create a floating point type variable for it.
1414             ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())
1415         }
1416         ast::LitNil => ty::mk_nil(),
1417         ast::LitBool(_) => ty::mk_bool()
1418     }
1419 }
1420
1421 pub fn valid_range_bounds(ccx: &CrateCtxt,
1422                           from: &ast::Expr,
1423                           to: &ast::Expr)
1424                        -> Option<bool> {
1425     match const_eval::compare_lit_exprs(ccx.tcx, from, to) {
1426         Some(val) => Some(val <= 0),
1427         None => None
1428     }
1429 }
1430
1431 pub fn check_expr_has_type(
1432     fcx: &FnCtxt, expr: &ast::Expr,
1433     expected: ty::t) {
1434     check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1435         demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
1436     });
1437 }
1438
1439 fn check_expr_coercable_to_type(fcx: &FnCtxt, expr: &ast::Expr, expected: ty::t) {
1440     check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1441         demand::coerce(fcx, expr.span, expected, expr)
1442     });
1443 }
1444
1445 fn check_expr_with_hint(fcx: &FnCtxt, expr: &ast::Expr, expected: ty::t) {
1446     check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || ())
1447 }
1448
1449 fn check_expr_with_opt_hint(fcx: &FnCtxt, expr: &ast::Expr,
1450                             expected: Option<ty::t>)  {
1451     check_expr_with_unifier(fcx, expr, expected, NoPreference, || ())
1452 }
1453
1454 fn check_expr_with_opt_hint_and_lvalue_pref(fcx: &FnCtxt,
1455                                             expr: &ast::Expr,
1456                                             expected: Option<ty::t>,
1457                                             lvalue_pref: LvaluePreference) {
1458     check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ())
1459 }
1460
1461 fn check_expr(fcx: &FnCtxt, expr: &ast::Expr)  {
1462     check_expr_with_unifier(fcx, expr, None, NoPreference, || ())
1463 }
1464
1465 fn check_expr_with_lvalue_pref(fcx: &FnCtxt, expr: &ast::Expr,
1466                                lvalue_pref: LvaluePreference)  {
1467     check_expr_with_unifier(fcx, expr, None, lvalue_pref, || ())
1468 }
1469
1470
1471 // determine the `self` type, using fresh variables for all variables
1472 // declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
1473 // would return ($0, $1) where $0 and $1 are freshly instantiated type
1474 // variables.
1475 pub fn impl_self_ty(vcx: &VtableContext,
1476                     span: Span, // (potential) receiver for this impl
1477                     did: ast::DefId)
1478                  -> ty_param_substs_and_ty {
1479     let tcx = vcx.tcx();
1480
1481     let ity = ty::lookup_item_type(tcx, did);
1482     let (n_tps, rps, raw_ty) =
1483         (ity.generics.type_param_defs().len(),
1484          ity.generics.region_param_defs(),
1485          ity.ty);
1486
1487     let rps = vcx.infcx.region_vars_for_defs(span, rps);
1488     let tps = vcx.infcx.next_ty_vars(n_tps);
1489
1490     let substs = substs {
1491         regions: ty::NonerasedRegions(rps),
1492         self_ty: None,
1493         tps: tps,
1494     };
1495     let substd_ty = ty::subst(tcx, &substs, raw_ty);
1496
1497     ty_param_substs_and_ty { substs: substs, ty: substd_ty }
1498 }
1499
1500 // Only for fields! Returns <none> for methods>
1501 // Indifferent to privacy flags
1502 pub fn lookup_field_ty(tcx: &ty::ctxt,
1503                        class_id: ast::DefId,
1504                        items: &[ty::field_ty],
1505                        fieldname: ast::Name,
1506                        substs: &ty::substs) -> Option<ty::t> {
1507
1508     let o_field = items.iter().find(|f| f.name == fieldname);
1509     o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
1510 }
1511
1512 // Controls whether the arguments are automatically referenced. This is useful
1513 // for overloaded binary and unary operators.
1514 pub enum DerefArgs {
1515     DontDerefArgs,
1516     DoDerefArgs
1517 }
1518
1519 // Given the provenance of a static method, returns the generics of the static
1520 // method's container.
1521 fn generics_of_static_method_container(type_context: &ty::ctxt,
1522                                        provenance: ast::MethodProvenance)
1523                                        -> ty::Generics {
1524     match provenance {
1525         ast::FromTrait(trait_def_id) => {
1526             ty::lookup_trait_def(type_context, trait_def_id).generics.clone()
1527         }
1528         ast::FromImpl(impl_def_id) => {
1529             ty::lookup_item_type(type_context, impl_def_id).generics.clone()
1530         }
1531     }
1532 }
1533
1534 // Verifies that type parameters supplied in paths are in the right
1535 // locations.
1536 fn check_type_parameter_positions_in_path(function_context: &FnCtxt,
1537                                           path: &ast::Path,
1538                                           def: ast::Def) {
1539     // We only care about checking the case in which the path has two or
1540     // more segments.
1541     if path.segments.len() < 2 {
1542         return
1543     }
1544
1545     // Verify that no lifetimes or type parameters are present anywhere
1546     // except the final two elements of the path.
1547     for i in range(0, path.segments.len() - 2) {
1548         for lifetime in path.segments.get(i).lifetimes.iter() {
1549             function_context.tcx()
1550                 .sess
1551                 .span_err(lifetime.span,
1552                           "lifetime parameters may not \
1553                           appear here");
1554             break;
1555         }
1556
1557         for typ in path.segments.get(i).types.iter() {
1558             function_context.tcx()
1559                             .sess
1560                             .span_err(typ.span,
1561                                       "type parameters may not appear here");
1562             break;
1563         }
1564     }
1565
1566     // If there are no parameters at all, there is nothing more to do; the
1567     // rest of typechecking will (attempt to) infer everything.
1568     if path.segments
1569            .iter()
1570            .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) {
1571         return
1572     }
1573
1574     match def {
1575         // If this is a static method of a trait or implementation, then
1576         // ensure that the segment of the path which names the trait or
1577         // implementation (the penultimate segment) is annotated with the
1578         // right number of type parameters.
1579         ast::DefStaticMethod(_, provenance, _) => {
1580             let generics =
1581                 generics_of_static_method_container(function_context.ccx.tcx,
1582                                                     provenance);
1583             let name = match provenance {
1584                 ast::FromTrait(_) => "trait",
1585                 ast::FromImpl(_) => "impl",
1586             };
1587
1588             let trait_segment = &path.segments.get(path.segments.len() - 2);
1589
1590             // Make sure lifetime parameterization agrees with the trait or
1591             // implementation type.
1592             let trait_region_parameter_count = generics.region_param_defs().len();
1593             let supplied_region_parameter_count = trait_segment.lifetimes.len();
1594             if trait_region_parameter_count != supplied_region_parameter_count
1595                 && supplied_region_parameter_count != 0 {
1596                 function_context.tcx()
1597                     .sess
1598                     .span_err(path.span,
1599                               format!("expected {nexpected, plural, =1{# lifetime parameter} \
1600                                                                  other{# lifetime parameters}}, \
1601                                        found {nsupplied, plural, =1{# lifetime parameter} \
1602                                                               other{# lifetime parameters}}",
1603                                       nexpected = trait_region_parameter_count,
1604                                       nsupplied = supplied_region_parameter_count));
1605             }
1606
1607             // Make sure the number of type parameters supplied on the trait
1608             // or implementation segment equals the number of type parameters
1609             // on the trait or implementation definition.
1610             let formal_ty_param_count = generics.type_param_defs().len();
1611             let required_ty_param_count = generics.type_param_defs().iter()
1612                                                   .take_while(|x| x.default.is_none())
1613                                                   .len();
1614             let supplied_ty_param_count = trait_segment.types.len();
1615             if supplied_ty_param_count < required_ty_param_count {
1616                 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1617                     format!("the {trait_or_impl} referenced by this path needs at least \
1618                              {nexpected, plural, =1{# type parameter} \
1619                                               other{# type parameters}}, \
1620                              but {nsupplied, plural, =1{# type parameter} \
1621                                                   other{# type parameters}} were supplied",
1622                             trait_or_impl = name,
1623                             nexpected = required_ty_param_count,
1624                             nsupplied = supplied_ty_param_count)
1625                 } else {
1626                     format!("the {trait_or_impl} referenced by this path needs \
1627                              {nexpected, plural, =1{# type parameter} \
1628                                               other{# type parameters}}, \
1629                              but {nsupplied, plural, =1{# type parameter} \
1630                                                   other{# type parameters}} were supplied",
1631                             trait_or_impl = name,
1632                             nexpected = required_ty_param_count,
1633                             nsupplied = supplied_ty_param_count)
1634                 };
1635                 function_context.tcx().sess.span_err(path.span, msg)
1636             } else if supplied_ty_param_count > formal_ty_param_count {
1637                 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1638                     format!("the {trait_or_impl} referenced by this path needs at most \
1639                              {nexpected, plural, =1{# type parameter} \
1640                                               other{# type parameters}}, \
1641                              but {nsupplied, plural, =1{# type parameter} \
1642                                                   other{# type parameters}} were supplied",
1643                             trait_or_impl = name,
1644                             nexpected = formal_ty_param_count,
1645                             nsupplied = supplied_ty_param_count)
1646                 } else {
1647                     format!("the {trait_or_impl} referenced by this path needs \
1648                              {nexpected, plural, =1{# type parameter} \
1649                                               other{# type parameters}}, \
1650                              but {nsupplied, plural, =1{# type parameter} \
1651                                                   other{# type parameters}} were supplied",
1652                             trait_or_impl = name,
1653                             nexpected = formal_ty_param_count,
1654                             nsupplied = supplied_ty_param_count)
1655                 };
1656                 function_context.tcx().sess.span_err(path.span, msg)
1657             }
1658         }
1659         _ => {
1660             // Verify that no lifetimes or type parameters are present on
1661             // the penultimate segment of the path.
1662             let segment = &path.segments.get(path.segments.len() - 2);
1663             for lifetime in segment.lifetimes.iter() {
1664                 function_context.tcx()
1665                     .sess
1666                     .span_err(lifetime.span,
1667                               "lifetime parameters may not
1668                               appear here");
1669                 break;
1670             }
1671             for typ in segment.types.iter() {
1672                 function_context.tcx()
1673                                 .sess
1674                                 .span_err(typ.span,
1675                                           "type parameters may not appear \
1676                                            here");
1677                 break;
1678             }
1679         }
1680     }
1681 }
1682
1683 /// Invariant:
1684 /// If an expression has any sub-expressions that result in a type error,
1685 /// inspecting that expression's type with `ty::type_is_error` will return
1686 /// true. Likewise, if an expression is known to diverge, inspecting its
1687 /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
1688 /// strict, _|_ can appear in the type of an expression that does not,
1689 /// itself, diverge: for example, fn() -> _|_.)
1690 /// Note that inspecting a type's structure *directly* may expose the fact
1691 /// that there are actually multiple representations for both `ty_err` and
1692 /// `ty_bot`, so avoid that when err and bot need to be handled differently.
1693 fn check_expr_with_unifier(fcx: &FnCtxt,
1694                            expr: &ast::Expr,
1695                            expected: Option<ty::t>,
1696                            lvalue_pref: LvaluePreference,
1697                            unifier: ||) {
1698     debug!(">> typechecking");
1699
1700     fn check_method_argument_types(
1701         fcx: &FnCtxt,
1702         sp: Span,
1703         method_fn_ty: ty::t,
1704         callee_expr: &ast::Expr,
1705         args: &[@ast::Expr],
1706         deref_args: DerefArgs) -> ty::t {
1707         // HACK(eddyb) ignore provided self (it has special typeck rules).
1708         let args = args.slice_from(1);
1709         if ty::type_is_error(method_fn_ty) {
1710             let err_inputs = err_args(args.len());
1711             check_argument_types(fcx, sp, err_inputs.as_slice(), callee_expr,
1712                                  args, deref_args, false);
1713             method_fn_ty
1714         } else {
1715             match ty::get(method_fn_ty).sty {
1716                 ty::ty_bare_fn(ref fty) => {
1717                     // HACK(eddyb) ignore self in the definition (see above).
1718                     check_argument_types(fcx, sp, fty.sig.inputs.slice_from(1),
1719                                          callee_expr, args, deref_args,
1720                                          fty.sig.variadic);
1721                     fty.sig.output
1722                 }
1723                 _ => {
1724                     fcx.tcx().sess.span_bug(
1725                         sp,
1726                         format!("method without bare fn type"));
1727                 }
1728             }
1729         }
1730     }
1731
1732     fn check_argument_types(fcx: &FnCtxt,
1733                             sp: Span,
1734                             fn_inputs: &[ty::t],
1735                             callee_expr: &ast::Expr,
1736                             args: &[@ast::Expr],
1737                             deref_args: DerefArgs,
1738                             variadic: bool) {
1739         /*!
1740          *
1741          * Generic function that factors out common logic from
1742          * function calls, method calls and overloaded operators.
1743          */
1744
1745         let tcx = fcx.ccx.tcx;
1746
1747         // Grab the argument types, supplying fresh type variables
1748         // if the wrong number of arguments were supplied
1749         let supplied_arg_count = args.len();
1750         let expected_arg_count = fn_inputs.len();
1751         let formal_tys = if expected_arg_count == supplied_arg_count {
1752             fn_inputs.iter().map(|a| *a).collect()
1753         } else if variadic {
1754             if supplied_arg_count >= expected_arg_count {
1755                 fn_inputs.iter().map(|a| *a).collect()
1756             } else {
1757                 let msg = format!(
1758                     "this function takes at least {nexpected, plural, =1{# parameter} \
1759                                                                    other{# parameters}} \
1760                      but {nsupplied, plural, =1{# parameter was} \
1761                                           other{# parameters were}} supplied",
1762                      nexpected = expected_arg_count,
1763                      nsupplied = supplied_arg_count);
1764
1765                 tcx.sess.span_err(sp, msg);
1766
1767                 err_args(supplied_arg_count)
1768             }
1769         } else {
1770             let msg = format!(
1771                 "this function takes {nexpected, plural, =1{# parameter} \
1772                                                       other{# parameters}} \
1773                  but {nsupplied, plural, =1{# parameter was} \
1774                                       other{# parameters were}} supplied",
1775                  nexpected = expected_arg_count,
1776                  nsupplied = supplied_arg_count);
1777
1778             tcx.sess.span_err(sp, msg);
1779
1780             err_args(supplied_arg_count)
1781         };
1782
1783         debug!("check_argument_types: formal_tys={:?}",
1784                formal_tys.iter().map(|t| fcx.infcx().ty_to_str(*t)).collect::<Vec<~str>>());
1785
1786         // Check the arguments.
1787         // We do this in a pretty awful way: first we typecheck any arguments
1788         // that are not anonymous functions, then we typecheck the anonymous
1789         // functions. This is so that we have more information about the types
1790         // of arguments when we typecheck the functions. This isn't really the
1791         // right way to do this.
1792         let xs = [false, true];
1793         for check_blocks in xs.iter() {
1794             let check_blocks = *check_blocks;
1795             debug!("check_blocks={}", check_blocks);
1796
1797             // More awful hacks: before we check the blocks, try to do
1798             // an "opportunistic" vtable resolution of any trait
1799             // bounds on the call.
1800             if check_blocks {
1801                 vtable::early_resolve_expr(callee_expr, fcx, true);
1802             }
1803
1804             // For variadic functions, we don't have a declared type for all of
1805             // the arguments hence we only do our usual type checking with
1806             // the arguments who's types we do know.
1807             let t = if variadic {
1808                 expected_arg_count
1809             } else {
1810                 supplied_arg_count
1811             };
1812             for (i, arg) in args.iter().take(t).enumerate() {
1813                 let is_block = match arg.node {
1814                     ast::ExprFnBlock(..) |
1815                     ast::ExprProc(..) => true,
1816                     _ => false
1817                 };
1818
1819                 if is_block == check_blocks {
1820                     debug!("checking the argument");
1821                     let mut formal_ty = *formal_tys.get(i);
1822
1823                     match deref_args {
1824                         DoDerefArgs => {
1825                             match ty::get(formal_ty).sty {
1826                                 ty::ty_rptr(_, mt) => formal_ty = mt.ty,
1827                                 ty::ty_err => (),
1828                                 _ => {
1829                                     // So we hit this case when one implements the
1830                                     // operator traits but leaves an argument as
1831                                     // just T instead of &T. We'll catch it in the
1832                                     // mismatch impl/trait method phase no need to
1833                                     // ICE here.
1834                                     // See: #11450
1835                                     formal_ty = ty::mk_err();
1836                                 }
1837                             }
1838                         }
1839                         DontDerefArgs => {}
1840                     }
1841
1842                     check_expr_coercable_to_type(fcx, *arg, formal_ty);
1843
1844                 }
1845             }
1846         }
1847
1848         // We also need to make sure we at least write the ty of the other
1849         // arguments which we skipped above.
1850         if variadic {
1851             for arg in args.iter().skip(expected_arg_count) {
1852                 check_expr(fcx, *arg);
1853
1854                 // There are a few types which get autopromoted when passed via varargs
1855                 // in C but we just error out instead and require explicit casts.
1856                 let arg_ty = structurally_resolved_type(fcx, arg.span, fcx.expr_ty(*arg));
1857                 match ty::get(arg_ty).sty {
1858                     ty::ty_float(ast::TyF32) => {
1859                         fcx.type_error_message(arg.span,
1860                                 |t| format!("can't pass an {} to variadic function, \
1861                                              cast to c_double", t), arg_ty, None);
1862                     }
1863                     ty::ty_int(ast::TyI8) | ty::ty_int(ast::TyI16) | ty::ty_bool => {
1864                         fcx.type_error_message(arg.span,
1865                                 |t| format!("can't pass {} to variadic function, cast to c_int",
1866                                             t), arg_ty, None);
1867                     }
1868                     ty::ty_uint(ast::TyU8) | ty::ty_uint(ast::TyU16) => {
1869                         fcx.type_error_message(arg.span,
1870                                 |t| format!("can't pass {} to variadic function, cast to c_uint",
1871                                             t), arg_ty, None);
1872                     }
1873                     _ => {}
1874                 }
1875             }
1876         }
1877     }
1878
1879     fn err_args(len: uint) -> Vec<ty::t> {
1880         Vec::from_fn(len, |_| ty::mk_err())
1881     }
1882
1883     fn write_call(fcx: &FnCtxt, call_expr: &ast::Expr, output: ty::t) {
1884         fcx.write_ty(call_expr.id, output);
1885     }
1886
1887     // A generic function for doing all of the checking for call expressions
1888     fn check_call(fcx: &FnCtxt,
1889                   call_expr: &ast::Expr,
1890                   f: &ast::Expr,
1891                   args: &[@ast::Expr]) {
1892         // Index expressions need to be handled separately, to inform them
1893         // that they appear in call position.
1894         check_expr(fcx, f);
1895
1896         // Store the type of `f` as the type of the callee
1897         let fn_ty = fcx.expr_ty(f);
1898
1899         // Extract the function signature from `in_fty`.
1900         let fn_sty = structure_of(fcx, f.span, fn_ty);
1901
1902         // This is the "default" function signature, used in case of error.
1903         // In that case, we check each argument against "error" in order to
1904         // set up all the node type bindings.
1905         let error_fn_sig = FnSig {
1906             binder_id: ast::CRATE_NODE_ID,
1907             inputs: err_args(args.len()),
1908             output: ty::mk_err(),
1909             variadic: false
1910         };
1911
1912         let fn_sig = match *fn_sty {
1913             ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, ..}) |
1914             ty::ty_closure(~ty::ClosureTy {sig: ref sig, ..}) => sig,
1915             _ => {
1916                 fcx.type_error_message(call_expr.span, |actual| {
1917                     format!("expected function but \
1918                           found `{}`", actual) }, fn_ty, None);
1919                 &error_fn_sig
1920             }
1921         };
1922
1923         // Replace any bound regions that appear in the function
1924         // signature with region variables
1925         let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
1926             fcx.infcx().next_region_var(infer::LateBoundRegion(call_expr.span, br))
1927         });
1928
1929         // Call the generic checker.
1930         check_argument_types(fcx, call_expr.span, fn_sig.inputs.as_slice(), f,
1931                              args, DontDerefArgs, fn_sig.variadic);
1932
1933         write_call(fcx, call_expr, fn_sig.output);
1934     }
1935
1936     // Checks a method call.
1937     fn check_method_call(fcx: &FnCtxt,
1938                          expr: &ast::Expr,
1939                          method_name: ast::Ident,
1940                          args: &[@ast::Expr],
1941                          tps: &[ast::P<ast::Ty>]) {
1942         let rcvr = args[0];
1943         // We can't know if we need &mut self before we look up the method,
1944         // so treat the receiver as mutable just in case - only explicit
1945         // overloaded dereferences care about the distinction.
1946         check_expr_with_lvalue_pref(fcx, rcvr, PreferMutLvalue);
1947
1948         // no need to check for bot/err -- callee does that
1949         let expr_t = structurally_resolved_type(fcx,
1950                                                 expr.span,
1951                                                 fcx.expr_ty(rcvr));
1952
1953         let tps = tps.iter().map(|&ast_ty| fcx.to_ty(ast_ty)).collect::<Vec<_>>();
1954         let fn_ty = match method::lookup(fcx, expr, rcvr,
1955                                          method_name.name,
1956                                          expr_t, tps.as_slice(),
1957                                          DontDerefArgs,
1958                                          CheckTraitsAndInherentMethods,
1959                                          AutoderefReceiver) {
1960             Some(method) => {
1961                 let method_ty = method.ty;
1962                 let method_call = MethodCall::expr(expr.id);
1963                 fcx.inh.method_map.borrow_mut().insert(method_call, method);
1964                 method_ty
1965             }
1966             None => {
1967                 debug!("(checking method call) failing expr is {}", expr.id);
1968
1969                 fcx.type_error_message(expr.span,
1970                   |actual| {
1971                       format!("type `{}` does not implement any method in scope \
1972                             named `{}`",
1973                            actual, token::get_ident(method_name))
1974                   },
1975                   expr_t,
1976                   None);
1977
1978                 // Add error type for the result
1979                 fcx.write_error(expr.id);
1980                 ty::mk_err()
1981             }
1982         };
1983
1984         // Call the generic checker.
1985         let ret_ty = check_method_argument_types(fcx, expr.span,
1986                                                  fn_ty, expr, args,
1987                                                  DontDerefArgs);
1988
1989         write_call(fcx, expr, ret_ty);
1990     }
1991
1992     // A generic function for checking the then and else in an if
1993     // or if-check
1994     fn check_then_else(fcx: &FnCtxt,
1995                        cond_expr: &ast::Expr,
1996                        then_blk: &ast::Block,
1997                        opt_else_expr: Option<@ast::Expr>,
1998                        id: ast::NodeId,
1999                        sp: Span,
2000                        expected: Option<ty::t>) {
2001         check_expr_has_type(fcx, cond_expr, ty::mk_bool());
2002
2003         let branches_ty = match opt_else_expr {
2004             Some(else_expr) => {
2005                 check_block_with_expected(fcx, then_blk, expected);
2006                 let then_ty = fcx.node_ty(then_blk.id);
2007                 check_expr_with_opt_hint(fcx, else_expr, expected);
2008                 let else_ty = fcx.expr_ty(else_expr);
2009                 infer::common_supertype(fcx.infcx(),
2010                                         infer::IfExpression(sp),
2011                                         true,
2012                                         then_ty,
2013                                         else_ty)
2014             }
2015             None => {
2016                 check_block_no_value(fcx, then_blk);
2017                 ty::mk_nil()
2018             }
2019         };
2020
2021         let cond_ty = fcx.expr_ty(cond_expr);
2022         let if_ty = if ty::type_is_error(cond_ty) {
2023             ty::mk_err()
2024         } else if ty::type_is_bot(cond_ty) {
2025             ty::mk_bot()
2026         } else {
2027             branches_ty
2028         };
2029
2030         fcx.write_ty(id, if_ty);
2031     }
2032
2033     fn lookup_op_method(fcx: &FnCtxt,
2034                         op_ex: &ast::Expr,
2035                         self_t: ty::t,
2036                         opname: ast::Name,
2037                         trait_did: Option<ast::DefId>,
2038                         args: &[@ast::Expr],
2039                         autoderef_receiver: AutoderefReceiverFlag,
2040                         unbound_method: ||) -> ty::t {
2041         let method = match trait_did {
2042             Some(trait_did) => {
2043                 method::lookup_in_trait(fcx, op_ex.span, Some(&*args[0]), opname,
2044                                         trait_did, self_t, [], autoderef_receiver)
2045             }
2046             None => None
2047         };
2048         match method {
2049             Some(method) => {
2050                 let method_ty = method.ty;
2051                 // HACK(eddyb) Fully qualified path to work around a resolve bug.
2052                 let method_call = ::middle::typeck::MethodCall::expr(op_ex.id);
2053                 fcx.inh.method_map.borrow_mut().insert(method_call, method);
2054                 check_method_argument_types(fcx, op_ex.span,
2055                                             method_ty, op_ex,
2056                                             args, DoDerefArgs)
2057             }
2058             None => {
2059                 unbound_method();
2060                 // Check the args anyway
2061                 // so we get all the error messages
2062                 let expected_ty = ty::mk_err();
2063                 check_method_argument_types(fcx, op_ex.span,
2064                                             expected_ty, op_ex,
2065                                             args, DoDerefArgs);
2066                 ty::mk_err()
2067             }
2068         }
2069     }
2070
2071     // could be either an expr_binop or an expr_assign_binop
2072     fn check_binop(fcx: &FnCtxt,
2073                    expr: &ast::Expr,
2074                    op: ast::BinOp,
2075                    lhs: @ast::Expr,
2076                    rhs: @ast::Expr,
2077                    is_binop_assignment: IsBinopAssignment) {
2078         let tcx = fcx.ccx.tcx;
2079
2080         let lvalue_pref = match is_binop_assignment {
2081             BinopAssignment => PreferMutLvalue,
2082             SimpleBinop => NoPreference
2083         };
2084         check_expr_with_lvalue_pref(fcx, lhs, lvalue_pref);
2085
2086         // Callee does bot / err checking
2087         let lhs_t = structurally_resolved_type(fcx, lhs.span,
2088                                                fcx.expr_ty(lhs));
2089
2090         if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) {
2091             // Shift is a special case: rhs can be any integral type
2092             check_expr(fcx, rhs);
2093             let rhs_t = fcx.expr_ty(rhs);
2094             require_integral(fcx, rhs.span, rhs_t);
2095             fcx.write_ty(expr.id, lhs_t);
2096             return;
2097         }
2098
2099         if ty::is_binopable(tcx, lhs_t, op) {
2100             let tvar = fcx.infcx().next_ty_var();
2101             demand::suptype(fcx, expr.span, tvar, lhs_t);
2102             check_expr_has_type(fcx, rhs, tvar);
2103
2104             let result_t = match op {
2105                 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGe |
2106                 ast::BiGt => ty::mk_bool(),
2107                 _ => lhs_t
2108             };
2109
2110             fcx.write_ty(expr.id, result_t);
2111             return;
2112         }
2113
2114         if op == ast::BiOr || op == ast::BiAnd {
2115             // This is an error; one of the operands must have the wrong
2116             // type
2117             fcx.write_error(expr.id);
2118             fcx.write_error(rhs.id);
2119             fcx.type_error_message(expr.span, |actual| {
2120                 format!("binary operation `{}` cannot be applied \
2121                       to type `{}`",
2122                      ast_util::binop_to_str(op), actual)},
2123                                    lhs_t, None)
2124
2125         }
2126
2127         // Check for overloaded operators if not an assignment.
2128         let result_t = if is_binop_assignment == SimpleBinop {
2129             check_user_binop(fcx, expr, lhs, lhs_t, op, rhs)
2130         } else {
2131             fcx.type_error_message(expr.span,
2132                                    |actual| {
2133                                         format!("binary assignment operation \
2134                                                 `{}=` cannot be applied to type `{}`",
2135                                                 ast_util::binop_to_str(op),
2136                                                 actual)
2137                                    },
2138                                    lhs_t,
2139                                    None);
2140             check_expr(fcx, rhs);
2141             ty::mk_err()
2142         };
2143
2144         fcx.write_ty(expr.id, result_t);
2145         if ty::type_is_error(result_t) {
2146             fcx.write_ty(rhs.id, result_t);
2147         }
2148     }
2149
2150     fn check_user_binop(fcx: &FnCtxt,
2151                         ex: &ast::Expr,
2152                         lhs_expr: @ast::Expr,
2153                         lhs_resolved_t: ty::t,
2154                         op: ast::BinOp,
2155                         rhs: @ast::Expr) -> ty::t {
2156         let tcx = fcx.ccx.tcx;
2157         let lang = &tcx.lang_items;
2158         let (name, trait_did) = match op {
2159             ast::BiAdd => ("add", lang.add_trait()),
2160             ast::BiSub => ("sub", lang.sub_trait()),
2161             ast::BiMul => ("mul", lang.mul_trait()),
2162             ast::BiDiv => ("div", lang.div_trait()),
2163             ast::BiRem => ("rem", lang.rem_trait()),
2164             ast::BiBitXor => ("bitxor", lang.bitxor_trait()),
2165             ast::BiBitAnd => ("bitand", lang.bitand_trait()),
2166             ast::BiBitOr => ("bitor", lang.bitor_trait()),
2167             ast::BiShl => ("shl", lang.shl_trait()),
2168             ast::BiShr => ("shr", lang.shr_trait()),
2169             ast::BiLt => ("lt", lang.ord_trait()),
2170             ast::BiLe => ("le", lang.ord_trait()),
2171             ast::BiGe => ("ge", lang.ord_trait()),
2172             ast::BiGt => ("gt", lang.ord_trait()),
2173             ast::BiEq => ("eq", lang.eq_trait()),
2174             ast::BiNe => ("ne", lang.eq_trait()),
2175             ast::BiAnd | ast::BiOr => {
2176                 check_expr(fcx, rhs);
2177                 return ty::mk_err();
2178             }
2179         };
2180         lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
2181                          trait_did, [lhs_expr, rhs], DontAutoderefReceiver, || {
2182             fcx.type_error_message(ex.span, |actual| {
2183                 format!("binary operation `{}` cannot be applied to type `{}`",
2184                     ast_util::binop_to_str(op), actual)
2185             }, lhs_resolved_t, None)
2186         })
2187     }
2188
2189     fn check_user_unop(fcx: &FnCtxt,
2190                        op_str: &str,
2191                        mname: &str,
2192                        trait_did: Option<ast::DefId>,
2193                        ex: &ast::Expr,
2194                        rhs_expr: @ast::Expr,
2195                        rhs_t: ty::t) -> ty::t {
2196        lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
2197                         trait_did, [rhs_expr], DontAutoderefReceiver, || {
2198             fcx.type_error_message(ex.span, |actual| {
2199                 format!("cannot apply unary operator `{}` to type `{}`", op_str, actual)
2200             }, rhs_t, None);
2201         })
2202     }
2203
2204     // Resolves `expected` by a single level if it is a variable and passes it
2205     // through the `unpack` function.  It there is no expected type or
2206     // resolution is not possible (e.g., no constraints yet present), just
2207     // returns `none`.
2208     fn unpack_expected<O>(
2209                        fcx: &FnCtxt,
2210                        expected: Option<ty::t>,
2211                        unpack: |&ty::sty| -> Option<O>)
2212                        -> Option<O> {
2213         match expected {
2214             Some(t) => {
2215                 match resolve_type(fcx.infcx(), t, force_tvar) {
2216                     Ok(t) => unpack(&ty::get(t).sty),
2217                     _ => None
2218                 }
2219             }
2220             _ => None
2221         }
2222     }
2223
2224     fn check_expr_fn(fcx: &FnCtxt,
2225                      expr: &ast::Expr,
2226                      store: ty::TraitStore,
2227                      decl: &ast::FnDecl,
2228                      body: ast::P<ast::Block>,
2229                      fn_kind: FnKind,
2230                      expected: Option<ty::t>) {
2231         let tcx = fcx.ccx.tcx;
2232
2233         // Find the expected input/output types (if any). Substitute
2234         // fresh bound regions for any bound regions we find in the
2235         // expected types so as to avoid capture.
2236         let expected_sty = unpack_expected(fcx,
2237                                            expected,
2238                                            |x| Some((*x).clone()));
2239         let (expected_sig,
2240              expected_onceness,
2241              expected_bounds) = {
2242             match expected_sty {
2243                 Some(ty::ty_closure(ref cenv)) => {
2244                     let (_, sig) =
2245                         replace_late_bound_regions_in_fn_sig(
2246                             tcx, &cenv.sig,
2247                             |_| fcx.inh.infcx.fresh_bound_region(expr.id));
2248                     let onceness = match (&store, &cenv.store) {
2249                         // As the closure type and onceness go, only three
2250                         // combinations are legit:
2251                         //      once closure
2252                         //      many closure
2253                         //      once proc
2254                         // If the actual and expected closure type disagree with
2255                         // each other, set expected onceness to be always Once or
2256                         // Many according to the actual type. Otherwise, it will
2257                         // yield either an illegal "many proc" or a less known
2258                         // "once closure" in the error message.
2259                         (&ty::UniqTraitStore, &ty::UniqTraitStore) |
2260                         (&ty::RegionTraitStore(..), &ty::RegionTraitStore(..)) =>
2261                             cenv.onceness,
2262                         (&ty::UniqTraitStore, _) => ast::Once,
2263                         (&ty::RegionTraitStore(..), _) => ast::Many,
2264                     };
2265                     (Some(sig), onceness, cenv.bounds)
2266                 }
2267                 _ => {
2268                     // Not an error! Means we're inferring the closure type
2269                     let mut bounds = ty::EmptyBuiltinBounds();
2270                     let onceness = match expr.node {
2271                         ast::ExprProc(..) => {
2272                             bounds.add(ty::BoundSend);
2273                             ast::Once
2274                         }
2275                         _ => ast::Many
2276                     };
2277                     (None, onceness, bounds)
2278                 }
2279             }
2280         };
2281
2282         // construct the function type
2283         let fn_ty = astconv::ty_of_closure(fcx,
2284                                            expr.id,
2285                                            ast::NormalFn,
2286                                            expected_onceness,
2287                                            expected_bounds,
2288                                            store,
2289                                            decl,
2290                                            expected_sig);
2291         let fty_sig = fn_ty.sig.clone();
2292         let fty = ty::mk_closure(tcx, fn_ty);
2293         debug!("check_expr_fn fty={}", fcx.infcx().ty_to_str(fty));
2294
2295         fcx.write_ty(expr.id, fty);
2296
2297         // If the closure is a stack closure and hasn't had some non-standard
2298         // style inferred for it, then check it under its parent's style.
2299         // Otherwise, use its own
2300         let (inherited_style, id) = match store {
2301             ty::RegionTraitStore(..) => (fcx.ps.borrow().fn_style,
2302                                          fcx.ps.borrow().def),
2303             ty::UniqTraitStore => (ast::NormalFn, expr.id)
2304         };
2305
2306         check_fn(fcx.ccx, inherited_style, &fty_sig,
2307                  decl, id, body, fn_kind, fcx.inh);
2308     }
2309
2310
2311     // Check field access expressions
2312     fn check_field(fcx: &FnCtxt,
2313                    expr: &ast::Expr,
2314                    lvalue_pref: LvaluePreference,
2315                    base: &ast::Expr,
2316                    field: ast::Name,
2317                    tys: &[ast::P<ast::Ty>]) {
2318         let tcx = fcx.ccx.tcx;
2319         check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
2320         let expr_t = structurally_resolved_type(fcx, expr.span,
2321                                                 fcx.expr_ty(base));
2322         // FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
2323         let (_, autoderefs, field_ty) =
2324             autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
2325                 match ty::get(base_t).sty {
2326                     ty::ty_struct(base_id, ref substs) => {
2327                         debug!("struct named {}", ppaux::ty_to_str(tcx, base_t));
2328                         let fields = ty::lookup_struct_fields(tcx, base_id);
2329                         lookup_field_ty(tcx, base_id, fields.as_slice(), field, &(*substs))
2330                     }
2331                     _ => None
2332                 }
2333             });
2334         match field_ty {
2335             Some(field_ty) => {
2336                 fcx.write_ty(expr.id, field_ty);
2337                 fcx.write_autoderef_adjustment(base.id, autoderefs);
2338                 return;
2339             }
2340             None => {}
2341         }
2342
2343         let tps: Vec<ty::t> = tys.iter().map(|&ty| fcx.to_ty(ty)).collect();
2344         match method::lookup(fcx,
2345                              expr,
2346                              base,
2347                              field,
2348                              expr_t,
2349                              tps.as_slice(),
2350                              DontDerefArgs,
2351                              CheckTraitsAndInherentMethods,
2352                              AutoderefReceiver) {
2353             Some(_) => {
2354                 fcx.type_error_message(
2355                     expr.span,
2356                     |actual| {
2357                         format!("attempted to take value of method `{}` on type `{}`",
2358                                 token::get_name(field), actual)
2359                     },
2360                     expr_t, None);
2361
2362                 tcx.sess.span_note(expr.span,
2363                     "maybe a missing `()` to call it? If not, try an anonymous function.");
2364             }
2365
2366             None => {
2367                 fcx.type_error_message(
2368                     expr.span,
2369                     |actual| {
2370                         format!("attempted access of field `{}` on type `{}`, \
2371                                  but no field with that name was found",
2372                                 token::get_name(field), actual)
2373                     },
2374                     expr_t, None);
2375             }
2376         }
2377
2378         fcx.write_error(expr.id);
2379     }
2380
2381     fn check_struct_or_variant_fields(fcx: &FnCtxt,
2382                                       struct_ty: ty::t,
2383                                       span: Span,
2384                                       class_id: ast::DefId,
2385                                       node_id: ast::NodeId,
2386                                       substitutions: ty::substs,
2387                                       field_types: &[ty::field_ty],
2388                                       ast_fields: &[ast::Field],
2389                                       check_completeness: bool)  {
2390         let tcx = fcx.ccx.tcx;
2391
2392         let mut class_field_map = HashMap::new();
2393         let mut fields_found = 0;
2394         for field in field_types.iter() {
2395             class_field_map.insert(field.name, (field.id, false));
2396         }
2397
2398         let mut error_happened = false;
2399
2400         // Typecheck each field.
2401         for field in ast_fields.iter() {
2402             let mut expected_field_type = ty::mk_err();
2403
2404             let pair = class_field_map.find(&field.ident.node.name).map(|x| *x);
2405             match pair {
2406                 None => {
2407                     fcx.type_error_message(
2408                       field.ident.span,
2409                       |actual| {
2410                           format!("structure `{}` has no field named `{}`",
2411                                   actual, token::get_ident(field.ident.node))
2412                     }, struct_ty, None);
2413                     error_happened = true;
2414                 }
2415                 Some((_, true)) => {
2416                     tcx.sess.span_err(
2417                         field.ident.span,
2418                         format!("field `{}` specified more than once",
2419                             token::get_ident(field.ident.node)));
2420                     error_happened = true;
2421                 }
2422                 Some((field_id, false)) => {
2423                     expected_field_type =
2424                         ty::lookup_field_type(
2425                             tcx, class_id, field_id, &substitutions);
2426                     class_field_map.insert(
2427                         field.ident.node.name, (field_id, true));
2428                     fields_found += 1;
2429                 }
2430             }
2431             // Make sure to give a type to the field even if there's
2432             // an error, so we can continue typechecking
2433             check_expr_coercable_to_type(
2434                     fcx,
2435                     field.expr,
2436                     expected_field_type);
2437         }
2438
2439         if error_happened {
2440             fcx.write_error(node_id);
2441         }
2442
2443         if check_completeness && !error_happened {
2444             // Make sure the programmer specified all the fields.
2445             assert!(fields_found <= field_types.len());
2446             if fields_found < field_types.len() {
2447                 let mut missing_fields = Vec::new();
2448                 for class_field in field_types.iter() {
2449                     let name = class_field.name;
2450                     let (_, seen) = *class_field_map.get(&name);
2451                     if !seen {
2452                         missing_fields.push("`".to_owned() + token::get_name(name).get() + "`");
2453                     }
2454                 }
2455
2456                 tcx.sess.span_err(span,
2457                     format!("missing {nfields, plural, =1{field} other{fields}}: {fields}",
2458                             nfields = missing_fields.len(),
2459                             fields = missing_fields.connect(", ")));
2460              }
2461         }
2462
2463         if !error_happened {
2464             fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx,
2465                                 class_id, substitutions));
2466         }
2467     }
2468
2469     fn check_struct_constructor(fcx: &FnCtxt,
2470                                 id: ast::NodeId,
2471                                 span: codemap::Span,
2472                                 class_id: ast::DefId,
2473                                 fields: &[ast::Field],
2474                                 base_expr: Option<@ast::Expr>) {
2475         let tcx = fcx.ccx.tcx;
2476
2477         // Look up the number of type parameters and the raw type, and
2478         // determine whether the class is region-parameterized.
2479         let item_type = ty::lookup_item_type(tcx, class_id);
2480         let type_parameter_count = item_type.generics.type_param_defs().len();
2481         let region_param_defs = item_type.generics.region_param_defs();
2482         let raw_type = item_type.ty;
2483
2484         // Generate the struct type.
2485         let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs);
2486         let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2487         let substitutions = substs {
2488             regions: ty::NonerasedRegions(regions),
2489             self_ty: None,
2490             tps: type_parameters
2491         };
2492
2493         let mut struct_type = ty::subst(tcx, &substitutions, raw_type);
2494
2495         // Look up and check the fields.
2496         let class_fields = ty::lookup_struct_fields(tcx, class_id);
2497         check_struct_or_variant_fields(fcx,
2498                                        struct_type,
2499                                        span,
2500                                        class_id,
2501                                        id,
2502                                        substitutions,
2503                                        class_fields.as_slice(),
2504                                        fields,
2505                                        base_expr.is_none());
2506         if ty::type_is_error(fcx.node_ty(id)) {
2507             struct_type = ty::mk_err();
2508         }
2509
2510         // Check the base expression if necessary.
2511         match base_expr {
2512             None => {}
2513             Some(base_expr) => {
2514                 check_expr_has_type(fcx, base_expr, struct_type);
2515                 if ty::type_is_bot(fcx.node_ty(base_expr.id)) {
2516                     struct_type = ty::mk_bot();
2517                 }
2518             }
2519         }
2520
2521         // Write in the resulting type.
2522         fcx.write_ty(id, struct_type);
2523     }
2524
2525     fn check_struct_enum_variant(fcx: &FnCtxt,
2526                                  id: ast::NodeId,
2527                                  span: codemap::Span,
2528                                  enum_id: ast::DefId,
2529                                  variant_id: ast::DefId,
2530                                  fields: &[ast::Field]) {
2531         let tcx = fcx.ccx.tcx;
2532
2533         // Look up the number of type parameters and the raw type, and
2534         // determine whether the enum is region-parameterized.
2535         let item_type = ty::lookup_item_type(tcx, enum_id);
2536         let type_parameter_count = item_type.generics.type_param_defs().len();
2537         let region_param_defs = item_type.generics.region_param_defs();
2538         let raw_type = item_type.ty;
2539
2540         // Generate the enum type.
2541         let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs);
2542         let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2543         let substitutions = substs {
2544             regions: ty::NonerasedRegions(regions),
2545             self_ty: None,
2546             tps: type_parameters
2547         };
2548
2549         let enum_type = ty::subst(tcx, &substitutions, raw_type);
2550
2551         // Look up and check the enum variant fields.
2552         let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2553         check_struct_or_variant_fields(fcx,
2554                                        enum_type,
2555                                        span,
2556                                        variant_id,
2557                                        id,
2558                                        substitutions,
2559                                        variant_fields.as_slice(),
2560                                        fields,
2561                                        true);
2562         fcx.write_ty(id, enum_type);
2563     }
2564
2565     let tcx = fcx.ccx.tcx;
2566     let id = expr.id;
2567     match expr.node {
2568       ast::ExprVstore(ev, vst) => {
2569         let typ = match ev.node {
2570           ast::ExprLit(lit) if ast_util::lit_is_str(lit) => {
2571             let v = ast_expr_vstore_to_vstore(fcx, ev, vst);
2572             ty::mk_str(tcx, v)
2573           }
2574           ast::ExprVec(ref args) => {
2575             let mutability = match vst {
2576                 ast::ExprVstoreMutSlice => ast::MutMutable,
2577                 _ => ast::MutImmutable,
2578             };
2579             let v = ast_expr_vstore_to_vstore(fcx, ev, vst);
2580             let mut any_error = false;
2581             let mut any_bot = false;
2582             let t: ty::t = fcx.infcx().next_ty_var();
2583             for e in args.iter() {
2584                 check_expr_has_type(fcx, *e, t);
2585                 let arg_t = fcx.expr_ty(*e);
2586                 if ty::type_is_error(arg_t) {
2587                     any_error = true;
2588                 }
2589                 else if ty::type_is_bot(arg_t) {
2590                     any_bot = true;
2591                 }
2592             }
2593             if any_error {
2594                 ty::mk_err()
2595             } else if any_bot {
2596                 ty::mk_bot()
2597             } else {
2598                 match v {
2599                     ty::VstoreFixed(sz) => ty::mk_vec(tcx,
2600                                                       ty::mt {ty: t, mutbl: mutability},
2601                                                       Some(sz)),
2602                     ty::VstoreUniq => ty::mk_uniq(tcx,
2603                                                   ty::mk_vec(tcx,
2604                                                              ty::mt {ty: t, mutbl: mutability},
2605                                                              None)), // Sadly, we know the length
2606                                                                      // - Some(args.len()) - but
2607                                                                      // must throw it away or cause
2608                                                                      // confusion further down the
2609                                                                      // pipeline. Hopefully we can
2610                                                                      // remedy this later.
2611                                                                      // See below (x3) too.
2612                     ty::VstoreSlice(r) => ty::mk_slice(tcx, r,
2613                                                        ty::mt {ty: t, mutbl: mutability}),
2614                 }
2615             }
2616           }
2617           ast::ExprRepeat(element, count_expr) => {
2618             check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2619             let _ = ty::eval_repeat_count(fcx, count_expr);
2620             let mutability = match vst {
2621                 ast::ExprVstoreMutSlice => ast::MutMutable,
2622                 _ => ast::MutImmutable,
2623             };
2624             let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2625             let t = fcx.infcx().next_ty_var();
2626             check_expr_has_type(fcx, element, t);
2627             let arg_t = fcx.expr_ty(element);
2628             if ty::type_is_error(arg_t) {
2629                 ty::mk_err()
2630             } else if ty::type_is_bot(arg_t) {
2631                 ty::mk_bot()
2632             } else {
2633                 match tt {
2634                     ty::VstoreFixed(sz) => ty::mk_vec(tcx,
2635                                                       ty::mt {ty: t, mutbl: mutability},
2636                                                       Some(sz)),
2637                     ty::VstoreUniq => ty::mk_uniq(tcx,
2638                                                   ty::mk_vec(tcx,
2639                                                              ty::mt {ty: t, mutbl: mutability},
2640                                                              None)),
2641                     ty::VstoreSlice(r) => ty::mk_slice(tcx, r,
2642                                                        ty::mt {ty: t, mutbl: mutability}),
2643                 }
2644             }
2645           }
2646           _ =>
2647             tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence")
2648         };
2649         fcx.write_ty(ev.id, typ);
2650         fcx.write_ty(id, typ);
2651       }
2652
2653       ast::ExprBox(place, subexpr) => {
2654           check_expr(fcx, place);
2655           check_expr(fcx, subexpr);
2656
2657           let mut checked = false;
2658           match place.node {
2659               ast::ExprPath(ref path) => {
2660                   // FIXME(pcwalton): For now we hardcode the two permissible
2661                   // places: the exchange heap and the managed heap.
2662                   let definition = lookup_def(fcx, path.span, place.id);
2663                   let def_id = ast_util::def_id_of_def(definition);
2664                   match tcx.lang_items
2665                            .items
2666                            .get(ExchangeHeapLangItem as uint) {
2667                       &Some(item_def_id) if def_id == item_def_id => {
2668                           fcx.write_ty(id, ty::mk_uniq(tcx,
2669                                                        fcx.expr_ty(subexpr)));
2670                           checked = true
2671                       }
2672                       &Some(_) | &None => {}
2673                   }
2674                   if !checked {
2675                       match tcx.lang_items
2676                                .items
2677                                .get(ManagedHeapLangItem as uint) {
2678                           &Some(item_def_id) if def_id == item_def_id => {
2679                               // Assign the magic `Gc<T>` struct.
2680                               let gc_struct_id =
2681                                   match tcx.lang_items
2682                                            .require(GcLangItem) {
2683                                       Ok(id) => id,
2684                                       Err(msg) => {
2685                                           tcx.sess.span_err(expr.span, msg);
2686                                           ast::DefId {
2687                                               krate: ast::CRATE_NODE_ID,
2688                                               node: ast::DUMMY_NODE_ID,
2689                                           }
2690                                       }
2691                                   };
2692                               let regions =
2693                                   ty::NonerasedRegions(OwnedSlice::empty());
2694                               let sty = ty::mk_struct(tcx,
2695                                                       gc_struct_id,
2696                                                       substs {
2697                                                         self_ty: None,
2698                                                         tps: vec!(
2699                                                             fcx.expr_ty(
2700                                                                 subexpr)
2701                                                         ),
2702                                                         regions: regions,
2703                                                       });
2704                               fcx.write_ty(id, sty);
2705                               checked = true
2706                           }
2707                           &Some(_) | &None => {}
2708                       }
2709                   }
2710               }
2711               _ => {}
2712           }
2713
2714           if !checked {
2715               tcx.sess.span_err(expr.span,
2716                                 "only the managed heap and exchange heap are \
2717                                  currently supported")
2718           }
2719       }
2720
2721       ast::ExprLit(lit) => {
2722         let typ = check_lit(fcx, lit);
2723         fcx.write_ty(id, typ);
2724       }
2725       ast::ExprBinary(op, lhs, rhs) => {
2726         check_binop(fcx, expr, op, lhs, rhs, SimpleBinop);
2727
2728         let lhs_ty = fcx.expr_ty(lhs);
2729         let rhs_ty = fcx.expr_ty(rhs);
2730         if ty::type_is_error(lhs_ty) ||
2731             ty::type_is_error(rhs_ty) {
2732             fcx.write_error(id);
2733         }
2734         else if ty::type_is_bot(lhs_ty) ||
2735           (ty::type_is_bot(rhs_ty) && !ast_util::lazy_binop(op)) {
2736             fcx.write_bot(id);
2737         }
2738       }
2739       ast::ExprAssignOp(op, lhs, rhs) => {
2740         check_binop(fcx, expr, op, lhs, rhs, BinopAssignment);
2741
2742         let lhs_t = fcx.expr_ty(lhs);
2743         let result_t = fcx.expr_ty(expr);
2744         demand::suptype(fcx, expr.span, result_t, lhs_t);
2745
2746         let tcx = fcx.tcx();
2747         if !ty::expr_is_lval(tcx, lhs) {
2748             tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2749         }
2750
2751         // Overwrite result of check_binop...this preserves existing behavior
2752         // but seems quite dubious with regard to user-defined methods
2753         // and so forth. - Niko
2754         if !ty::type_is_error(result_t)
2755             && !ty::type_is_bot(result_t) {
2756             fcx.write_nil(expr.id);
2757         }
2758       }
2759       ast::ExprUnary(unop, oprnd) => {
2760         let exp_inner = unpack_expected(fcx, expected, |sty| {
2761             match unop {
2762                 ast::UnBox | ast::UnUniq => match *sty {
2763                     ty::ty_box(ty) | ty::ty_uniq(ty) => Some(ty),
2764                     _ => None
2765                 },
2766                 ast::UnNot | ast::UnNeg => expected,
2767                 ast::UnDeref => None
2768             }
2769         });
2770         let lvalue_pref = match unop {
2771             ast::UnDeref => lvalue_pref,
2772             _ => NoPreference
2773         };
2774         check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, exp_inner, lvalue_pref);
2775         let mut oprnd_t = fcx.expr_ty(oprnd);
2776         if !ty::type_is_error(oprnd_t) && !ty::type_is_bot(oprnd_t) {
2777             match unop {
2778                 ast::UnBox => {
2779                     oprnd_t = ty::mk_box(tcx, oprnd_t)
2780                 }
2781                 ast::UnUniq => {
2782                     oprnd_t = ty::mk_uniq(tcx, oprnd_t);
2783                 }
2784                 ast::UnDeref => {
2785                     oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
2786                     oprnd_t = match ty::deref(oprnd_t, true) {
2787                         Some(mt) => mt.ty,
2788                         None => match try_overloaded_deref(fcx, expr.span,
2789                                                            Some(MethodCall::expr(expr.id)),
2790                                                            Some(&*oprnd), oprnd_t, lvalue_pref) {
2791                             Some(mt) => mt.ty,
2792                             None => {
2793                                 let is_newtype = match ty::get(oprnd_t).sty {
2794                                     ty::ty_struct(did, ref substs) => {
2795                                         let fields = ty::struct_fields(fcx.tcx(), did, substs);
2796                                         fields.len() == 1
2797                                         && fields.get(0).ident ==
2798                                         token::special_idents::unnamed_field
2799                                     }
2800                                     _ => false
2801                                 };
2802                                 if is_newtype {
2803                                     // This is an obsolete struct deref
2804                                     tcx.sess.span_err(expr.span,
2805                                         "single-field tuple-structs can \
2806                                          no longer be dereferenced");
2807                                 } else {
2808                                     fcx.type_error_message(expr.span, |actual| {
2809                                         format!("type `{}` cannot be dereferenced", actual)
2810                                     }, oprnd_t, None);
2811                                 }
2812                                 ty::mk_err()
2813                             }
2814                         }
2815                     };
2816                 }
2817                 ast::UnNot => {
2818                     oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2819                                                          oprnd_t);
2820                     if !(ty::type_is_integral(oprnd_t) ||
2821                          ty::get(oprnd_t).sty == ty::ty_bool) {
2822                         oprnd_t = check_user_unop(fcx, "!", "not",
2823                                                   tcx.lang_items.not_trait(),
2824                                                   expr, oprnd, oprnd_t);
2825                     }
2826                 }
2827                 ast::UnNeg => {
2828                     oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2829                                                          oprnd_t);
2830                     if !(ty::type_is_integral(oprnd_t) ||
2831                          ty::type_is_fp(oprnd_t)) {
2832                         oprnd_t = check_user_unop(fcx, "-", "neg",
2833                                                   tcx.lang_items.neg_trait(),
2834                                                   expr, oprnd, oprnd_t);
2835                     }
2836                 }
2837             }
2838         }
2839         fcx.write_ty(id, oprnd_t);
2840       }
2841       ast::ExprAddrOf(mutbl, oprnd) => {
2842           let hint = unpack_expected(
2843               fcx, expected,
2844               |sty| match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty),
2845                                  _ => None });
2846         let lvalue_pref = match mutbl {
2847             ast::MutMutable => PreferMutLvalue,
2848             ast::MutImmutable => NoPreference
2849         };
2850         check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, hint, lvalue_pref);
2851
2852         // Note: at this point, we cannot say what the best lifetime
2853         // is to use for resulting pointer.  We want to use the
2854         // shortest lifetime possible so as to avoid spurious borrowck
2855         // errors.  Moreover, the longest lifetime will depend on the
2856         // precise details of the value whose address is being taken
2857         // (and how long it is valid), which we don't know yet until type
2858         // inference is complete.
2859         //
2860         // Therefore, here we simply generate a region variable.  The
2861         // region inferencer will then select the ultimate value.
2862         // Finally, borrowck is charged with guaranteeing that the
2863         // value whose address was taken can actually be made to live
2864         // as long as it needs to live.
2865         let region = fcx.infcx().next_region_var(
2866             infer::AddrOfRegion(expr.span));
2867
2868         let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
2869         let oprnd_t = if ty::type_is_error(tm.ty) {
2870             ty::mk_err()
2871         } else if ty::type_is_bot(tm.ty) {
2872             ty::mk_bot()
2873         }
2874         else {
2875             ty::mk_rptr(tcx, region, tm)
2876         };
2877         fcx.write_ty(id, oprnd_t);
2878       }
2879       ast::ExprPath(ref pth) => {
2880         let defn = lookup_def(fcx, pth.span, id);
2881
2882         check_type_parameter_positions_in_path(fcx, pth, defn);
2883         let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2884         instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
2885       }
2886       ast::ExprInlineAsm(ref ia) => {
2887           for &(_, input) in ia.inputs.iter() {
2888               check_expr(fcx, input);
2889           }
2890           for &(_, out) in ia.outputs.iter() {
2891               check_expr(fcx, out);
2892           }
2893           fcx.write_nil(id);
2894       }
2895       ast::ExprMac(_) => tcx.sess.bug("unexpanded macro"),
2896       ast::ExprBreak(_) => { fcx.write_bot(id); }
2897       ast::ExprAgain(_) => { fcx.write_bot(id); }
2898       ast::ExprRet(expr_opt) => {
2899         let ret_ty = fcx.ret_ty;
2900         match expr_opt {
2901           None => match fcx.mk_eqty(false, infer::Misc(expr.span),
2902                                     ret_ty, ty::mk_nil()) {
2903             Ok(_) => { /* fall through */ }
2904             Err(_) => {
2905                 tcx.sess.span_err(
2906                     expr.span,
2907                     "`return;` in function returning non-nil");
2908             }
2909           },
2910           Some(e) => {
2911               check_expr_has_type(fcx, e, ret_ty);
2912           }
2913         }
2914         fcx.write_bot(id);
2915       }
2916       ast::ExprParen(a) => {
2917         check_expr_with_opt_hint_and_lvalue_pref(fcx, a, expected, lvalue_pref);
2918         fcx.write_ty(id, fcx.expr_ty(a));
2919       }
2920       ast::ExprAssign(lhs, rhs) => {
2921         check_expr_with_lvalue_pref(fcx, lhs, PreferMutLvalue);
2922
2923         let tcx = fcx.tcx();
2924         if !ty::expr_is_lval(tcx, lhs) {
2925             tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2926         }
2927
2928         let lhs_ty = fcx.expr_ty(lhs);
2929         check_expr_has_type(fcx, rhs, lhs_ty);
2930         let rhs_ty = fcx.expr_ty(rhs);
2931
2932         if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
2933             fcx.write_error(id);
2934         } else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
2935             fcx.write_bot(id);
2936         } else {
2937             fcx.write_nil(id);
2938         }
2939       }
2940       ast::ExprIf(cond, then_blk, opt_else_expr) => {
2941         check_then_else(fcx, cond, then_blk, opt_else_expr,
2942                         id, expr.span, expected);
2943       }
2944       ast::ExprWhile(cond, body) => {
2945         check_expr_has_type(fcx, cond, ty::mk_bool());
2946         check_block_no_value(fcx, body);
2947         let cond_ty = fcx.expr_ty(cond);
2948         let body_ty = fcx.node_ty(body.id);
2949         if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) {
2950             fcx.write_error(id);
2951         }
2952         else if ty::type_is_bot(cond_ty) {
2953             fcx.write_bot(id);
2954         }
2955         else {
2956             fcx.write_nil(id);
2957         }
2958       }
2959       ast::ExprForLoop(..) =>
2960           fail!("non-desugared expr_for_loop"),
2961       ast::ExprLoop(body, _) => {
2962         check_block_no_value(fcx, (body));
2963         if !may_break(tcx, expr.id, body) {
2964             fcx.write_bot(id);
2965         }
2966         else {
2967             fcx.write_nil(id);
2968         }
2969       }
2970       ast::ExprMatch(discrim, ref arms) => {
2971         _match::check_match(fcx, expr, discrim, arms.as_slice());
2972       }
2973       ast::ExprFnBlock(decl, body) => {
2974         let region = astconv::opt_ast_region_to_region(fcx,
2975                                                        fcx.infcx(),
2976                                                        expr.span,
2977                                                        &None);
2978         check_expr_fn(fcx,
2979                       expr,
2980                       ty::RegionTraitStore(region, ast::MutMutable),
2981                       decl,
2982                       body,
2983                       Vanilla,
2984                       expected);
2985       }
2986       ast::ExprProc(decl, body) => {
2987         check_expr_fn(fcx,
2988                       expr,
2989                       ty::UniqTraitStore,
2990                       decl,
2991                       body,
2992                       Vanilla,
2993                       expected);
2994       }
2995       ast::ExprBlock(b) => {
2996         check_block_with_expected(fcx, b, expected);
2997         fcx.write_ty(id, fcx.node_ty(b.id));
2998       }
2999       ast::ExprCall(f, ref args) => {
3000           check_call(fcx, expr, f, args.as_slice());
3001           let f_ty = fcx.expr_ty(f);
3002           let (args_bot, args_err) = args.iter().fold((false, false),
3003              |(rest_bot, rest_err), a| {
3004                  // is this not working?
3005                  let a_ty = fcx.expr_ty(*a);
3006                  (rest_bot || ty::type_is_bot(a_ty),
3007                   rest_err || ty::type_is_error(a_ty))});
3008           if ty::type_is_error(f_ty) || args_err {
3009               fcx.write_error(id);
3010           }
3011           else if ty::type_is_bot(f_ty) || args_bot {
3012               fcx.write_bot(id);
3013           }
3014       }
3015       ast::ExprMethodCall(ident, ref tps, ref args) => {
3016         check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice());
3017         let mut arg_tys = args.iter().map(|a| fcx.expr_ty(*a));
3018         let (args_bot, args_err) = arg_tys.fold((false, false),
3019              |(rest_bot, rest_err), a| {
3020               (rest_bot || ty::type_is_bot(a),
3021                rest_err || ty::type_is_error(a))});
3022         if args_err {
3023             fcx.write_error(id);
3024         } else if args_bot {
3025             fcx.write_bot(id);
3026         }
3027       }
3028       ast::ExprCast(e, t) => {
3029         check_expr(fcx, e);
3030         let t_1 = fcx.to_ty(t);
3031         let t_e = fcx.expr_ty(e);
3032
3033         debug!("t_1={}", fcx.infcx().ty_to_str(t_1));
3034         debug!("t_e={}", fcx.infcx().ty_to_str(t_e));
3035
3036         if ty::type_is_error(t_e) {
3037             fcx.write_error(id);
3038         }
3039         else if ty::type_is_bot(t_e) {
3040             fcx.write_bot(id);
3041         }
3042         else {
3043             match ty::get(t_1).sty {
3044                 // This will be looked up later on
3045                 ty::ty_trait(..) => (),
3046
3047                 _ => {
3048                     if ty::type_is_nil(t_e) {
3049                         fcx.type_error_message(expr.span, |actual| {
3050                             format!("cast from nil: `{}` as `{}`", actual,
3051                                  fcx.infcx().ty_to_str(t_1))
3052                         }, t_e, None);
3053                     } else if ty::type_is_nil(t_1) {
3054                         fcx.type_error_message(expr.span, |actual| {
3055                             format!("cast to nil: `{}` as `{}`", actual,
3056                                  fcx.infcx().ty_to_str(t_1))
3057                         }, t_e, None);
3058                     }
3059
3060                     let t1 = structurally_resolved_type(fcx, e.span, t_1);
3061                     let te = structurally_resolved_type(fcx, e.span, t_e);
3062                     let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
3063                     let t_1_is_char = type_is_char(fcx, expr.span, t_1);
3064                     let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1);
3065
3066                     // casts to scalars other than `char` and `bare fn` are trivial
3067                     let t_1_is_trivial = t_1_is_scalar &&
3068                         !t_1_is_char && !t_1_is_bare_fn;
3069
3070                     if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial {
3071                         // casts from C-like enums are allowed
3072                     } else if t_1_is_char {
3073                         let te = fcx.infcx().resolve_type_vars_if_possible(te);
3074                         if ty::get(te).sty != ty::ty_uint(ast::TyU8) {
3075                             fcx.type_error_message(expr.span, |actual| {
3076                                 format!("only `u8` can be cast as `char`, not `{}`", actual)
3077                             }, t_e, None);
3078                         }
3079                     } else if ty::get(t1).sty == ty::ty_bool {
3080                         fcx.tcx().sess.span_err(expr.span,
3081                                                 "cannot cast as `bool`, compare with zero instead");
3082                     } else if type_is_region_ptr(fcx, expr.span, t_e) &&
3083                         type_is_unsafe_ptr(fcx, expr.span, t_1) {
3084
3085                         fn is_vec(t: ty::t) -> bool {
3086                             match ty::get(t).sty {
3087                                 ty::ty_vec(..) => true,
3088                                 ty::ty_ptr(ty::mt{ty: t, ..}) | ty::ty_rptr(_, ty::mt{ty: t, ..}) |
3089                                 ty::ty_box(t) | ty::ty_uniq(t) => match ty::get(t).sty {
3090                                     ty::ty_vec(_, None) => true,
3091                                     _ => false,
3092                                 },
3093                                 _ => false
3094                             }
3095                         }
3096                         fn types_compatible(fcx: &FnCtxt, sp: Span,
3097                                             t1: ty::t, t2: ty::t) -> bool {
3098                             if !is_vec(t1) {
3099                                 false
3100                             } else {
3101                                 let el = ty::sequence_element_type(fcx.tcx(),
3102                                                                    t1);
3103                                 infer::mk_eqty(fcx.infcx(), false,
3104                                                infer::Misc(sp), el, t2).is_ok()
3105                             }
3106                         }
3107
3108                         // Due to the limitations of LLVM global constants,
3109                         // region pointers end up pointing at copies of
3110                         // vector elements instead of the original values.
3111                         // To allow unsafe pointers to work correctly, we
3112                         // need to special-case obtaining an unsafe pointer
3113                         // from a region pointer to a vector.
3114
3115                         /* this cast is only allowed from &[T] to *T or
3116                         &T to *T. */
3117                         match (&ty::get(te).sty, &ty::get(t_1).sty) {
3118                             (&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
3119                             if types_compatible(fcx, e.span,
3120                                                 mt1.ty, mt2.ty) => {
3121                                 /* this case is allowed */
3122                             }
3123                             _ => {
3124                                 demand::coerce(fcx, e.span, t_1, e);
3125                             }
3126                         }
3127                     } else if !(type_is_scalar(fcx,expr.span,t_e)
3128                                 && t_1_is_trivial) {
3129                         /*
3130                         If more type combinations should be supported than are
3131                         supported here, then file an enhancement issue and
3132                         record the issue number in this comment.
3133                         */
3134                         fcx.type_error_message(expr.span, |actual| {
3135                             format!("non-scalar cast: `{}` as `{}`", actual,
3136                                  fcx.infcx().ty_to_str(t_1))
3137                         }, t_e, None);
3138                     }
3139                 }
3140             }
3141             fcx.write_ty(id, t_1);
3142         }
3143       }
3144       ast::ExprVec(ref args) => {
3145         let t: ty::t = fcx.infcx().next_ty_var();
3146         for e in args.iter() {
3147             check_expr_has_type(fcx, *e, t);
3148         }
3149         let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable},
3150                              Some(args.len()));
3151         fcx.write_ty(id, typ);
3152       }
3153       ast::ExprRepeat(element, count_expr) => {
3154         check_expr_with_hint(fcx, count_expr, ty::mk_uint());
3155         let count = ty::eval_repeat_count(fcx, count_expr);
3156         let t: ty::t = fcx.infcx().next_ty_var();
3157         check_expr_has_type(fcx, element, t);
3158         let element_ty = fcx.expr_ty(element);
3159         if ty::type_is_error(element_ty) {
3160             fcx.write_error(id);
3161         }
3162         else if ty::type_is_bot(element_ty) {
3163             fcx.write_bot(id);
3164         }
3165         else {
3166             let t = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable},
3167                                Some(count));
3168             fcx.write_ty(id, t);
3169         }
3170       }
3171       ast::ExprTup(ref elts) => {
3172         let flds = unpack_expected(fcx, expected, |sty| {
3173             match *sty {
3174                 ty::ty_tup(ref flds) => Some((*flds).clone()),
3175                 _ => None
3176             }
3177         });
3178         let mut bot_field = false;
3179         let mut err_field = false;
3180
3181         let elt_ts = elts.iter().enumerate().map(|(i, e)| {
3182             let opt_hint = match flds {
3183                 Some(ref fs) if i < fs.len() => Some(*fs.get(i)),
3184                 _ => None
3185             };
3186             check_expr_with_opt_hint(fcx, *e, opt_hint);
3187             let t = fcx.expr_ty(*e);
3188             err_field = err_field || ty::type_is_error(t);
3189             bot_field = bot_field || ty::type_is_bot(t);
3190             t
3191         }).collect();
3192         if bot_field {
3193             fcx.write_bot(id);
3194         } else if err_field {
3195             fcx.write_error(id);
3196         } else {
3197             let typ = ty::mk_tup(tcx, elt_ts);
3198             fcx.write_ty(id, typ);
3199         }
3200       }
3201       ast::ExprStruct(ref path, ref fields, base_expr) => {
3202         // Resolve the path.
3203         match tcx.def_map.borrow().find(&id) {
3204             Some(&ast::DefStruct(type_def_id)) => {
3205                 check_struct_constructor(fcx, id, expr.span, type_def_id,
3206                                          fields.as_slice(), base_expr);
3207             }
3208             Some(&ast::DefVariant(enum_id, variant_id, _)) => {
3209                 check_struct_enum_variant(fcx, id, expr.span, enum_id,
3210                                           variant_id, fields.as_slice());
3211             }
3212             _ => {
3213                 tcx.sess.span_bug(path.span,
3214                                   "structure constructor does not name a structure type");
3215             }
3216         }
3217       }
3218       ast::ExprField(base, field, ref tys) => {
3219         check_field(fcx, expr, lvalue_pref, base, field.name, tys.as_slice());
3220       }
3221       ast::ExprIndex(base, idx) => {
3222           check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
3223           check_expr(fcx, idx);
3224           let raw_base_t = fcx.expr_ty(base);
3225           let idx_t = fcx.expr_ty(idx);
3226           if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
3227               fcx.write_ty(id, raw_base_t);
3228           } else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
3229               fcx.write_ty(id, idx_t);
3230           } else {
3231               let (base_t, autoderefs, field_ty) =
3232                 autoderef(fcx, expr.span, raw_base_t, Some(base.id),
3233                           lvalue_pref, |base_t, _| ty::index(base_t));
3234               match field_ty {
3235                   Some(mt) => {
3236                       check_expr_has_type(fcx, idx, ty::mk_uint());
3237                       fcx.write_ty(id, mt.ty);
3238                       fcx.write_autoderef_adjustment(base.id, autoderefs);
3239                   }
3240                   None => {
3241                       let resolved = structurally_resolved_type(fcx,
3242                                                                 expr.span,
3243                                                                 raw_base_t);
3244                       let ret_ty = lookup_op_method(fcx,
3245                                                     expr,
3246                                                     resolved,
3247                                                     token::intern("index"),
3248                                                     tcx.lang_items.index_trait(),
3249                                                     [base, idx],
3250                                                     AutoderefReceiver,
3251                                                     || {
3252                         fcx.type_error_message(expr.span,
3253                                                |actual| {
3254                                                 format!("cannot index a value \
3255                                                       of type `{}`",
3256                                                      actual)
3257                                                },
3258                                                base_t,
3259                                                None);
3260                       });
3261                       fcx.write_ty(id, ret_ty);
3262                   }
3263               }
3264           }
3265        }
3266     }
3267
3268     debug!("type of expr({}) {} is...", expr.id,
3269            syntax::print::pprust::expr_to_str(expr));
3270     debug!("... {}, expected is {}",
3271            ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
3272            match expected {
3273                Some(t) => ppaux::ty_to_str(tcx, t),
3274                _ => "empty".to_owned()
3275            });
3276
3277     unifier();
3278 }
3279
3280 pub fn require_uint(fcx: &FnCtxt, sp: Span, t: ty::t) {
3281     if !type_is_uint(fcx, sp, t) {
3282         fcx.type_error_message(sp, |actual| {
3283             format!("mismatched types: expected `uint` type but found `{}`",
3284                  actual)
3285         }, t, None);
3286     }
3287 }
3288
3289 pub fn require_integral(fcx: &FnCtxt, sp: Span, t: ty::t) {
3290     if !type_is_integral(fcx, sp, t) {
3291         fcx.type_error_message(sp, |actual| {
3292             format!("mismatched types: expected integral type but found `{}`",
3293                  actual)
3294         }, t, None);
3295     }
3296 }
3297
3298 pub fn check_decl_initializer(fcx: &FnCtxt,
3299                               nid: ast::NodeId,
3300                               init: &ast::Expr)
3301                             {
3302     let local_ty = fcx.local_ty(init.span, nid);
3303     check_expr_coercable_to_type(fcx, init, local_ty)
3304 }
3305
3306 pub fn check_decl_local(fcx: &FnCtxt, local: &ast::Local)  {
3307     let tcx = fcx.ccx.tcx;
3308
3309     let t = fcx.local_ty(local.span, local.id);
3310     fcx.write_ty(local.id, t);
3311
3312     match local.init {
3313         Some(init) => {
3314             check_decl_initializer(fcx, local.id, init);
3315             let init_ty = fcx.expr_ty(init);
3316             if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
3317                 fcx.write_ty(local.id, init_ty);
3318             }
3319         }
3320         _ => {}
3321     }
3322
3323     let pcx = pat_ctxt {
3324         fcx: fcx,
3325         map: pat_id_map(&tcx.def_map, local.pat),
3326     };
3327     _match::check_pat(&pcx, local.pat, t);
3328     let pat_ty = fcx.node_ty(local.pat.id);
3329     if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
3330         fcx.write_ty(local.id, pat_ty);
3331     }
3332 }
3333
3334 pub fn check_stmt(fcx: &FnCtxt, stmt: &ast::Stmt)  {
3335     let node_id;
3336     let mut saw_bot = false;
3337     let mut saw_err = false;
3338     match stmt.node {
3339       ast::StmtDecl(decl, id) => {
3340         node_id = id;
3341         match decl.node {
3342           ast::DeclLocal(ref l) => {
3343               check_decl_local(fcx, *l);
3344               let l_t = fcx.node_ty(l.id);
3345               saw_bot = saw_bot || ty::type_is_bot(l_t);
3346               saw_err = saw_err || ty::type_is_error(l_t);
3347           }
3348           ast::DeclItem(_) => {/* ignore for now */ }
3349         }
3350       }
3351       ast::StmtExpr(expr, id) => {
3352         node_id = id;
3353         // Check with expected type of ()
3354         check_expr_has_type(fcx, expr, ty::mk_nil());
3355         let expr_ty = fcx.expr_ty(expr);
3356         saw_bot = saw_bot || ty::type_is_bot(expr_ty);
3357         saw_err = saw_err || ty::type_is_error(expr_ty);
3358       }
3359       ast::StmtSemi(expr, id) => {
3360         node_id = id;
3361         check_expr(fcx, expr);
3362         let expr_ty = fcx.expr_ty(expr);
3363         saw_bot |= ty::type_is_bot(expr_ty);
3364         saw_err |= ty::type_is_error(expr_ty);
3365       }
3366       ast::StmtMac(..) => fcx.ccx.tcx.sess.bug("unexpanded macro")
3367     }
3368     if saw_bot {
3369         fcx.write_bot(node_id);
3370     }
3371     else if saw_err {
3372         fcx.write_error(node_id);
3373     }
3374     else {
3375         fcx.write_nil(node_id)
3376     }
3377 }
3378
3379 pub fn check_block_no_value(fcx: &FnCtxt, blk: &ast::Block)  {
3380     check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
3381     let blkty = fcx.node_ty(blk.id);
3382     if ty::type_is_error(blkty) {
3383         fcx.write_error(blk.id);
3384     }
3385     else if ty::type_is_bot(blkty) {
3386         fcx.write_bot(blk.id);
3387     }
3388     else {
3389         let nilty = ty::mk_nil();
3390         demand::suptype(fcx, blk.span, nilty, blkty);
3391     }
3392 }
3393
3394 pub fn check_block_with_expected(fcx: &FnCtxt,
3395                                  blk: &ast::Block,
3396                                  expected: Option<ty::t>) {
3397     let prev = {
3398         let mut fcx_ps = fcx.ps.borrow_mut();
3399         let fn_style_state = fcx_ps.recurse(blk);
3400         replace(&mut *fcx_ps, fn_style_state)
3401     };
3402
3403     fcx.with_region_lb(blk.id, || {
3404         let mut warned = false;
3405         let mut last_was_bot = false;
3406         let mut any_bot = false;
3407         let mut any_err = false;
3408         for s in blk.stmts.iter() {
3409             check_stmt(fcx, *s);
3410             let s_id = ast_util::stmt_id(*s);
3411             let s_ty = fcx.node_ty(s_id);
3412             if last_was_bot && !warned && match s.node {
3413                   ast::StmtDecl(decl, _) => {
3414                       match decl.node {
3415                           ast::DeclLocal(_) => true,
3416                           _ => false,
3417                       }
3418                   }
3419                   ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true,
3420                   _ => false
3421                 } {
3422                 fcx.ccx.tcx.sess.add_lint(UnreachableCode, s_id, s.span,
3423                                           "unreachable statement".to_owned());
3424                 warned = true;
3425             }
3426             if ty::type_is_bot(s_ty) {
3427                 last_was_bot = true;
3428             }
3429             any_bot = any_bot || ty::type_is_bot(s_ty);
3430             any_err = any_err || ty::type_is_error(s_ty);
3431         }
3432         match blk.expr {
3433             None => if any_err {
3434                 fcx.write_error(blk.id);
3435             }
3436             else if any_bot {
3437                 fcx.write_bot(blk.id);
3438             }
3439             else  {
3440                 fcx.write_nil(blk.id);
3441             },
3442           Some(e) => {
3443             if any_bot && !warned {
3444                 fcx.ccx.tcx.sess.add_lint(UnreachableCode, e.id, e.span,
3445                                           "unreachable expression".to_owned());
3446             }
3447             check_expr_with_opt_hint(fcx, e, expected);
3448               let ety = fcx.expr_ty(e);
3449               fcx.write_ty(blk.id, ety);
3450               if any_err {
3451                   fcx.write_error(blk.id);
3452               }
3453               else if any_bot {
3454                   fcx.write_bot(blk.id);
3455               }
3456           }
3457         };
3458     });
3459
3460     *fcx.ps.borrow_mut() = prev;
3461 }
3462
3463 pub fn check_const(ccx: &CrateCtxt,
3464                    sp: Span,
3465                    e: &ast::Expr,
3466                    id: ast::NodeId) {
3467     let inh = blank_inherited_fields(ccx);
3468     let rty = ty::node_id_to_type(ccx.tcx, id);
3469     let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
3470     let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty;
3471     check_const_with_ty(&fcx, sp, e, declty);
3472 }
3473
3474 pub fn check_const_with_ty(fcx: &FnCtxt,
3475                            _: Span,
3476                            e: &ast::Expr,
3477                            declty: ty::t) {
3478     check_expr(fcx, e);
3479     let cty = fcx.expr_ty(e);
3480     demand::suptype(fcx, e.span, declty, cty);
3481     regionck::regionck_expr(fcx, e);
3482     writeback::resolve_type_vars_in_expr(fcx, e);
3483 }
3484
3485 /// Checks whether a type can be represented in memory. In particular, it
3486 /// identifies types that contain themselves without indirection through a
3487 /// pointer, which would mean their size is unbounded. This is different from
3488 /// the question of whether a type can be instantiated. See the definition of
3489 /// `check_instantiable`.
3490 pub fn check_representable(tcx: &ty::ctxt,
3491                            sp: Span,
3492                            item_id: ast::NodeId,
3493                            designation: &str) -> bool {
3494     let rty = ty::node_id_to_type(tcx, item_id);
3495
3496     // Check that it is possible to represent this type. This call identifies
3497     // (1) types that contain themselves and (2) types that contain a different
3498     // recursive type. It is only necessary to throw an error on those that
3499     // contain themselves. For case 2, there must be an inner type that will be
3500     // caught by case 1.
3501     match ty::is_type_representable(tcx, sp, rty) {
3502       ty::SelfRecursive => {
3503         tcx.sess.span_err(
3504           sp, format!("illegal recursive {} type; \
3505                        wrap the inner value in a box to make it representable",
3506                       designation));
3507         return false
3508       }
3509       ty::Representable | ty::ContainsRecursive => (),
3510     }
3511     return true
3512 }
3513
3514 /// Checks whether a type can be created without an instance of itself.
3515 /// This is similar but different from the question of whether a type
3516 /// can be represented.  For example, the following type:
3517 ///
3518 ///     enum foo { None, Some(foo) }
3519 ///
3520 /// is instantiable but is not representable.  Similarly, the type
3521 ///
3522 ///     enum foo { Some(@foo) }
3523 ///
3524 /// is representable, but not instantiable.
3525 pub fn check_instantiable(tcx: &ty::ctxt,
3526                           sp: Span,
3527                           item_id: ast::NodeId)
3528                           -> bool {
3529     let item_ty = ty::node_id_to_type(tcx, item_id);
3530     if !ty::is_instantiable(tcx, item_ty) {
3531         tcx.sess.span_err(sp, format!("this type cannot be instantiated \
3532                   without an instance of itself; \
3533                   consider using `Option<{}>`",
3534                                    ppaux::ty_to_str(tcx, item_ty)));
3535         false
3536     } else {
3537         true
3538     }
3539 }
3540
3541 pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
3542     let t = ty::node_id_to_type(tcx, id);
3543     if ty::type_needs_subst(t) {
3544         tcx.sess.span_err(sp, "SIMD vector cannot be generic");
3545         return;
3546     }
3547     match ty::get(t).sty {
3548         ty::ty_struct(did, ref substs) => {
3549             let fields = ty::lookup_struct_fields(tcx, did);
3550             if fields.is_empty() {
3551                 tcx.sess.span_err(sp, "SIMD vector cannot be empty");
3552                 return;
3553             }
3554             let e = ty::lookup_field_type(tcx, did, fields.get(0).id, substs);
3555             if !fields.iter().all(
3556                          |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
3557                 tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
3558                 return;
3559             }
3560             if !ty::type_is_machine(e) {
3561                 tcx.sess.span_err(sp, "SIMD vector element type should be \
3562                                        machine type");
3563                 return;
3564             }
3565         }
3566         _ => ()
3567     }
3568 }
3569
3570 pub fn check_enum_variants_sized(ccx: &CrateCtxt,
3571                                  vs: &[ast::P<ast::Variant>]) {
3572     for &v in vs.iter() {
3573         match v.node.kind {
3574             ast::TupleVariantKind(ref args) if args.len() > 0 => {
3575                 let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id);
3576                 let arg_tys: Vec<ty::t> = ty::ty_fn_args(ctor_ty).iter().map(|a| *a).collect();
3577                 let len = arg_tys.len();
3578                 if len == 0 {
3579                     return;
3580                 }
3581                 for (i, t) in arg_tys.slice_to(len - 1).iter().enumerate() {
3582                     // Allow the last field in an enum to be unsized.
3583                     // We want to do this so that we can support smart pointers.
3584                     // A struct value with an unsized final field is itself
3585                     // unsized and we must track this in the type system.
3586                     if !ty::type_is_sized(ccx.tcx, *t) {
3587                         ccx.tcx.sess.span_err(args.get(i).ty.span,
3588                                               format!("type `{}` is dynamically sized. \
3589                                                        dynamically sized types may only \
3590                                                        appear as the final type in a variant",
3591                                                       ppaux::ty_to_str(ccx.tcx, *t)));
3592                     }
3593                 }
3594             },
3595             ast::StructVariantKind(struct_def) => check_fields_sized(ccx.tcx, struct_def),
3596             _ => {}
3597         }
3598     }
3599 }
3600
3601 pub fn check_enum_variants(ccx: &CrateCtxt,
3602                            sp: Span,
3603                            vs: &[ast::P<ast::Variant>],
3604                            id: ast::NodeId) {
3605
3606     fn disr_in_range(ccx: &CrateCtxt,
3607                      ty: attr::IntType,
3608                      disr: ty::Disr) -> bool {
3609         fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
3610             match ty {
3611                 ast::TyU8 => disr as u8 as Disr == disr,
3612                 ast::TyU16 => disr as u16 as Disr == disr,
3613                 ast::TyU32 => disr as u32 as Disr == disr,
3614                 ast::TyU64 => disr as u64 as Disr == disr,
3615                 ast::TyU => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
3616             }
3617         }
3618         fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
3619             match ty {
3620                 ast::TyI8 => disr as i8 as Disr == disr,
3621                 ast::TyI16 => disr as i16 as Disr == disr,
3622                 ast::TyI32 => disr as i32 as Disr == disr,
3623                 ast::TyI64 => disr as i64 as Disr == disr,
3624                 ast::TyI => int_in_range(ccx, ccx.tcx.sess.targ_cfg.int_type, disr)
3625             }
3626         }
3627         match ty {
3628             attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
3629             attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
3630         }
3631     }
3632
3633     fn do_check(ccx: &CrateCtxt,
3634                 vs: &[ast::P<ast::Variant>],
3635                 id: ast::NodeId,
3636                 hint: attr::ReprAttr)
3637                 -> Vec<Rc<ty::VariantInfo>> {
3638
3639         let rty = ty::node_id_to_type(ccx.tcx, id);
3640         let mut variants: Vec<Rc<ty::VariantInfo>> = Vec::new();
3641         let mut disr_vals: Vec<ty::Disr> = Vec::new();
3642         let mut prev_disr_val: Option<ty::Disr> = None;
3643
3644         for &v in vs.iter() {
3645
3646             // If the discriminant value is specified explicitly in the enum check whether the
3647             // initialization expression is valid, otherwise use the last value plus one.
3648             let mut current_disr_val = match prev_disr_val {
3649                 Some(prev_disr_val) => prev_disr_val + 1,
3650                 None => ty::INITIAL_DISCRIMINANT_VALUE
3651             };
3652
3653             match v.node.disr_expr {
3654                 Some(e) => {
3655                     debug!("disr expr, checking {}", pprust::expr_to_str(e));
3656
3657                     let inh = blank_inherited_fields(ccx);
3658                     let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
3659                     let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
3660                     check_const_with_ty(&fcx, e.span, e, declty);
3661                     // check_expr (from check_const pass) doesn't guarantee
3662                     // that the expression is in an form that eval_const_expr can
3663                     // handle, so we may still get an internal compiler error
3664
3665                     match const_eval::eval_const_expr_partial(ccx.tcx, e) {
3666                         Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
3667                         Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
3668                         Ok(_) => {
3669                             ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
3670                         }
3671                         Err(ref err) => {
3672                             ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", *err));
3673                         }
3674                     }
3675                 },
3676                 None => ()
3677             };
3678
3679             // Check for duplicate discriminant values
3680             if disr_vals.contains(&current_disr_val) {
3681                 ccx.tcx.sess.span_err(v.span, "discriminant value already exists");
3682             }
3683             // Check for unrepresentable discriminant values
3684             match hint {
3685                 attr::ReprAny | attr::ReprExtern => (),
3686                 attr::ReprInt(sp, ity) => {
3687                     if !disr_in_range(ccx, ity, current_disr_val) {
3688                         ccx.tcx.sess.span_err(v.span,
3689                                               "discriminant value outside specified type");
3690                         ccx.tcx.sess.span_note(sp, "discriminant type specified here");
3691                     }
3692                 }
3693             }
3694             disr_vals.push(current_disr_val);
3695
3696             let variant_info = Rc::new(VariantInfo::from_ast_variant(ccx.tcx, v,
3697                                                                      current_disr_val));
3698             prev_disr_val = Some(current_disr_val);
3699
3700             variants.push(variant_info);
3701         }
3702
3703         return variants;
3704     }
3705
3706     let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id });
3707     if hint != attr::ReprAny && vs.len() <= 1 {
3708         let msg = if vs.len() == 1 {
3709             "unsupported representation for univariant enum"
3710         } else {
3711             "unsupported representation for zero-variant enum"
3712         };
3713         ccx.tcx.sess.span_err(sp, msg)
3714     }
3715
3716     let variants = do_check(ccx, vs, id, hint);
3717
3718     // cache so that ty::enum_variants won't repeat this work
3719     ccx.tcx.enum_var_cache.borrow_mut().insert(local_def(id), Rc::new(variants));
3720
3721     check_representable(ccx.tcx, sp, id, "enum");
3722
3723     // Check that it is possible to instantiate this enum:
3724     //
3725     // This *sounds* like the same that as representable, but it's
3726     // not.  See def'n of `check_instantiable()` for details.
3727     check_instantiable(ccx.tcx, sp, id);
3728 }
3729
3730 pub fn lookup_def(fcx: &FnCtxt, sp: Span, id: ast::NodeId) -> ast::Def {
3731     lookup_def_ccx(fcx.ccx, sp, id)
3732 }
3733
3734 // Returns the type parameter count and the type for the given definition.
3735 pub fn ty_param_bounds_and_ty_for_def(fcx: &FnCtxt,
3736                                       sp: Span,
3737                                       defn: ast::Def)
3738                                    -> ty_param_bounds_and_ty {
3739     match defn {
3740       ast::DefArg(nid, _) | ast::DefLocal(nid, _) |
3741       ast::DefBinding(nid, _) => {
3742           let typ = fcx.local_ty(sp, nid);
3743           return no_params(typ);
3744       }
3745       ast::DefFn(id, _) | ast::DefStaticMethod(id, _, _) |
3746       ast::DefStatic(id, _) | ast::DefVariant(_, id, _) |
3747       ast::DefStruct(id) => {
3748         return ty::lookup_item_type(fcx.ccx.tcx, id);
3749       }
3750       ast::DefUpvar(_, inner, _, _) => {
3751         return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
3752       }
3753       ast::DefTrait(_) |
3754       ast::DefTy(_) |
3755       ast::DefPrimTy(_) |
3756       ast::DefTyParam(..)=> {
3757         fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type");
3758       }
3759       ast::DefMod(..) | ast::DefForeignMod(..) => {
3760         fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module");
3761       }
3762       ast::DefUse(..) => {
3763         fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use");
3764       }
3765       ast::DefRegion(..) => {
3766         fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region");
3767       }
3768       ast::DefTyParamBinder(..) => {
3769         fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter");
3770       }
3771       ast::DefLabel(..) => {
3772         fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label");
3773       }
3774       ast::DefSelfTy(..) => {
3775         fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty");
3776       }
3777       ast::DefMethod(..) => {
3778         fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method");
3779       }
3780     }
3781 }
3782
3783 // Instantiates the given path, which must refer to an item with the given
3784 // number of type parameters and type.
3785 pub fn instantiate_path(fcx: &FnCtxt,
3786                         pth: &ast::Path,
3787                         tpt: ty_param_bounds_and_ty,
3788                         def: ast::Def,
3789                         span: Span,
3790                         node_id: ast::NodeId) {
3791     debug!(">>> instantiate_path");
3792
3793     let ty_param_count = tpt.generics.type_param_defs().len();
3794     let ty_param_req = tpt.generics.type_param_defs().iter()
3795                                                    .take_while(|x| x.default.is_none())
3796                                                    .len();
3797     let mut ty_substs_len = 0;
3798     for segment in pth.segments.iter() {
3799         ty_substs_len += segment.types.len()
3800     }
3801
3802     debug!("tpt={} ty_param_count={:?} ty_substs_len={:?}",
3803            tpt.repr(fcx.tcx()),
3804            ty_param_count,
3805            ty_substs_len);
3806
3807     // determine the region parameters, using the value given by the user
3808     // (if any) and otherwise using a fresh region variable
3809     let num_expected_regions = tpt.generics.region_param_defs().len();
3810     let num_supplied_regions = pth.segments.last().unwrap().lifetimes.len();
3811     let regions = if num_expected_regions == num_supplied_regions {
3812         OwnedSlice::from_vec(pth.segments.last().unwrap().lifetimes.iter().map(
3813             |l| ast_region_to_region(fcx.tcx(), l)).collect())
3814     } else {
3815         if num_supplied_regions != 0 {
3816             fcx.ccx.tcx.sess.span_err(
3817                 span,
3818                 format!("expected {nexpected, plural, =1{# lifetime parameter} \
3819                                                    other{# lifetime parameters}}, \
3820                          found {nsupplied, plural, =1{# lifetime parameter} \
3821                                                 other{# lifetime parameters}}",
3822                         nexpected = num_expected_regions,
3823                         nsupplied = num_supplied_regions));
3824         }
3825
3826         fcx.infcx().region_vars_for_defs(span, tpt.generics.region_param_defs.as_slice())
3827     };
3828     let regions = ty::NonerasedRegions(regions);
3829
3830     // Special case: If there is a self parameter, omit it from the list of
3831     // type parameters.
3832     //
3833     // Here we calculate the "user type parameter count", which is the number
3834     // of type parameters actually manifest in the AST. This will differ from
3835     // the internal type parameter count when there are self types involved.
3836     let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def {
3837         ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
3838             let generics = generics_of_static_method_container(fcx.ccx.tcx,
3839                                                                provenance);
3840             (ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs().len()))
3841         }
3842         _ => (ty_param_count, ty_param_req, None),
3843     };
3844
3845     // determine values for type parameters, using the values given by
3846     // the user (if any) and otherwise using fresh type variables
3847     let (tps, regions) = if ty_substs_len == 0 {
3848         (fcx.infcx().next_ty_vars(ty_param_count), regions)
3849     } else if ty_param_count == 0 {
3850         fcx.ccx.tcx.sess.span_err
3851             (span, "this item does not take type parameters");
3852         (fcx.infcx().next_ty_vars(ty_param_count), regions)
3853     } else if ty_substs_len > user_ty_param_count {
3854         let expected = if user_ty_param_req < user_ty_param_count {
3855             "expected at most"
3856         } else {
3857             "expected"
3858         };
3859         fcx.ccx.tcx.sess.span_err
3860             (span,
3861              format!("too many type parameters provided: {} {}, found {}",
3862                   expected, user_ty_param_count, ty_substs_len));
3863         (fcx.infcx().next_ty_vars(ty_param_count), regions)
3864     } else if ty_substs_len < user_ty_param_req {
3865         let expected = if user_ty_param_req < user_ty_param_count {
3866             "expected at least"
3867         } else {
3868             "expected"
3869         };
3870         fcx.ccx.tcx.sess.span_err
3871             (span,
3872              format!("not enough type parameters provided: {} {}, found {}",
3873                   expected, user_ty_param_req, ty_substs_len));
3874         (fcx.infcx().next_ty_vars(ty_param_count), regions)
3875     } else {
3876         if ty_substs_len > user_ty_param_req
3877             && !fcx.tcx().sess.features.default_type_params.get() {
3878             fcx.tcx().sess.span_err(pth.span, "default type parameters are \
3879                                                experimental and possibly buggy");
3880             fcx.tcx().sess.span_note(pth.span, "add #![feature(default_type_params)] \
3881                                                 to the crate attributes to enable");
3882         }
3883
3884         // Build up the list of type parameters, inserting the self parameter
3885         // at the appropriate position.
3886         let mut tps = Vec::new();
3887         let mut pushed = false;
3888         for (i, ty) in pth.segments.iter()
3889                                    .flat_map(|segment| segment.types.iter())
3890                                    .map(|&ast_type| fcx.to_ty(ast_type))
3891                                    .enumerate() {
3892             match self_parameter_index {
3893                 Some(index) if index == i => {
3894                     tps.push(*fcx.infcx().next_ty_vars(1).get(0));
3895                     pushed = true;
3896                 }
3897                 _ => {}
3898             }
3899             tps.push(ty)
3900         }
3901
3902         let mut substs = substs {
3903             regions: regions,
3904             self_ty: None,
3905             tps: tps
3906         };
3907
3908         let defaults = tpt.generics.type_param_defs().iter()
3909                           .enumerate().filter_map(|(i, x)| {
3910             match self_parameter_index {
3911                 Some(index) if index == i => None,
3912                 _ => Some(x.default)
3913             }
3914         });
3915         for (i, default) in defaults.skip(ty_substs_len).enumerate() {
3916             match self_parameter_index {
3917                 Some(index) if index == i + ty_substs_len => {
3918                     substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0));
3919                     pushed = true;
3920                 }
3921                 _ => {}
3922             }
3923             match default {
3924                 Some(default) => {
3925                     let ty = default.subst_spanned(fcx.tcx(), &substs, Some(span));
3926                     substs.tps.push(ty);
3927                 }
3928                 None => {
3929                     fcx.tcx().sess.span_bug(span,
3930                         "missing default for a not explicitely provided type param")
3931                 }
3932             }
3933         }
3934
3935         // If the self parameter goes at the end, insert it there.
3936         if !pushed && self_parameter_index.is_some() {
3937             substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0))
3938         }
3939
3940         assert_eq!(substs.tps.len(), ty_param_count)
3941
3942         let substs {tps, regions, ..} = substs;
3943         (tps, regions)
3944     };
3945
3946     fcx.write_ty_substs(node_id, tpt.ty, substs {
3947         regions: regions,
3948         self_ty: None,
3949         tps: tps
3950     });
3951
3952     debug!("<<<");
3953 }
3954
3955 // Resolves `typ` by a single level if `typ` is a type variable.  If no
3956 // resolution is possible, then an error is reported.
3957 pub fn structurally_resolved_type(fcx: &FnCtxt, sp: Span, tp: ty::t) -> ty::t {
3958     match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
3959         Ok(t_s) if !ty::type_is_ty_var(t_s) => t_s,
3960         _ => {
3961             fcx.type_error_message(sp, |_actual| {
3962                 "the type of this value must be known in this context".to_owned()
3963             }, tp, None);
3964             demand::suptype(fcx, sp, ty::mk_err(), tp);
3965             tp
3966         }
3967     }
3968 }
3969
3970 // Returns the one-level-deep structure of the given type.
3971 pub fn structure_of<'a>(fcx: &FnCtxt, sp: Span, typ: ty::t)
3972                         -> &'a ty::sty {
3973     &ty::get(structurally_resolved_type(fcx, sp, typ)).sty
3974 }
3975
3976 pub fn type_is_integral(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3977     let typ_s = structurally_resolved_type(fcx, sp, typ);
3978     return ty::type_is_integral(typ_s);
3979 }
3980
3981 pub fn type_is_uint(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3982     let typ_s = structurally_resolved_type(fcx, sp, typ);
3983     return ty::type_is_uint(typ_s);
3984 }
3985
3986 pub fn type_is_scalar(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3987     let typ_s = structurally_resolved_type(fcx, sp, typ);
3988     return ty::type_is_scalar(typ_s);
3989 }
3990
3991 pub fn type_is_char(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3992     let typ_s = structurally_resolved_type(fcx, sp, typ);
3993     return ty::type_is_char(typ_s);
3994 }
3995
3996 pub fn type_is_bare_fn(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3997     let typ_s = structurally_resolved_type(fcx, sp, typ);
3998     return ty::type_is_bare_fn(typ_s);
3999 }
4000
4001 pub fn type_is_unsafe_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4002     let typ_s = structurally_resolved_type(fcx, sp, typ);
4003     return ty::type_is_unsafe_ptr(typ_s);
4004 }
4005
4006 pub fn type_is_region_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4007     let typ_s = structurally_resolved_type(fcx, sp, typ);
4008     return ty::type_is_region_ptr(typ_s);
4009 }
4010
4011 pub fn type_is_c_like_enum(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4012     let typ_s = structurally_resolved_type(fcx, sp, typ);
4013     return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
4014 }
4015
4016 pub fn ast_expr_vstore_to_vstore(fcx: &FnCtxt,
4017                                  e: &ast::Expr,
4018                                  v: ast::ExprVstore)
4019                                  -> ty::Vstore {
4020     match v {
4021         ast::ExprVstoreUniq => ty::VstoreUniq,
4022         ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => {
4023             match e.node {
4024                 ast::ExprLit(..) => {
4025                     // string literals and *empty slices* live in static memory
4026                     ty::VstoreSlice(ty::ReStatic)
4027                 }
4028                 ast::ExprVec(ref elements) if elements.len() == 0 => {
4029                     // string literals and *empty slices* live in static memory
4030                     ty::VstoreSlice(ty::ReStatic)
4031                 }
4032                 ast::ExprRepeat(..) |
4033                 ast::ExprVec(..) => {
4034                     // vector literals are temporaries on the stack
4035                     match fcx.tcx().region_maps.temporary_scope(e.id) {
4036                         Some(scope) => {
4037                             ty::VstoreSlice(ty::ReScope(scope))
4038                         }
4039                         None => {
4040                             // this slice occurs in a static somewhere
4041                             ty::VstoreSlice(ty::ReStatic)
4042                         }
4043                     }
4044                 }
4045                 _ => {
4046                     fcx.ccx.tcx.sess.span_bug(
4047                         e.span, format!("vstore with unexpected contents"))
4048                 }
4049             }
4050         }
4051     }
4052 }
4053
4054 // Returns true if b contains a break that can exit from b
4055 pub fn may_break(cx: &ty::ctxt, id: ast::NodeId, b: ast::P<ast::Block>) -> bool {
4056     // First: is there an unlabeled break immediately
4057     // inside the loop?
4058     (loop_query(b, |e| {
4059         match *e {
4060             ast::ExprBreak(_) => true,
4061             _ => false
4062         }
4063     })) ||
4064    // Second: is there a labeled break with label
4065    // <id> nested anywhere inside the loop?
4066     (block_query(b, |e| {
4067         match e.node {
4068             ast::ExprBreak(Some(_)) => {
4069                 match cx.def_map.borrow().find(&e.id) {
4070                     Some(&ast::DefLabel(loop_id)) if id == loop_id => true,
4071                     _ => false,
4072                 }
4073             }
4074             _ => false
4075         }}))
4076 }
4077
4078 pub fn check_bounds_are_used(ccx: &CrateCtxt,
4079                              span: Span,
4080                              tps: &OwnedSlice<ast::TyParam>,
4081                              ty: ty::t) {
4082     debug!("check_bounds_are_used(n_tps={}, ty={})",
4083            tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
4084
4085     // make a vector of booleans initially false, set to true when used
4086     if tps.len() == 0u { return; }
4087     let mut tps_used = Vec::from_elem(tps.len(), false);
4088
4089     ty::walk_ty(ty, |t| {
4090             match ty::get(t).sty {
4091                 ty::ty_param(param_ty {idx, ..}) => {
4092                     debug!("Found use of ty param \\#{}", idx);
4093                     *tps_used.get_mut(idx) = true;
4094                 }
4095                 _ => ()
4096             }
4097         });
4098
4099     for (i, b) in tps_used.iter().enumerate() {
4100         if !*b {
4101             ccx.tcx.sess.span_err(
4102                 span, format!("type parameter `{}` is unused",
4103                               token::get_ident(tps.get(i).ident)));
4104         }
4105     }
4106 }
4107
4108 pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
4109     fn param(ccx: &CrateCtxt, n: uint) -> ty::t {
4110         ty::mk_param(ccx.tcx, n, local_def(0))
4111     }
4112
4113     let tcx = ccx.tcx;
4114     let name = token::get_ident(it.ident);
4115     let (n_tps, inputs, output) = if name.get().starts_with("atomic_") {
4116         let split : Vec<&str> = name.get().split('_').collect();
4117         assert!(split.len() >= 2, "Atomic intrinsic not correct format");
4118
4119         //We only care about the operation here
4120         match *split.get(1) {
4121             "cxchg" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)),
4122                                 param(ccx, 0),
4123                                 param(ccx, 0)),
4124                         param(ccx, 0)),
4125             "load" => (1, vec!(ty::mk_imm_ptr(tcx, param(ccx, 0))),
4126                        param(ccx, 0)),
4127             "store" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)),
4128                         ty::mk_nil()),
4129
4130             "xchg" | "xadd" | "xsub" | "and"  | "nand" | "or" | "xor" | "max" |
4131             "min"  | "umax" | "umin" => {
4132                 (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)),
4133                  param(ccx, 0))
4134             }
4135             "fence" => {
4136                 (0, Vec::new(), ty::mk_nil())
4137             }
4138             op => {
4139                 tcx.sess.span_err(it.span,
4140                                   format!("unrecognized atomic operation function: `{}`",
4141                                        op));
4142                 return;
4143             }
4144         }
4145
4146     } else {
4147         match name.get() {
4148             "abort" => (0, Vec::new(), ty::mk_bot()),
4149             "breakpoint" => (0, Vec::new(), ty::mk_nil()),
4150             "size_of" |
4151             "pref_align_of" | "min_align_of" => (1u, Vec::new(), ty::mk_uint()),
4152             "init" => (1u, Vec::new(), param(ccx, 0u)),
4153             "uninit" => (1u, Vec::new(), param(ccx, 0u)),
4154             "forget" => (1u, vec!( param(ccx, 0) ), ty::mk_nil()),
4155             "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)),
4156             "move_val_init" => {
4157                 (1u,
4158                  vec!(
4159                     ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), param(ccx, 0)),
4160                     param(ccx, 0u)
4161                   ),
4162                ty::mk_nil())
4163             }
4164             "needs_drop" => (1u, Vec::new(), ty::mk_bool()),
4165             "owns_managed" => (1u, Vec::new(), ty::mk_bool()),
4166
4167             "get_tydesc" => {
4168               let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4169                   Ok(t) => t,
4170                   Err(s) => { tcx.sess.span_fatal(it.span, s); }
4171               };
4172               let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4173                   ty: tydesc_ty,
4174                   mutbl: ast::MutImmutable
4175               });
4176               (1u, Vec::new(), td_ptr)
4177             }
4178             "type_id" => {
4179                 let langid = ccx.tcx.lang_items.require(TypeIdLangItem);
4180                 match langid {
4181                     Ok(did) => (1u, Vec::new(), ty::mk_struct(ccx.tcx, did, substs {
4182                                                  self_ty: None,
4183                                                  tps: Vec::new(),
4184                                                  regions: ty::NonerasedRegions(OwnedSlice::empty())
4185                                                  }) ),
4186                     Err(msg) => { tcx.sess.span_fatal(it.span, msg); }
4187                 }
4188             },
4189             "visit_tydesc" => {
4190               let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4191                   Ok(t) => t,
4192                   Err(s) => { tcx.sess.span_fatal(it.span, s); }
4193               };
4194               let region = ty::ReLateBound(it.id, ty::BrAnon(0));
4195               let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
4196                   Ok((_, vot)) => vot,
4197                   Err(s) => { tcx.sess.span_fatal(it.span, s); }
4198               };
4199
4200               let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4201                   ty: tydesc_ty,
4202                   mutbl: ast::MutImmutable
4203               });
4204               (0, vec!( td_ptr, visitor_object_ty ), ty::mk_nil())
4205             }
4206             "offset" => {
4207               (1,
4208                vec!(
4209                   ty::mk_ptr(tcx, ty::mt {
4210                       ty: param(ccx, 0),
4211                       mutbl: ast::MutImmutable
4212                   }),
4213                   ty::mk_int()
4214                ),
4215                ty::mk_ptr(tcx, ty::mt {
4216                    ty: param(ccx, 0),
4217                    mutbl: ast::MutImmutable
4218                }))
4219             }
4220             "copy_memory" | "copy_nonoverlapping_memory" |
4221             "volatile_copy_memory" | "volatile_copy_nonoverlapping_memory" => {
4222               (1,
4223                vec!(
4224                   ty::mk_ptr(tcx, ty::mt {
4225                       ty: param(ccx, 0),
4226                       mutbl: ast::MutMutable
4227                   }),
4228                   ty::mk_ptr(tcx, ty::mt {
4229                       ty: param(ccx, 0),
4230                       mutbl: ast::MutImmutable
4231                   }),
4232                   ty::mk_uint()
4233                ),
4234                ty::mk_nil())
4235             }
4236             "set_memory" | "volatile_set_memory" => {
4237               (1,
4238                vec!(
4239                   ty::mk_ptr(tcx, ty::mt {
4240                       ty: param(ccx, 0),
4241                       mutbl: ast::MutMutable
4242                   }),
4243                   ty::mk_u8(),
4244                   ty::mk_uint()
4245                ),
4246                ty::mk_nil())
4247             }
4248             "sqrtf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4249             "sqrtf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4250             "powif32" => {
4251                (0,
4252                 vec!( ty::mk_f32(), ty::mk_i32() ),
4253                 ty::mk_f32())
4254             }
4255             "powif64" => {
4256                (0,
4257                 vec!( ty::mk_f64(), ty::mk_i32() ),
4258                 ty::mk_f64())
4259             }
4260             "sinf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4261             "sinf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4262             "cosf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4263             "cosf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4264             "powf32" => {
4265                (0,
4266                 vec!( ty::mk_f32(), ty::mk_f32() ),
4267                 ty::mk_f32())
4268             }
4269             "powf64" => {
4270                (0,
4271                 vec!( ty::mk_f64(), ty::mk_f64() ),
4272                 ty::mk_f64())
4273             }
4274             "expf32"   => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4275             "expf64"   => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4276             "exp2f32"  => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4277             "exp2f64"  => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4278             "logf32"   => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4279             "logf64"   => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4280             "log10f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4281             "log10f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4282             "log2f32"  => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4283             "log2f64"  => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4284             "fmaf32" => {
4285                 (0,
4286                  vec!( ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ),
4287                  ty::mk_f32())
4288             }
4289             "fmaf64" => {
4290                 (0,
4291                  vec!( ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ),
4292                  ty::mk_f64())
4293             }
4294             "fabsf32"      => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4295             "fabsf64"      => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4296             "copysignf32"  => (0, vec!( ty::mk_f32(), ty::mk_f32() ), ty::mk_f32()),
4297             "copysignf64"  => (0, vec!( ty::mk_f64(), ty::mk_f64() ), ty::mk_f64()),
4298             "floorf32"     => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4299             "floorf64"     => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4300             "ceilf32"      => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4301             "ceilf64"      => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4302             "truncf32"     => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4303             "truncf64"     => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4304             "rintf32"      => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4305             "rintf64"      => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4306             "nearbyintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4307             "nearbyintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4308             "roundf32"     => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4309             "roundf64"     => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4310             "ctpop8"       => (0, vec!( ty::mk_u8()  ), ty::mk_u8()),
4311             "ctpop16"      => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4312             "ctpop32"      => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4313             "ctpop64"      => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4314             "ctlz8"        => (0, vec!( ty::mk_u8()  ), ty::mk_u8()),
4315             "ctlz16"       => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4316             "ctlz32"       => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4317             "ctlz64"       => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4318             "cttz8"        => (0, vec!( ty::mk_u8()  ), ty::mk_u8()),
4319             "cttz16"       => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4320             "cttz32"       => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4321             "cttz64"       => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4322             "bswap16"      => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4323             "bswap32"      => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4324             "bswap64"      => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4325
4326             "volatile_load" =>
4327                 (1, vec!( ty::mk_imm_ptr(tcx, param(ccx, 0)) ), param(ccx, 0)),
4328             "volatile_store" =>
4329                 (1, vec!( ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ), ty::mk_nil()),
4330
4331             "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
4332                 (0, vec!(ty::mk_i8(), ty::mk_i8()),
4333                 ty::mk_tup(tcx, vec!(ty::mk_i8(), ty::mk_bool()))),
4334
4335             "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
4336                 (0, vec!(ty::mk_i16(), ty::mk_i16()),
4337                 ty::mk_tup(tcx, vec!(ty::mk_i16(), ty::mk_bool()))),
4338
4339             "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
4340                 (0, vec!(ty::mk_i32(), ty::mk_i32()),
4341                 ty::mk_tup(tcx, vec!(ty::mk_i32(), ty::mk_bool()))),
4342
4343             "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
4344                 (0, vec!(ty::mk_i64(), ty::mk_i64()),
4345                 ty::mk_tup(tcx, vec!(ty::mk_i64(), ty::mk_bool()))),
4346
4347             "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
4348                 (0, vec!(ty::mk_u8(), ty::mk_u8()),
4349                 ty::mk_tup(tcx, vec!(ty::mk_u8(), ty::mk_bool()))),
4350
4351             "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
4352                 (0, vec!(ty::mk_u16(), ty::mk_u16()),
4353                 ty::mk_tup(tcx, vec!(ty::mk_u16(), ty::mk_bool()))),
4354
4355             "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
4356                 (0, vec!(ty::mk_u32(), ty::mk_u32()),
4357                 ty::mk_tup(tcx, vec!(ty::mk_u32(), ty::mk_bool()))),
4358
4359             "u64_add_with_overflow" | "u64_sub_with_overflow"  | "u64_mul_with_overflow" =>
4360                 (0, vec!(ty::mk_u64(), ty::mk_u64()),
4361                 ty::mk_tup(tcx, vec!(ty::mk_u64(), ty::mk_bool()))),
4362
4363             ref other => {
4364                 tcx.sess.span_err(it.span,
4365                                   format!("unrecognized intrinsic function: `{}`",
4366                                        *other));
4367                 return;
4368             }
4369         }
4370     };
4371     let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
4372         fn_style: ast::UnsafeFn,
4373         abi: abi::RustIntrinsic,
4374         sig: FnSig {binder_id: it.id,
4375                     inputs: inputs,
4376                     output: output,
4377                     variadic: false}
4378     });
4379     let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
4380     let i_n_tps = i_ty.generics.type_param_defs().len();
4381     if i_n_tps != n_tps {
4382         tcx.sess.span_err(it.span, format!("intrinsic has wrong number \
4383                                          of type parameters: found {}, \
4384                                          expected {}", i_n_tps, n_tps));
4385     } else {
4386         require_same_types(
4387             tcx, None, false, it.span, i_ty.ty, fty,
4388             || format!("intrinsic has wrong type: \
4389                       expected `{}`",
4390                      ppaux::ty_to_str(ccx.tcx, fty)));
4391     }
4392 }