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