1 // Copyright 2012-2013 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.
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.
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
20 By far the most complex case is checking the body of a function. This
21 can be broken down into several distinct phases:
23 - gather: creates type variables to represent the type of each local
24 variable and pattern binding.
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.
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.
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
43 - vtable: find and records the impls to use for each trait bound that
44 appears on a type parameter.
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.
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`.
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.
65 The types of top-level items, which never contain unbound type
66 variables, are stored directly into the `tcx` tables.
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
80 use middle::const_eval;
81 use middle::pat_util::pat_id_map;
83 use middle::lint::unreachable_code;
84 use middle::ty::{FnSig, VariantInfo};
85 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
86 use middle::ty::{substs, param_ty, Disr, ExprTyProvider};
88 use middle::typeck::astconv::AstConv;
89 use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
90 use middle::typeck::astconv;
91 use middle::typeck::check::_match::pat_ctxt;
92 use middle::typeck::check::method::{AutoderefReceiver};
93 use middle::typeck::check::method::{AutoderefReceiverFlag};
94 use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
95 use middle::typeck::check::method::{CheckTraitsOnly, DontAutoderefReceiver};
96 use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
97 use middle::typeck::check::regionmanip::relate_free_regions;
98 use middle::typeck::check::vtable::{LocationInfo, VtableContext};
99 use middle::typeck::CrateCtxt;
100 use middle::typeck::infer::{resolve_type, force_tvar};
101 use middle::typeck::infer;
102 use middle::typeck::rscope::bound_self_region;
103 use middle::typeck::rscope::{RegionError};
104 use middle::typeck::rscope::RegionScope;
105 use middle::typeck::{isr_alist, lookup_def_ccx};
106 use middle::typeck::no_params;
107 use middle::typeck::{require_same_types, method_map, vtable_map};
108 use util::common::{block_query, indenter, loop_query};
109 use util::ppaux::{bound_region_ptr_to_str};
113 use std::cast::transmute;
114 use std::hashmap::HashMap;
116 use std::util::replace;
118 use extra::list::Nil;
119 use syntax::abi::AbiSet;
120 use syntax::ast::{provided, required};
123 use syntax::ast_util::local_def;
124 use syntax::ast_util;
125 use syntax::codemap::Span;
127 use syntax::opt_vec::OptVec;
129 use syntax::parse::token;
130 use syntax::parse::token::special_idents;
131 use syntax::print::pprust;
133 use syntax::visit::Visitor;
144 pub struct SelfInfo {
146 self_id: ast::NodeId,
150 /// Fields that are part of a `FnCtxt` which are inherited by
151 /// closures defined within the function. For example:
157 /// Here, the function `foo()` and the closure passed to
158 /// `bar()` will each have their own `FnCtxt`, but they will
159 /// share the inherited fields.
160 pub struct inherited {
161 infcx: @mut infer::InferCtxt,
162 locals: @mut HashMap<ast::NodeId, ty::t>,
165 node_types: @mut HashMap<ast::NodeId, ty::t>,
166 node_type_substs: @mut HashMap<ast::NodeId, ty::substs>,
167 adjustments: @mut HashMap<ast::NodeId, @ty::AutoAdjustment>,
168 method_map: method_map,
169 vtable_map: vtable_map,
177 // A normal closure or fn item.
182 pub struct PurityState {
189 pub fn function(purity: ast::purity, def: ast::NodeId) -> PurityState {
190 PurityState { def: def, purity: purity, from_fn: true }
193 pub fn recurse(&mut self, blk: &ast::Block) -> PurityState {
195 // If this unsafe, then if the outer function was already marked as
196 // unsafe we shouldn't attribute the unsafe'ness to the block. This
197 // way the block can be warned about instead of ignoring this
198 // extraneous block (functions are never warned about).
199 ast::unsafe_fn if self.from_fn => *self,
202 let (purity, def) = match blk.rules {
203 ast::UnsafeBlock => (ast::unsafe_fn, blk.id),
204 ast::DefaultBlock => (purity, self.def),
206 PurityState{ def: def,
214 /// Whether `check_binop` allows overloaded operators to be invoked.
216 enum AllowOverloadedOperatorsFlag {
217 AllowOverloadedOperators,
218 DontAllowOverloadedOperators,
223 // Number of errors that had been reported when we started
224 // checking this function. On exit, if we find that *more* errors
225 // have been reported, we will skip regionck and other work that
226 // expects the types within the function to be consistent.
227 err_count_on_creation: uint,
232 // Sometimes we generate region pointers where the precise region
233 // to use is not known. For example, an expression like `&x.f`
234 // where `x` is of type `@T`: in this case, we will be rooting
235 // `x` onto the stack frame, and we could choose to root it until
236 // the end of (almost) any enclosing block or expression. We
237 // want to pick the narrowest block that encompasses all uses.
239 // What we do in such cases is to generate a region variable with
240 // `region_lb` as a lower bound. The regionck pass then adds
241 // other constriants based on how the variable is used and region
242 // inference selects the ultimate value. Finally, borrowck is
243 // charged with guaranteeing that the value whose address was taken
244 // can actually be made to live as long as it needs to live.
245 region_lb: ast::NodeId,
247 // Says whether we're inside a for loop, in a do block
248 // or neither. Helps with error messages involving the
249 // function return type.
252 in_scope_regions: isr_alist,
259 pub fn blank_inherited(ccx: @mut CrateCtxt) -> @inherited {
261 infcx: infer::new_infer_ctxt(ccx.tcx),
262 locals: @mut HashMap::new(),
263 node_types: @mut HashMap::new(),
264 node_type_substs: @mut HashMap::new(),
265 adjustments: @mut HashMap::new(),
266 method_map: @mut HashMap::new(),
267 vtable_map: @mut HashMap::new(),
271 // Used by check_const and check_enum_variants
272 pub fn blank_fn_ctxt(ccx: @mut CrateCtxt,
274 region_bnd: ast::NodeId)
276 // It's kind of a kludge to manufacture a fake function context
277 // and statement context, but we might as well do write the code only once
279 err_count_on_creation: ccx.tcx.sess.err_count(),
281 ps: PurityState::function(ast::impure_fn, 0),
282 region_lb: region_bnd,
283 in_scope_regions: @Nil,
285 inh: blank_inherited(ccx),
290 impl ExprTyProvider for FnCtxt {
291 fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
295 fn ty_ctxt(&self) -> ty::ctxt {
300 struct CheckItemTypesVisitor { ccx: @mut CrateCtxt }
302 impl Visitor<()> for CheckItemTypesVisitor {
303 fn visit_item(&mut self, i:@ast::item, _:()) {
304 check_item(self.ccx, i);
305 visit::walk_item(self, i, ());
309 pub fn check_item_types(ccx: @mut CrateCtxt, crate: &ast::Crate) {
310 let mut visit = CheckItemTypesVisitor { ccx: ccx };
311 visit::walk_crate(&mut visit, crate, ());
314 pub fn check_bare_fn(ccx: @mut CrateCtxt,
318 self_info: Option<SelfInfo>) {
319 let fty = ty::node_id_to_type(ccx.tcx, id);
320 match ty::get(fty).sty {
321 ty::ty_bare_fn(ref fn_ty) => {
323 check_fn(ccx, self_info, fn_ty.purity,
324 &fn_ty.sig, decl, id, body, Vanilla,
325 @Nil, blank_inherited(ccx));;
327 vtable::resolve_in_block(fcx, body);
328 regionck::regionck_fn(fcx, body);
329 writeback::resolve_type_vars_in_fn(fcx, decl, body, self_info);
331 _ => ccx.tcx.sess.impossible_case(body.span,
332 "check_bare_fn: function type expected")
336 struct GatherLocalsVisitor {
341 impl GatherLocalsVisitor {
342 fn assign(&mut self, nid: ast::NodeId, ty_opt: Option<ty::t>) {
345 // infer the variable's type
346 let var_id = self.fcx.infcx().next_ty_var_id();
347 let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
348 self.fcx.inh.locals.insert(nid, var_ty);
351 // take type that the user specified
352 self.fcx.inh.locals.insert(nid, typ);
358 impl Visitor<()> for GatherLocalsVisitor {
359 // Add explicitly-declared locals.
360 fn visit_local(&mut self, local:@ast::Local, _:()) {
361 let o_ty = match local.ty.node {
362 ast::ty_infer => None,
363 _ => Some(self.fcx.to_ty(&local.ty))
365 self.assign(local.id, o_ty);
366 debug!("Local variable %s is assigned type %s",
367 self.fcx.pat_to_str(local.pat),
368 self.fcx.infcx().ty_to_str(
369 self.fcx.inh.locals.get_copy(&local.id)));
370 visit::walk_local(self, local, ());
373 // Add pattern bindings.
374 fn visit_pat(&mut self, p:@ast::Pat, _:()) {
376 ast::PatIdent(_, ref path, _)
377 if pat_util::pat_is_binding(self.fcx.ccx.tcx.def_map, p) => {
378 self.assign(p.id, None);
379 debug!("Pattern binding %s is assigned to %s",
380 self.tcx.sess.str_of(path.segments[0].identifier),
381 self.fcx.infcx().ty_to_str(
382 self.fcx.inh.locals.get_copy(&p.id)));
386 visit::walk_pat(self, p, ());
390 fn visit_block(&mut self, b:&ast::Block, _:()) {
391 // non-obvious: the `blk` variable maps to region lb, so
392 // we have to keep this up-to-date. This
393 // is... unfortunate. It'd be nice to not need this.
394 do self.fcx.with_region_lb(b.id) {
395 visit::walk_block(self, b, ());
399 // Don't descend into fns and items
400 fn visit_fn(&mut self, _:&visit::fn_kind, _:&ast::fn_decl,
401 _:&ast::Block, _:Span, _:ast::NodeId, _:()) { }
402 fn visit_item(&mut self, _:@ast::item, _:()) { }
406 pub fn check_fn(ccx: @mut CrateCtxt,
407 opt_self_info: Option<SelfInfo>,
414 inherited_isr: isr_alist,
415 inherited: @inherited) -> @mut FnCtxt
419 * Helper used by check_bare_fn and check_expr_fn. Does the
420 * grungy work of checking a function body and returns the
421 * function context used for that purpose, since in the case of a
422 * fn item there is still a bit more to do.
425 * - inherited_isr: regions in scope from the enclosing fn (if any)
426 * - inherited: other fields inherited from the enclosing fn (if any)
430 let err_count_on_creation = tcx.sess.err_count();
432 // ______________________________________________________________________
433 // First, we have to replace any bound regions in the fn and self
434 // types with free ones. The free region references will be bound
435 // the node_id of the body block.
436 let (isr, opt_self_info, fn_sig) = {
437 let opt_self_ty = opt_self_info.map(|i| i.self_ty);
438 let (isr, opt_self_ty, fn_sig) =
439 replace_bound_regions_in_fn_sig(
440 tcx, inherited_isr, opt_self_ty, fn_sig,
441 |br| ty::re_free(ty::FreeRegion {scope_id: body.id,
444 opt_self_info.map_move(
445 |si| SelfInfo {self_ty: opt_self_ty.unwrap(), .. si});
446 (isr, opt_self_info, fn_sig)
449 relate_free_regions(tcx, opt_self_info.map(|s| s.self_ty), &fn_sig);
451 let arg_tys = fn_sig.inputs.map(|a| *a);
452 let ret_ty = fn_sig.output;
454 debug!("check_fn(arg_tys=%?, ret_ty=%?, opt_self_ty=%?)",
455 arg_tys.map(|&a| ppaux::ty_to_str(tcx, a)),
456 ppaux::ty_to_str(tcx, ret_ty),
457 opt_self_info.map(|si| ppaux::ty_to_str(tcx, si.self_ty)));
459 // ______________________________________________________________________
460 // Create the function context. This is either derived from scratch or,
461 // in the case of function expressions, based on the outer context.
462 let fcx: @mut FnCtxt = {
464 err_count_on_creation: err_count_on_creation,
466 ps: PurityState::function(purity, id),
468 in_scope_regions: isr,
475 gather_locals(fcx, decl, body, arg_tys, opt_self_info);
476 check_block_with_expected(fcx, body, Some(ret_ty));
478 // We unify the tail expr's type with the
479 // function result type, if there is a tail expr.
482 let tail_expr_ty = fcx.expr_ty(tail_expr);
483 // Special case: we print a special error if there appears
484 // to be do-block/for-loop confusion
485 demand::suptype_with_fn(fcx, tail_expr.span, false,
486 fcx.ret_ty, tail_expr_ty,
488 fcx.report_mismatched_return_types(sp, e, a, s) });
493 for self_info in opt_self_info.iter() {
494 fcx.write_ty(self_info.self_id, self_info.self_ty);
496 for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
497 fcx.write_ty(input.id, *arg);
502 fn gather_locals(fcx: @mut FnCtxt,
506 opt_self_info: Option<SelfInfo>) {
507 let tcx = fcx.ccx.tcx;
509 let mut visit = GatherLocalsVisitor { fcx: fcx, tcx: tcx, };
511 // Add the self parameter
512 for self_info in opt_self_info.iter() {
513 visit.assign(self_info.self_id, Some(self_info.self_ty));
514 debug!("self is assigned to %s",
515 fcx.infcx().ty_to_str(
516 fcx.inh.locals.get_copy(&self_info.self_id)));
519 // Add formal parameters.
520 for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
521 // Create type variables for each argument.
522 do pat_util::pat_bindings(tcx.def_map, input.pat)
523 |_bm, pat_id, _sp, _path| {
524 visit.assign(pat_id, None);
527 // Check the pattern.
530 map: pat_id_map(tcx.def_map, input.pat),
532 _match::check_pat(&pcx, input.pat, *arg_ty);
535 visit.visit_block(body, ());
539 pub fn check_method(ccx: @mut CrateCtxt,
540 method: @ast::method)
542 let method_def_id = local_def(method.id);
543 let method_ty = ty::method(ccx.tcx, method_def_id);
544 let opt_self_info = method_ty.transformed_self_ty.map_move(|ty| {
545 SelfInfo {self_ty: ty,
546 self_id: method.self_id,
547 span: method.explicit_self.span}
559 pub fn check_no_duplicate_fields(tcx: ty::ctxt,
560 fields: ~[(ast::Ident, Span)]) {
561 let mut field_names = HashMap::new();
563 for p in fields.iter() {
565 let orig_sp = field_names.find(&id).map_move(|x| *x);
568 tcx.sess.span_err(sp, fmt!("Duplicate field name %s in record type declaration",
569 tcx.sess.str_of(id)));
570 tcx.sess.span_note(orig_sp, "First declaration of this field occurred here");
574 field_names.insert(id, sp);
580 pub fn check_struct(ccx: @mut CrateCtxt, id: ast::NodeId, span: Span) {
583 // Check that the class is instantiable
584 check_instantiable(tcx, span, id);
586 if ty::lookup_simd(tcx, local_def(id)) {
587 check_simd(tcx, span, id);
591 pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
592 debug!("check_item(it.id=%d, it.ident=%s)",
594 ty::item_path_str(ccx.tcx, local_def(it.id)));
595 let _indenter = indenter();
598 ast::item_static(_, _, e) => check_const(ccx, it.span, e, it.id),
599 ast::item_enum(ref enum_definition, _) => {
600 check_enum_variants(ccx,
602 enum_definition.variants,
605 ast::item_fn(ref decl, _, _, _, ref body) => {
606 check_bare_fn(ccx, decl, body, it.id, None);
608 ast::item_impl(_, _, _, ref ms) => {
609 let rp = ccx.tcx.region_paramd_items.find(&it.id).map_move(|x| *x);
610 debug!("item_impl %s with id %d rp %?",
611 ccx.tcx.sess.str_of(it.ident), it.id, rp);
613 check_method(ccx, *m);
615 vtable::resolve_impl(ccx, it);
617 ast::item_trait(_, _, ref trait_methods) => {
618 for trait_method in (*trait_methods).iter() {
619 match *trait_method {
621 // Nothing to do, since required methods don't have
625 check_method(ccx, m);
630 ast::item_struct(*) => {
631 check_struct(ccx, it.id, it.span);
633 ast::item_ty(ref t, ref generics) => {
634 let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id);
635 check_bounds_are_used(ccx, t.span, &generics.ty_params, tpt_ty);
637 ast::item_foreign_mod(ref m) => {
638 if m.abis.is_intrinsic() {
639 for item in m.items.iter() {
640 check_intrinsic_type(ccx, *item);
643 for item in m.items.iter() {
644 let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id));
645 if tpt.generics.has_type_params() {
646 ccx.tcx.sess.span_err(
648 fmt!("foreign items may not have type parameters"));
653 _ => {/* nothing to do */ }
657 impl AstConv for FnCtxt {
658 fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
660 fn get_item_ty(&self, id: ast::DefId) -> ty::ty_param_bounds_and_ty {
661 ty::lookup_item_type(self.tcx(), id)
664 fn get_trait_def(&self, id: ast::DefId) -> @ty::TraitDef {
665 ty::lookup_trait_def(self.tcx(), id)
668 fn ty_infer(&self, _span: Span) -> ty::t {
669 self.infcx().next_ty_var()
674 pub fn infcx(&self) -> @mut infer::InferCtxt {
677 pub fn err_count_since_creation(&self) -> uint {
678 self.ccx.tcx.sess.err_count() - self.err_count_on_creation
680 pub fn search_in_scope_regions(&self,
682 br: ty::bound_region)
683 -> Result<ty::Region, RegionError> {
684 let in_scope_regions = self.in_scope_regions;
685 match in_scope_regions.find(br) {
686 Some(r) => result::Ok(r),
688 let blk_br = ty::br_named(special_idents::blk);
690 result::Ok(self.block_region())
692 result::Err(RegionError {
694 fmt!("named region `%s` not in scope here",
695 bound_region_ptr_to_str(self.tcx(), br))
698 self.infcx().next_region_var(
699 infer::BoundRegionError(span))
708 impl RegionScope for FnCtxt {
709 fn anon_region(&self, span: Span) -> Result<ty::Region, RegionError> {
710 result::Ok(self.infcx().next_region_var(infer::MiscVariable(span)))
712 fn self_region(&self, span: Span) -> Result<ty::Region, RegionError> {
713 self.search_in_scope_regions(span, ty::br_self)
715 fn named_region(&self,
717 id: ast::Ident) -> Result<ty::Region, RegionError> {
718 self.search_in_scope_regions(span, ty::br_named(id))
723 pub fn tag(&self) -> ~str {
725 fmt!("%x", transmute(self))
729 pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t {
730 match self.inh.locals.find(&nid) {
733 self.tcx().sess.span_bug(
735 fmt!("No type for local variable %?", nid));
740 pub fn block_region(&self) -> ty::Region {
741 ty::re_scope(self.region_lb)
745 pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
746 debug!("write_ty(%d, %s) in fcx %s",
747 node_id, ppaux::ty_to_str(self.tcx(), ty), self.tag());
748 self.inh.node_types.insert(node_id, ty);
751 pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::substs) {
752 if !ty::substs_is_noop(&substs) {
753 debug!("write_substs(%d, %s) in fcx %s",
755 ty::substs_to_str(self.tcx(), &substs),
757 self.inh.node_type_substs.insert(node_id, substs);
761 pub fn write_ty_substs(&self,
762 node_id: ast::NodeId,
764 substs: ty::substs) {
765 let ty = ty::subst(self.tcx(), &substs, ty);
766 self.write_ty(node_id, ty);
767 self.write_substs(node_id, substs);
770 pub fn write_autoderef_adjustment(&self,
771 node_id: ast::NodeId,
773 if derefs == 0 { return; }
774 self.write_adjustment(
776 @ty::AutoDerefRef(ty::AutoDerefRef {
782 pub fn write_adjustment(&self,
783 node_id: ast::NodeId,
784 adj: @ty::AutoAdjustment) {
785 debug!("write_adjustment(node_id=%?, adj=%?)", node_id, adj);
786 self.inh.adjustments.insert(node_id, adj);
789 pub fn write_nil(&self, node_id: ast::NodeId) {
790 self.write_ty(node_id, ty::mk_nil());
792 pub fn write_bot(&self, node_id: ast::NodeId) {
793 self.write_ty(node_id, ty::mk_bot());
795 pub fn write_error(@mut self, node_id: ast::NodeId) {
796 self.write_ty(node_id, ty::mk_err());
799 pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
800 ast_ty_to_ty(self, self, ast_t)
803 pub fn pat_to_str(&self, pat: @ast::Pat) -> ~str {
807 pub fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
808 match self.inh.node_types.find(&ex.id) {
811 self.tcx().sess.bug(fmt!("no type for expr in fcx %s",
817 pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
818 match self.inh.node_types.find(&id) {
822 fmt!("no type for node %d: %s in fcx %s",
823 id, ast_map::node_id_to_str(
824 self.tcx().items, id,
825 token::get_ident_interner()),
831 pub fn node_ty_substs(&self, id: ast::NodeId) -> ty::substs {
832 match self.inh.node_type_substs.find(&id) {
833 Some(ts) => (*ts).clone(),
836 fmt!("no type substs for node %d: %s in fcx %s",
837 id, ast_map::node_id_to_str(
838 self.tcx().items, id,
839 token::get_ident_interner()),
845 pub fn opt_node_ty_substs(&self,
847 f: &fn(&ty::substs) -> bool)
849 match self.inh.node_type_substs.find(&id) {
855 pub fn mk_subty(&self,
857 origin: infer::TypeOrigin,
860 -> Result<(), ty::type_err> {
861 infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
864 pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t)
865 -> Result<(), ty::type_err> {
866 infer::can_mk_subty(self.infcx(), sub, sup)
869 pub fn mk_assignty(&self,
873 -> Result<(), ty::type_err> {
874 match infer::mk_coercety(self.infcx(),
876 infer::ExprAssignable(expr),
879 Ok(None) => result::Ok(()),
880 Err(ref e) => result::Err((*e)),
881 Ok(Some(adjustment)) => {
882 self.write_adjustment(expr.id, adjustment);
888 pub fn can_mk_assignty(&self, sub: ty::t, sup: ty::t)
889 -> Result<(), ty::type_err> {
890 infer::can_mk_coercety(self.infcx(), sub, sup)
893 pub fn mk_eqty(&self,
895 origin: infer::TypeOrigin,
898 -> Result<(), ty::type_err> {
899 infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
902 pub fn mk_subr(&self,
904 origin: infer::SubregionOrigin,
907 infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
910 pub fn with_region_lb<R>(@mut self, lb: ast::NodeId, f: &fn() -> R)
912 let old_region_lb = self.region_lb;
915 self.region_lb = old_region_lb;
919 pub fn region_var_if_parameterized(&self,
920 rp: Option<ty::region_variance>,
922 -> OptVec<ty::Region> {
924 None => opt_vec::Empty,
927 self.infcx().next_region_var(
928 infer::BoundRegionInTypeOrImpl(span)))
933 pub fn type_error_message(&self,
935 mk_msg: &fn(~str) -> ~str,
937 err: Option<&ty::type_err>) {
938 self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
941 pub fn report_mismatched_return_types(&self,
945 err: &ty::type_err) {
947 if ty::type_is_error(e) || ty::type_is_error(a) {
950 self.infcx().report_mismatched_types(sp, e, a, err)
953 pub fn report_mismatched_types(&self,
957 err: &ty::type_err) {
958 self.infcx().report_mismatched_types(sp, e, a, err)
962 pub fn do_autoderef(fcx: @mut FnCtxt, sp: Span, t: ty::t) -> (ty::t, uint) {
965 * Autoderefs the type `t` as many times as possible, returning
966 * a new type and a counter for how many times the type was
967 * deref'd. If the counter is non-zero, the receiver is responsible
968 * for inserting an AutoAdjustment record into `tcx.adjustments`
969 * so that trans/borrowck/etc know about this autoderef. */
972 let mut enum_dids = ~[];
973 let mut autoderefs = 0;
975 let sty = structure_of(fcx, sp, t1);
977 // Some extra checks to detect weird cycles and so forth:
979 ty::ty_box(inner) | ty::ty_uniq(inner) |
980 ty::ty_rptr(_, inner) => {
981 match ty::get(t1).sty {
982 ty::ty_infer(ty::TyVar(v1)) => {
983 ty::occurs_check(fcx.ccx.tcx, sp, v1,
984 ty::mk_box(fcx.ccx.tcx, inner));
989 ty::ty_enum(ref did, _) => {
990 // Watch out for a type like `enum t = @t`. Such a
991 // type would otherwise infinitely auto-deref. Only
992 // autoderef loops during typeck (basically, this one
993 // and the loops in typeck::check::method) need to be
994 // concerned with this, as an error will be reported
995 // on the enum definition as well because the enum is
997 if enum_dids.contains(did) {
998 return (t1, autoderefs);
1000 enum_dids.push(*did);
1005 // Otherwise, deref if type is derefable:
1006 match ty::deref_sty(fcx.ccx.tcx, sty, false) {
1008 return (t1, autoderefs);
1018 // AST fragment checking
1019 pub fn check_lit(fcx: @mut FnCtxt, lit: @ast::lit) -> ty::t {
1020 let tcx = fcx.ccx.tcx;
1023 ast::lit_str(*) => ty::mk_estr(tcx, ty::vstore_slice(ty::re_static)),
1024 ast::lit_char(_) => ty::mk_char(),
1025 ast::lit_int(_, t) => ty::mk_mach_int(t),
1026 ast::lit_uint(_, t) => ty::mk_mach_uint(t),
1027 ast::lit_int_unsuffixed(_) => {
1028 // An unsuffixed integer literal could have any integral type,
1029 // so we create an integral type variable for it.
1030 ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
1032 ast::lit_float(_, t) => ty::mk_mach_float(t),
1033 ast::lit_float_unsuffixed(_) => {
1034 // An unsuffixed floating point literal could have any floating point
1035 // type, so we create a floating point type variable for it.
1036 ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())
1038 ast::lit_nil => ty::mk_nil(),
1039 ast::lit_bool(_) => ty::mk_bool()
1043 pub fn valid_range_bounds(ccx: @mut CrateCtxt,
1047 match const_eval::compare_lit_exprs(ccx.tcx, from, to) {
1048 Some(val) => Some(val <= 0),
1053 pub fn check_expr_has_type(
1054 fcx: @mut FnCtxt, expr: @ast::Expr,
1056 do check_expr_with_unifier(fcx, expr, Some(expected)) {
1057 demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
1061 pub fn check_expr_coercable_to_type(
1062 fcx: @mut FnCtxt, expr: @ast::Expr,
1064 do check_expr_with_unifier(fcx, expr, Some(expected)) {
1065 demand::coerce(fcx, expr.span, expected, expr)
1069 pub fn check_expr_with_hint(
1070 fcx: @mut FnCtxt, expr: @ast::Expr,
1072 check_expr_with_unifier(fcx, expr, Some(expected), || ())
1075 pub fn check_expr_with_opt_hint(
1076 fcx: @mut FnCtxt, expr: @ast::Expr,
1077 expected: Option<ty::t>) {
1078 check_expr_with_unifier(fcx, expr, expected, || ())
1081 pub fn check_expr(fcx: @mut FnCtxt, expr: @ast::Expr) {
1082 check_expr_with_unifier(fcx, expr, None, || ())
1085 // determine the `self` type, using fresh variables for all variables
1086 // declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
1087 // would return ($0, $1) where $0 and $1 are freshly instantiated type
1089 pub fn impl_self_ty(vcx: &VtableContext,
1090 location_info: &LocationInfo, // (potential) receiver for
1093 -> ty_param_substs_and_ty {
1094 let tcx = vcx.tcx();
1096 let (n_tps, region_param, raw_ty) = {
1097 let ity = ty::lookup_item_type(tcx, did);
1098 (ity.generics.type_param_defs.len(), ity.generics.region_param, ity.ty)
1101 let regions = ty::NonerasedRegions(if region_param.is_some() {
1102 opt_vec::with(vcx.infcx.next_region_var(
1103 infer::BoundRegionInTypeOrImpl(location_info.span)))
1107 let tps = vcx.infcx.next_ty_vars(n_tps);
1109 let substs = substs {regions: regions, self_ty: None, tps: tps};
1110 let substd_ty = ty::subst(tcx, &substs, raw_ty);
1112 ty_param_substs_and_ty { substs: substs, ty: substd_ty }
1115 // Only for fields! Returns <none> for methods>
1116 // Indifferent to privacy flags
1117 pub fn lookup_field_ty(tcx: ty::ctxt,
1118 class_id: ast::DefId,
1119 items: &[ty::field_ty],
1120 fieldname: ast::Name,
1121 substs: &ty::substs) -> Option<ty::t> {
1123 let o_field = items.iter().find(|f| f.ident.name == fieldname);
1124 do o_field.map() |f| {
1125 ty::lookup_field_type(tcx, class_id, f.id, substs)
1129 // Controls whether the arguments are automatically referenced. This is useful
1130 // for overloaded binary and unary operators.
1131 pub enum DerefArgs {
1136 // Given the provenance of a static method, returns the generics of the static
1137 // method's container.
1138 fn generics_of_static_method_container(type_context: ty::ctxt,
1139 provenance: ast::MethodProvenance)
1142 ast::FromTrait(trait_def_id) => {
1143 ty::lookup_trait_def(type_context, trait_def_id).generics
1145 ast::FromImpl(impl_def_id) => {
1146 ty::lookup_item_type(type_context, impl_def_id).generics
1151 // Verifies that type parameters supplied in paths are in the right
1153 fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt,
1156 // We only care about checking the case in which the path has two or
1158 if path.segments.len() < 2 {
1162 // Verify that no lifetimes or type parameters are present anywhere
1163 // except the final two elements of the path.
1164 for i in range(0, path.segments.len() - 2) {
1165 match path.segments[i].lifetime {
1168 function_context.tcx()
1170 .span_err(lifetime.span,
1171 "lifetime parameters may not \
1176 for typ in path.segments[i].types.iter() {
1177 function_context.tcx()
1180 "type parameters may not appear here")
1184 // If there are no parameters at all, there is nothing more to do; the
1185 // rest of typechecking will (attempt to) infer everything.
1188 .all(|s| s.lifetime.is_none() && s.types.is_empty()) {
1193 // If this is a static method of a trait or implementation, then
1194 // ensure that the segment of the path which names the trait or
1195 // implementation (the penultimate segment) is annotated with the
1196 // right number of type parameters.
1197 ast::DefStaticMethod(_, provenance, _) => {
1199 generics_of_static_method_container(function_context.ccx.tcx,
1201 let name = match provenance {
1202 ast::FromTrait(_) => "trait",
1203 ast::FromImpl(_) => "impl",
1206 let trait_segment = &path.segments[path.segments.len() - 2];
1208 // Make sure lifetime parameterization agrees with the trait or
1209 // implementation type.
1210 match (generics.region_param, trait_segment.lifetime) {
1211 (Some(_), None) => {
1212 function_context.tcx()
1214 .span_err(path.span,
1215 fmt!("this %s has a lifetime \
1217 lifetime was specified",
1220 (None, Some(_)) => {
1221 function_context.tcx()
1223 .span_err(path.span,
1224 fmt!("this %s has no lifetime \
1225 parameter but a lifetime \
1229 (Some(_), Some(_)) | (None, None) => {}
1232 // Make sure the number of type parameters supplied on the trait
1233 // or implementation segment equals the number of type parameters
1234 // on the trait or implementation definition.
1235 let trait_type_parameter_count = generics.type_param_defs.len();
1236 let supplied_type_parameter_count = trait_segment.types.len();
1237 if trait_type_parameter_count != supplied_type_parameter_count {
1238 let trait_count_suffix = if trait_type_parameter_count == 1 {
1243 let supplied_count_suffix =
1244 if supplied_type_parameter_count == 1 {
1249 function_context.tcx()
1251 .span_err(path.span,
1252 fmt!("the %s referenced by this \
1254 parameter%s, but %u type \
1255 parameter%s were supplied",
1257 trait_type_parameter_count,
1259 supplied_type_parameter_count,
1260 supplied_count_suffix))
1264 // Verify that no lifetimes or type parameters are present on
1265 // the penultimate segment of the path.
1266 let segment = &path.segments[path.segments.len() - 2];
1267 match segment.lifetime {
1270 function_context.tcx()
1272 .span_err(lifetime.span,
1273 "lifetime parameters may not
1277 for typ in segment.types.iter() {
1278 function_context.tcx()
1281 "type parameters may not appear \
1283 function_context.tcx()
1285 .span_note(typ.span,
1286 fmt!("this is a %?", def));
1293 /// If an expression has any sub-expressions that result in a type error,
1294 /// inspecting that expression's type with `ty::type_is_error` will return
1295 /// true. Likewise, if an expression is known to diverge, inspecting its
1296 /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
1297 /// strict, _|_ can appear in the type of an expression that does not,
1298 /// itself, diverge: for example, fn() -> _|_.)
1299 /// Note that inspecting a type's structure *directly* may expose the fact
1300 /// that there are actually multiple representations for both `ty_err` and
1301 /// `ty_bot`, so avoid that when err and bot need to be handled differently.
1302 pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
1304 expected: Option<ty::t>,
1306 debug!(">> typechecking");
1308 fn check_method_argument_types(
1311 method_fn_ty: ty::t,
1312 callee_expr: @ast::Expr,
1313 args: &[@ast::Expr],
1314 sugar: ast::CallSugar,
1315 deref_args: DerefArgs) -> ty::t
1317 if ty::type_is_error(method_fn_ty) {
1318 let err_inputs = err_args(args.len());
1319 check_argument_types(fcx, sp, err_inputs, callee_expr,
1320 args, sugar, deref_args);
1323 match ty::get(method_fn_ty).sty {
1324 ty::ty_bare_fn(ref fty) => {
1325 check_argument_types(fcx, sp, fty.sig.inputs, callee_expr,
1326 args, sugar, deref_args);
1330 fcx.tcx().sess.span_bug(
1332 fmt!("Method without bare fn type"));
1338 fn check_argument_types(
1341 fn_inputs: &[ty::t],
1342 callee_expr: @ast::Expr,
1343 args: &[@ast::Expr],
1344 sugar: ast::CallSugar,
1345 deref_args: DerefArgs)
1349 * Generic function that factors out common logic from
1350 * function calls, method calls and overloaded operators.
1353 let tcx = fcx.ccx.tcx;
1355 // Grab the argument types, supplying fresh type variables
1356 // if the wrong number of arguments were supplied
1357 let supplied_arg_count = args.len();
1358 let expected_arg_count = fn_inputs.len();
1359 let formal_tys = if expected_arg_count == supplied_arg_count {
1360 fn_inputs.map(|a| *a)
1362 let suffix = match sugar {
1364 ast::DoSugar => " (including the closure passed by \
1366 ast::ForSugar => " (including the closure passed by \
1369 let msg = fmt!("this function takes %u parameter%s but \
1370 %u parameter%s supplied%s",
1372 if expected_arg_count == 1 {""}
1375 if supplied_arg_count == 1 {" was"}
1379 tcx.sess.span_err(sp, msg);
1381 vec::from_elem(supplied_arg_count, ty::mk_err())
1384 debug!("check_argument_types: formal_tys=%?",
1385 formal_tys.map(|t| fcx.infcx().ty_to_str(*t)));
1387 // Check the arguments.
1388 // We do this in a pretty awful way: first we typecheck any arguments
1389 // that are not anonymous functions, then we typecheck the anonymous
1390 // functions. This is so that we have more information about the types
1391 // of arguments when we typecheck the functions. This isn't really the
1392 // right way to do this.
1393 let xs = [false, true];
1394 for check_blocks in xs.iter() {
1395 let check_blocks = *check_blocks;
1396 debug!("check_blocks=%b", check_blocks);
1398 // More awful hacks: before we check the blocks, try to do
1399 // an "opportunistic" vtable resolution of any trait
1400 // bounds on the call.
1402 vtable::early_resolve_expr(callee_expr, fcx, true);
1405 for (i, arg) in args.iter().enumerate() {
1406 let is_block = match arg.node {
1407 ast::ExprFnBlock(*) |
1408 ast::ExprDoBody(*) => true,
1412 if is_block == check_blocks {
1413 debug!("checking the argument");
1414 let mut formal_ty = formal_tys[i];
1418 match ty::get(formal_ty).sty {
1419 ty::ty_rptr(_, mt) => formal_ty = mt.ty,
1422 fcx.ccx.tcx.sess.span_bug(arg.span, "no ref");
1429 check_expr_coercable_to_type(
1430 fcx, *arg, formal_ty);
1437 fn err_args(len: uint) -> ~[ty::t] {
1438 vec::from_fn(len, |_| ty::mk_err())
1441 // A generic function for checking assignment expressions
1442 fn check_assignment(fcx: @mut FnCtxt,
1446 check_expr(fcx, lhs);
1447 let lhs_type = fcx.expr_ty(lhs);
1448 check_expr_has_type(fcx, rhs, lhs_type);
1449 fcx.write_ty(id, ty::mk_nil());
1450 // The callee checks for bot / err, we don't need to
1453 fn write_call(fcx: @mut FnCtxt,
1454 call_expr: @ast::Expr,
1456 sugar: ast::CallSugar) {
1457 let ret_ty = match sugar {
1459 match ty::get(output).sty {
1461 _ => fcx.type_error_message(call_expr.span, |actual| {
1462 fmt!("expected `for` closure to return `bool`, \
1463 but found `%s`", actual) },
1470 fcx.write_ty(call_expr.id, ret_ty);
1473 // A generic function for doing all of the checking for call expressions
1474 fn check_call(fcx: @mut FnCtxt,
1475 callee_id: ast::NodeId,
1476 call_expr: @ast::Expr,
1478 args: &[@ast::Expr],
1479 sugar: ast::CallSugar) {
1480 // Index expressions need to be handled separately, to inform them
1481 // that they appear in call position.
1484 // Store the type of `f` as the type of the callee
1485 let fn_ty = fcx.expr_ty(f);
1487 // FIXME(#6273) should write callee type AFTER regions have
1488 // been subst'd. However, it is awkward to deal with this
1489 // now. Best thing would I think be to just have a separate
1490 // "callee table" that contains the FnSig and not a general
1492 fcx.write_ty(callee_id, fn_ty);
1494 // Extract the function signature from `in_fty`.
1495 let fn_sty = structure_of(fcx, f.span, fn_ty);
1497 // This is the "default" function signature, used in case of error.
1498 // In that case, we check each argument against "error" in order to
1499 // set up all the node type bindings.
1500 let error_fn_sig = FnSig {
1501 bound_lifetime_names: opt_vec::Empty,
1502 inputs: err_args(args.len()),
1503 output: ty::mk_err()
1506 let fn_sig = match *fn_sty {
1507 ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) |
1508 ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => sig,
1510 fcx.type_error_message(call_expr.span, |actual| {
1511 fmt!("expected function but \
1512 found `%s`", actual) }, fn_ty, None);
1517 // Replace any bound regions that appear in the function
1518 // signature with region variables
1519 let (_, _, fn_sig) =
1520 replace_bound_regions_in_fn_sig(fcx.tcx(),
1526 infer::BoundRegionInFnCall(call_expr.span, br)));
1528 // Call the generic checker.
1529 check_argument_types(fcx, call_expr.span, fn_sig.inputs, f,
1530 args, sugar, DontDerefArgs);
1532 write_call(fcx, call_expr, fn_sig.output, sugar);
1535 // Checks a method call.
1536 fn check_method_call(fcx: @mut FnCtxt,
1537 callee_id: ast::NodeId,
1540 method_name: ast::Ident,
1541 args: &[@ast::Expr],
1543 sugar: ast::CallSugar) {
1544 check_expr(fcx, rcvr);
1546 // no need to check for bot/err -- callee does that
1547 let expr_t = structurally_resolved_type(fcx,
1551 let tps = tps.map(|ast_ty| fcx.to_ty(ast_ty));
1552 match method::lookup(fcx,
1560 CheckTraitsAndInherentMethods,
1561 AutoderefReceiver) {
1562 Some(ref entry) => {
1563 let method_map = fcx.inh.method_map;
1564 method_map.insert(expr.id, (*entry));
1567 debug!("(checking method call) failing expr is %d", expr.id);
1569 fcx.type_error_message(expr.span,
1571 fmt!("type `%s` does not implement any method in scope \
1574 fcx.ccx.tcx.sess.str_of(method_name))
1579 // Add error type for the result
1580 fcx.write_error(expr.id);
1581 fcx.write_error(callee_id);
1585 // Call the generic checker.
1586 let fn_ty = fcx.node_ty(callee_id);
1587 let ret_ty = check_method_argument_types(fcx, expr.span,
1588 fn_ty, expr, args, sugar,
1591 write_call(fcx, expr, ret_ty, sugar);
1594 // A generic function for checking the then and else in an if
1596 fn check_then_else(fcx: @mut FnCtxt,
1597 cond_expr: @ast::Expr,
1598 then_blk: &ast::Block,
1599 opt_else_expr: Option<@ast::Expr>,
1602 expected: Option<ty::t>) {
1603 check_expr_has_type(fcx, cond_expr, ty::mk_bool());
1605 let branches_ty = match opt_else_expr {
1606 Some(else_expr) => {
1607 check_block_with_expected(fcx, then_blk, expected);
1608 let then_ty = fcx.node_ty(then_blk.id);
1609 check_expr_with_opt_hint(fcx, else_expr, expected);
1610 let else_ty = fcx.expr_ty(else_expr);
1611 infer::common_supertype(fcx.infcx(),
1612 infer::IfExpression(sp),
1618 check_block_no_value(fcx, then_blk);
1623 let cond_ty = fcx.expr_ty(cond_expr);
1624 let if_ty = if ty::type_is_error(cond_ty) {
1626 } else if ty::type_is_bot(cond_ty) {
1632 fcx.write_ty(id, if_ty);
1635 fn lookup_op_method(fcx: @mut FnCtxt,
1636 callee_id: ast::NodeId,
1638 self_ex: @ast::Expr,
1641 args: ~[@ast::Expr],
1642 deref_args: DerefArgs,
1643 autoderef_receiver: AutoderefReceiverFlag,
1644 unbound_method: &fn(),
1645 _expected_result: Option<ty::t>
1648 match method::lookup(fcx, op_ex, self_ex,
1649 callee_id, opname, self_t, [],
1650 deref_args, CheckTraitsOnly, autoderef_receiver) {
1651 Some(ref origin) => {
1652 let method_ty = fcx.node_ty(callee_id);
1653 let method_map = fcx.inh.method_map;
1654 method_map.insert(op_ex.id, *origin);
1655 check_method_argument_types(fcx, op_ex.span,
1656 method_ty, op_ex, args,
1657 ast::NoSugar, deref_args)
1661 // Check the args anyway
1662 // so we get all the error messages
1663 let expected_ty = ty::mk_err();
1664 check_method_argument_types(fcx, op_ex.span,
1665 expected_ty, op_ex, args,
1666 ast::NoSugar, deref_args);
1672 // could be either a expr_binop or an expr_assign_binop
1673 fn check_binop(fcx: @mut FnCtxt,
1674 callee_id: ast::NodeId,
1679 // Used only in the error case
1680 expected_result: Option<ty::t>,
1681 allow_overloaded_operators: AllowOverloadedOperatorsFlag
1683 let tcx = fcx.ccx.tcx;
1685 check_expr(fcx, lhs);
1686 // Callee does bot / err checking
1687 let lhs_t = structurally_resolved_type(fcx, lhs.span,
1690 if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) {
1691 // Shift is a special case: rhs can be any integral type
1692 check_expr(fcx, rhs);
1693 let rhs_t = fcx.expr_ty(rhs);
1694 require_integral(fcx, rhs.span, rhs_t);
1695 fcx.write_ty(expr.id, lhs_t);
1699 if ty::is_binopable(tcx, lhs_t, op) {
1700 let tvar = fcx.infcx().next_ty_var();
1701 demand::suptype(fcx, expr.span, tvar, lhs_t);
1702 check_expr_has_type(fcx, rhs, tvar);
1704 let result_t = match op {
1705 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGe |
1714 fcx.write_ty(expr.id, result_t);
1718 if op == ast::BiOr || op == ast::BiAnd {
1719 // This is an error; one of the operands must have the wrong
1721 fcx.write_error(expr.id);
1722 fcx.write_error(rhs.id);
1723 fcx.type_error_message(expr.span, |actual| {
1724 fmt!("binary operation %s cannot be applied \
1726 ast_util::binop_to_str(op), actual)},
1731 // Check for overloaded operators if allowed.
1733 if allow_overloaded_operators == AllowOverloadedOperators {
1734 result_t = check_user_binop(fcx,
1743 fcx.type_error_message(expr.span,
1745 fmt!("binary operation %s cannot be \
1746 applied to type `%s`",
1747 ast_util::binop_to_str(op),
1752 result_t = ty::mk_err();
1755 fcx.write_ty(expr.id, result_t);
1756 if ty::type_is_error(result_t) {
1757 fcx.write_ty(rhs.id, result_t);
1761 fn check_user_binop(fcx: @mut FnCtxt,
1762 callee_id: ast::NodeId,
1764 lhs_expr: @ast::Expr,
1765 lhs_resolved_t: ty::t,
1768 expected_result: Option<ty::t>) -> ty::t {
1769 let tcx = fcx.ccx.tcx;
1770 match ast_util::binop_to_method_name(op) {
1772 let if_op_unbound = || {
1773 fcx.type_error_message(ex.span, |actual| {
1774 fmt!("binary operation %s cannot be applied \
1776 ast_util::binop_to_str(op), actual)},
1777 lhs_resolved_t, None)
1779 return lookup_op_method(fcx, callee_id, ex, lhs_expr, lhs_resolved_t,
1780 token::intern(*name),
1781 ~[rhs], DoDerefArgs, DontAutoderefReceiver, if_op_unbound,
1786 check_expr(fcx, rhs);
1788 // If the or operator is used it might be that the user forgot to
1789 // supply the do keyword. Let's be more helpful in that situation.
1790 if op == ast::BiOr {
1791 match ty::get(lhs_resolved_t).sty {
1792 ty::ty_bare_fn(_) | ty::ty_closure(_) => {
1794 ex.span, "did you forget the `do` keyword for the call?");
1803 fn check_user_unop(fcx: @mut FnCtxt,
1804 callee_id: ast::NodeId,
1808 rhs_expr: @ast::Expr,
1810 expected_t: Option<ty::t>)
1813 fcx, callee_id, ex, rhs_expr, rhs_t,
1814 token::intern(mname), ~[],
1815 DoDerefArgs, DontAutoderefReceiver,
1817 fcx.type_error_message(ex.span, |actual| {
1818 fmt!("cannot apply unary operator `%s` to type `%s`",
1824 // Resolves `expected` by a single level if it is a variable and passes it
1825 // through the `unpack` function. It there is no expected type or
1826 // resolution is not possible (e.g., no constraints yet present), just
1828 fn unpack_expected<O>(fcx: @mut FnCtxt,
1829 expected: Option<ty::t>,
1830 unpack: &fn(&ty::sty) -> Option<O>)
1834 match resolve_type(fcx.infcx(), t, force_tvar) {
1835 Ok(t) => unpack(&ty::get(t).sty),
1843 fn check_expr_fn(fcx: @mut FnCtxt,
1845 ast_sigil_opt: Option<ast::Sigil>,
1846 decl: &ast::fn_decl,
1849 expected: Option<ty::t>) {
1850 let tcx = fcx.ccx.tcx;
1852 // Find the expected input/output types (if any). Careful to
1853 // avoid capture of bound regions in the expected type. See
1854 // def'n of br_cap_avoid() for a more lengthy explanation of
1855 // what's going on here.
1856 // Also try to pick up inferred purity and sigil, defaulting
1857 // to impure and block. Note that we only will use those for
1858 // block syntax lambdas; that is, lambdas without explicit
1860 let expected_sty = unpack_expected(fcx,
1862 |x| Some((*x).clone()));
1863 let error_happened = false;
1868 expected_bounds) = {
1869 match expected_sty {
1870 Some(ty::ty_closure(ref cenv)) => {
1873 replace_bound_regions_in_fn_sig(
1874 tcx, @Nil, None, &cenv.sig,
1875 |br| ty::re_bound(ty::br_cap_avoid(id, @br)));
1876 (Some(sig), cenv.purity, cenv.sigil,
1877 cenv.onceness, cenv.bounds)
1880 // Not an error! Means we're inferring the closure type
1881 (None, ast::impure_fn, ast::BorrowedSigil,
1882 ast::Many, ty::EmptyBuiltinBounds())
1887 // If the proto is specified, use that, otherwise select a
1888 // proto based on inference.
1889 let (sigil, purity) = match ast_sigil_opt {
1890 Some(p) => (p, ast::impure_fn),
1891 None => (expected_sigil, expected_purity)
1894 // construct the function type
1895 let fn_ty = astconv::ty_of_closure(fcx,
1908 let fty = if error_happened {
1910 bound_lifetime_names: opt_vec::Empty,
1911 inputs: fn_ty.sig.inputs.map(|_| ty::mk_err()),
1912 output: ty::mk_err()
1916 let fn_ty_copy = fn_ty.clone();
1917 fty_sig = fn_ty.sig.clone();
1918 ty::mk_closure(tcx, fn_ty_copy)
1921 debug!("check_expr_fn_with_unifier fty=%s",
1922 fcx.infcx().ty_to_str(fty));
1924 fcx.write_ty(expr.id, fty);
1926 let (inherited_purity, id) =
1927 ty::determine_inherited_purity((fcx.ps.purity, fcx.ps.def),
1931 check_fn(fcx.ccx, None, inherited_purity, &fty_sig,
1932 decl, id, body, fn_kind, fcx.in_scope_regions, fcx.inh);
1936 // Check field access expressions
1937 fn check_field(fcx: @mut FnCtxt,
1942 let tcx = fcx.ccx.tcx;
1943 let bot = check_expr(fcx, base);
1944 let expr_t = structurally_resolved_type(fcx, expr.span,
1946 let (base_t, derefs) = do_autoderef(fcx, expr.span, expr_t);
1948 match *structure_of(fcx, expr.span, base_t) {
1949 ty::ty_struct(base_id, ref substs) => {
1950 // This is just for fields -- the same code handles
1951 // methods in both classes and traits
1953 // (1) verify that the class id actually has a field called
1955 debug!("class named %s", ppaux::ty_to_str(tcx, base_t));
1956 let cls_items = ty::lookup_struct_fields(tcx, base_id);
1957 match lookup_field_ty(tcx, base_id, cls_items,
1958 field, &(*substs)) {
1960 // (2) look up what field's type is, and return it
1961 fcx.write_ty(expr.id, field_ty);
1962 fcx.write_autoderef_adjustment(base.id, derefs);
1971 let tps : ~[ty::t] = tys.iter().map(|ty| fcx.to_ty(ty)).collect();
1972 match method::lookup(fcx,
1980 CheckTraitsAndInherentMethods,
1981 AutoderefReceiver) {
1983 fcx.type_error_message(
1986 fmt!("attempted to take value of method `%s` on type `%s` \
1987 (try writing an anonymous function)",
1988 token::interner_get(field), actual)
1994 fcx.type_error_message(
1997 fmt!("attempted access of field `%s` on type `%s`, \
1998 but no field with that name was found",
1999 token::interner_get(field), actual)
2005 fcx.write_error(expr.id);
2008 fn check_struct_or_variant_fields(fcx: @mut FnCtxt,
2010 class_id: ast::DefId,
2011 node_id: ast::NodeId,
2012 substitutions: ty::substs,
2013 field_types: &[ty::field_ty],
2014 ast_fields: &[ast::Field],
2015 check_completeness: bool) {
2016 let tcx = fcx.ccx.tcx;
2018 let mut class_field_map = HashMap::new();
2019 let mut fields_found = 0;
2020 for field in field_types.iter() {
2021 class_field_map.insert(field.ident.name, (field.id, false));
2024 let mut error_happened = false;
2026 // Typecheck each field.
2027 for field in ast_fields.iter() {
2028 let mut expected_field_type = ty::mk_err();
2030 let pair = class_field_map.find(&field.ident.name).map_move(|x| *x);
2035 fmt!("structure has no field named `%s`",
2036 tcx.sess.str_of(field.ident)));
2037 error_happened = true;
2039 Some((_, true)) => {
2042 fmt!("field `%s` specified more than once",
2043 tcx.sess.str_of(field.ident)));
2044 error_happened = true;
2046 Some((field_id, false)) => {
2047 expected_field_type =
2048 ty::lookup_field_type(
2049 tcx, class_id, field_id, &substitutions);
2050 class_field_map.insert(
2051 field.ident.name, (field_id, true));
2055 // Make sure to give a type to the field even if there's
2056 // an error, so we can continue typechecking
2057 check_expr_coercable_to_type(
2060 expected_field_type);
2064 fcx.write_error(node_id);
2067 if check_completeness && !error_happened {
2068 // Make sure the programmer specified all the fields.
2069 assert!(fields_found <= field_types.len());
2070 if fields_found < field_types.len() {
2071 let mut missing_fields = ~[];
2072 for class_field in field_types.iter() {
2073 let name = class_field.ident.name;
2074 let (_, seen) = *class_field_map.get(&name);
2076 missing_fields.push(
2077 ~"`" + token::interner_get(name) + "`");
2081 tcx.sess.span_err(span,
2082 fmt!("missing field%s: %s",
2083 if missing_fields.len() == 1 {
2088 missing_fields.connect(", ")));
2092 if !error_happened {
2093 fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx,
2094 class_id, substitutions));
2098 fn check_struct_constructor(fcx: @mut FnCtxt,
2100 span: codemap::Span,
2101 class_id: ast::DefId,
2102 fields: &[ast::Field],
2103 base_expr: Option<@ast::Expr>) {
2104 let tcx = fcx.ccx.tcx;
2106 // Look up the number of type parameters and the raw type, and
2107 // determine whether the class is region-parameterized.
2108 let type_parameter_count;
2109 let region_parameterized;
2111 if class_id.crate == ast::LOCAL_CRATE {
2112 region_parameterized =
2113 tcx.region_paramd_items.find(&class_id.node).
2115 match tcx.items.find(&class_id.node) {
2116 Some(&ast_map::node_item(@ast::item {
2117 node: ast::item_struct(_, ref generics),
2121 type_parameter_count = generics.ty_params.len();
2124 bound_self_region(region_parameterized);
2126 raw_type = ty::mk_struct(tcx, class_id, substs {
2127 regions: ty::NonerasedRegions(self_region),
2129 tps: ty::ty_params_to_tys(
2135 tcx.sess.span_bug(span,
2136 "resolve didn't map this to a class");
2140 let item_type = ty::lookup_item_type(tcx, class_id);
2141 type_parameter_count = item_type.generics.type_param_defs.len();
2142 region_parameterized = item_type.generics.region_param;
2143 raw_type = item_type.ty;
2146 // Generate the struct type.
2148 fcx.region_var_if_parameterized(region_parameterized, span);
2149 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2150 let substitutions = substs {
2151 regions: ty::NonerasedRegions(regions),
2153 tps: type_parameters
2156 let mut struct_type = ty::subst(tcx, &substitutions, raw_type);
2158 // Look up and check the fields.
2159 let class_fields = ty::lookup_struct_fields(tcx, class_id);
2160 check_struct_or_variant_fields(fcx,
2167 base_expr.is_none());
2168 if ty::type_is_error(fcx.node_ty(id)) {
2169 struct_type = ty::mk_err();
2172 // Check the base expression if necessary.
2175 Some(base_expr) => {
2176 check_expr_has_type(fcx, base_expr, struct_type);
2177 if ty::type_is_bot(fcx.node_ty(base_expr.id)) {
2178 struct_type = ty::mk_bot();
2183 // Write in the resulting type.
2184 fcx.write_ty(id, struct_type);
2187 fn check_struct_enum_variant(fcx: @mut FnCtxt,
2189 span: codemap::Span,
2190 enum_id: ast::DefId,
2191 variant_id: ast::DefId,
2192 fields: &[ast::Field]) {
2193 let tcx = fcx.ccx.tcx;
2195 // Look up the number of type parameters and the raw type, and
2196 // determine whether the enum is region-parameterized.
2197 let type_parameter_count;
2198 let region_parameterized;
2200 if enum_id.crate == ast::LOCAL_CRATE {
2201 region_parameterized =
2202 tcx.region_paramd_items.find(&enum_id.node).map_move(|x| *x);
2203 match tcx.items.find(&enum_id.node) {
2204 Some(&ast_map::node_item(@ast::item {
2205 node: ast::item_enum(_, ref generics),
2209 type_parameter_count = generics.ty_params.len();
2211 let regions = bound_self_region(region_parameterized);
2213 raw_type = ty::mk_enum(tcx, enum_id, substs {
2214 regions: ty::NonerasedRegions(regions),
2216 tps: ty::ty_params_to_tys(
2222 tcx.sess.span_bug(span,
2223 "resolve didn't map this to an enum");
2227 let item_type = ty::lookup_item_type(tcx, enum_id);
2228 type_parameter_count = item_type.generics.type_param_defs.len();
2229 region_parameterized = item_type.generics.region_param;
2230 raw_type = item_type.ty;
2233 // Generate the enum type.
2235 fcx.region_var_if_parameterized(region_parameterized, span);
2236 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2237 let substitutions = substs {
2238 regions: ty::NonerasedRegions(regions),
2240 tps: type_parameters
2243 let enum_type = ty::subst(tcx, &substitutions, raw_type);
2245 // Look up and check the enum variant fields.
2246 let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2247 check_struct_or_variant_fields(fcx,
2255 fcx.write_ty(id, enum_type);
2258 let tcx = fcx.ccx.tcx;
2261 ast::ExprVstore(ev, vst) => {
2262 let typ = match ev.node {
2263 ast::ExprLit(@codemap::Spanned { node: ast::lit_str(_), _ }) => {
2264 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2265 ty::mk_estr(tcx, tt)
2267 ast::ExprVec(ref args, mutbl) => {
2268 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2270 let mut any_error = false;
2271 let mut any_bot = false;
2273 ast::ExprVstoreMutBox | ast::ExprVstoreMutSlice => {
2274 mutability = ast::MutMutable
2276 _ => mutability = mutbl
2278 let t: ty::t = fcx.infcx().next_ty_var();
2279 for e in args.iter() {
2280 check_expr_has_type(fcx, *e, t);
2281 let arg_t = fcx.expr_ty(*e);
2282 if ty::type_is_error(arg_t) {
2285 else if ty::type_is_bot(arg_t) {
2296 ty::mk_evec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2299 ast::ExprRepeat(element, count_expr, mutbl) => {
2300 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2301 let _ = ty::eval_repeat_count(fcx, count_expr);
2302 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2303 let mutability = match vst {
2304 ast::ExprVstoreMutBox | ast::ExprVstoreMutSlice => {
2309 let t: ty::t = fcx.infcx().next_ty_var();
2310 check_expr_has_type(fcx, element, t);
2311 let arg_t = fcx.expr_ty(element);
2312 if ty::type_is_error(arg_t) {
2314 } else if ty::type_is_bot(arg_t) {
2317 ty::mk_evec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2321 tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence")
2323 fcx.write_ty(ev.id, typ);
2324 fcx.write_ty(id, typ);
2327 ast::ExprLit(lit) => {
2328 let typ = check_lit(fcx, lit);
2329 fcx.write_ty(id, typ);
2331 ast::ExprBinary(callee_id, op, lhs, rhs) => {
2339 AllowOverloadedOperators);
2341 let lhs_ty = fcx.expr_ty(lhs);
2342 let rhs_ty = fcx.expr_ty(rhs);
2343 if ty::type_is_error(lhs_ty) ||
2344 ty::type_is_error(rhs_ty) {
2345 fcx.write_error(id);
2347 else if ty::type_is_bot(lhs_ty) ||
2348 (ty::type_is_bot(rhs_ty) && !ast_util::lazy_binop(op)) {
2352 ast::ExprAssignOp(callee_id, op, lhs, rhs) => {
2360 DontAllowOverloadedOperators);
2362 let lhs_t = fcx.expr_ty(lhs);
2363 let result_t = fcx.expr_ty(expr);
2364 demand::suptype(fcx, expr.span, result_t, lhs_t);
2366 // Overwrite result of check_binop...this preserves existing behavior
2367 // but seems quite dubious with regard to user-defined methods
2368 // and so forth. - Niko
2369 if !ty::type_is_error(result_t)
2370 && !ty::type_is_bot(result_t) {
2371 fcx.write_nil(expr.id);
2374 ast::ExprUnary(callee_id, unop, oprnd) => {
2375 let exp_inner = do unpack_expected(fcx, expected) |sty| {
2377 ast::UnBox(_) | ast::UnUniq => match *sty {
2378 ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => Some(mt.ty),
2381 ast::UnNot | ast::UnNeg => expected,
2382 ast::UnDeref => None
2385 check_expr_with_opt_hint(fcx, oprnd, exp_inner);
2386 let mut oprnd_t = fcx.expr_ty(oprnd);
2387 if !ty::type_is_error(oprnd_t) &&
2388 !ty::type_is_bot(oprnd_t) {
2390 ast::UnBox(mutbl) => {
2391 oprnd_t = ty::mk_box(tcx,
2392 ty::mt {ty: oprnd_t, mutbl: mutbl});
2395 oprnd_t = ty::mk_uniq(tcx,
2396 ty::mt {ty: oprnd_t,
2397 mutbl: ast::MutImmutable});
2400 let sty = structure_of(fcx, expr.span, oprnd_t);
2401 let operand_ty = ty::deref_sty(tcx, sty, true);
2411 "can only dereference enums with a single variant which \
2412 has a single argument");
2414 ty::ty_struct(*) => {
2417 "can only dereference structs with one anonymous field");
2420 fcx.type_error_message(expr.span,
2422 fmt!("type %s cannot be dereferenced", actual)
2430 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2432 if !(ty::type_is_integral(oprnd_t) ||
2433 ty::get(oprnd_t).sty == ty::ty_bool) {
2434 oprnd_t = check_user_unop(fcx, callee_id,
2435 "!", "not", expr, oprnd, oprnd_t,
2440 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2442 if !(ty::type_is_integral(oprnd_t) ||
2443 ty::type_is_fp(oprnd_t)) {
2444 oprnd_t = check_user_unop(fcx, callee_id,
2445 "-", "neg", expr, oprnd, oprnd_t, expected);
2450 fcx.write_ty(id, oprnd_t);
2452 ast::ExprAddrOf(mutbl, oprnd) => {
2453 let hint = unpack_expected(
2455 |sty| match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty),
2457 check_expr_with_opt_hint(fcx, oprnd, hint);
2459 // Note: at this point, we cannot say what the best lifetime
2460 // is to use for resulting pointer. We want to use the
2461 // shortest lifetime possible so as to avoid spurious borrowck
2462 // errors. Moreover, the longest lifetime will depend on the
2463 // precise details of the value whose address is being taken
2464 // (and how long it is valid), which we don't know yet until type
2465 // inference is complete.
2467 // Therefore, here we simply generate a region variable. The
2468 // region inferencer will then select the ultimate value.
2469 // Finally, borrowck is charged with guaranteeing that the
2470 // value whose address was taken can actually be made to live
2471 // as long as it needs to live.
2472 let region = fcx.infcx().next_region_var(
2473 infer::AddrOfRegion(expr.span));
2475 let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
2476 let oprnd_t = if ty::type_is_error(tm.ty) {
2478 } else if ty::type_is_bot(tm.ty) {
2482 ty::mk_rptr(tcx, region, tm)
2484 fcx.write_ty(id, oprnd_t);
2486 ast::ExprPath(ref pth) => {
2487 let defn = lookup_def(fcx, pth.span, id);
2489 check_type_parameter_positions_in_path(fcx, pth, defn);
2490 let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2491 instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
2494 let definition = lookup_def(fcx, expr.span, id);
2495 let ty_param_bounds_and_ty =
2496 ty_param_bounds_and_ty_for_def(fcx, expr.span, definition);
2497 fcx.write_ty(id, ty_param_bounds_and_ty.ty);
2499 ast::ExprInlineAsm(ref ia) => {
2500 for &(_, input) in ia.inputs.iter() {
2501 check_expr(fcx, input);
2503 for &(_, out) in ia.outputs.iter() {
2504 check_expr(fcx, out);
2508 ast::ExprMac(_) => tcx.sess.bug("unexpanded macro"),
2509 ast::ExprBreak(_) => { fcx.write_bot(id); }
2510 ast::ExprAgain(_) => { fcx.write_bot(id); }
2511 ast::ExprRet(expr_opt) => {
2512 let ret_ty = fcx.ret_ty;
2514 None => match fcx.mk_eqty(false, infer::Misc(expr.span),
2515 ret_ty, ty::mk_nil()) {
2516 result::Ok(_) => { /* fall through */ }
2520 "`return;` in function returning non-nil");
2524 check_expr_has_type(fcx, e, ret_ty);
2529 ast::ExprLogLevel => {
2530 fcx.write_ty(id, ty::mk_u32())
2532 ast::ExprParen(a) => {
2533 check_expr_with_opt_hint(fcx, a, expected);
2534 fcx.write_ty(id, fcx.expr_ty(a));
2536 ast::ExprAssign(lhs, rhs) => {
2537 check_assignment(fcx, lhs, rhs, id);
2538 let lhs_ty = fcx.expr_ty(lhs);
2539 let rhs_ty = fcx.expr_ty(rhs);
2540 if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
2541 fcx.write_error(id);
2543 else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
2550 ast::ExprIf(cond, ref then_blk, opt_else_expr) => {
2551 check_then_else(fcx, cond, then_blk, opt_else_expr,
2552 id, expr.span, expected);
2554 ast::ExprWhile(cond, ref body) => {
2555 check_expr_has_type(fcx, cond, ty::mk_bool());
2556 check_block_no_value(fcx, body);
2557 let cond_ty = fcx.expr_ty(cond);
2558 let body_ty = fcx.node_ty(body.id);
2559 if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) {
2560 fcx.write_error(id);
2562 else if ty::type_is_bot(cond_ty) {
2569 ast::ExprForLoop(*) =>
2570 fail!("non-desugared expr_for_loop"),
2571 ast::ExprLoop(ref body, _) => {
2572 check_block_no_value(fcx, (body));
2573 if !may_break(tcx, expr.id, body) {
2580 ast::ExprMatch(discrim, ref arms) => {
2581 _match::check_match(fcx, expr, discrim, *arms);
2583 ast::ExprFnBlock(ref decl, ref body) => {
2584 check_expr_fn(fcx, expr, None,
2585 decl, body, Vanilla, expected);
2587 ast::ExprDoBody(b) => {
2588 let expected_sty = unpack_expected(fcx,
2590 |x| Some((*x).clone()));
2591 let inner_ty = match expected_sty {
2592 Some(ty::ty_closure(_)) => expected.unwrap(),
2593 _ => match expected {
2594 Some(expected_t) => {
2595 fcx.type_error_message(expr.span, |actual| {
2596 fmt!("last argument in `do` call \
2597 has non-closure type: %s",
2599 }, expected_t, None);
2600 let err_ty = ty::mk_err();
2601 fcx.write_ty(id, err_ty);
2605 fcx.tcx().sess.impossible_case(
2607 "do body must have expected type")
2612 ast::ExprFnBlock(ref decl, ref body) => {
2613 check_expr_fn(fcx, b, None,
2614 decl, body, DoBlock, Some(inner_ty));
2615 demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
2618 _ => fail!("expected fn ty")
2620 fcx.write_ty(expr.id, fcx.node_ty(b.id));
2622 ast::ExprBlock(ref b) => {
2623 check_block_with_expected(fcx, b, expected);
2624 fcx.write_ty(id, fcx.node_ty(b.id));
2626 ast::ExprCall(f, ref args, sugar) => {
2627 check_call(fcx, expr.id, expr, f, *args, sugar);
2628 let f_ty = fcx.expr_ty(f);
2629 let (args_bot, args_err) = args.iter().fold((false, false),
2630 |(rest_bot, rest_err), a| {
2631 // is this not working?
2632 let a_ty = fcx.expr_ty(*a);
2633 (rest_bot || ty::type_is_bot(a_ty),
2634 rest_err || ty::type_is_error(a_ty))});
2635 if ty::type_is_error(f_ty) || args_err {
2636 fcx.write_error(id);
2638 else if ty::type_is_bot(f_ty) || args_bot {
2642 ast::ExprMethodCall(callee_id, rcvr, ident, ref tps, ref args, sugar) => {
2643 check_method_call(fcx, callee_id, expr, rcvr, ident, *args, *tps, sugar);
2644 let f_ty = fcx.expr_ty(rcvr);
2645 let arg_tys = args.map(|a| fcx.expr_ty(*a));
2646 let (args_bot, args_err) = arg_tys.iter().fold((false, false),
2647 |(rest_bot, rest_err), a| {
2648 (rest_bot || ty::type_is_bot(*a),
2649 rest_err || ty::type_is_error(*a))});
2650 if ty::type_is_error(f_ty) || args_err {
2651 fcx.write_error(id);
2653 else if ty::type_is_bot(f_ty) || args_bot {
2657 ast::ExprCast(e, ref t) => {
2659 let t_1 = fcx.to_ty(t);
2660 let t_e = fcx.expr_ty(e);
2662 debug!("t_1=%s", fcx.infcx().ty_to_str(t_1));
2663 debug!("t_e=%s", fcx.infcx().ty_to_str(t_e));
2665 if ty::type_is_error(t_e) {
2666 fcx.write_error(id);
2668 else if ty::type_is_bot(t_e) {
2672 match ty::get(t_1).sty {
2673 // This will be looked up later on
2674 ty::ty_trait(*) => (),
2677 if ty::type_is_nil(t_e) {
2678 fcx.type_error_message(expr.span, |actual| {
2679 fmt!("cast from nil: `%s` as `%s`", actual,
2680 fcx.infcx().ty_to_str(t_1))
2682 } else if ty::type_is_nil(t_1) {
2683 fcx.type_error_message(expr.span, |actual| {
2684 fmt!("cast to nil: `%s` as `%s`", actual,
2685 fcx.infcx().ty_to_str(t_1))
2689 let t1 = structurally_resolved_type(fcx, e.span, t_1);
2690 let te = structurally_resolved_type(fcx, e.span, t_e);
2691 let t_1_is_char = type_is_char(fcx, expr.span, t_1);
2693 // casts to scalars other than `char` are allowed
2694 let t_1_is_trivial = type_is_scalar(fcx, expr.span, t_1) && !t_1_is_char;
2696 if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial {
2697 // casts from C-like enums are allowed
2698 } else if t_1_is_char {
2699 if ty::get(te).sty != ty::ty_uint(ast::ty_u8) {
2700 fcx.type_error_message(expr.span, |actual| {
2701 fmt!("only `u8` can be cast as `char`, not `%s`", actual)
2704 } else if ty::get(t1).sty == ty::ty_bool {
2705 fcx.tcx().sess.span_err(expr.span,
2706 "cannot cast as `bool`, compare with zero instead");
2707 } else if type_is_region_ptr(fcx, expr.span, t_e) &&
2708 type_is_unsafe_ptr(fcx, expr.span, t_1) {
2710 fn is_vec(t: ty::t) -> bool {
2711 match ty::get(t).sty {
2712 ty::ty_evec(_,_) => true,
2716 fn types_compatible(fcx: @mut FnCtxt, sp: Span,
2717 t1: ty::t, t2: ty::t) -> bool {
2721 let el = ty::sequence_element_type(fcx.tcx(),
2723 infer::mk_eqty(fcx.infcx(), false,
2724 infer::Misc(sp), el, t2).is_ok()
2728 // Due to the limitations of LLVM global constants,
2729 // region pointers end up pointing at copies of
2730 // vector elements instead of the original values.
2731 // To allow unsafe pointers to work correctly, we
2732 // need to special-case obtaining an unsafe pointer
2733 // from a region pointer to a vector.
2735 /* this cast is only allowed from &[T] to *T or
2737 match (&ty::get(te).sty, &ty::get(t_1).sty) {
2738 (&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
2739 if types_compatible(fcx, e.span,
2740 mt1.ty, mt2.ty) => {
2741 /* this case is allowed */
2744 demand::coerce(fcx, e.span, t_1, e);
2747 } else if !(type_is_scalar(fcx,expr.span,t_e)
2748 && t_1_is_trivial) {
2750 If more type combinations should be supported than are
2751 supported here, then file an enhancement issue and
2752 record the issue number in this comment.
2754 fcx.type_error_message(expr.span, |actual| {
2755 fmt!("non-scalar cast: `%s` as `%s`", actual,
2756 fcx.infcx().ty_to_str(t_1))
2761 fcx.write_ty(id, t_1);
2764 ast::ExprVec(ref args, mutbl) => {
2765 let t: ty::t = fcx.infcx().next_ty_var();
2766 for e in args.iter() {
2767 check_expr_has_type(fcx, *e, t);
2769 let typ = ty::mk_evec(tcx, ty::mt {ty: t, mutbl: mutbl},
2770 ty::vstore_fixed(args.len()));
2771 fcx.write_ty(id, typ);
2773 ast::ExprRepeat(element, count_expr, mutbl) => {
2774 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2775 let count = ty::eval_repeat_count(fcx, count_expr);
2776 let t: ty::t = fcx.infcx().next_ty_var();
2777 check_expr_has_type(fcx, element, t);
2778 let element_ty = fcx.expr_ty(element);
2779 if ty::type_is_error(element_ty) {
2780 fcx.write_error(id);
2782 else if ty::type_is_bot(element_ty) {
2786 let t = ty::mk_evec(tcx, ty::mt {ty: t, mutbl: mutbl},
2787 ty::vstore_fixed(count));
2788 fcx.write_ty(id, t);
2791 ast::ExprTup(ref elts) => {
2792 let flds = unpack_expected(fcx, expected, |sty| {
2794 ty::ty_tup(ref flds) => Some((*flds).clone()),
2798 let mut bot_field = false;
2799 let mut err_field = false;
2801 let elt_ts = do elts.iter().enumerate().map |(i, e)| {
2802 let opt_hint = match flds {
2803 Some(ref fs) if i < fs.len() => Some(fs[i]),
2806 check_expr_with_opt_hint(fcx, *e, opt_hint);
2807 let t = fcx.expr_ty(*e);
2808 err_field = err_field || ty::type_is_error(t);
2809 bot_field = bot_field || ty::type_is_bot(t);
2814 } else if err_field {
2815 fcx.write_error(id);
2817 let typ = ty::mk_tup(tcx, elt_ts);
2818 fcx.write_ty(id, typ);
2821 ast::ExprStruct(ref path, ref fields, base_expr) => {
2822 // Resolve the path.
2823 match tcx.def_map.find(&id) {
2824 Some(&ast::DefStruct(type_def_id)) => {
2825 check_struct_constructor(fcx, id, expr.span, type_def_id,
2826 *fields, base_expr);
2828 Some(&ast::DefVariant(enum_id, variant_id)) => {
2829 check_struct_enum_variant(fcx, id, expr.span, enum_id,
2830 variant_id, *fields);
2833 tcx.sess.span_bug(path.span,
2834 "structure constructor does not name a structure type");
2838 ast::ExprField(base, field, ref tys) => {
2839 check_field(fcx, expr, base, field.name, *tys);
2841 ast::ExprIndex(callee_id, base, idx) => {
2842 check_expr(fcx, base);
2843 check_expr(fcx, idx);
2844 let raw_base_t = fcx.expr_ty(base);
2845 let idx_t = fcx.expr_ty(idx);
2846 if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
2847 fcx.write_ty(id, raw_base_t);
2848 } else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
2849 fcx.write_ty(id, idx_t);
2851 let (base_t, derefs) = do_autoderef(fcx, expr.span, raw_base_t);
2852 let base_sty = structure_of(fcx, expr.span, base_t);
2853 match ty::index_sty(base_sty) {
2855 require_integral(fcx, idx.span, idx_t);
2856 fcx.write_ty(id, mt.ty);
2857 fcx.write_autoderef_adjustment(base.id, derefs);
2860 let resolved = structurally_resolved_type(fcx,
2863 let index_ident = tcx.sess.ident_of("index");
2864 let error_message = || {
2865 fcx.type_error_message(expr.span,
2867 fmt!("cannot index a value \
2874 let ret_ty = lookup_op_method(fcx,
2885 fcx.write_ty(id, ret_ty);
2892 debug!("type of expr(%d) %s is...", expr.id,
2893 syntax::print::pprust::expr_to_str(expr, tcx.sess.intr()));
2894 debug!("... %s, expected is %s",
2895 ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
2897 Some(t) => ppaux::ty_to_str(tcx, t),
2904 pub fn require_integral(fcx: @mut FnCtxt, sp: Span, t: ty::t) {
2905 if !type_is_integral(fcx, sp, t) {
2906 fcx.type_error_message(sp, |actual| {
2907 fmt!("mismatched types: expected integral type but found `%s`",
2913 pub fn check_decl_initializer(fcx: @mut FnCtxt,
2917 let local_ty = fcx.local_ty(init.span, nid);
2918 check_expr_coercable_to_type(fcx, init, local_ty)
2921 pub fn check_decl_local(fcx: @mut FnCtxt, local: @ast::Local) {
2922 let tcx = fcx.ccx.tcx;
2924 let t = fcx.local_ty(local.span, local.id);
2925 fcx.write_ty(local.id, t);
2929 check_decl_initializer(fcx, local.id, init);
2930 let init_ty = fcx.expr_ty(init);
2931 if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
2932 fcx.write_ty(local.id, init_ty);
2938 let pcx = pat_ctxt {
2940 map: pat_id_map(tcx.def_map, local.pat),
2942 _match::check_pat(&pcx, local.pat, t);
2943 let pat_ty = fcx.node_ty(local.pat.id);
2944 if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
2945 fcx.write_ty(local.id, pat_ty);
2949 pub fn check_stmt(fcx: @mut FnCtxt, stmt: @ast::Stmt) {
2951 let mut saw_bot = false;
2952 let mut saw_err = false;
2954 ast::StmtDecl(decl, id) => {
2957 ast::DeclLocal(ref l) => {
2958 check_decl_local(fcx, *l);
2959 let l_t = fcx.node_ty(l.id);
2960 saw_bot = saw_bot || ty::type_is_bot(l_t);
2961 saw_err = saw_err || ty::type_is_error(l_t);
2963 ast::DeclItem(_) => {/* ignore for now */ }
2966 ast::StmtExpr(expr, id) => {
2968 // Check with expected type of ()
2969 check_expr_has_type(fcx, expr, ty::mk_nil());
2970 let expr_ty = fcx.expr_ty(expr);
2971 saw_bot = saw_bot || ty::type_is_bot(expr_ty);
2972 saw_err = saw_err || ty::type_is_error(expr_ty);
2974 ast::StmtSemi(expr, id) => {
2976 check_expr(fcx, expr);
2977 let expr_ty = fcx.expr_ty(expr);
2978 saw_bot |= ty::type_is_bot(expr_ty);
2979 saw_err |= ty::type_is_error(expr_ty);
2981 ast::StmtMac(*) => fcx.ccx.tcx.sess.bug("unexpanded macro")
2984 fcx.write_bot(node_id);
2987 fcx.write_error(node_id);
2990 fcx.write_nil(node_id)
2994 pub fn check_block_no_value(fcx: @mut FnCtxt, blk: &ast::Block) {
2995 check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
2996 let blkty = fcx.node_ty(blk.id);
2997 if ty::type_is_error(blkty) {
2998 fcx.write_error(blk.id);
3000 else if ty::type_is_bot(blkty) {
3001 fcx.write_bot(blk.id);
3004 let nilty = ty::mk_nil();
3005 demand::suptype(fcx, blk.span, nilty, blkty);
3009 pub fn check_block(fcx0: @mut FnCtxt, blk: &ast::Block) {
3010 check_block_with_expected(fcx0, blk, None)
3013 pub fn check_block_with_expected(fcx: @mut FnCtxt,
3015 expected: Option<ty::t>) {
3016 let purity_state = fcx.ps.recurse(blk);
3017 let prev = replace(&mut fcx.ps, purity_state);
3019 do fcx.with_region_lb(blk.id) {
3020 let mut warned = false;
3021 let mut last_was_bot = false;
3022 let mut any_bot = false;
3023 let mut any_err = false;
3024 for s in blk.stmts.iter() {
3025 check_stmt(fcx, *s);
3026 let s_id = ast_util::stmt_id(*s);
3027 let s_ty = fcx.node_ty(s_id);
3028 if last_was_bot && !warned && match s.node {
3029 ast::StmtDecl(@codemap::Spanned { node: ast::DeclLocal(_),
3031 ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => {
3036 fcx.ccx.tcx.sess.add_lint(unreachable_code, s_id, s.span,
3037 ~"unreachable statement");
3040 if ty::type_is_bot(s_ty) {
3041 last_was_bot = true;
3043 any_bot = any_bot || ty::type_is_bot(s_ty);
3044 any_err = any_err || ty::type_is_error(s_ty);
3047 None => if any_err {
3048 fcx.write_error(blk.id);
3051 fcx.write_bot(blk.id);
3054 fcx.write_nil(blk.id);
3057 if any_bot && !warned {
3058 fcx.ccx.tcx.sess.span_warn(e.span, "unreachable expression");
3060 check_expr_with_opt_hint(fcx, e, expected);
3061 let ety = fcx.expr_ty(e);
3062 fcx.write_ty(blk.id, ety);
3064 fcx.write_error(blk.id);
3067 fcx.write_bot(blk.id);
3076 pub fn check_const(ccx: @mut CrateCtxt,
3080 let rty = ty::node_id_to_type(ccx.tcx, id);
3081 let fcx = blank_fn_ctxt(ccx, rty, e.id);
3082 let declty = fcx.ccx.tcx.tcache.get(&local_def(id)).ty;
3083 check_const_with_ty(fcx, sp, e, declty);
3086 pub fn check_const_with_ty(fcx: @mut FnCtxt,
3091 let cty = fcx.expr_ty(e);
3092 demand::suptype(fcx, e.span, declty, cty);
3093 regionck::regionck_expr(fcx, e);
3094 writeback::resolve_type_vars_in_expr(fcx, e);
3097 /// Checks whether a type can be created without an instance of itself.
3098 /// This is similar but different from the question of whether a type
3099 /// can be represented. For example, the following type:
3101 /// enum foo { None, Some(foo) }
3103 /// is instantiable but is not representable. Similarly, the type
3105 /// enum foo { Some(@foo) }
3107 /// is representable, but not instantiable.
3108 pub fn check_instantiable(tcx: ty::ctxt,
3110 item_id: ast::NodeId) {
3111 let item_ty = ty::node_id_to_type(tcx, item_id);
3112 if !ty::is_instantiable(tcx, item_ty) {
3113 tcx.sess.span_err(sp, fmt!("this type cannot be instantiated \
3114 without an instance of itself; \
3115 consider using `Option<%s>`",
3116 ppaux::ty_to_str(tcx, item_ty)));
3120 pub fn check_simd(tcx: ty::ctxt, sp: Span, id: ast::NodeId) {
3121 let t = ty::node_id_to_type(tcx, id);
3122 if ty::type_needs_subst(t) {
3123 tcx.sess.span_err(sp, "SIMD vector cannot be generic");
3126 match ty::get(t).sty {
3127 ty::ty_struct(did, ref substs) => {
3128 let fields = ty::lookup_struct_fields(tcx, did);
3129 if fields.is_empty() {
3130 tcx.sess.span_err(sp, "SIMD vector cannot be empty");
3133 let e = ty::lookup_field_type(tcx, did, fields[0].id, substs);
3134 if !fields.iter().all(
3135 |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
3136 tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
3139 if !ty::type_is_machine(e) {
3140 tcx.sess.span_err(sp, "SIMD vector element type should be \
3149 pub fn check_enum_variants(ccx: @mut CrateCtxt,
3151 vs: &[ast::variant],
3153 fn do_check(ccx: @mut CrateCtxt,
3154 vs: &[ast::variant],
3156 -> ~[@ty::VariantInfo] {
3158 let rty = ty::node_id_to_type(ccx.tcx, id);
3159 let mut variants: ~[@ty::VariantInfo] = ~[];
3160 let mut disr_vals: ~[ty::Disr] = ~[];
3161 let mut prev_disr_val: Option<ty::Disr> = None;
3163 for v in vs.iter() {
3165 // If the discriminant value is specified explicitly in the enum check whether the
3166 // initialization expression is valid, otherwise use the last value plus one.
3167 let mut current_disr_val = match prev_disr_val {
3168 Some(prev_disr_val) => prev_disr_val + 1,
3169 None => ty::INITIAL_DISCRIMINANT_VALUE
3172 match v.node.disr_expr {
3174 debug!("disr expr, checking %s", pprust::expr_to_str(e, ccx.tcx.sess.intr()));
3176 let fcx = blank_fn_ctxt(ccx, rty, e.id);
3177 let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
3178 check_const_with_ty(fcx, e.span, e, declty);
3179 // check_expr (from check_const pass) doesn't guarantee
3180 // that the expression is in an form that eval_const_expr can
3181 // handle, so we may still get an internal compiler error
3183 match const_eval::eval_const_expr_partial(&ccx.tcx, e) {
3184 Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
3185 Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
3187 ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
3190 ccx.tcx.sess.span_err(e.span, fmt!("expected constant: %s", (*err)));
3197 // Check for duplicate discriminator values
3198 if disr_vals.contains(¤t_disr_val) {
3199 ccx.tcx.sess.span_err(v.span, "discriminator value already exists");
3201 disr_vals.push(current_disr_val);
3203 let variant_info = @VariantInfo::from_ast_variant(ccx.tcx, v, current_disr_val);
3204 prev_disr_val = Some(current_disr_val);
3206 variants.push(variant_info);
3212 let rty = ty::node_id_to_type(ccx.tcx, id);
3214 let variants = do_check(ccx, vs, id);
3216 // cache so that ty::enum_variants won't repeat this work
3217 ccx.tcx.enum_var_cache.insert(local_def(id), @variants);
3219 // Check that it is possible to represent this enum:
3220 let mut outer = true;
3221 let did = local_def(id);
3222 if ty::type_structurally_contains(ccx.tcx, rty, |sty| {
3224 ty::ty_enum(id, _) if id == did => {
3225 if outer { outer = false; false }
3231 ccx.tcx.sess.span_err(sp,
3232 "illegal recursive enum type; \
3233 wrap the inner value in a box to make it representable");
3236 // Check that it is possible to instantiate this enum:
3238 // This *sounds* like the same that as representable, but it's
3239 // not. See def'n of `check_instantiable()` for details.
3240 check_instantiable(ccx.tcx, sp, id);
3243 pub fn lookup_def(fcx: @mut FnCtxt, sp: Span, id: ast::NodeId) -> ast::Def {
3244 lookup_def_ccx(fcx.ccx, sp, id)
3247 // Returns the type parameter count and the type for the given definition.
3248 pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt,
3251 -> ty_param_bounds_and_ty {
3253 ast::DefArg(nid, _) | ast::DefLocal(nid, _) | ast::DefSelf(nid) |
3254 ast::DefBinding(nid, _) => {
3255 let typ = fcx.local_ty(sp, nid);
3256 return no_params(typ);
3258 ast::DefFn(id, _) | ast::DefStaticMethod(id, _, _) |
3259 ast::DefStatic(id, _) | ast::DefVariant(_, id) |
3260 ast::DefStruct(id) => {
3261 return ty::lookup_item_type(fcx.ccx.tcx, id);
3263 ast::DefUpvar(_, inner, _, _) => {
3264 return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
3269 ast::DefTyParam(*)=> {
3270 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type");
3272 ast::DefMod(*) | ast::DefForeignMod(*) => {
3273 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module");
3276 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use");
3278 ast::DefRegion(*) => {
3279 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region");
3281 ast::DefTyParamBinder(*) => {
3282 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter");
3284 ast::DefLabel(*) => {
3285 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label");
3287 ast::DefSelfTy(*) => {
3288 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty");
3290 ast::DefMethod(*) => {
3291 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method");
3296 // Instantiates the given path, which must refer to an item with the given
3297 // number of type parameters and type.
3298 pub fn instantiate_path(fcx: @mut FnCtxt,
3300 tpt: ty_param_bounds_and_ty,
3303 node_id: ast::NodeId) {
3304 debug!(">>> instantiate_path");
3306 let ty_param_count = tpt.generics.type_param_defs.len();
3307 let mut ty_substs_len = 0;
3308 for segment in pth.segments.iter() {
3309 ty_substs_len += segment.types.len()
3312 debug!("tpt=%s ty_param_count=%? ty_substs_len=%?",
3313 tpt.repr(fcx.tcx()),
3317 // determine the region bound, using the value given by the user
3318 // (if any) and otherwise using a fresh region variable
3319 let regions = match pth.segments.last().lifetime {
3320 Some(_) => { // user supplied a lifetime parameter...
3321 match tpt.generics.region_param {
3322 None => { // ...but the type is not lifetime parameterized!
3323 fcx.ccx.tcx.sess.span_err
3324 (span, "this item is not region-parameterized");
3327 Some(_) => { // ...and the type is lifetime parameterized, ok.
3329 ast_region_to_region(fcx,
3332 &pth.segments.last().lifetime))
3336 None => { // no lifetime parameter supplied, insert default
3337 fcx.region_var_if_parameterized(tpt.generics.region_param, span)
3341 // Special case: If there is a self parameter, omit it from the list of
3344 // Here we calculate the "user type parameter count", which is the number
3345 // of type parameters actually manifest in the AST. This will differ from
3346 // the internal type parameter count when there are self types involved.
3347 let (user_type_parameter_count, self_parameter_index) = match def {
3348 ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
3349 let generics = generics_of_static_method_container(fcx.ccx.tcx,
3351 (ty_param_count - 1, Some(generics.type_param_defs.len()))
3353 _ => (ty_param_count, None),
3356 // determine values for type parameters, using the values given by
3357 // the user (if any) and otherwise using fresh type variables
3358 let tps = if ty_substs_len == 0 {
3359 fcx.infcx().next_ty_vars(ty_param_count)
3360 } else if ty_param_count == 0 {
3361 fcx.ccx.tcx.sess.span_err
3362 (span, "this item does not take type parameters");
3363 fcx.infcx().next_ty_vars(ty_param_count)
3364 } else if ty_substs_len > user_type_parameter_count {
3365 fcx.ccx.tcx.sess.span_err
3367 fmt!("too many type parameters provided: expected %u, found %u",
3368 user_type_parameter_count, ty_substs_len));
3369 fcx.infcx().next_ty_vars(ty_param_count)
3370 } else if ty_substs_len < user_type_parameter_count {
3371 fcx.ccx.tcx.sess.span_err
3373 fmt!("not enough type parameters provided: expected %u, found %u",
3374 user_type_parameter_count, ty_substs_len));
3375 fcx.infcx().next_ty_vars(ty_param_count)
3377 // Build up the list of type parameters, inserting the self parameter
3378 // at the appropriate position.
3379 let mut result = ~[];
3380 let mut pushed = false;
3381 for (i, ast_type) in pth.segments
3383 .flat_map(|segment| segment.types.iter())
3385 match self_parameter_index {
3386 Some(index) if index == i => {
3387 result.push(fcx.infcx().next_ty_vars(1)[0]);
3392 result.push(fcx.to_ty(ast_type))
3395 // If the self parameter goes at the end, insert it there.
3396 if !pushed && self_parameter_index.is_some() {
3397 result.push(fcx.infcx().next_ty_vars(1)[0])
3400 assert_eq!(result.len(), ty_param_count)
3404 let substs = substs {
3405 regions: ty::NonerasedRegions(regions),
3409 fcx.write_ty_substs(node_id, tpt.ty, substs);
3414 // Resolves `typ` by a single level if `typ` is a type variable. If no
3415 // resolution is possible, then an error is reported.
3416 pub fn structurally_resolved_type(fcx: @mut FnCtxt, sp: Span, tp: ty::t)
3418 match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
3419 Ok(t_s) if !ty::type_is_ty_var(t_s) => t_s,
3421 fcx.type_error_message(sp, |_actual| {
3422 ~"the type of this value must be known in this context"
3424 demand::suptype(fcx, sp, ty::mk_err(), tp);
3430 // Returns the one-level-deep structure of the given type.
3431 pub fn structure_of<'a>(fcx: @mut FnCtxt, sp: Span, typ: ty::t)
3433 &ty::get(structurally_resolved_type(fcx, sp, typ)).sty
3436 pub fn type_is_integral(fcx: @mut FnCtxt, sp: Span, typ: ty::t) -> bool {
3437 let typ_s = structurally_resolved_type(fcx, sp, typ);
3438 return ty::type_is_integral(typ_s);
3441 pub fn type_is_scalar(fcx: @mut FnCtxt, sp: Span, typ: ty::t) -> bool {
3442 let typ_s = structurally_resolved_type(fcx, sp, typ);
3443 return ty::type_is_scalar(typ_s);
3446 pub fn type_is_char(fcx: @mut FnCtxt, sp: Span, typ: ty::t) -> bool {
3447 let typ_s = structurally_resolved_type(fcx, sp, typ);
3448 return ty::type_is_char(typ_s);
3451 pub fn type_is_unsafe_ptr(fcx: @mut FnCtxt, sp: Span, typ: ty::t) -> bool {
3452 let typ_s = structurally_resolved_type(fcx, sp, typ);
3453 return ty::type_is_unsafe_ptr(typ_s);
3456 pub fn type_is_region_ptr(fcx: @mut FnCtxt, sp: Span, typ: ty::t) -> bool {
3457 let typ_s = structurally_resolved_type(fcx, sp, typ);
3458 return ty::type_is_region_ptr(typ_s);
3461 pub fn type_is_c_like_enum(fcx: @mut FnCtxt, sp: Span, typ: ty::t) -> bool {
3462 let typ_s = structurally_resolved_type(fcx, sp, typ);
3463 return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
3466 pub fn ast_expr_vstore_to_vstore(fcx: @mut FnCtxt,
3471 ast::ExprVstoreUniq => ty::vstore_uniq,
3472 ast::ExprVstoreBox | ast::ExprVstoreMutBox => ty::vstore_box,
3473 ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => {
3474 let r = fcx.infcx().next_region_var(infer::AddrOfSlice(e.span));
3480 // Returns true if b contains a break that can exit from b
3481 pub fn may_break(cx: ty::ctxt, id: ast::NodeId, b: &ast::Block) -> bool {
3482 // First: is there an unlabeled break immediately
3484 (loop_query(b, |e| {
3486 ast::ExprBreak(_) => true,
3490 // Second: is there a labeled break with label
3491 // <id> nested anywhere inside the loop?
3492 (block_query(b, |e| {
3494 ast::ExprBreak(Some(_)) =>
3495 match cx.def_map.find(&e.id) {
3496 Some(&ast::DefLabel(loop_id)) if id == loop_id => true,
3503 pub fn check_bounds_are_used(ccx: @mut CrateCtxt,
3505 tps: &OptVec<ast::TyParam>,
3507 debug!("check_bounds_are_used(n_tps=%u, ty=%s)",
3508 tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
3510 // make a vector of booleans initially false, set to true when used
3511 if tps.len() == 0u { return; }
3512 let mut tps_used = vec::from_elem(tps.len(), false);
3514 ty::walk_regions_and_ty(
3518 match ty::get(t).sty {
3519 ty::ty_param(param_ty {idx, _}) => {
3520 debug!("Found use of ty param #%u", idx);
3521 tps_used[idx] = true;
3528 for (i, b) in tps_used.iter().enumerate() {
3530 ccx.tcx.sess.span_err(
3531 span, fmt!("type parameter `%s` is unused",
3532 ccx.tcx.sess.str_of(tps.get(i).ident)));
3537 pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
3538 fn param(ccx: @mut CrateCtxt, n: uint) -> ty::t {
3539 ty::mk_param(ccx.tcx, n, local_def(0))
3543 let nm = ccx.tcx.sess.str_of(it.ident);
3544 let name = nm.as_slice();
3545 let (n_tps, inputs, output) = if name.starts_with("atomic_") {
3546 let split : ~[&str] = name.split_iter('_').collect();
3547 assert!(split.len() >= 2, "Atomic intrinsic not correct format");
3549 //We only care about the operation here
3551 "cxchg" => (0, ~[ty::mk_mut_rptr(tcx,
3552 ty::re_bound(ty::br_anon(0)),
3559 ty::mk_imm_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int())
3564 ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()),
3569 "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
3570 "min" | "umax" | "umin" => {
3571 (0, ~[ty::mk_mut_rptr(tcx,
3572 ty::re_bound(ty::br_anon(0)),
3573 ty::mk_int()), ty::mk_int() ], ty::mk_int())
3576 (0, ~[], ty::mk_nil())
3579 tcx.sess.span_err(it.span,
3580 fmt!("unrecognized atomic operation function: `%s`",
3589 "pref_align_of" | "min_align_of" => (1u, ~[], ty::mk_uint()),
3590 "init" => (1u, ~[], param(ccx, 0u)),
3591 "uninit" => (1u, ~[], param(ccx, 0u)),
3592 "forget" => (1u, ~[ param(ccx, 0) ], ty::mk_nil()),
3593 "transmute" => (2, ~[ param(ccx, 0) ], param(ccx, 1)),
3594 "move_val" | "move_val_init" => {
3597 ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), param(ccx, 0)),
3602 "needs_drop" => (1u, ~[], ty::mk_bool()),
3603 "contains_managed" => (1u, ~[], ty::mk_bool()),
3604 "atomic_xchg" | "atomic_xadd" | "atomic_xsub" |
3605 "atomic_xchg_acq" | "atomic_xadd_acq" | "atomic_xsub_acq" |
3606 "atomic_xchg_rel" | "atomic_xadd_rel" | "atomic_xsub_rel" => {
3609 ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()),
3616 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
3618 Err(s) => { tcx.sess.span_fatal(it.span, s); }
3620 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
3622 mutbl: ast::MutImmutable
3627 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
3629 Err(s) => { tcx.sess.span_fatal(it.span, s); }
3631 let region = ty::re_bound(ty::br_anon(0));
3632 let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
3633 Ok((_, vot)) => vot,
3634 Err(s) => { tcx.sess.span_fatal(it.span, s); }
3637 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
3639 mutbl: ast::MutImmutable
3641 (0, ~[ td_ptr, visitor_object_ty ], ty::mk_nil())
3643 "frame_address" => {
3644 let fty = ty::mk_closure(ccx.tcx, ty::ClosureTy {
3645 purity: ast::impure_fn,
3646 sigil: ast::BorrowedSigil,
3647 onceness: ast::Once,
3648 region: ty::re_bound(ty::br_anon(0)),
3649 bounds: ty::EmptyBuiltinBounds(),
3651 bound_lifetime_names: opt_vec::Empty,
3652 inputs: ~[ty::mk_imm_ptr(ccx.tcx, ty::mk_mach_uint(ast::ty_u8))],
3653 output: ty::mk_nil()
3656 (0u, ~[fty], ty::mk_nil())
3658 "morestack_addr" => {
3659 (0u, ~[], ty::mk_nil_ptr(ccx.tcx))
3664 ty::mk_ptr(tcx, ty::mt {
3666 mutbl: ast::MutImmutable
3670 ty::mk_ptr(tcx, ty::mt {
3672 mutbl: ast::MutImmutable
3678 ty::mk_ptr(tcx, ty::mt {
3680 mutbl: ast::MutMutable
3682 ty::mk_ptr(tcx, ty::mt {
3684 mutbl: ast::MutImmutable
3693 ty::mk_ptr(tcx, ty::mt {
3695 mutbl: ast::MutMutable
3697 ty::mk_ptr(tcx, ty::mt {
3699 mutbl: ast::MutImmutable
3708 ty::mk_ptr(tcx, ty::mt {
3710 mutbl: ast::MutMutable
3712 ty::mk_ptr(tcx, ty::mt {
3714 mutbl: ast::MutImmutable
3723 ty::mk_ptr(tcx, ty::mt {
3725 mutbl: ast::MutMutable
3727 ty::mk_ptr(tcx, ty::mt {
3729 mutbl: ast::MutImmutable
3738 ty::mk_ptr(tcx, ty::mt {
3740 mutbl: ast::MutMutable
3750 ty::mk_ptr(tcx, ty::mt {
3752 mutbl: ast::MutMutable
3759 "sqrtf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3760 "sqrtf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3763 ~[ ty::mk_f32(), ty::mk_i32() ],
3768 ~[ ty::mk_f64(), ty::mk_i32() ],
3771 "sinf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3772 "sinf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3773 "cosf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3774 "cosf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3777 ~[ ty::mk_f32(), ty::mk_f32() ],
3782 ~[ ty::mk_f64(), ty::mk_f64() ],
3785 "expf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3786 "expf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3787 "exp2f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3788 "exp2f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3789 "logf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3790 "logf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3791 "log10f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3792 "log10f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3793 "log2f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3794 "log2f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3797 ~[ ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ],
3802 ~[ ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ],
3805 "fabsf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3806 "fabsf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3807 "floorf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3808 "floorf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3809 "ceilf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3810 "ceilf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3811 "truncf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3812 "truncf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3813 "ctpop8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()),
3814 "ctpop16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
3815 "ctpop32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
3816 "ctpop64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
3817 "ctlz8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()),
3818 "ctlz16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
3819 "ctlz32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
3820 "ctlz64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
3821 "cttz8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()),
3822 "cttz16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
3823 "cttz32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
3824 "cttz64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
3825 "bswap16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
3826 "bswap32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
3827 "bswap64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
3829 "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
3830 (0, ~[ty::mk_i8(), ty::mk_i8()],
3831 ty::mk_tup(tcx, ~[ty::mk_i8(), ty::mk_bool()])),
3833 "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
3834 (0, ~[ty::mk_i16(), ty::mk_i16()],
3835 ty::mk_tup(tcx, ~[ty::mk_i16(), ty::mk_bool()])),
3837 "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
3838 (0, ~[ty::mk_i32(), ty::mk_i32()],
3839 ty::mk_tup(tcx, ~[ty::mk_i32(), ty::mk_bool()])),
3841 "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
3842 (0, ~[ty::mk_i64(), ty::mk_i64()],
3843 ty::mk_tup(tcx, ~[ty::mk_i64(), ty::mk_bool()])),
3845 "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
3846 (0, ~[ty::mk_u8(), ty::mk_u8()],
3847 ty::mk_tup(tcx, ~[ty::mk_u8(), ty::mk_bool()])),
3849 "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
3850 (0, ~[ty::mk_u16(), ty::mk_u16()],
3851 ty::mk_tup(tcx, ~[ty::mk_u16(), ty::mk_bool()])),
3853 "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
3854 (0, ~[ty::mk_u32(), ty::mk_u32()],
3855 ty::mk_tup(tcx, ~[ty::mk_u32(), ty::mk_bool()])),
3857 "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" =>
3858 (0, ~[ty::mk_u64(), ty::mk_u64()],
3859 ty::mk_tup(tcx, ~[ty::mk_u64(), ty::mk_bool()])),
3862 tcx.sess.span_err(it.span,
3863 fmt!("unrecognized intrinsic function: `%s`",
3869 let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
3870 purity: ast::unsafe_fn,
3871 abis: AbiSet::Intrinsic(),
3872 sig: FnSig {bound_lifetime_names: opt_vec::Empty,
3876 let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
3877 let i_n_tps = i_ty.generics.type_param_defs.len();
3878 if i_n_tps != n_tps {
3879 tcx.sess.span_err(it.span, fmt!("intrinsic has wrong number \
3880 of type parameters: found %u, \
3881 expected %u", i_n_tps, n_tps));
3884 tcx, None, false, it.span, i_ty.ty, fty,
3885 || fmt!("intrinsic has wrong type: \
3887 ppaux::ty_to_str(ccx.tcx, fty)));