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