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