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