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