1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
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::lang_items::{ExchangeHeapLangItem, GcLangItem};
82 use middle::lang_items::{ManagedHeapLangItem};
83 use middle::lint::UnreachableCode;
84 use middle::pat_util::pat_id_map;
86 use middle::subst::Subst;
87 use middle::ty::{FnSig, VariantInfo};
88 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
89 use middle::ty::{substs, param_ty, Disr, ExprTyProvider};
91 use middle::ty_fold::TypeFolder;
92 use middle::typeck::astconv::AstConv;
93 use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
94 use middle::typeck::astconv;
95 use middle::typeck::check::_match::pat_ctxt;
96 use middle::typeck::check::method::{AutoderefReceiver};
97 use middle::typeck::check::method::{AutoderefReceiverFlag};
98 use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
99 use middle::typeck::check::method::{DontAutoderefReceiver};
100 use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
101 use middle::typeck::check::regionmanip::relate_free_regions;
102 use middle::typeck::check::vtable::{LocationInfo, VtableContext};
103 use middle::typeck::CrateCtxt;
104 use middle::typeck::infer::{resolve_type, force_tvar};
105 use middle::typeck::infer;
106 use middle::typeck::rscope::RegionScope;
107 use middle::typeck::{lookup_def_ccx};
108 use middle::typeck::no_params;
109 use middle::typeck::{require_same_types, MethodMap, vtable_map};
110 use middle::lang_items::TypeIdLangItem;
111 use util::common::{block_query, indenter, loop_query};
113 use util::ppaux::{UserString, Repr};
115 use std::cell::{Cell, RefCell};
116 use collections::HashMap;
117 use std::mem::replace;
120 use syntax::abi::AbiSet;
121 use syntax::ast::{Provided, Required};
123 use syntax::ast_util::local_def;
124 use syntax::ast_util;
126 use syntax::codemap::Span;
128 use syntax::opt_vec::OptVec;
130 use syntax::parse::token;
131 use syntax::print::pprust;
133 use syntax::visit::Visitor;
144 /// Fields that are part of a `FnCtxt` which are inherited by
145 /// closures defined within the function. For example:
148 /// bar(proc() { ... })
151 /// Here, the function `foo()` and the closure passed to
152 /// `bar()` will each have their own `FnCtxt`, but they will
153 /// share the inherited fields.
154 pub struct Inherited {
155 infcx: infer::InferCtxt,
156 locals: @RefCell<HashMap<ast::NodeId, ty::t>>,
157 param_env: ty::ParameterEnvironment,
160 node_types: RefCell<HashMap<ast::NodeId, ty::t>>,
161 node_type_substs: RefCell<HashMap<ast::NodeId, ty::substs>>,
162 adjustments: RefCell<HashMap<ast::NodeId, @ty::AutoAdjustment>>,
163 method_map: MethodMap,
164 vtable_map: vtable_map,
165 upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
173 // A normal closure or fn item.
178 pub struct PurityState {
185 pub fn function(purity: ast::Purity, def: ast::NodeId) -> PurityState {
186 PurityState { def: def, purity: purity, from_fn: true }
189 pub fn recurse(&mut self, blk: &ast::Block) -> PurityState {
191 // If this unsafe, then if the outer function was already marked as
192 // unsafe we shouldn't attribute the unsafe'ness to the block. This
193 // way the block can be warned about instead of ignoring this
194 // extraneous block (functions are never warned about).
195 ast::UnsafeFn if self.from_fn => *self,
198 let (purity, def) = match blk.rules {
199 ast::UnsafeBlock(..) => (ast::UnsafeFn, blk.id),
200 ast::DefaultBlock => (purity, self.def),
202 PurityState{ def: def,
210 /// Whether `check_binop` is part of an assignment or not.
211 /// Used to know wether we allow user overloads and to print
212 /// better messages on error.
214 enum IsBinopAssignment{
221 // Number of errors that had been reported when we started
222 // checking this function. On exit, if we find that *more* errors
223 // have been reported, we will skip regionck and other work that
224 // expects the types within the function to be consistent.
225 err_count_on_creation: uint,
228 ps: RefCell<PurityState>,
230 // Sometimes we generate region pointers where the precise region
231 // to use is not known. For example, an expression like `&x.f`
232 // where `x` is of type `@T`: in this case, we will be rooting
233 // `x` onto the stack frame, and we could choose to root it until
234 // the end of (almost) any enclosing block or expression. We
235 // want to pick the narrowest block that encompasses all uses.
237 // What we do in such cases is to generate a region variable with
238 // `region_lb` as a lower bound. The regionck pass then adds
239 // other constriants based on how the variable is used and region
240 // inference selects the ultimate value. Finally, borrowck is
241 // charged with guaranteeing that the value whose address was taken
242 // can actually be made to live as long as it needs to live.
243 region_lb: Cell<ast::NodeId>,
245 // Says whether we're inside a for loop, in a do block
246 // or neither. Helps with error messages involving the
247 // function return type.
256 fn new(tcx: ty::ctxt,
257 param_env: ty::ParameterEnvironment)
260 infcx: infer::new_infer_ctxt(tcx),
261 locals: @RefCell::new(HashMap::new()),
262 param_env: param_env,
263 node_types: RefCell::new(HashMap::new()),
264 node_type_substs: RefCell::new(HashMap::new()),
265 adjustments: RefCell::new(HashMap::new()),
266 method_map: @RefCell::new(HashMap::new()),
267 vtable_map: @RefCell::new(HashMap::new()),
268 upvar_borrow_map: RefCell::new(HashMap::new()),
273 // Used by check_const and check_enum_variants
274 pub fn blank_fn_ctxt(ccx: @CrateCtxt,
276 region_bnd: ast::NodeId)
278 // It's kind of a kludge to manufacture a fake function context
279 // and statement context, but we might as well do write the code only once
280 let param_env = ty::ParameterEnvironment { free_substs: substs::empty(),
281 self_param_bound: None,
282 type_param_bounds: ~[] };
284 err_count_on_creation: ccx.tcx.sess.err_count(),
286 ps: RefCell::new(PurityState::function(ast::ImpureFn, 0)),
287 region_lb: Cell::new(region_bnd),
289 inh: @Inherited::new(ccx.tcx, param_env),
294 impl ExprTyProvider for FnCtxt {
295 fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
299 fn ty_ctxt(&self) -> ty::ctxt {
304 struct CheckItemTypesVisitor { ccx: @CrateCtxt }
306 impl Visitor<()> for CheckItemTypesVisitor {
307 fn visit_item(&mut self, i: &ast::Item, _: ()) {
308 check_item(self.ccx, i);
309 visit::walk_item(self, i, ());
313 pub fn check_item_types(ccx: @CrateCtxt, krate: &ast::Crate) {
314 let mut visit = CheckItemTypesVisitor { ccx: ccx };
315 visit::walk_crate(&mut visit, krate, ());
318 fn check_bare_fn(ccx: @CrateCtxt,
323 param_env: ty::ParameterEnvironment) {
324 match ty::get(fty).sty {
325 ty::ty_bare_fn(ref fn_ty) => {
327 check_fn(ccx, fn_ty.purity, &fn_ty.sig, decl, id, body,
328 Vanilla, @Inherited::new(ccx.tcx, param_env));
330 vtable::resolve_in_block(fcx, body);
331 regionck::regionck_fn(fcx, body);
332 writeback::resolve_type_vars_in_fn(fcx, decl, body);
334 _ => ccx.tcx.sess.impossible_case(body.span,
335 "check_bare_fn: function type expected")
339 struct GatherLocalsVisitor {
344 impl GatherLocalsVisitor {
345 fn assign(&mut self, nid: ast::NodeId, ty_opt: Option<ty::t>) {
348 // infer the variable's type
349 let var_id = self.fcx.infcx().next_ty_var_id();
350 let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
351 let mut locals = self.fcx.inh.locals.borrow_mut();
352 locals.get().insert(nid, var_ty);
355 // take type that the user specified
356 let mut locals = self.fcx.inh.locals.borrow_mut();
357 locals.get().insert(nid, typ);
363 impl Visitor<()> for GatherLocalsVisitor {
364 // Add explicitly-declared locals.
365 fn visit_local(&mut self, local: &ast::Local, _: ()) {
366 let o_ty = match local.ty.node {
367 ast::TyInfer => None,
368 _ => Some(self.fcx.to_ty(local.ty))
370 self.assign(local.id, o_ty);
372 let locals = self.fcx.inh.locals.borrow();
373 debug!("Local variable {} is assigned type {}",
374 self.fcx.pat_to_str(local.pat),
375 self.fcx.infcx().ty_to_str(
376 locals.get().get_copy(&local.id)));
378 visit::walk_local(self, local, ());
381 // Add pattern bindings.
382 fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
384 ast::PatIdent(_, ref path, _)
385 if pat_util::pat_is_binding(self.fcx.ccx.tcx.def_map, p) => {
386 self.assign(p.id, None);
388 let locals = self.fcx.inh.locals.borrow();
389 debug!("Pattern binding {} is assigned to {}",
390 token::get_ident(path.segments.get(0).identifier),
391 self.fcx.infcx().ty_to_str(
392 locals.get().get_copy(&p.id)));
397 visit::walk_pat(self, p, ());
401 fn visit_block(&mut self, b: &ast::Block, _: ()) {
402 // non-obvious: the `blk` variable maps to region lb, so
403 // we have to keep this up-to-date. This
404 // is... unfortunate. It'd be nice to not need this.
405 self.fcx.with_region_lb(b.id, || visit::walk_block(self, b, ()));
408 // Don't descend into fns and items
409 fn visit_fn(&mut self, _: &visit::FnKind, _: &ast::FnDecl,
410 _: &ast::Block, _: Span, _: ast::NodeId, _: ()) { }
411 fn visit_item(&mut self, _: &ast::Item, _: ()) { }
415 fn check_fn(ccx: @CrateCtxt,
422 inherited: @Inherited) -> @FnCtxt
425 * Helper used by check_bare_fn and check_expr_fn. Does the
426 * grungy work of checking a function body and returns the
427 * function context used for that purpose, since in the case of a
428 * fn item there is still a bit more to do.
431 * - inherited: other fields inherited from the enclosing fn (if any)
435 let err_count_on_creation = tcx.sess.err_count();
437 // First, we have to replace any bound regions in the fn type with free ones.
438 // The free region references will be bound the node_id of the body block.
439 let (_, fn_sig) = replace_bound_regions_in_fn_sig(tcx, fn_sig, |br| {
440 ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
443 relate_free_regions(tcx, &fn_sig);
445 let arg_tys = fn_sig.inputs.as_slice();
446 let ret_ty = fn_sig.output;
448 debug!("check_fn(arg_tys={:?}, ret_ty={:?})",
449 arg_tys.map(|&a| ppaux::ty_to_str(tcx, a)),
450 ppaux::ty_to_str(tcx, ret_ty));
452 // Create the function context. This is either derived from scratch or,
453 // in the case of function expressions, based on the outer context.
455 err_count_on_creation: err_count_on_creation,
457 ps: RefCell::new(PurityState::function(purity, id)),
458 region_lb: Cell::new(body.id),
466 let mut visit = GatherLocalsVisitor { fcx: fcx, tcx: tcx, };
467 // Add formal parameters.
468 for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
469 // Create type variables for each argument.
470 pat_util::pat_bindings(tcx.def_map,
472 |_bm, pat_id, _sp, _path| {
473 visit.assign(pat_id, None);
476 // Check the pattern.
479 map: pat_id_map(tcx.def_map, input.pat),
481 _match::check_pat(&pcx, input.pat, *arg_ty);
484 visit.visit_block(body, ());
487 check_block_with_expected(fcx, body, Some(ret_ty));
489 // We unify the tail expr's type with the
490 // function result type, if there is a tail expr.
493 // Special case: we print a special error if there appears
494 // to be do-block/for-loop confusion
495 demand::suptype_with_fn(fcx, tail_expr.span, false,
496 fcx.ret_ty, fcx.expr_ty(tail_expr),
498 fcx.report_mismatched_return_types(sp, e, a, s);
504 for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
505 fcx.write_ty(input.id, *arg);
511 pub fn check_no_duplicate_fields(tcx: ty::ctxt,
512 fields: ~[(ast::Ident, Span)]) {
513 let mut field_names = HashMap::new();
515 for p in fields.iter() {
517 let orig_sp = field_names.find(&id).map(|x| *x);
520 tcx.sess.span_err(sp, format!("duplicate field name {} in record type declaration",
521 token::get_ident(id)));
522 tcx.sess.span_note(orig_sp, "first declaration of this field occurred here");
526 field_names.insert(id, sp);
532 pub fn check_struct(ccx: @CrateCtxt, id: ast::NodeId, span: Span) {
535 // Check that the struct is representable
536 check_representable(tcx, span, id, "struct");
538 // Check that the struct is instantiable
539 check_instantiable(tcx, span, id);
541 if ty::lookup_simd(tcx, local_def(id)) {
542 check_simd(tcx, span, id);
546 pub fn check_item(ccx: @CrateCtxt, it: &ast::Item) {
547 debug!("check_item(it.id={}, it.ident={})",
549 ty::item_path_str(ccx.tcx, local_def(it.id)));
550 let _indenter = indenter();
553 ast::ItemStatic(_, _, e) => check_const(ccx, it.span, e, it.id),
554 ast::ItemEnum(ref enum_definition, _) => {
555 check_enum_variants(ccx,
557 enum_definition.variants.as_slice(),
560 ast::ItemFn(decl, _, _, _, body) => {
561 let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
563 // FIXME(#5121) -- won't work for lifetimes that appear in type bounds
564 let param_env = ty::construct_parameter_environment(
567 fn_tpt.generics.type_param_defs(),
572 check_bare_fn(ccx, decl, body, it.id, fn_tpt.ty, param_env);
574 ast::ItemImpl(_, ref opt_trait_ref, _, ref ms) => {
575 debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
577 let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
579 check_method_body(ccx, &impl_tpt.generics, None, *m);
582 match *opt_trait_ref {
583 Some(ref ast_trait_ref) => {
585 ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id);
586 check_impl_methods_against_trait(ccx,
592 vtable::resolve_impl(ccx.tcx, it, &impl_tpt.generics, impl_trait_ref);
598 ast::ItemTrait(_, _, ref trait_methods) => {
599 let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
600 for trait_method in (*trait_methods).iter() {
601 match *trait_method {
603 // Nothing to do, since required methods don't have
607 check_method_body(ccx, &trait_def.generics,
608 Some(trait_def.trait_ref), m);
613 ast::ItemStruct(..) => {
614 check_struct(ccx, it.id, it.span);
616 ast::ItemTy(ref t, ref generics) => {
617 let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id);
618 check_bounds_are_used(ccx, t.span, &generics.ty_params, tpt_ty);
620 ast::ItemForeignMod(ref m) => {
621 if m.abis.is_intrinsic() {
622 for item in m.items.iter() {
623 check_intrinsic_type(ccx, *item);
626 for item in m.items.iter() {
627 let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id));
628 if tpt.generics.has_type_params() {
629 ccx.tcx.sess.span_err(item.span, "foreign items may not have type parameters");
633 ast::ForeignItemFn(ref fn_decl, _) => {
634 if fn_decl.variadic && !m.abis.is_c() {
635 ccx.tcx.sess.span_err(
636 item.span, "variadic function must have C calling convention");
644 _ => {/* nothing to do */ }
648 fn check_method_body(ccx: @CrateCtxt,
649 item_generics: &ty::Generics,
650 self_bound: Option<@ty::TraitRef>,
651 method: &ast::Method) {
653 * Type checks a method body.
656 * - `item_generics`: generics defined on the impl/trait that contains
658 * - `self_bound`: bound for the `Self` type parameter, if any
659 * - `method`: the method definition
662 debug!("check_method_body(item_generics={}, \
665 item_generics.repr(ccx.tcx),
666 self_bound.repr(ccx.tcx),
668 let method_def_id = local_def(method.id);
669 let method_ty = ty::method(ccx.tcx, method_def_id);
670 let method_generics = &method_ty.generics;
673 ty::construct_parameter_environment(
676 item_generics.type_param_defs(),
677 method_generics.type_param_defs(),
678 item_generics.region_param_defs(),
681 // Compute the fty from point of view of inside fn
682 let fty = ty::node_id_to_type(ccx.tcx, method.id);
683 let fty = fty.subst(ccx.tcx, ¶m_env.free_substs);
685 check_bare_fn(ccx, method.decl, method.body, method.id, fty, param_env);
688 fn check_impl_methods_against_trait(ccx: @CrateCtxt,
690 impl_generics: &ty::Generics,
691 ast_trait_ref: &ast::TraitRef,
692 impl_trait_ref: &ty::TraitRef,
693 impl_methods: &[@ast::Method]) {
694 // Locate trait methods
696 let trait_methods = ty::trait_methods(tcx, impl_trait_ref.def_id);
698 // Check existing impl methods to see if they are both present in trait
699 // and compatible with trait signature
700 for impl_method in impl_methods.iter() {
701 let impl_method_def_id = local_def(impl_method.id);
702 let impl_method_ty = ty::method(ccx.tcx, impl_method_def_id);
704 // If this is an impl of a trait method, find the corresponding
705 // method definition in the trait.
706 let opt_trait_method_ty =
707 trait_methods.iter().
708 find(|tm| tm.ident.name == impl_method_ty.ident.name);
709 match opt_trait_method_ty {
710 Some(trait_method_ty) => {
711 compare_impl_method(ccx.tcx,
717 &impl_trait_ref.substs);
722 format!("method `{}` is not a member of trait `{}`",
723 token::get_ident(impl_method_ty.ident),
724 pprust::path_to_str(&ast_trait_ref.path)));
729 // Check for missing methods from trait
730 let provided_methods = ty::provided_trait_methods(tcx,
731 impl_trait_ref.def_id);
732 let mut missing_methods = ~[];
733 for trait_method in trait_methods.iter() {
735 impl_methods.iter().any(
736 |m| m.ident.name == trait_method.ident.name);
738 provided_methods.iter().any(
739 |m| m.ident.name == trait_method.ident.name);
740 if !is_implemented && !is_provided {
741 missing_methods.push(
742 format!("`{}`", token::get_ident(trait_method.ident)));
746 if !missing_methods.is_empty() {
749 format!("not all trait methods implemented, missing: {}",
750 missing_methods.connect(", ")));
755 * Checks that a method from an impl/class conforms to the signature of
756 * the same method as declared in the trait.
760 * - impl_generics: the generics declared on the impl itself (not the method!)
761 * - impl_m: type of the method we are checking
762 * - impl_m_span: span to use for reporting errors
763 * - impl_m_body_id: id of the method body
764 * - trait_m: the method in the trait
765 * - trait_substs: the substitutions used on the type of the trait
767 fn compare_impl_method(tcx: ty::ctxt,
768 impl_generics: &ty::Generics,
771 impl_m_body_id: ast::NodeId,
772 trait_m: &ty::Method,
773 trait_substs: &ty::substs) {
774 debug!("compare_impl_method()");
775 let infcx = infer::new_infer_ctxt(tcx);
777 let impl_tps = impl_generics.type_param_defs().len();
779 // Try to give more informative error messages about self typing
780 // mismatches. Note that any mismatch will also be detected
781 // below, where we construct a canonical function type that
782 // includes the self parameter as a normal parameter. It's just
783 // that the error messages you get out of this code are a bit more
784 // inscrutable, particularly for cases where one method has no
786 match (&trait_m.explicit_self, &impl_m.explicit_self) {
787 (&ast::SelfStatic, &ast::SelfStatic) => {}
788 (&ast::SelfStatic, _) => {
791 format!("method `{}` has a `{}` declaration in the impl, \
792 but not in the trait",
793 token::get_ident(trait_m.ident),
794 pprust::explicit_self_to_str(&impl_m.explicit_self)));
797 (_, &ast::SelfStatic) => {
800 format!("method `{}` has a `{}` declaration in the trait, \
801 but not in the impl",
802 token::get_ident(trait_m.ident),
803 pprust::explicit_self_to_str(&trait_m.explicit_self)));
807 // Let the type checker catch other errors below
811 let num_impl_m_type_params = impl_m.generics.type_param_defs().len();
812 let num_trait_m_type_params = trait_m.generics.type_param_defs().len();
813 if num_impl_m_type_params != num_trait_m_type_params {
816 format!("method `{}` has {} type parameter(s), but its trait \
817 declaration has {} type parameter(s)",
818 token::get_ident(trait_m.ident),
819 num_impl_m_type_params,
820 num_trait_m_type_params));
824 if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() {
827 format!("method `{}` has {} parameter{} \
828 but the declaration in trait `{}` has {}",
829 token::get_ident(trait_m.ident),
830 impl_m.fty.sig.inputs.len(),
831 if impl_m.fty.sig.inputs.len() == 1 { "" } else { "s" },
832 ty::item_path_str(tcx, trait_m.def_id),
833 trait_m.fty.sig.inputs.len()));
837 let it = trait_m.generics.type_param_defs().iter()
838 .zip(impl_m.generics.type_param_defs().iter());
840 for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
841 // Check that the impl does not require any builtin-bounds
842 // that the trait does not guarantee:
844 impl_param_def.bounds.builtin_bounds -
845 trait_param_def.bounds.builtin_bounds;
846 if !extra_bounds.is_empty() {
849 format!("in method `{}`, \
850 type parameter {} requires `{}`, \
851 which is not required by \
852 the corresponding type parameter \
853 in the trait declaration",
854 token::get_ident(trait_m.ident),
856 extra_bounds.user_string(tcx)));
860 // FIXME(#2687)---we should be checking that the bounds of the
861 // trait imply the bounds of the subtype, but it appears we
862 // are...not checking this.
863 if impl_param_def.bounds.trait_bounds.len() !=
864 trait_param_def.bounds.trait_bounds.len()
868 format!("in method `{}`, \
869 type parameter {} has {} trait bound(s), but the \
870 corresponding type parameter in \
871 the trait declaration has {} trait bound(s)",
872 token::get_ident(trait_m.ident),
873 i, impl_param_def.bounds.trait_bounds.len(),
874 trait_param_def.bounds.trait_bounds.len()));
879 // Create a substitution that maps the type parameters on the impl
880 // to themselves and which replace any references to bound regions
881 // in the self type with free regions. So, for example, if the
882 // impl type is "&'a str", then this would replace the self
883 // type with a free region `self`.
884 let dummy_impl_tps: ~[ty::t] =
885 impl_generics.type_param_defs().iter().enumerate().
886 map(|(i,t)| ty::mk_param(tcx, i, t.def_id)).
888 let dummy_method_tps: ~[ty::t] =
889 impl_m.generics.type_param_defs().iter().enumerate().
890 map(|(i,t)| ty::mk_param(tcx, i + impl_tps, t.def_id)).
892 let dummy_impl_regions: OptVec<ty::Region> =
893 impl_generics.region_param_defs().iter().
894 map(|l| ty::ReFree(ty::FreeRegion {
895 scope_id: impl_m_body_id,
896 bound_region: ty::BrNamed(l.def_id, l.ident)})).
898 let dummy_substs = ty::substs {
899 tps: vec::append(dummy_impl_tps, dummy_method_tps),
900 regions: ty::NonerasedRegions(dummy_impl_regions),
903 // Create a bare fn type for trait/impl
904 // It'd be nice to refactor so as to provide the bare fn types instead.
905 let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
906 let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
908 // Perform substitutions so that the trait/impl methods are expressed
909 // in terms of the same set of type/region parameters:
910 // - replace trait type parameters with those from `trait_substs`,
911 // except with any reference to bound self replaced with `dummy_self_r`
912 // - replace method parameters on the trait with fresh, dummy parameters
913 // that correspond to the parameters we will find on the impl
914 // - replace self region with a fresh, dummy region
916 debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
917 impl_fty.subst(tcx, &dummy_substs)
919 debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
921 let substs { regions: trait_regions,
923 self_ty: self_ty } = trait_substs.subst(tcx, &dummy_substs);
924 let substs = substs {
925 regions: trait_regions,
926 tps: vec::append(trait_tps, dummy_method_tps),
929 debug!("trait_fty (pre-subst): {} substs={}",
930 trait_fty.repr(tcx), substs.repr(tcx));
931 trait_fty.subst(tcx, &substs)
933 debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx));
935 match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span),
936 impl_fty, trait_fty) {
938 result::Err(ref terr) => {
941 format!("method `{}` has an incompatible type: {}",
942 token::get_ident(trait_m.ident),
943 ty::type_err_to_str(tcx, terr)));
944 ty::note_and_explain_type_err(tcx, terr);
949 impl AstConv for FnCtxt {
950 fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
952 fn get_item_ty(&self, id: ast::DefId) -> ty::ty_param_bounds_and_ty {
953 ty::lookup_item_type(self.tcx(), id)
956 fn get_trait_def(&self, id: ast::DefId) -> @ty::TraitDef {
957 ty::lookup_trait_def(self.tcx(), id)
960 fn ty_infer(&self, _span: Span) -> ty::t {
961 self.infcx().next_ty_var()
966 pub fn infcx<'a>(&'a self) -> &'a infer::InferCtxt {
970 pub fn err_count_since_creation(&self) -> uint {
971 self.ccx.tcx.sess.err_count() - self.err_count_on_creation
974 pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
977 param_env: &self.inh.param_env
982 impl RegionScope for infer::InferCtxt {
983 fn anon_regions(&self, span: Span, count: uint)
984 -> Result<~[ty::Region], ()> {
985 Ok(vec::from_fn(count, |_| {
986 self.next_region_var(infer::MiscVariable(span))
992 pub fn tag(&self) -> ~str {
993 format!("{}", self as *FnCtxt)
996 pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t {
997 let locals = self.inh.locals.borrow();
998 match locals.get().find(&nid) {
1001 self.tcx().sess.span_bug(
1003 format!("no type for local variable {:?}", nid));
1008 pub fn block_region(&self) -> ty::Region {
1009 ty::ReScope(self.region_lb.get())
1013 pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
1014 debug!("write_ty({}, {}) in fcx {}",
1015 node_id, ppaux::ty_to_str(self.tcx(), ty), self.tag());
1016 let mut node_types = self.inh.node_types.borrow_mut();
1017 node_types.get().insert(node_id, ty);
1020 pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::substs) {
1021 if !ty::substs_is_noop(&substs) {
1022 debug!("write_substs({}, {}) in fcx {}",
1024 ty::substs_to_str(self.tcx(), &substs),
1027 let mut node_type_substs = self.inh.node_type_substs.borrow_mut();
1028 node_type_substs.get().insert(node_id, substs);
1032 pub fn write_ty_substs(&self,
1033 node_id: ast::NodeId,
1035 substs: ty::substs) {
1036 let ty = ty::subst(self.tcx(), &substs, ty);
1037 self.write_ty(node_id, ty);
1038 self.write_substs(node_id, substs);
1041 pub fn write_autoderef_adjustment(&self,
1042 node_id: ast::NodeId,
1044 if derefs == 0 { return; }
1045 self.write_adjustment(
1047 @ty::AutoDerefRef(ty::AutoDerefRef {
1053 pub fn write_adjustment(&self,
1054 node_id: ast::NodeId,
1055 adj: @ty::AutoAdjustment) {
1056 debug!("write_adjustment(node_id={:?}, adj={:?})", node_id, adj);
1057 let mut adjustments = self.inh.adjustments.borrow_mut();
1058 adjustments.get().insert(node_id, adj);
1061 pub fn write_nil(&self, node_id: ast::NodeId) {
1062 self.write_ty(node_id, ty::mk_nil());
1064 pub fn write_bot(&self, node_id: ast::NodeId) {
1065 self.write_ty(node_id, ty::mk_bot());
1067 pub fn write_error(&self, node_id: ast::NodeId) {
1068 self.write_ty(node_id, ty::mk_err());
1071 pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
1072 ast_ty_to_ty(self, self.infcx(), ast_t)
1075 pub fn pat_to_str(&self, pat: &ast::Pat) -> ~str {
1076 pat.repr(self.tcx())
1079 pub fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
1080 let node_types = self.inh.node_types.borrow();
1081 match node_types.get().find(&ex.id) {
1084 self.tcx().sess.bug(format!("no type for expr in fcx {}",
1090 pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
1091 match self.inh.node_types.borrow().get().find(&id) {
1094 self.tcx().sess.bug(
1095 format!("no type for node {}: {} in fcx {}",
1096 id, self.tcx().map.node_to_str(id),
1102 pub fn method_ty(&self, id: ast::NodeId) -> ty::t {
1103 match self.inh.method_map.borrow().get().find(&id) {
1104 Some(method) => method.ty,
1106 self.tcx().sess.bug(
1107 format!("no method entry for node {}: {} in fcx {}",
1108 id, self.tcx().map.node_to_str(id),
1114 pub fn node_ty_substs(&self, id: ast::NodeId) -> ty::substs {
1115 match self.inh.node_type_substs.borrow().get().find(&id) {
1116 Some(ts) => (*ts).clone(),
1118 self.tcx().sess.bug(
1119 format!("no type substs for node {}: {} in fcx {}",
1120 id, self.tcx().map.node_to_str(id),
1126 pub fn method_ty_substs(&self, id: ast::NodeId) -> ty::substs {
1127 match self.inh.method_map.borrow().get().find(&id) {
1128 Some(method) => method.substs.clone(),
1130 self.tcx().sess.bug(
1131 format!("no method entry for node {}: {} in fcx {}",
1132 id, self.tcx().map.node_to_str(id),
1138 pub fn opt_node_ty_substs(&self,
1140 f: |&ty::substs| -> bool)
1142 let node_type_substs = self.inh.node_type_substs.borrow();
1143 match node_type_substs.get().find(&id) {
1149 pub fn mk_subty(&self,
1150 a_is_expected: bool,
1151 origin: infer::TypeOrigin,
1154 -> Result<(), ty::type_err> {
1155 infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
1158 pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t)
1159 -> Result<(), ty::type_err> {
1160 infer::can_mk_subty(self.infcx(), sub, sup)
1163 pub fn mk_assignty(&self,
1167 -> Result<(), ty::type_err> {
1168 match infer::mk_coercety(self.infcx(),
1170 infer::ExprAssignable(expr.span),
1173 Ok(None) => result::Ok(()),
1174 Err(ref e) => result::Err((*e)),
1175 Ok(Some(adjustment)) => {
1176 self.write_adjustment(expr.id, adjustment);
1182 pub fn can_mk_assignty(&self, sub: ty::t, sup: ty::t)
1183 -> Result<(), ty::type_err> {
1184 infer::can_mk_coercety(self.infcx(), sub, sup)
1187 pub fn mk_eqty(&self,
1188 a_is_expected: bool,
1189 origin: infer::TypeOrigin,
1192 -> Result<(), ty::type_err> {
1193 infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
1196 pub fn mk_subr(&self,
1197 a_is_expected: bool,
1198 origin: infer::SubregionOrigin,
1201 infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
1204 pub fn with_region_lb<R>(&self, lb: ast::NodeId, f: || -> R) -> R {
1205 let old_region_lb = self.region_lb.get();
1206 self.region_lb.set(lb);
1208 self.region_lb.set(old_region_lb);
1212 pub fn type_error_message(&self,
1214 mk_msg: |~str| -> ~str,
1216 err: Option<&ty::type_err>) {
1217 self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
1220 pub fn report_mismatched_return_types(&self,
1224 err: &ty::type_err) {
1226 if ty::type_is_error(e) || ty::type_is_error(a) {
1229 self.infcx().report_mismatched_types(sp, e, a, err)
1232 pub fn report_mismatched_types(&self,
1236 err: &ty::type_err) {
1237 self.infcx().report_mismatched_types(sp, e, a, err)
1241 pub fn do_autoderef(fcx: @FnCtxt, sp: Span, t: ty::t) -> (ty::t, uint) {
1244 * Autoderefs the type `t` as many times as possible, returning
1245 * a new type and a counter for how many times the type was
1246 * deref'd. If the counter is non-zero, the receiver is responsible
1247 * for inserting an AutoAdjustment record into `tcx.adjustments`
1248 * so that trans/borrowck/etc know about this autoderef. */
1251 let mut enum_dids = ~[];
1252 let mut autoderefs = 0;
1254 let sty = structure_of(fcx, sp, t1);
1256 // Some extra checks to detect weird cycles and so forth:
1258 ty::ty_box(inner) | ty::ty_uniq(inner) => {
1259 match ty::get(t1).sty {
1260 ty::ty_infer(ty::TyVar(v1)) => {
1261 ty::occurs_check(fcx.ccx.tcx, sp, v1,
1262 ty::mk_box(fcx.ccx.tcx, inner));
1267 ty::ty_rptr(_, inner) => {
1268 match ty::get(t1).sty {
1269 ty::ty_infer(ty::TyVar(v1)) => {
1270 ty::occurs_check(fcx.ccx.tcx, sp, v1,
1271 ty::mk_box(fcx.ccx.tcx, inner.ty));
1276 ty::ty_enum(ref did, _) => {
1277 // Watch out for a type like `enum t = @t`. Such a
1278 // type would otherwise infinitely auto-deref. Only
1279 // autoderef loops during typeck (basically, this one
1280 // and the loops in typeck::check::method) need to be
1281 // concerned with this, as an error will be reported
1282 // on the enum definition as well because the enum is
1283 // not instantiable.
1284 if enum_dids.contains(did) {
1285 return (t1, autoderefs);
1287 enum_dids.push(*did);
1292 // Otherwise, deref if type is derefable:
1293 match ty::deref_sty(sty, false) {
1295 return (t1, autoderefs);
1305 // AST fragment checking
1306 pub fn check_lit(fcx: @FnCtxt, lit: &ast::Lit) -> ty::t {
1307 let tcx = fcx.ccx.tcx;
1310 ast::LitStr(..) => ty::mk_str(tcx, ty::vstore_slice(ty::ReStatic)),
1311 ast::LitBinary(..) => {
1312 ty::mk_vec(tcx, ty::mt{ ty: ty::mk_u8(), mutbl: ast::MutImmutable },
1313 ty::vstore_slice(ty::ReStatic))
1315 ast::LitChar(_) => ty::mk_char(),
1316 ast::LitInt(_, t) => ty::mk_mach_int(t),
1317 ast::LitUint(_, t) => ty::mk_mach_uint(t),
1318 ast::LitIntUnsuffixed(_) => {
1319 // An unsuffixed integer literal could have any integral type,
1320 // so we create an integral type variable for it.
1321 ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
1323 ast::LitFloat(_, t) => ty::mk_mach_float(t),
1324 ast::LitFloatUnsuffixed(_) => {
1325 // An unsuffixed floating point literal could have any floating point
1326 // type, so we create a floating point type variable for it.
1327 ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())
1329 ast::LitNil => ty::mk_nil(),
1330 ast::LitBool(_) => ty::mk_bool()
1334 pub fn valid_range_bounds(ccx: @CrateCtxt,
1338 match const_eval::compare_lit_exprs(ccx.tcx, from, to) {
1339 Some(val) => Some(val <= 0),
1344 pub fn check_expr_has_type(
1345 fcx: @FnCtxt, expr: &ast::Expr,
1347 check_expr_with_unifier(fcx, expr, Some(expected), || {
1348 demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
1352 pub fn check_expr_coercable_to_type(
1353 fcx: @FnCtxt, expr: &ast::Expr,
1355 check_expr_with_unifier(fcx, expr, Some(expected), || {
1356 demand::coerce(fcx, expr.span, expected, expr)
1360 pub fn check_expr_with_hint(
1361 fcx: @FnCtxt, expr: &ast::Expr,
1363 check_expr_with_unifier(fcx, expr, Some(expected), || ())
1366 pub fn check_expr_with_opt_hint(
1367 fcx: @FnCtxt, expr: &ast::Expr,
1368 expected: Option<ty::t>) {
1369 check_expr_with_unifier(fcx, expr, expected, || ())
1372 pub fn check_expr(fcx: @FnCtxt, expr: &ast::Expr) {
1373 check_expr_with_unifier(fcx, expr, None, || ())
1376 // determine the `self` type, using fresh variables for all variables
1377 // declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
1378 // would return ($0, $1) where $0 and $1 are freshly instantiated type
1380 pub fn impl_self_ty(vcx: &VtableContext,
1381 location_info: &LocationInfo, // (potential) receiver for
1384 -> ty_param_substs_and_ty {
1385 let tcx = vcx.tcx();
1387 let (n_tps, n_rps, raw_ty) = {
1388 let ity = ty::lookup_item_type(tcx, did);
1389 (ity.generics.type_param_defs().len(),
1390 ity.generics.region_param_defs().len(),
1395 vcx.infcx.next_region_vars(
1396 infer::BoundRegionInTypeOrImpl(location_info.span),
1398 let tps = vcx.infcx.next_ty_vars(n_tps);
1400 let substs = substs {
1401 regions: ty::NonerasedRegions(opt_vec::from(rps.move_iter()
1406 let substd_ty = ty::subst(tcx, &substs, raw_ty);
1408 ty_param_substs_and_ty { substs: substs, ty: substd_ty }
1411 // Only for fields! Returns <none> for methods>
1412 // Indifferent to privacy flags
1413 pub fn lookup_field_ty(tcx: ty::ctxt,
1414 class_id: ast::DefId,
1415 items: &[ty::field_ty],
1416 fieldname: ast::Name,
1417 substs: &ty::substs) -> Option<ty::t> {
1419 let o_field = items.iter().find(|f| f.name == fieldname);
1420 o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
1423 // Controls whether the arguments are automatically referenced. This is useful
1424 // for overloaded binary and unary operators.
1425 pub enum DerefArgs {
1430 // Given the provenance of a static method, returns the generics of the static
1431 // method's container.
1432 fn generics_of_static_method_container(type_context: ty::ctxt,
1433 provenance: ast::MethodProvenance)
1436 ast::FromTrait(trait_def_id) => {
1437 ty::lookup_trait_def(type_context, trait_def_id).generics.clone()
1439 ast::FromImpl(impl_def_id) => {
1440 ty::lookup_item_type(type_context, impl_def_id).generics.clone()
1445 // Verifies that type parameters supplied in paths are in the right
1447 fn check_type_parameter_positions_in_path(function_context: @FnCtxt,
1450 // We only care about checking the case in which the path has two or
1452 if path.segments.len() < 2 {
1456 // Verify that no lifetimes or type parameters are present anywhere
1457 // except the final two elements of the path.
1458 for i in range(0, path.segments.len() - 2) {
1459 for lifetime in path.segments.get(i).lifetimes.iter() {
1460 function_context.tcx()
1462 .span_err(lifetime.span,
1463 "lifetime parameters may not \
1468 for typ in path.segments.get(i).types.iter() {
1469 function_context.tcx()
1472 "type parameters may not appear here");
1477 // If there are no parameters at all, there is nothing more to do; the
1478 // rest of typechecking will (attempt to) infer everything.
1481 .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) {
1486 // If this is a static method of a trait or implementation, then
1487 // ensure that the segment of the path which names the trait or
1488 // implementation (the penultimate segment) is annotated with the
1489 // right number of type parameters.
1490 ast::DefStaticMethod(_, provenance, _) => {
1492 generics_of_static_method_container(function_context.ccx.tcx,
1494 let name = match provenance {
1495 ast::FromTrait(_) => "trait",
1496 ast::FromImpl(_) => "impl",
1499 let trait_segment = &path.segments.get(path.segments.len() - 2);
1501 // Make sure lifetime parameterization agrees with the trait or
1502 // implementation type.
1503 let trait_region_parameter_count = generics.region_param_defs().len();
1504 let supplied_region_parameter_count = trait_segment.lifetimes.len();
1505 if trait_region_parameter_count != supplied_region_parameter_count
1506 && supplied_region_parameter_count != 0 {
1507 function_context.tcx()
1509 .span_err(path.span,
1510 format!("expected {} lifetime parameter(s), \
1511 found {} lifetime parameter(s)",
1512 trait_region_parameter_count,
1513 supplied_region_parameter_count));
1516 // Make sure the number of type parameters supplied on the trait
1517 // or implementation segment equals the number of type parameters
1518 // on the trait or implementation definition.
1519 let formal_ty_param_count = generics.type_param_defs().len();
1520 let required_ty_param_count = generics.type_param_defs().iter()
1521 .take_while(|x| x.default.is_none())
1523 let supplied_ty_param_count = trait_segment.types.len();
1524 if supplied_ty_param_count < required_ty_param_count {
1525 let trait_count_suffix = if required_ty_param_count == 1 {
1530 let supplied_count_suffix = if supplied_ty_param_count == 1 {
1535 let needs = if required_ty_param_count < generics.type_param_defs().len() {
1540 function_context.tcx().sess.span_err(path.span,
1541 format!("the {} referenced by this path {} {} type \
1542 parameter{}, but {} type parameter{} were supplied",
1544 required_ty_param_count, trait_count_suffix,
1545 supplied_ty_param_count, supplied_count_suffix))
1546 } else if supplied_ty_param_count > formal_ty_param_count {
1547 let trait_count_suffix = if formal_ty_param_count == 1 {
1552 let supplied_count_suffix = if supplied_ty_param_count == 1 {
1557 let needs = if required_ty_param_count < generics.type_param_defs().len() {
1562 function_context.tcx().sess.span_err(path.span,
1563 format!("the {} referenced by this path {} {} type \
1564 parameter{}, but {} type parameter{} were supplied",
1566 formal_ty_param_count, trait_count_suffix,
1567 supplied_ty_param_count, supplied_count_suffix))
1571 // Verify that no lifetimes or type parameters are present on
1572 // the penultimate segment of the path.
1573 let segment = &path.segments.get(path.segments.len() - 2);
1574 for lifetime in segment.lifetimes.iter() {
1575 function_context.tcx()
1577 .span_err(lifetime.span,
1578 "lifetime parameters may not
1582 for typ in segment.types.iter() {
1583 function_context.tcx()
1586 "type parameters may not appear \
1595 /// If an expression has any sub-expressions that result in a type error,
1596 /// inspecting that expression's type with `ty::type_is_error` will return
1597 /// true. Likewise, if an expression is known to diverge, inspecting its
1598 /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
1599 /// strict, _|_ can appear in the type of an expression that does not,
1600 /// itself, diverge: for example, fn() -> _|_.)
1601 /// Note that inspecting a type's structure *directly* may expose the fact
1602 /// that there are actually multiple representations for both `ty_err` and
1603 /// `ty_bot`, so avoid that when err and bot need to be handled differently.
1604 pub fn check_expr_with_unifier(fcx: @FnCtxt,
1606 expected: Option<ty::t>,
1608 debug!(">> typechecking");
1610 fn check_method_argument_types(
1613 method_fn_ty: ty::t,
1614 callee_expr: &ast::Expr,
1615 args: &[@ast::Expr],
1616 deref_args: DerefArgs) -> ty::t {
1617 // HACK(eddyb) ignore provided self (it has special typeck rules).
1618 let args = args.slice_from(1);
1619 if ty::type_is_error(method_fn_ty) {
1620 let err_inputs = err_args(args.len());
1621 check_argument_types(fcx, sp, err_inputs, callee_expr,
1622 args, deref_args, false);
1625 match ty::get(method_fn_ty).sty {
1626 ty::ty_bare_fn(ref fty) => {
1627 // HACK(eddyb) ignore self in the definition (see above).
1628 check_argument_types(fcx, sp, fty.sig.inputs.slice_from(1),
1629 callee_expr, args, deref_args,
1634 fcx.tcx().sess.span_bug(
1636 format!("method without bare fn type"));
1642 fn check_argument_types(fcx: @FnCtxt,
1644 fn_inputs: &[ty::t],
1645 callee_expr: &ast::Expr,
1646 args: &[@ast::Expr],
1647 deref_args: DerefArgs,
1651 * Generic function that factors out common logic from
1652 * function calls, method calls and overloaded operators.
1655 let tcx = fcx.ccx.tcx;
1657 // Grab the argument types, supplying fresh type variables
1658 // if the wrong number of arguments were supplied
1659 let supplied_arg_count = args.len();
1660 let expected_arg_count = fn_inputs.len();
1661 let formal_tys = if expected_arg_count == supplied_arg_count {
1662 fn_inputs.map(|a| *a)
1663 } else if variadic {
1664 if supplied_arg_count >= expected_arg_count {
1665 fn_inputs.map(|a| *a)
1668 "this function takes at least {} parameter{} \
1669 but {} parameter{} supplied",
1671 if expected_arg_count == 1 {""} else {"s"},
1673 if supplied_arg_count == 1 {" was"} else {"s were"});
1675 tcx.sess.span_err(sp, msg);
1677 err_args(supplied_arg_count)
1681 "this function takes {} parameter{} \
1682 but {} parameter{} supplied",
1683 expected_arg_count, if expected_arg_count == 1 {""} else {"s"},
1685 if supplied_arg_count == 1 {" was"} else {"s were"});
1687 tcx.sess.span_err(sp, msg);
1689 err_args(supplied_arg_count)
1692 debug!("check_argument_types: formal_tys={:?}",
1693 formal_tys.map(|t| fcx.infcx().ty_to_str(*t)));
1695 // Check the arguments.
1696 // We do this in a pretty awful way: first we typecheck any arguments
1697 // that are not anonymous functions, then we typecheck the anonymous
1698 // functions. This is so that we have more information about the types
1699 // of arguments when we typecheck the functions. This isn't really the
1700 // right way to do this.
1701 let xs = [false, true];
1702 for check_blocks in xs.iter() {
1703 let check_blocks = *check_blocks;
1704 debug!("check_blocks={}", check_blocks);
1706 // More awful hacks: before we check the blocks, try to do
1707 // an "opportunistic" vtable resolution of any trait
1708 // bounds on the call.
1710 vtable::early_resolve_expr(callee_expr, fcx, true);
1713 // For variadic functions, we don't have a declared type for all of
1714 // the arguments hence we only do our usual type checking with
1715 // the arguments who's types we do know.
1716 let t = if variadic {
1721 for (i, arg) in args.iter().take(t).enumerate() {
1722 let is_block = match arg.node {
1723 ast::ExprFnBlock(..) |
1724 ast::ExprProc(..) => true,
1728 if is_block == check_blocks {
1729 debug!("checking the argument");
1730 let mut formal_ty = formal_tys[i];
1734 match ty::get(formal_ty).sty {
1735 ty::ty_rptr(_, mt) => formal_ty = mt.ty,
1738 // So we hit this case when one implements the
1739 // operator traits but leaves an argument as
1740 // just T instead of &T. We'll catch it in the
1741 // mismatch impl/trait method phase no need to
1744 formal_ty = ty::mk_err();
1751 check_expr_coercable_to_type(fcx, *arg, formal_ty);
1757 // We also need to make sure we at least write the ty of the other
1758 // arguments which we skipped above.
1760 for arg in args.iter().skip(expected_arg_count) {
1761 check_expr(fcx, *arg);
1763 // There are a few types which get autopromoted when passed via varargs
1764 // in C but we just error out instead and require explicit casts.
1765 let arg_ty = structurally_resolved_type(fcx, arg.span, fcx.expr_ty(*arg));
1766 match ty::get(arg_ty).sty {
1767 ty::ty_float(ast::TyF32) => {
1768 fcx.type_error_message(arg.span,
1769 |t| format!("can't pass an {} to variadic function, \
1770 cast to c_double", t), arg_ty, None);
1772 ty::ty_int(ast::TyI8) | ty::ty_int(ast::TyI16) | ty::ty_bool => {
1773 fcx.type_error_message(arg.span,
1774 |t| format!("can't pass {} to variadic function, cast to c_int",
1777 ty::ty_uint(ast::TyU8) | ty::ty_uint(ast::TyU16) => {
1778 fcx.type_error_message(arg.span,
1779 |t| format!("can't pass {} to variadic function, cast to c_uint",
1788 fn err_args(len: uint) -> ~[ty::t] {
1789 vec::from_fn(len, |_| ty::mk_err())
1792 // A generic function for checking assignment expressions
1793 fn check_assignment(fcx: @FnCtxt,
1797 check_expr(fcx, lhs);
1798 let lhs_type = fcx.expr_ty(lhs);
1799 check_expr_has_type(fcx, rhs, lhs_type);
1800 fcx.write_ty(id, ty::mk_nil());
1801 // The callee checks for bot / err, we don't need to
1804 fn write_call(fcx: @FnCtxt, call_expr: &ast::Expr, output: ty::t) {
1805 fcx.write_ty(call_expr.id, output);
1808 // A generic function for doing all of the checking for call expressions
1809 fn check_call(fcx: @FnCtxt,
1810 call_expr: &ast::Expr,
1812 args: &[@ast::Expr]) {
1813 // Index expressions need to be handled separately, to inform them
1814 // that they appear in call position.
1817 // Store the type of `f` as the type of the callee
1818 let fn_ty = fcx.expr_ty(f);
1820 // Extract the function signature from `in_fty`.
1821 let fn_sty = structure_of(fcx, f.span, fn_ty);
1823 // This is the "default" function signature, used in case of error.
1824 // In that case, we check each argument against "error" in order to
1825 // set up all the node type bindings.
1826 let error_fn_sig = FnSig {
1827 binder_id: ast::CRATE_NODE_ID,
1828 inputs: err_args(args.len()),
1829 output: ty::mk_err(),
1833 let fn_sig = match *fn_sty {
1834 ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, ..}) |
1835 ty::ty_closure(ty::ClosureTy {sig: ref sig, ..}) => sig,
1837 fcx.type_error_message(call_expr.span, |actual| {
1838 format!("expected function but \
1839 found `{}`", actual) }, fn_ty, None);
1844 // Replace any bound regions that appear in the function
1845 // signature with region variables
1846 let (_, fn_sig) = replace_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
1848 .next_region_var(infer::BoundRegionInFnCall(call_expr.span, br))
1851 // Call the generic checker.
1852 check_argument_types(fcx, call_expr.span, fn_sig.inputs, f,
1853 args, DontDerefArgs, fn_sig.variadic);
1855 write_call(fcx, call_expr, fn_sig.output);
1858 // Checks a method call.
1859 fn check_method_call(fcx: @FnCtxt,
1861 method_name: ast::Ident,
1862 args: &[@ast::Expr],
1863 tps: &[ast::P<ast::Ty>]) {
1865 check_expr(fcx, rcvr);
1867 // no need to check for bot/err -- callee does that
1868 let expr_t = structurally_resolved_type(fcx,
1872 let tps = tps.map(|&ast_ty| fcx.to_ty(ast_ty));
1873 let fn_ty = match method::lookup(fcx, expr, rcvr,
1877 CheckTraitsAndInherentMethods,
1878 AutoderefReceiver) {
1880 let method_ty = method.ty;
1881 fcx.inh.method_map.borrow_mut().get().insert(expr.id, method);
1885 debug!("(checking method call) failing expr is {}", expr.id);
1887 fcx.type_error_message(expr.span,
1889 format!("type `{}` does not implement any method in scope \
1891 actual, token::get_ident(method_name))
1896 // Add error type for the result
1897 fcx.write_error(expr.id);
1902 // Call the generic checker.
1903 let ret_ty = check_method_argument_types(fcx, expr.span,
1907 write_call(fcx, expr, ret_ty);
1910 // A generic function for checking the then and else in an if
1912 fn check_then_else(fcx: @FnCtxt,
1913 cond_expr: &ast::Expr,
1914 then_blk: &ast::Block,
1915 opt_else_expr: Option<@ast::Expr>,
1918 expected: Option<ty::t>) {
1919 check_expr_has_type(fcx, cond_expr, ty::mk_bool());
1921 let branches_ty = match opt_else_expr {
1922 Some(else_expr) => {
1923 check_block_with_expected(fcx, then_blk, expected);
1924 let then_ty = fcx.node_ty(then_blk.id);
1925 check_expr_with_opt_hint(fcx, else_expr, expected);
1926 let else_ty = fcx.expr_ty(else_expr);
1927 infer::common_supertype(fcx.infcx(),
1928 infer::IfExpression(sp),
1934 check_block_no_value(fcx, then_blk);
1939 let cond_ty = fcx.expr_ty(cond_expr);
1940 let if_ty = if ty::type_is_error(cond_ty) {
1942 } else if ty::type_is_bot(cond_ty) {
1948 fcx.write_ty(id, if_ty);
1951 fn lookup_op_method(fcx: @FnCtxt,
1955 trait_did: Option<ast::DefId>,
1956 args: &[@ast::Expr],
1957 autoderef_receiver: AutoderefReceiverFlag,
1958 unbound_method: ||) -> ty::t {
1959 let method = match trait_did {
1960 Some(trait_did) => {
1961 method::lookup_in_trait(fcx, op_ex, args[0], opname, trait_did,
1962 self_t, [], autoderef_receiver)
1968 let method_ty = method.ty;
1969 fcx.inh.method_map.borrow_mut().get().insert(op_ex.id, method);
1970 check_method_argument_types(fcx, op_ex.span,
1976 // Check the args anyway
1977 // so we get all the error messages
1978 let expected_ty = ty::mk_err();
1979 check_method_argument_types(fcx, op_ex.span,
1987 // could be either an expr_binop or an expr_assign_binop
1988 fn check_binop(fcx: @FnCtxt,
1993 is_binop_assignment: IsBinopAssignment) {
1994 let tcx = fcx.ccx.tcx;
1996 check_expr(fcx, lhs);
1997 // Callee does bot / err checking
1998 let lhs_t = structurally_resolved_type(fcx, lhs.span,
2001 if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) {
2002 // Shift is a special case: rhs can be any integral type
2003 check_expr(fcx, rhs);
2004 let rhs_t = fcx.expr_ty(rhs);
2005 require_integral(fcx, rhs.span, rhs_t);
2006 fcx.write_ty(expr.id, lhs_t);
2010 if ty::is_binopable(tcx, lhs_t, op) {
2011 let tvar = fcx.infcx().next_ty_var();
2012 demand::suptype(fcx, expr.span, tvar, lhs_t);
2013 check_expr_has_type(fcx, rhs, tvar);
2015 let result_t = match op {
2016 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGe |
2017 ast::BiGt => ty::mk_bool(),
2021 fcx.write_ty(expr.id, result_t);
2025 if op == ast::BiOr || op == ast::BiAnd {
2026 // This is an error; one of the operands must have the wrong
2028 fcx.write_error(expr.id);
2029 fcx.write_error(rhs.id);
2030 fcx.type_error_message(expr.span, |actual| {
2031 format!("binary operation `{}` cannot be applied \
2033 ast_util::binop_to_str(op), actual)},
2038 // Check for overloaded operators if not an assignment.
2039 let result_t = if is_binop_assignment == SimpleBinop {
2040 check_user_binop(fcx, expr, lhs, lhs_t, op, rhs)
2042 fcx.type_error_message(expr.span,
2044 format!("binary assignment operation \
2045 `{}=` cannot be applied to type `{}`",
2046 ast_util::binop_to_str(op),
2051 check_expr(fcx, rhs);
2055 fcx.write_ty(expr.id, result_t);
2056 if ty::type_is_error(result_t) {
2057 fcx.write_ty(rhs.id, result_t);
2061 fn check_user_binop(fcx: @FnCtxt,
2063 lhs_expr: @ast::Expr,
2064 lhs_resolved_t: ty::t,
2066 rhs: @ast::Expr) -> ty::t {
2067 let tcx = fcx.ccx.tcx;
2068 let lang = tcx.lang_items;
2069 let (name, trait_did) = match op {
2070 ast::BiAdd => ("add", lang.add_trait()),
2071 ast::BiSub => ("sub", lang.sub_trait()),
2072 ast::BiMul => ("mul", lang.mul_trait()),
2073 ast::BiDiv => ("div", lang.div_trait()),
2074 ast::BiRem => ("rem", lang.rem_trait()),
2075 ast::BiBitXor => ("bitxor", lang.bitxor_trait()),
2076 ast::BiBitAnd => ("bitand", lang.bitand_trait()),
2077 ast::BiBitOr => ("bitor", lang.bitor_trait()),
2078 ast::BiShl => ("shl", lang.shl_trait()),
2079 ast::BiShr => ("shr", lang.shr_trait()),
2080 ast::BiLt => ("lt", lang.ord_trait()),
2081 ast::BiLe => ("le", lang.ord_trait()),
2082 ast::BiGe => ("ge", lang.ord_trait()),
2083 ast::BiGt => ("gt", lang.ord_trait()),
2084 ast::BiEq => ("eq", lang.eq_trait()),
2085 ast::BiNe => ("ne", lang.eq_trait()),
2086 ast::BiAnd | ast::BiOr => {
2087 check_expr(fcx, rhs);
2088 return ty::mk_err();
2091 lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
2092 trait_did, [lhs_expr, rhs], DontAutoderefReceiver, || {
2093 fcx.type_error_message(ex.span, |actual| {
2094 format!("binary operation `{}` cannot be applied to type `{}`",
2095 ast_util::binop_to_str(op), actual)
2096 }, lhs_resolved_t, None)
2100 fn check_user_unop(fcx: @FnCtxt,
2103 trait_did: Option<ast::DefId>,
2105 rhs_expr: @ast::Expr,
2106 rhs_t: ty::t) -> ty::t {
2107 lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
2108 trait_did, [rhs_expr], DontAutoderefReceiver, || {
2109 fcx.type_error_message(ex.span, |actual| {
2110 format!("cannot apply unary operator `{}` to type `{}`", op_str, actual)
2115 // Resolves `expected` by a single level if it is a variable and passes it
2116 // through the `unpack` function. It there is no expected type or
2117 // resolution is not possible (e.g., no constraints yet present), just
2119 fn unpack_expected<O>(
2121 expected: Option<ty::t>,
2122 unpack: |&ty::sty| -> Option<O>)
2126 match resolve_type(fcx.infcx(), t, force_tvar) {
2127 Ok(t) => unpack(&ty::get(t).sty),
2135 fn check_expr_fn(fcx: @FnCtxt,
2137 ast_sigil_opt: Option<ast::Sigil>,
2139 body: ast::P<ast::Block>,
2141 expected: Option<ty::t>) {
2142 let tcx = fcx.ccx.tcx;
2144 // Find the expected input/output types (if any). Substitute
2145 // fresh bound regions for any bound regions we find in the
2146 // expected types so as to avoid capture.
2148 // Also try to pick up inferred purity and sigil, defaulting
2149 // to impure and block. Note that we only will use those for
2150 // block syntax lambdas; that is, lambdas without explicit
2152 let expected_sty = unpack_expected(fcx,
2154 |x| Some((*x).clone()));
2155 let error_happened = false;
2160 expected_bounds) = {
2161 match expected_sty {
2162 Some(ty::ty_closure(ref cenv)) => {
2164 replace_bound_regions_in_fn_sig(
2166 |_| fcx.inh.infcx.fresh_bound_region(expr.id));
2167 (Some(sig), cenv.purity, cenv.sigil,
2168 cenv.onceness, cenv.bounds)
2171 // Not an error! Means we're inferring the closure type
2172 let mut sigil = ast::BorrowedSigil;
2173 let mut onceness = ast::Many;
2174 let mut bounds = ty::EmptyBuiltinBounds();
2176 ast::ExprProc(..) => {
2177 sigil = ast::OwnedSigil;
2178 onceness = ast::Once;
2179 bounds.add(ty::BoundSend);
2183 (None, ast::ImpureFn, sigil,
2189 // If the proto is specified, use that, otherwise select a
2190 // proto based on inference.
2191 let (sigil, purity) = match ast_sigil_opt {
2192 Some(p) => (p, ast::ImpureFn),
2193 None => (expected_sigil, expected_purity)
2196 // construct the function type
2197 let fn_ty = astconv::ty_of_closure(fcx,
2210 let fty = if error_happened {
2212 binder_id: ast::CRATE_NODE_ID,
2213 inputs: fn_ty.sig.inputs.map(|_| ty::mk_err()),
2214 output: ty::mk_err(),
2219 let fn_ty_copy = fn_ty.clone();
2220 fty_sig = fn_ty.sig.clone();
2221 ty::mk_closure(tcx, fn_ty_copy)
2224 debug!("check_expr_fn_with_unifier fty={}",
2225 fcx.infcx().ty_to_str(fty));
2227 fcx.write_ty(expr.id, fty);
2229 let (inherited_purity, id) =
2230 ty::determine_inherited_purity((fcx.ps.get().purity,
2235 check_fn(fcx.ccx, inherited_purity, &fty_sig,
2236 decl, id, body, fn_kind, fcx.inh);
2240 // Check field access expressions
2241 fn check_field(fcx: @FnCtxt,
2245 tys: &[ast::P<ast::Ty>]) {
2246 let tcx = fcx.ccx.tcx;
2247 let bot = check_expr(fcx, base);
2248 let expr_t = structurally_resolved_type(fcx, expr.span,
2250 let (base_t, derefs) = do_autoderef(fcx, expr.span, expr_t);
2252 match *structure_of(fcx, expr.span, base_t) {
2253 ty::ty_struct(base_id, ref substs) => {
2254 // This is just for fields -- the same code handles
2255 // methods in both classes and traits
2257 // (1) verify that the class id actually has a field called
2259 debug!("class named {}", ppaux::ty_to_str(tcx, base_t));
2260 let cls_items = ty::lookup_struct_fields(tcx, base_id);
2261 match lookup_field_ty(tcx, base_id, cls_items,
2262 field, &(*substs)) {
2264 // (2) look up what field's type is, and return it
2265 fcx.write_ty(expr.id, field_ty);
2266 fcx.write_autoderef_adjustment(base.id, derefs);
2275 let tps : ~[ty::t] = tys.iter().map(|&ty| fcx.to_ty(ty)).collect();
2276 match method::lookup(fcx,
2283 CheckTraitsAndInherentMethods,
2284 AutoderefReceiver) {
2286 fcx.type_error_message(
2289 format!("attempted to take value of method `{}` on type `{}` \
2290 (try writing an anonymous function)",
2291 token::get_name(field), actual)
2297 fcx.type_error_message(
2300 format!("attempted access of field `{}` on type `{}`, \
2301 but no field with that name was found",
2302 token::get_name(field), actual)
2308 fcx.write_error(expr.id);
2311 fn check_struct_or_variant_fields(fcx: @FnCtxt,
2314 class_id: ast::DefId,
2315 node_id: ast::NodeId,
2316 substitutions: ty::substs,
2317 field_types: &[ty::field_ty],
2318 ast_fields: &[ast::Field],
2319 check_completeness: bool) {
2320 let tcx = fcx.ccx.tcx;
2322 let mut class_field_map = HashMap::new();
2323 let mut fields_found = 0;
2324 for field in field_types.iter() {
2325 class_field_map.insert(field.name, (field.id, false));
2328 let mut error_happened = false;
2330 // Typecheck each field.
2331 for field in ast_fields.iter() {
2332 let mut expected_field_type = ty::mk_err();
2334 let pair = class_field_map.find(&field.ident.node.name).map(|x| *x);
2337 fcx.type_error_message(
2340 format!("structure `{}` has no field named `{}`",
2341 actual, token::get_ident(field.ident.node))
2342 }, struct_ty, None);
2343 error_happened = true;
2345 Some((_, true)) => {
2348 format!("field `{}` specified more than once",
2349 token::get_ident(field.ident.node)));
2350 error_happened = true;
2352 Some((field_id, false)) => {
2353 expected_field_type =
2354 ty::lookup_field_type(
2355 tcx, class_id, field_id, &substitutions);
2356 class_field_map.insert(
2357 field.ident.node.name, (field_id, true));
2361 // Make sure to give a type to the field even if there's
2362 // an error, so we can continue typechecking
2363 check_expr_coercable_to_type(
2366 expected_field_type);
2370 fcx.write_error(node_id);
2373 if check_completeness && !error_happened {
2374 // Make sure the programmer specified all the fields.
2375 assert!(fields_found <= field_types.len());
2376 if fields_found < field_types.len() {
2377 let mut missing_fields = ~[];
2378 for class_field in field_types.iter() {
2379 let name = class_field.name;
2380 let (_, seen) = *class_field_map.get(&name);
2382 missing_fields.push(~"`" + token::get_name(name).get() + "`");
2386 tcx.sess.span_err(span,
2387 format!("missing field{}: {}",
2388 if missing_fields.len() == 1 {
2393 missing_fields.connect(", ")));
2397 if !error_happened {
2398 fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx,
2399 class_id, substitutions));
2403 fn check_struct_constructor(fcx: @FnCtxt,
2405 span: codemap::Span,
2406 class_id: ast::DefId,
2407 fields: &[ast::Field],
2408 base_expr: Option<@ast::Expr>) {
2409 let tcx = fcx.ccx.tcx;
2411 // Look up the number of type parameters and the raw type, and
2412 // determine whether the class is region-parameterized.
2413 let item_type = ty::lookup_item_type(tcx, class_id);
2414 let type_parameter_count = item_type.generics.type_param_defs().len();
2415 let region_parameter_count = item_type.generics.region_param_defs().len();
2416 let raw_type = item_type.ty;
2418 // Generate the struct type.
2419 let regions = fcx.infcx().next_region_vars(
2420 infer::BoundRegionInTypeOrImpl(span),
2421 region_parameter_count).move_iter().collect();
2422 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2423 let substitutions = substs {
2424 regions: ty::NonerasedRegions(opt_vec::from(regions)),
2426 tps: type_parameters
2429 let mut struct_type = ty::subst(tcx, &substitutions, raw_type);
2431 // Look up and check the fields.
2432 let class_fields = ty::lookup_struct_fields(tcx, class_id);
2433 check_struct_or_variant_fields(fcx,
2441 base_expr.is_none());
2442 if ty::type_is_error(fcx.node_ty(id)) {
2443 struct_type = ty::mk_err();
2446 // Check the base expression if necessary.
2449 Some(base_expr) => {
2450 check_expr_has_type(fcx, base_expr, struct_type);
2451 if ty::type_is_bot(fcx.node_ty(base_expr.id)) {
2452 struct_type = ty::mk_bot();
2457 // Write in the resulting type.
2458 fcx.write_ty(id, struct_type);
2461 fn check_struct_enum_variant(fcx: @FnCtxt,
2463 span: codemap::Span,
2464 enum_id: ast::DefId,
2465 variant_id: ast::DefId,
2466 fields: &[ast::Field]) {
2467 let tcx = fcx.ccx.tcx;
2469 // Look up the number of type parameters and the raw type, and
2470 // determine whether the enum is region-parameterized.
2471 let item_type = ty::lookup_item_type(tcx, enum_id);
2472 let type_parameter_count = item_type.generics.type_param_defs().len();
2473 let region_parameter_count = item_type.generics.region_param_defs().len();
2474 let raw_type = item_type.ty;
2476 // Generate the enum type.
2477 let regions = fcx.infcx().next_region_vars(
2478 infer::BoundRegionInTypeOrImpl(span),
2479 region_parameter_count).move_iter().collect();
2480 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2481 let substitutions = substs {
2482 regions: ty::NonerasedRegions(opt_vec::from(regions)),
2484 tps: type_parameters
2487 let enum_type = ty::subst(tcx, &substitutions, raw_type);
2489 // Look up and check the enum variant fields.
2490 let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2491 check_struct_or_variant_fields(fcx,
2500 fcx.write_ty(id, enum_type);
2503 let tcx = fcx.ccx.tcx;
2506 ast::ExprVstore(ev, vst) => {
2507 let typ = match ev.node {
2508 ast::ExprLit(lit) if ast_util::lit_is_str(lit) => {
2509 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2512 ast::ExprVec(ref args, mutbl) => {
2513 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2514 let mut any_error = false;
2515 let mut any_bot = false;
2516 let mutability = match vst {
2517 ast::ExprVstoreMutSlice => ast::MutMutable,
2520 let t: ty::t = fcx.infcx().next_ty_var();
2521 for e in args.iter() {
2522 check_expr_has_type(fcx, *e, t);
2523 let arg_t = fcx.expr_ty(*e);
2524 if ty::type_is_error(arg_t) {
2527 else if ty::type_is_bot(arg_t) {
2536 ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2539 ast::ExprRepeat(element, count_expr, mutbl) => {
2540 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2541 let _ = ty::eval_repeat_count(fcx, count_expr);
2542 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2543 let mutability = match vst {
2544 ast::ExprVstoreMutSlice => ast::MutMutable,
2547 let t: ty::t = fcx.infcx().next_ty_var();
2548 check_expr_has_type(fcx, element, t);
2549 let arg_t = fcx.expr_ty(element);
2550 if ty::type_is_error(arg_t) {
2552 } else if ty::type_is_bot(arg_t) {
2555 ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2559 tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence")
2561 fcx.write_ty(ev.id, typ);
2562 fcx.write_ty(id, typ);
2565 ast::ExprBox(place, subexpr) => {
2566 check_expr(fcx, place);
2567 check_expr(fcx, subexpr);
2569 let mut checked = false;
2571 ast::ExprPath(ref path) => {
2572 // FIXME(pcwalton): For now we hardcode the two permissible
2573 // places: the exchange heap and the managed heap.
2574 let definition = lookup_def(fcx, path.span, place.id);
2575 let def_id = ast_util::def_id_of_def(definition);
2576 match tcx.lang_items.items[ExchangeHeapLangItem as uint] {
2577 Some(item_def_id) if def_id == item_def_id => {
2578 fcx.write_ty(id, ty::mk_uniq(tcx,
2579 fcx.expr_ty(subexpr)));
2582 Some(_) | None => {}
2585 match tcx.lang_items
2586 .items[ManagedHeapLangItem as uint] {
2587 Some(item_def_id) if def_id == item_def_id => {
2588 // Assign the magic `Gc<T>` struct.
2590 match tcx.lang_items
2591 .require(GcLangItem) {
2594 tcx.sess.span_err(expr.span, msg);
2596 krate: ast::CRATE_NODE_ID,
2597 node: ast::DUMMY_NODE_ID,
2602 ty::NonerasedRegions(opt_vec::Empty);
2603 let sty = ty::mk_struct(tcx,
2613 fcx.write_ty(id, sty);
2616 Some(_) | None => {}
2624 tcx.sess.span_err(expr.span,
2625 "only the managed heap and exchange heap are \
2626 currently supported")
2630 ast::ExprLit(lit) => {
2631 let typ = check_lit(fcx, lit);
2632 fcx.write_ty(id, typ);
2634 ast::ExprBinary(op, lhs, rhs) => {
2635 check_binop(fcx, expr, op, lhs, rhs, SimpleBinop);
2637 let lhs_ty = fcx.expr_ty(lhs);
2638 let rhs_ty = fcx.expr_ty(rhs);
2639 if ty::type_is_error(lhs_ty) ||
2640 ty::type_is_error(rhs_ty) {
2641 fcx.write_error(id);
2643 else if ty::type_is_bot(lhs_ty) ||
2644 (ty::type_is_bot(rhs_ty) && !ast_util::lazy_binop(op)) {
2648 ast::ExprAssignOp(op, lhs, rhs) => {
2649 check_binop(fcx, expr, op, lhs, rhs, BinopAssignment);
2651 let lhs_t = fcx.expr_ty(lhs);
2652 let result_t = fcx.expr_ty(expr);
2653 demand::suptype(fcx, expr.span, result_t, lhs_t);
2655 let tcx = fcx.tcx();
2656 if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
2657 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2660 // Overwrite result of check_binop...this preserves existing behavior
2661 // but seems quite dubious with regard to user-defined methods
2662 // and so forth. - Niko
2663 if !ty::type_is_error(result_t)
2664 && !ty::type_is_bot(result_t) {
2665 fcx.write_nil(expr.id);
2668 ast::ExprUnary(unop, oprnd) => {
2669 let exp_inner = unpack_expected(fcx, expected, |sty| {
2671 ast::UnBox | ast::UnUniq => match *sty {
2672 ty::ty_box(ty) | ty::ty_uniq(ty) => Some(ty),
2675 ast::UnNot | ast::UnNeg => expected,
2676 ast::UnDeref => None
2679 check_expr_with_opt_hint(fcx, oprnd, exp_inner);
2680 let mut oprnd_t = fcx.expr_ty(oprnd);
2681 if !ty::type_is_error(oprnd_t) &&
2682 !ty::type_is_bot(oprnd_t) {
2685 oprnd_t = ty::mk_box(tcx, oprnd_t)
2688 oprnd_t = ty::mk_uniq(tcx, oprnd_t);
2691 let sty = structure_of(fcx, expr.span, oprnd_t);
2692 let operand_ty = ty::deref_sty(sty, true);
2699 ty::ty_struct(did, ref substs) if {
2700 let fields = ty::struct_fields(fcx.tcx(), did, substs);
2702 && fields[0].ident == token::special_idents::unnamed_field
2704 // This is an obsolete struct deref
2707 "single-field tuple-structs can no longer be dereferenced");
2710 fcx.type_error_message(expr.span,
2712 format!("type `{}` cannot be dereferenced", actual)
2720 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2722 if !(ty::type_is_integral(oprnd_t) ||
2723 ty::get(oprnd_t).sty == ty::ty_bool) {
2724 oprnd_t = check_user_unop(fcx, "!", "not",
2725 tcx.lang_items.not_trait(),
2726 expr, oprnd, oprnd_t);
2730 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2732 if !(ty::type_is_integral(oprnd_t) ||
2733 ty::type_is_fp(oprnd_t)) {
2734 oprnd_t = check_user_unop(fcx, "-", "neg",
2735 tcx.lang_items.neg_trait(),
2736 expr, oprnd, oprnd_t);
2741 fcx.write_ty(id, oprnd_t);
2743 ast::ExprAddrOf(mutbl, oprnd) => {
2744 let hint = unpack_expected(
2746 |sty| match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty),
2748 check_expr_with_opt_hint(fcx, oprnd, hint);
2750 // Note: at this point, we cannot say what the best lifetime
2751 // is to use for resulting pointer. We want to use the
2752 // shortest lifetime possible so as to avoid spurious borrowck
2753 // errors. Moreover, the longest lifetime will depend on the
2754 // precise details of the value whose address is being taken
2755 // (and how long it is valid), which we don't know yet until type
2756 // inference is complete.
2758 // Therefore, here we simply generate a region variable. The
2759 // region inferencer will then select the ultimate value.
2760 // Finally, borrowck is charged with guaranteeing that the
2761 // value whose address was taken can actually be made to live
2762 // as long as it needs to live.
2763 let region = fcx.infcx().next_region_var(
2764 infer::AddrOfRegion(expr.span));
2766 let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
2767 let oprnd_t = if ty::type_is_error(tm.ty) {
2769 } else if ty::type_is_bot(tm.ty) {
2773 ty::mk_rptr(tcx, region, tm)
2775 fcx.write_ty(id, oprnd_t);
2777 ast::ExprPath(ref pth) => {
2778 let defn = lookup_def(fcx, pth.span, id);
2780 check_type_parameter_positions_in_path(fcx, pth, defn);
2781 let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2782 instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
2784 ast::ExprInlineAsm(ref ia) => {
2785 for &(_, input) in ia.inputs.iter() {
2786 check_expr(fcx, input);
2788 for &(_, out) in ia.outputs.iter() {
2789 check_expr(fcx, out);
2793 ast::ExprMac(_) => tcx.sess.bug("unexpanded macro"),
2794 ast::ExprBreak(_) => { fcx.write_bot(id); }
2795 ast::ExprAgain(_) => { fcx.write_bot(id); }
2796 ast::ExprRet(expr_opt) => {
2797 let ret_ty = fcx.ret_ty;
2799 None => match fcx.mk_eqty(false, infer::Misc(expr.span),
2800 ret_ty, ty::mk_nil()) {
2801 result::Ok(_) => { /* fall through */ }
2805 "`return;` in function returning non-nil");
2809 check_expr_has_type(fcx, e, ret_ty);
2814 ast::ExprLogLevel => {
2815 fcx.write_ty(id, ty::mk_u32())
2817 ast::ExprParen(a) => {
2818 check_expr_with_opt_hint(fcx, a, expected);
2819 fcx.write_ty(id, fcx.expr_ty(a));
2821 ast::ExprAssign(lhs, rhs) => {
2822 check_assignment(fcx, lhs, rhs, id);
2824 let tcx = fcx.tcx();
2825 if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
2826 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2829 let lhs_ty = fcx.expr_ty(lhs);
2830 let rhs_ty = fcx.expr_ty(rhs);
2831 if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
2832 fcx.write_error(id);
2834 else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
2841 ast::ExprIf(cond, then_blk, opt_else_expr) => {
2842 check_then_else(fcx, cond, then_blk, opt_else_expr,
2843 id, expr.span, expected);
2845 ast::ExprWhile(cond, body) => {
2846 check_expr_has_type(fcx, cond, ty::mk_bool());
2847 check_block_no_value(fcx, body);
2848 let cond_ty = fcx.expr_ty(cond);
2849 let body_ty = fcx.node_ty(body.id);
2850 if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) {
2851 fcx.write_error(id);
2853 else if ty::type_is_bot(cond_ty) {
2860 ast::ExprForLoop(..) =>
2861 fail!("non-desugared expr_for_loop"),
2862 ast::ExprLoop(body, _) => {
2863 check_block_no_value(fcx, (body));
2864 if !may_break(tcx, expr.id, body) {
2871 ast::ExprMatch(discrim, ref arms) => {
2872 _match::check_match(fcx, expr, discrim, arms.as_slice());
2874 ast::ExprFnBlock(decl, body) => {
2877 Some(ast::BorrowedSigil),
2883 ast::ExprProc(decl, body) => {
2886 Some(ast::OwnedSigil),
2892 ast::ExprBlock(b) => {
2893 check_block_with_expected(fcx, b, expected);
2894 fcx.write_ty(id, fcx.node_ty(b.id));
2896 ast::ExprCall(f, ref args) => {
2897 check_call(fcx, expr, f, args.as_slice());
2898 let f_ty = fcx.expr_ty(f);
2899 let (args_bot, args_err) = args.iter().fold((false, false),
2900 |(rest_bot, rest_err), a| {
2901 // is this not working?
2902 let a_ty = fcx.expr_ty(*a);
2903 (rest_bot || ty::type_is_bot(a_ty),
2904 rest_err || ty::type_is_error(a_ty))});
2905 if ty::type_is_error(f_ty) || args_err {
2906 fcx.write_error(id);
2908 else if ty::type_is_bot(f_ty) || args_bot {
2912 ast::ExprMethodCall(ident, ref tps, ref args) => {
2913 check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice());
2914 let arg_tys = args.map(|a| fcx.expr_ty(*a));
2915 let (args_bot, args_err) = arg_tys.iter().fold((false, false),
2916 |(rest_bot, rest_err), a| {
2917 (rest_bot || ty::type_is_bot(*a),
2918 rest_err || ty::type_is_error(*a))});
2920 fcx.write_error(id);
2921 } else if args_bot {
2925 ast::ExprCast(e, t) => {
2927 let t_1 = fcx.to_ty(t);
2928 let t_e = fcx.expr_ty(e);
2930 debug!("t_1={}", fcx.infcx().ty_to_str(t_1));
2931 debug!("t_e={}", fcx.infcx().ty_to_str(t_e));
2933 if ty::type_is_error(t_e) {
2934 fcx.write_error(id);
2936 else if ty::type_is_bot(t_e) {
2940 match ty::get(t_1).sty {
2941 // This will be looked up later on
2942 ty::ty_trait(..) => (),
2945 if ty::type_is_nil(t_e) {
2946 fcx.type_error_message(expr.span, |actual| {
2947 format!("cast from nil: `{}` as `{}`", actual,
2948 fcx.infcx().ty_to_str(t_1))
2950 } else if ty::type_is_nil(t_1) {
2951 fcx.type_error_message(expr.span, |actual| {
2952 format!("cast to nil: `{}` as `{}`", actual,
2953 fcx.infcx().ty_to_str(t_1))
2957 let t1 = structurally_resolved_type(fcx, e.span, t_1);
2958 let te = structurally_resolved_type(fcx, e.span, t_e);
2959 let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
2960 let t_1_is_char = type_is_char(fcx, expr.span, t_1);
2961 let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1);
2963 // casts to scalars other than `char` and `bare fn` are trivial
2964 let t_1_is_trivial = t_1_is_scalar &&
2965 !t_1_is_char && !t_1_is_bare_fn;
2967 if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial {
2968 // casts from C-like enums are allowed
2969 } else if t_1_is_char {
2970 let te = fcx.infcx().resolve_type_vars_if_possible(te);
2971 if ty::get(te).sty != ty::ty_uint(ast::TyU8) {
2972 fcx.type_error_message(expr.span, |actual| {
2973 format!("only `u8` can be cast as `char`, not `{}`", actual)
2976 } else if ty::get(t1).sty == ty::ty_bool {
2977 fcx.tcx().sess.span_err(expr.span,
2978 "cannot cast as `bool`, compare with zero instead");
2979 } else if type_is_region_ptr(fcx, expr.span, t_e) &&
2980 type_is_unsafe_ptr(fcx, expr.span, t_1) {
2982 fn is_vec(t: ty::t) -> bool {
2983 match ty::get(t).sty {
2984 ty::ty_vec(..) => true,
2988 fn types_compatible(fcx: @FnCtxt, sp: Span,
2989 t1: ty::t, t2: ty::t) -> bool {
2993 let el = ty::sequence_element_type(fcx.tcx(),
2995 infer::mk_eqty(fcx.infcx(), false,
2996 infer::Misc(sp), el, t2).is_ok()
3000 // Due to the limitations of LLVM global constants,
3001 // region pointers end up pointing at copies of
3002 // vector elements instead of the original values.
3003 // To allow unsafe pointers to work correctly, we
3004 // need to special-case obtaining an unsafe pointer
3005 // from a region pointer to a vector.
3007 /* this cast is only allowed from &[T] to *T or
3009 match (&ty::get(te).sty, &ty::get(t_1).sty) {
3010 (&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
3011 if types_compatible(fcx, e.span,
3012 mt1.ty, mt2.ty) => {
3013 /* this case is allowed */
3016 demand::coerce(fcx, e.span, t_1, e);
3019 } else if !(type_is_scalar(fcx,expr.span,t_e)
3020 && t_1_is_trivial) {
3022 If more type combinations should be supported than are
3023 supported here, then file an enhancement issue and
3024 record the issue number in this comment.
3026 fcx.type_error_message(expr.span, |actual| {
3027 format!("non-scalar cast: `{}` as `{}`", actual,
3028 fcx.infcx().ty_to_str(t_1))
3033 fcx.write_ty(id, t_1);
3036 ast::ExprVec(ref args, mutbl) => {
3037 let t: ty::t = fcx.infcx().next_ty_var();
3038 for e in args.iter() {
3039 check_expr_has_type(fcx, *e, t);
3041 let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutbl},
3042 ty::vstore_fixed(args.len()));
3043 fcx.write_ty(id, typ);
3045 ast::ExprRepeat(element, count_expr, mutbl) => {
3046 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
3047 let count = ty::eval_repeat_count(fcx, count_expr);
3048 let t: ty::t = fcx.infcx().next_ty_var();
3049 check_expr_has_type(fcx, element, t);
3050 let element_ty = fcx.expr_ty(element);
3051 if ty::type_is_error(element_ty) {
3052 fcx.write_error(id);
3054 else if ty::type_is_bot(element_ty) {
3058 let t = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutbl},
3059 ty::vstore_fixed(count));
3060 fcx.write_ty(id, t);
3063 ast::ExprTup(ref elts) => {
3064 let flds = unpack_expected(fcx, expected, |sty| {
3066 ty::ty_tup(ref flds) => Some((*flds).clone()),
3070 let mut bot_field = false;
3071 let mut err_field = false;
3073 let elt_ts = elts.iter().enumerate().map(|(i, e)| {
3074 let opt_hint = match flds {
3075 Some(ref fs) if i < fs.len() => Some(fs[i]),
3078 check_expr_with_opt_hint(fcx, *e, opt_hint);
3079 let t = fcx.expr_ty(*e);
3080 err_field = err_field || ty::type_is_error(t);
3081 bot_field = bot_field || ty::type_is_bot(t);
3086 } else if err_field {
3087 fcx.write_error(id);
3089 let typ = ty::mk_tup(tcx, elt_ts);
3090 fcx.write_ty(id, typ);
3093 ast::ExprStruct(ref path, ref fields, base_expr) => {
3094 // Resolve the path.
3095 let def_map = tcx.def_map.borrow();
3096 match def_map.get().find(&id) {
3097 Some(&ast::DefStruct(type_def_id)) => {
3098 check_struct_constructor(fcx, id, expr.span, type_def_id,
3099 fields.as_slice(), base_expr);
3101 Some(&ast::DefVariant(enum_id, variant_id, _)) => {
3102 check_struct_enum_variant(fcx, id, expr.span, enum_id,
3103 variant_id, fields.as_slice());
3106 tcx.sess.span_bug(path.span,
3107 "structure constructor does not name a structure type");
3111 ast::ExprField(base, field, ref tys) => {
3112 check_field(fcx, expr, base, field.name, tys.as_slice());
3114 ast::ExprIndex(base, idx) => {
3115 check_expr(fcx, base);
3116 check_expr(fcx, idx);
3117 let raw_base_t = fcx.expr_ty(base);
3118 let idx_t = fcx.expr_ty(idx);
3119 if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
3120 fcx.write_ty(id, raw_base_t);
3121 } else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
3122 fcx.write_ty(id, idx_t);
3124 let (base_t, derefs) = do_autoderef(fcx, expr.span, raw_base_t);
3125 let base_sty = structure_of(fcx, expr.span, base_t);
3126 match ty::index_sty(base_sty) {
3128 require_integral(fcx, idx.span, idx_t);
3129 fcx.write_ty(id, mt.ty);
3130 fcx.write_autoderef_adjustment(base.id, derefs);
3133 let resolved = structurally_resolved_type(fcx,
3136 let error_message = || {
3137 fcx.type_error_message(expr.span,
3139 format!("cannot index a value \
3146 let ret_ty = lookup_op_method(fcx,
3149 token::intern("index"),
3150 tcx.lang_items.index_trait(),
3154 fcx.write_ty(id, ret_ty);
3161 debug!("type of expr({}) {} is...", expr.id,
3162 syntax::print::pprust::expr_to_str(expr));
3163 debug!("... {}, expected is {}",
3164 ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
3166 Some(t) => ppaux::ty_to_str(tcx, t),
3173 pub fn require_integral(fcx: @FnCtxt, sp: Span, t: ty::t) {
3174 if !type_is_integral(fcx, sp, t) {
3175 fcx.type_error_message(sp, |actual| {
3176 format!("mismatched types: expected integral type but found `{}`",
3182 pub fn check_decl_initializer(fcx: @FnCtxt,
3186 let local_ty = fcx.local_ty(init.span, nid);
3187 check_expr_coercable_to_type(fcx, init, local_ty)
3190 pub fn check_decl_local(fcx: @FnCtxt, local: &ast::Local) {
3191 let tcx = fcx.ccx.tcx;
3193 let t = fcx.local_ty(local.span, local.id);
3194 fcx.write_ty(local.id, t);
3198 check_decl_initializer(fcx, local.id, init);
3199 let init_ty = fcx.expr_ty(init);
3200 if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
3201 fcx.write_ty(local.id, init_ty);
3207 let pcx = pat_ctxt {
3209 map: pat_id_map(tcx.def_map, local.pat),
3211 _match::check_pat(&pcx, local.pat, t);
3212 let pat_ty = fcx.node_ty(local.pat.id);
3213 if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
3214 fcx.write_ty(local.id, pat_ty);
3218 pub fn check_stmt(fcx: @FnCtxt, stmt: &ast::Stmt) {
3220 let mut saw_bot = false;
3221 let mut saw_err = false;
3223 ast::StmtDecl(decl, id) => {
3226 ast::DeclLocal(ref l) => {
3227 check_decl_local(fcx, *l);
3228 let l_t = fcx.node_ty(l.id);
3229 saw_bot = saw_bot || ty::type_is_bot(l_t);
3230 saw_err = saw_err || ty::type_is_error(l_t);
3232 ast::DeclItem(_) => {/* ignore for now */ }
3235 ast::StmtExpr(expr, id) => {
3237 // Check with expected type of ()
3238 check_expr_has_type(fcx, expr, ty::mk_nil());
3239 let expr_ty = fcx.expr_ty(expr);
3240 saw_bot = saw_bot || ty::type_is_bot(expr_ty);
3241 saw_err = saw_err || ty::type_is_error(expr_ty);
3243 ast::StmtSemi(expr, id) => {
3245 check_expr(fcx, expr);
3246 let expr_ty = fcx.expr_ty(expr);
3247 saw_bot |= ty::type_is_bot(expr_ty);
3248 saw_err |= ty::type_is_error(expr_ty);
3250 ast::StmtMac(..) => fcx.ccx.tcx.sess.bug("unexpanded macro")
3253 fcx.write_bot(node_id);
3256 fcx.write_error(node_id);
3259 fcx.write_nil(node_id)
3263 pub fn check_block_no_value(fcx: @FnCtxt, blk: &ast::Block) {
3264 check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
3265 let blkty = fcx.node_ty(blk.id);
3266 if ty::type_is_error(blkty) {
3267 fcx.write_error(blk.id);
3269 else if ty::type_is_bot(blkty) {
3270 fcx.write_bot(blk.id);
3273 let nilty = ty::mk_nil();
3274 demand::suptype(fcx, blk.span, nilty, blkty);
3278 pub fn check_block(fcx0: @FnCtxt, blk: &ast::Block) {
3279 check_block_with_expected(fcx0, blk, None)
3282 pub fn check_block_with_expected(fcx: @FnCtxt,
3284 expected: Option<ty::t>) {
3286 let mut fcx_ps = fcx.ps.borrow_mut();
3287 let purity_state = fcx_ps.get().recurse(blk);
3288 replace(fcx_ps.get(), purity_state)
3291 fcx.with_region_lb(blk.id, || {
3292 let mut warned = false;
3293 let mut last_was_bot = false;
3294 let mut any_bot = false;
3295 let mut any_err = false;
3296 for s in blk.stmts.iter() {
3297 check_stmt(fcx, *s);
3298 let s_id = ast_util::stmt_id(*s);
3299 let s_ty = fcx.node_ty(s_id);
3300 if last_was_bot && !warned && match s.node {
3301 ast::StmtDecl(decl, _) => {
3303 ast::DeclLocal(_) => true,
3307 ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true,
3310 fcx.ccx.tcx.sess.add_lint(UnreachableCode, s_id, s.span,
3311 ~"unreachable statement");
3314 if ty::type_is_bot(s_ty) {
3315 last_was_bot = true;
3317 any_bot = any_bot || ty::type_is_bot(s_ty);
3318 any_err = any_err || ty::type_is_error(s_ty);
3321 None => if any_err {
3322 fcx.write_error(blk.id);
3325 fcx.write_bot(blk.id);
3328 fcx.write_nil(blk.id);
3331 if any_bot && !warned {
3332 fcx.ccx.tcx.sess.add_lint(UnreachableCode, e.id, e.span,
3333 ~"unreachable expression");
3335 check_expr_with_opt_hint(fcx, e, expected);
3336 let ety = fcx.expr_ty(e);
3337 fcx.write_ty(blk.id, ety);
3339 fcx.write_error(blk.id);
3342 fcx.write_bot(blk.id);
3351 pub fn check_const(ccx: @CrateCtxt,
3355 let rty = ty::node_id_to_type(ccx.tcx, id);
3356 let fcx = blank_fn_ctxt(ccx, rty, e.id);
3358 let tcache = fcx.ccx.tcx.tcache.borrow();
3359 tcache.get().get(&local_def(id)).ty
3361 check_const_with_ty(fcx, sp, e, declty);
3364 pub fn check_const_with_ty(fcx: @FnCtxt,
3369 let cty = fcx.expr_ty(e);
3370 demand::suptype(fcx, e.span, declty, cty);
3371 regionck::regionck_expr(fcx, e);
3372 writeback::resolve_type_vars_in_expr(fcx, e);
3375 /// Checks whether a type can be represented in memory. In particular, it
3376 /// identifies types that contain themselves without indirection through a
3377 /// pointer, which would mean their size is unbounded. This is different from
3378 /// the question of whether a type can be instantiated. See the definition of
3379 /// `check_instantiable`.
3380 pub fn check_representable(tcx: ty::ctxt,
3382 item_id: ast::NodeId,
3383 designation: &str) {
3384 let rty = ty::node_id_to_type(tcx, item_id);
3386 // Check that it is possible to represent this type. This call identifies
3387 // (1) types that contain themselves and (2) types that contain a different
3388 // recursive type. It is only necessary to throw an error on those that
3389 // contain themselves. For case 2, there must be an inner type that will be
3390 // caught by case 1.
3391 match ty::is_type_representable(tcx, rty) {
3392 ty::SelfRecursive => {
3394 sp, format!("illegal recursive {} type; \
3395 wrap the inner value in a box to make it representable",
3398 ty::Representable | ty::ContainsRecursive => (),
3402 /// Checks whether a type can be created without an instance of itself.
3403 /// This is similar but different from the question of whether a type
3404 /// can be represented. For example, the following type:
3406 /// enum foo { None, Some(foo) }
3408 /// is instantiable but is not representable. Similarly, the type
3410 /// enum foo { Some(@foo) }
3412 /// is representable, but not instantiable.
3413 pub fn check_instantiable(tcx: ty::ctxt,
3415 item_id: ast::NodeId) {
3416 let item_ty = ty::node_id_to_type(tcx, item_id);
3417 if !ty::is_instantiable(tcx, item_ty) {
3418 tcx.sess.span_err(sp, format!("this type cannot be instantiated \
3419 without an instance of itself; \
3420 consider using `Option<{}>`",
3421 ppaux::ty_to_str(tcx, item_ty)));
3425 pub fn check_simd(tcx: ty::ctxt, sp: Span, id: ast::NodeId) {
3426 let t = ty::node_id_to_type(tcx, id);
3427 if ty::type_needs_subst(t) {
3428 tcx.sess.span_err(sp, "SIMD vector cannot be generic");
3431 match ty::get(t).sty {
3432 ty::ty_struct(did, ref substs) => {
3433 let fields = ty::lookup_struct_fields(tcx, did);
3434 if fields.is_empty() {
3435 tcx.sess.span_err(sp, "SIMD vector cannot be empty");
3438 let e = ty::lookup_field_type(tcx, did, fields[0].id, substs);
3439 if !fields.iter().all(
3440 |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
3441 tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
3444 if !ty::type_is_machine(e) {
3445 tcx.sess.span_err(sp, "SIMD vector element type should be \
3454 pub fn check_enum_variants(ccx: @CrateCtxt,
3456 vs: &[ast::P<ast::Variant>],
3459 fn disr_in_range(ccx: @CrateCtxt,
3461 disr: ty::Disr) -> bool {
3462 fn uint_in_range(ccx: @CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
3464 ast::TyU8 => disr as u8 as Disr == disr,
3465 ast::TyU16 => disr as u16 as Disr == disr,
3466 ast::TyU32 => disr as u32 as Disr == disr,
3467 ast::TyU64 => disr as u64 as Disr == disr,
3468 ast::TyU => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
3471 fn int_in_range(ccx: @CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
3473 ast::TyI8 => disr as i8 as Disr == disr,
3474 ast::TyI16 => disr as i16 as Disr == disr,
3475 ast::TyI32 => disr as i32 as Disr == disr,
3476 ast::TyI64 => disr as i64 as Disr == disr,
3477 ast::TyI => int_in_range(ccx, ccx.tcx.sess.targ_cfg.int_type, disr)
3481 attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
3482 attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
3486 fn do_check(ccx: @CrateCtxt,
3487 vs: &[ast::P<ast::Variant>],
3489 hint: attr::ReprAttr)
3490 -> ~[@ty::VariantInfo] {
3492 let rty = ty::node_id_to_type(ccx.tcx, id);
3493 let mut variants: ~[@ty::VariantInfo] = ~[];
3494 let mut disr_vals: ~[ty::Disr] = ~[];
3495 let mut prev_disr_val: Option<ty::Disr> = None;
3497 for &v in vs.iter() {
3499 // If the discriminant value is specified explicitly in the enum check whether the
3500 // initialization expression is valid, otherwise use the last value plus one.
3501 let mut current_disr_val = match prev_disr_val {
3502 Some(prev_disr_val) => prev_disr_val + 1,
3503 None => ty::INITIAL_DISCRIMINANT_VALUE
3506 match v.node.disr_expr {
3508 debug!("disr expr, checking {}", pprust::expr_to_str(e));
3510 let fcx = blank_fn_ctxt(ccx, rty, e.id);
3511 let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
3512 check_const_with_ty(fcx, e.span, e, declty);
3513 // check_expr (from check_const pass) doesn't guarantee
3514 // that the expression is in an form that eval_const_expr can
3515 // handle, so we may still get an internal compiler error
3517 match const_eval::eval_const_expr_partial(&ccx.tcx, e) {
3518 Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
3519 Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
3521 ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
3524 ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", *err));
3531 // Check for duplicate discriminant values
3532 if disr_vals.contains(¤t_disr_val) {
3533 ccx.tcx.sess.span_err(v.span, "discriminant value already exists");
3535 // Check for unrepresentable discriminant values
3537 attr::ReprAny | attr::ReprExtern => (),
3538 attr::ReprInt(sp, ity) => {
3539 if !disr_in_range(ccx, ity, current_disr_val) {
3540 ccx.tcx.sess.span_err(v.span,
3541 "discriminant value outside specified type");
3542 ccx.tcx.sess.span_note(sp, "discriminant type specified here");
3546 disr_vals.push(current_disr_val);
3548 let variant_info = @VariantInfo::from_ast_variant(ccx.tcx, v, current_disr_val);
3549 prev_disr_val = Some(current_disr_val);
3551 variants.push(variant_info);
3557 let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id });
3558 if hint != attr::ReprAny && vs.len() <= 1 {
3559 ccx.tcx.sess.span_err(sp, format!("unsupported representation for {}variant enum",
3560 if vs.len() == 1 { "uni" } else { "zero-" }))
3563 let variants = do_check(ccx, vs, id, hint);
3565 // cache so that ty::enum_variants won't repeat this work
3567 let mut enum_var_cache = ccx.tcx.enum_var_cache.borrow_mut();
3568 enum_var_cache.get().insert(local_def(id), @variants);
3571 // Check that it is possible to represent this enum.
3572 check_representable(ccx.tcx, sp, id, "enum");
3574 // Check that it is possible to instantiate this enum:
3576 // This *sounds* like the same that as representable, but it's
3577 // not. See def'n of `check_instantiable()` for details.
3578 check_instantiable(ccx.tcx, sp, id);
3581 pub fn lookup_def(fcx: @FnCtxt, sp: Span, id: ast::NodeId) -> ast::Def {
3582 lookup_def_ccx(fcx.ccx, sp, id)
3585 // Returns the type parameter count and the type for the given definition.
3586 pub fn ty_param_bounds_and_ty_for_def(fcx: @FnCtxt,
3589 -> ty_param_bounds_and_ty {
3591 ast::DefArg(nid, _) | ast::DefLocal(nid, _) |
3592 ast::DefBinding(nid, _) => {
3593 let typ = fcx.local_ty(sp, nid);
3594 return no_params(typ);
3596 ast::DefFn(id, _) | ast::DefStaticMethod(id, _, _) |
3597 ast::DefStatic(id, _) | ast::DefVariant(_, id, _) |
3598 ast::DefStruct(id) => {
3599 return ty::lookup_item_type(fcx.ccx.tcx, id);
3601 ast::DefUpvar(_, inner, _, _) => {
3602 return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
3607 ast::DefTyParam(..)=> {
3608 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type");
3610 ast::DefMod(..) | ast::DefForeignMod(..) => {
3611 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module");
3613 ast::DefUse(..) => {
3614 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use");
3616 ast::DefRegion(..) => {
3617 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region");
3619 ast::DefTyParamBinder(..) => {
3620 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter");
3622 ast::DefLabel(..) => {
3623 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label");
3625 ast::DefSelfTy(..) => {
3626 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty");
3628 ast::DefMethod(..) => {
3629 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method");
3634 // Instantiates the given path, which must refer to an item with the given
3635 // number of type parameters and type.
3636 pub fn instantiate_path(fcx: @FnCtxt,
3638 tpt: ty_param_bounds_and_ty,
3641 node_id: ast::NodeId) {
3642 debug!(">>> instantiate_path");
3644 let ty_param_count = tpt.generics.type_param_defs().len();
3645 let ty_param_req = tpt.generics.type_param_defs().iter()
3646 .take_while(|x| x.default.is_none())
3648 let mut ty_substs_len = 0;
3649 for segment in pth.segments.iter() {
3650 ty_substs_len += segment.types.len()
3653 debug!("tpt={} ty_param_count={:?} ty_substs_len={:?}",
3654 tpt.repr(fcx.tcx()),
3658 // determine the region parameters, using the value given by the user
3659 // (if any) and otherwise using a fresh region variable
3660 let num_expected_regions = tpt.generics.region_param_defs().len();
3661 let num_supplied_regions = pth.segments.last().unwrap().lifetimes.len();
3662 let regions = if num_expected_regions == num_supplied_regions {
3663 pth.segments.last().unwrap().lifetimes.map(
3664 |l| ast_region_to_region(fcx.tcx(), l))
3666 if num_supplied_regions != 0 {
3667 fcx.ccx.tcx.sess.span_err(
3669 format!("expected {} lifetime parameter(s), \
3670 found {} lifetime parameter(s)",
3671 num_expected_regions, num_supplied_regions));
3674 opt_vec::from(fcx.infcx().next_region_vars(
3675 infer::BoundRegionInTypeOrImpl(span),
3676 num_expected_regions).move_iter().collect())
3678 let regions = ty::NonerasedRegions(regions);
3680 // Special case: If there is a self parameter, omit it from the list of
3683 // Here we calculate the "user type parameter count", which is the number
3684 // of type parameters actually manifest in the AST. This will differ from
3685 // the internal type parameter count when there are self types involved.
3686 let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def {
3687 ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
3688 let generics = generics_of_static_method_container(fcx.ccx.tcx,
3690 (ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs().len()))
3692 _ => (ty_param_count, ty_param_req, None),
3695 // determine values for type parameters, using the values given by
3696 // the user (if any) and otherwise using fresh type variables
3697 let (tps, regions) = if ty_substs_len == 0 {
3698 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3699 } else if ty_param_count == 0 {
3700 fcx.ccx.tcx.sess.span_err
3701 (span, "this item does not take type parameters");
3702 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3703 } else if ty_substs_len > user_ty_param_count {
3704 let expected = if user_ty_param_req < user_ty_param_count {
3709 fcx.ccx.tcx.sess.span_err
3711 format!("too many type parameters provided: {} {}, found {}",
3712 expected, user_ty_param_count, ty_substs_len));
3713 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3714 } else if ty_substs_len < user_ty_param_req {
3715 let expected = if user_ty_param_req < user_ty_param_count {
3720 fcx.ccx.tcx.sess.span_err
3722 format!("not enough type parameters provided: {} {}, found {}",
3723 expected, user_ty_param_req, ty_substs_len));
3724 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3726 if ty_substs_len > user_ty_param_req
3727 && !fcx.tcx().sess.features.default_type_params.get() {
3728 fcx.tcx().sess.span_err(pth.span, "default type parameters are \
3729 experimental and possibly buggy");
3730 fcx.tcx().sess.span_note(pth.span, "add #[feature(default_type_params)] \
3731 to the crate attributes to enable");
3734 // Build up the list of type parameters, inserting the self parameter
3735 // at the appropriate position.
3737 let mut pushed = false;
3738 for (i, ty) in pth.segments.iter()
3739 .flat_map(|segment| segment.types.iter())
3740 .map(|&ast_type| fcx.to_ty(ast_type))
3742 match self_parameter_index {
3743 Some(index) if index == i => {
3744 tps.push(fcx.infcx().next_ty_vars(1)[0]);
3752 let mut substs = substs {
3758 let defaults = tpt.generics.type_param_defs().iter()
3759 .enumerate().filter_map(|(i, x)| {
3760 match self_parameter_index {
3761 Some(index) if index == i => None,
3762 _ => Some(x.default)
3765 for (i, default) in defaults.skip(ty_substs_len).enumerate() {
3766 match self_parameter_index {
3767 Some(index) if index == i + ty_substs_len => {
3768 substs.tps.push(fcx.infcx().next_ty_vars(1)[0]);
3775 let ty = default.subst_spanned(fcx.tcx(), &substs, Some(span));
3776 substs.tps.push(ty);
3779 fcx.tcx().sess.span_bug(span,
3780 "missing default for a not explicitely provided type param")
3785 // If the self parameter goes at the end, insert it there.
3786 if !pushed && self_parameter_index.is_some() {
3787 substs.tps.push(fcx.infcx().next_ty_vars(1)[0])
3790 assert_eq!(substs.tps.len(), ty_param_count)
3792 let substs {tps, regions, ..} = substs;
3796 fcx.write_ty_substs(node_id, tpt.ty, substs {
3805 // Resolves `typ` by a single level if `typ` is a type variable. If no
3806 // resolution is possible, then an error is reported.
3807 pub fn structurally_resolved_type(fcx: &FnCtxt, sp: Span, tp: ty::t) -> ty::t {
3808 match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
3809 Ok(t_s) if !ty::type_is_ty_var(t_s) => t_s,
3811 fcx.type_error_message(sp, |_actual| {
3812 ~"the type of this value must be known in this context"
3814 demand::suptype(fcx, sp, ty::mk_err(), tp);
3820 // Returns the one-level-deep structure of the given type.
3821 pub fn structure_of<'a>(fcx: @FnCtxt, sp: Span, typ: ty::t)
3823 &ty::get(structurally_resolved_type(fcx, sp, typ)).sty
3826 pub fn type_is_integral(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3827 let typ_s = structurally_resolved_type(fcx, sp, typ);
3828 return ty::type_is_integral(typ_s);
3831 pub fn type_is_scalar(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3832 let typ_s = structurally_resolved_type(fcx, sp, typ);
3833 return ty::type_is_scalar(typ_s);
3836 pub fn type_is_char(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3837 let typ_s = structurally_resolved_type(fcx, sp, typ);
3838 return ty::type_is_char(typ_s);
3841 pub fn type_is_bare_fn(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3842 let typ_s = structurally_resolved_type(fcx, sp, typ);
3843 return ty::type_is_bare_fn(typ_s);
3846 pub fn type_is_unsafe_ptr(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3847 let typ_s = structurally_resolved_type(fcx, sp, typ);
3848 return ty::type_is_unsafe_ptr(typ_s);
3851 pub fn type_is_region_ptr(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3852 let typ_s = structurally_resolved_type(fcx, sp, typ);
3853 return ty::type_is_region_ptr(typ_s);
3856 pub fn type_is_c_like_enum(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3857 let typ_s = structurally_resolved_type(fcx, sp, typ);
3858 return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
3861 pub fn ast_expr_vstore_to_vstore(fcx: @FnCtxt,
3866 ast::ExprVstoreUniq => ty::vstore_uniq,
3867 ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => {
3869 ast::ExprLit(..) => {
3870 // string literals and *empty slices* live in static memory
3871 ty::vstore_slice(ty::ReStatic)
3873 ast::ExprVec(ref elements, _) if elements.len() == 0 => {
3874 // string literals and *empty slices* live in static memory
3875 ty::vstore_slice(ty::ReStatic)
3877 ast::ExprRepeat(..) |
3878 ast::ExprVec(..) => {
3879 // vector literals are temporaries on the stack
3880 match fcx.tcx().region_maps.temporary_scope(e.id) {
3882 let r = ty::ReScope(scope);
3886 // this slice occurs in a static somewhere
3887 ty::vstore_slice(ty::ReStatic)
3892 fcx.ccx.tcx.sess.span_bug(
3893 e.span, format!("vstore with unexpected contents"))
3900 // Returns true if b contains a break that can exit from b
3901 pub fn may_break(cx: ty::ctxt, id: ast::NodeId, b: ast::P<ast::Block>) -> bool {
3902 // First: is there an unlabeled break immediately
3904 (loop_query(b, |e| {
3906 ast::ExprBreak(_) => true,
3910 // Second: is there a labeled break with label
3911 // <id> nested anywhere inside the loop?
3912 (block_query(b, |e| {
3914 ast::ExprBreak(Some(_)) => {
3915 let def_map = cx.def_map.borrow();
3916 match def_map.get().find(&e.id) {
3917 Some(&ast::DefLabel(loop_id)) if id == loop_id => true,
3925 pub fn check_bounds_are_used(ccx: @CrateCtxt,
3927 tps: &OptVec<ast::TyParam>,
3929 debug!("check_bounds_are_used(n_tps={}, ty={})",
3930 tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
3932 // make a vector of booleans initially false, set to true when used
3933 if tps.len() == 0u { return; }
3934 let mut tps_used = vec::from_elem(tps.len(), false);
3936 ty::walk_ty(ty, |t| {
3937 match ty::get(t).sty {
3938 ty::ty_param(param_ty {idx, ..}) => {
3939 debug!("Found use of ty param \\#{}", idx);
3940 tps_used[idx] = true;
3946 for (i, b) in tps_used.iter().enumerate() {
3948 ccx.tcx.sess.span_err(
3949 span, format!("type parameter `{}` is unused",
3950 token::get_ident(tps.get(i).ident)));
3955 pub fn check_intrinsic_type(ccx: @CrateCtxt, it: &ast::ForeignItem) {
3956 fn param(ccx: @CrateCtxt, n: uint) -> ty::t {
3957 ty::mk_param(ccx.tcx, n, local_def(0))
3961 let name = token::get_ident(it.ident);
3962 let (n_tps, inputs, output) = if name.get().starts_with("atomic_") {
3963 let split : ~[&str] = name.get().split('_').collect();
3964 assert!(split.len() >= 2, "Atomic intrinsic not correct format");
3966 //We only care about the operation here
3968 "cxchg" => (1, ~[ty::mk_mut_rptr(tcx,
3969 ty::ReLateBound(it.id, ty::BrAnon(0)),
3976 ty::mk_imm_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)),
3982 ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)),
3988 "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
3989 "min" | "umax" | "umin" => {
3990 (1, ~[ty::mk_mut_rptr(tcx,
3991 ty::ReLateBound(it.id, ty::BrAnon(0)),
3992 param(ccx, 0)), param(ccx, 0) ],
3996 (0, ~[], ty::mk_nil())
3999 tcx.sess.span_err(it.span,
4000 format!("unrecognized atomic operation function: `{}`",
4008 "abort" => (0, ~[], ty::mk_bot()),
4009 "breakpoint" => (0, ~[], ty::mk_nil()),
4011 "pref_align_of" | "min_align_of" => (1u, ~[], ty::mk_uint()),
4012 "init" => (1u, ~[], param(ccx, 0u)),
4013 "uninit" => (1u, ~[], param(ccx, 0u)),
4014 "forget" => (1u, ~[ param(ccx, 0) ], ty::mk_nil()),
4015 "transmute" => (2, ~[ param(ccx, 0) ], param(ccx, 1)),
4016 "move_val_init" => {
4019 ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), param(ccx, 0)),
4024 "needs_drop" => (1u, ~[], ty::mk_bool()),
4025 "owns_managed" => (1u, ~[], ty::mk_bool()),
4028 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4030 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4032 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4034 mutbl: ast::MutImmutable
4039 let langid = ccx.tcx.lang_items.require(TypeIdLangItem);
4041 Ok(did) => (1u, ~[], ty::mk_struct(ccx.tcx, did, substs {
4044 regions: ty::NonerasedRegions(opt_vec::Empty)
4046 Err(msg) => { tcx.sess.span_fatal(it.span, msg); }
4050 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4052 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4054 let region = ty::ReLateBound(it.id, ty::BrAnon(0));
4055 let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
4056 Ok((_, vot)) => vot,
4057 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4060 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4062 mutbl: ast::MutImmutable
4064 (0, ~[ td_ptr, visitor_object_ty ], ty::mk_nil())
4069 ty::mk_ptr(tcx, ty::mt {
4071 mutbl: ast::MutImmutable
4075 ty::mk_ptr(tcx, ty::mt {
4077 mutbl: ast::MutImmutable
4080 "copy_nonoverlapping_memory" => {
4083 ty::mk_ptr(tcx, ty::mt {
4085 mutbl: ast::MutMutable
4087 ty::mk_ptr(tcx, ty::mt {
4089 mutbl: ast::MutImmutable
4098 ty::mk_ptr(tcx, ty::mt {
4100 mutbl: ast::MutMutable
4102 ty::mk_ptr(tcx, ty::mt {
4104 mutbl: ast::MutImmutable
4113 ty::mk_ptr(tcx, ty::mt {
4115 mutbl: ast::MutMutable
4122 "sqrtf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4123 "sqrtf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4126 ~[ ty::mk_f32(), ty::mk_i32() ],
4131 ~[ ty::mk_f64(), ty::mk_i32() ],
4134 "sinf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4135 "sinf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4136 "cosf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4137 "cosf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4140 ~[ ty::mk_f32(), ty::mk_f32() ],
4145 ~[ ty::mk_f64(), ty::mk_f64() ],
4148 "expf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4149 "expf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4150 "exp2f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4151 "exp2f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4152 "logf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4153 "logf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4154 "log10f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4155 "log10f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4156 "log2f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4157 "log2f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4160 ~[ ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ],
4165 ~[ ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ],
4168 "fabsf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4169 "fabsf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4170 "copysignf32" => (0, ~[ ty::mk_f32(), ty::mk_f32() ], ty::mk_f32()),
4171 "copysignf64" => (0, ~[ ty::mk_f64(), ty::mk_f64() ], ty::mk_f64()),
4172 "floorf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4173 "floorf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4174 "ceilf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4175 "ceilf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4176 "truncf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4177 "truncf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4178 "rintf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4179 "rintf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4180 "nearbyintf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4181 "nearbyintf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4182 "roundf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4183 "roundf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4184 "ctpop8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()),
4185 "ctpop16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
4186 "ctpop32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
4187 "ctpop64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
4188 "ctlz8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()),
4189 "ctlz16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
4190 "ctlz32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
4191 "ctlz64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
4192 "cttz8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()),
4193 "cttz16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
4194 "cttz32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
4195 "cttz64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
4196 "bswap16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
4197 "bswap32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
4198 "bswap64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
4201 (1, ~[ ty::mk_imm_ptr(tcx, param(ccx, 0)) ], param(ccx, 0)),
4203 (1, ~[ ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ], ty::mk_nil()),
4205 "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
4206 (0, ~[ty::mk_i8(), ty::mk_i8()],
4207 ty::mk_tup(tcx, ~[ty::mk_i8(), ty::mk_bool()])),
4209 "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
4210 (0, ~[ty::mk_i16(), ty::mk_i16()],
4211 ty::mk_tup(tcx, ~[ty::mk_i16(), ty::mk_bool()])),
4213 "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
4214 (0, ~[ty::mk_i32(), ty::mk_i32()],
4215 ty::mk_tup(tcx, ~[ty::mk_i32(), ty::mk_bool()])),
4217 "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
4218 (0, ~[ty::mk_i64(), ty::mk_i64()],
4219 ty::mk_tup(tcx, ~[ty::mk_i64(), ty::mk_bool()])),
4221 "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
4222 (0, ~[ty::mk_u8(), ty::mk_u8()],
4223 ty::mk_tup(tcx, ~[ty::mk_u8(), ty::mk_bool()])),
4225 "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
4226 (0, ~[ty::mk_u16(), ty::mk_u16()],
4227 ty::mk_tup(tcx, ~[ty::mk_u16(), ty::mk_bool()])),
4229 "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
4230 (0, ~[ty::mk_u32(), ty::mk_u32()],
4231 ty::mk_tup(tcx, ~[ty::mk_u32(), ty::mk_bool()])),
4233 "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" =>
4234 (0, ~[ty::mk_u64(), ty::mk_u64()],
4235 ty::mk_tup(tcx, ~[ty::mk_u64(), ty::mk_bool()])),
4238 tcx.sess.span_err(it.span,
4239 format!("unrecognized intrinsic function: `{}`",
4245 let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
4246 purity: ast::UnsafeFn,
4247 abis: AbiSet::Intrinsic(),
4248 sig: FnSig {binder_id: it.id,
4253 let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
4254 let i_n_tps = i_ty.generics.type_param_defs().len();
4255 if i_n_tps != n_tps {
4256 tcx.sess.span_err(it.span, format!("intrinsic has wrong number \
4257 of type parameters: found {}, \
4258 expected {}", i_n_tps, n_tps));
4261 tcx, None, false, it.span, i_ty.ty, fty,
4262 || format!("intrinsic has wrong type: \
4264 ppaux::ty_to_str(ccx.tcx, fty)));