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