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[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,
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 {regions: ty::NonerasedRegions(opt_vec::from(rps)),
1403 let substd_ty = ty::subst(tcx, &substs, raw_ty);
1405 ty_param_substs_and_ty { substs: substs, ty: substd_ty }
1408 // Only for fields! Returns <none> for methods>
1409 // Indifferent to privacy flags
1410 pub fn lookup_field_ty(tcx: ty::ctxt,
1411 class_id: ast::DefId,
1412 items: &[ty::field_ty],
1413 fieldname: ast::Name,
1414 substs: &ty::substs) -> Option<ty::t> {
1416 let o_field = items.iter().find(|f| f.name == fieldname);
1417 o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
1420 // Controls whether the arguments are automatically referenced. This is useful
1421 // for overloaded binary and unary operators.
1422 pub enum DerefArgs {
1427 // Given the provenance of a static method, returns the generics of the static
1428 // method's container.
1429 fn generics_of_static_method_container(type_context: ty::ctxt,
1430 provenance: ast::MethodProvenance)
1433 ast::FromTrait(trait_def_id) => {
1434 ty::lookup_trait_def(type_context, trait_def_id).generics.clone()
1436 ast::FromImpl(impl_def_id) => {
1437 ty::lookup_item_type(type_context, impl_def_id).generics.clone()
1442 // Verifies that type parameters supplied in paths are in the right
1444 fn check_type_parameter_positions_in_path(function_context: @FnCtxt,
1447 // We only care about checking the case in which the path has two or
1449 if path.segments.len() < 2 {
1453 // Verify that no lifetimes or type parameters are present anywhere
1454 // except the final two elements of the path.
1455 for i in range(0, path.segments.len() - 2) {
1456 for lifetime in path.segments[i].lifetimes.iter() {
1457 function_context.tcx()
1459 .span_err(lifetime.span,
1460 "lifetime parameters may not \
1465 for typ in path.segments[i].types.iter() {
1466 function_context.tcx()
1469 "type parameters may not appear here");
1474 // If there are no parameters at all, there is nothing more to do; the
1475 // rest of typechecking will (attempt to) infer everything.
1478 .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) {
1483 // If this is a static method of a trait or implementation, then
1484 // ensure that the segment of the path which names the trait or
1485 // implementation (the penultimate segment) is annotated with the
1486 // right number of type parameters.
1487 ast::DefStaticMethod(_, provenance, _) => {
1489 generics_of_static_method_container(function_context.ccx.tcx,
1491 let name = match provenance {
1492 ast::FromTrait(_) => "trait",
1493 ast::FromImpl(_) => "impl",
1496 let trait_segment = &path.segments[path.segments.len() - 2];
1498 // Make sure lifetime parameterization agrees with the trait or
1499 // implementation type.
1500 let trait_region_parameter_count = generics.region_param_defs().len();
1501 let supplied_region_parameter_count = trait_segment.lifetimes.len();
1502 if trait_region_parameter_count != supplied_region_parameter_count
1503 && supplied_region_parameter_count != 0 {
1504 function_context.tcx()
1506 .span_err(path.span,
1507 format!("expected {} lifetime parameter(s), \
1508 found {} lifetime parameter(s)",
1509 trait_region_parameter_count,
1510 supplied_region_parameter_count));
1513 // Make sure the number of type parameters supplied on the trait
1514 // or implementation segment equals the number of type parameters
1515 // on the trait or implementation definition.
1516 let formal_ty_param_count = generics.type_param_defs().len();
1517 let required_ty_param_count = generics.type_param_defs().iter()
1518 .take_while(|x| x.default.is_none())
1520 let supplied_ty_param_count = trait_segment.types.len();
1521 if supplied_ty_param_count < required_ty_param_count {
1522 let trait_count_suffix = if required_ty_param_count == 1 {
1527 let supplied_count_suffix = if supplied_ty_param_count == 1 {
1532 let needs = if required_ty_param_count < generics.type_param_defs().len() {
1537 function_context.tcx().sess.span_err(path.span,
1538 format!("the {} referenced by this path {} {} type \
1539 parameter{}, but {} type parameter{} were supplied",
1541 required_ty_param_count, trait_count_suffix,
1542 supplied_ty_param_count, supplied_count_suffix))
1543 } else if supplied_ty_param_count > formal_ty_param_count {
1544 let trait_count_suffix = if formal_ty_param_count == 1 {
1549 let supplied_count_suffix = if supplied_ty_param_count == 1 {
1554 let needs = if required_ty_param_count < generics.type_param_defs().len() {
1559 function_context.tcx().sess.span_err(path.span,
1560 format!("the {} referenced by this path {} {} type \
1561 parameter{}, but {} type parameter{} were supplied",
1563 formal_ty_param_count, trait_count_suffix,
1564 supplied_ty_param_count, supplied_count_suffix))
1568 // Verify that no lifetimes or type parameters are present on
1569 // the penultimate segment of the path.
1570 let segment = &path.segments[path.segments.len() - 2];
1571 for lifetime in segment.lifetimes.iter() {
1572 function_context.tcx()
1574 .span_err(lifetime.span,
1575 "lifetime parameters may not
1579 for typ in segment.types.iter() {
1580 function_context.tcx()
1583 "type parameters may not appear \
1592 /// If an expression has any sub-expressions that result in a type error,
1593 /// inspecting that expression's type with `ty::type_is_error` will return
1594 /// true. Likewise, if an expression is known to diverge, inspecting its
1595 /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
1596 /// strict, _|_ can appear in the type of an expression that does not,
1597 /// itself, diverge: for example, fn() -> _|_.)
1598 /// Note that inspecting a type's structure *directly* may expose the fact
1599 /// that there are actually multiple representations for both `ty_err` and
1600 /// `ty_bot`, so avoid that when err and bot need to be handled differently.
1601 pub fn check_expr_with_unifier(fcx: @FnCtxt,
1603 expected: Option<ty::t>,
1605 debug!(">> typechecking");
1607 fn check_method_argument_types(
1610 method_fn_ty: ty::t,
1611 callee_expr: &ast::Expr,
1612 args: &[@ast::Expr],
1613 deref_args: DerefArgs) -> ty::t {
1614 // HACK(eddyb) ignore provided self (it has special typeck rules).
1615 let args = args.slice_from(1);
1616 if ty::type_is_error(method_fn_ty) {
1617 let err_inputs = err_args(args.len());
1618 check_argument_types(fcx, sp, err_inputs, callee_expr,
1619 args, deref_args, false);
1622 match ty::get(method_fn_ty).sty {
1623 ty::ty_bare_fn(ref fty) => {
1624 // HACK(eddyb) ignore self in the definition (see above).
1625 check_argument_types(fcx, sp, fty.sig.inputs.slice_from(1),
1626 callee_expr, args, deref_args,
1631 fcx.tcx().sess.span_bug(
1633 format!("method without bare fn type"));
1639 fn check_argument_types(fcx: @FnCtxt,
1641 fn_inputs: &[ty::t],
1642 callee_expr: &ast::Expr,
1643 args: &[@ast::Expr],
1644 deref_args: DerefArgs,
1648 * Generic function that factors out common logic from
1649 * function calls, method calls and overloaded operators.
1652 let tcx = fcx.ccx.tcx;
1654 // Grab the argument types, supplying fresh type variables
1655 // if the wrong number of arguments were supplied
1656 let supplied_arg_count = args.len();
1657 let expected_arg_count = fn_inputs.len();
1658 let formal_tys = if expected_arg_count == supplied_arg_count {
1659 fn_inputs.map(|a| *a)
1660 } else if variadic {
1661 if supplied_arg_count >= expected_arg_count {
1662 fn_inputs.map(|a| *a)
1665 "this function takes at least {} parameter{} \
1666 but {} parameter{} supplied",
1668 if expected_arg_count == 1 {""} else {"s"},
1670 if supplied_arg_count == 1 {" was"} else {"s were"});
1672 tcx.sess.span_err(sp, msg);
1674 err_args(supplied_arg_count)
1678 "this function takes {} parameter{} \
1679 but {} parameter{} supplied",
1680 expected_arg_count, if expected_arg_count == 1 {""} else {"s"},
1682 if supplied_arg_count == 1 {" was"} else {"s were"});
1684 tcx.sess.span_err(sp, msg);
1686 err_args(supplied_arg_count)
1689 debug!("check_argument_types: formal_tys={:?}",
1690 formal_tys.map(|t| fcx.infcx().ty_to_str(*t)));
1692 // Check the arguments.
1693 // We do this in a pretty awful way: first we typecheck any arguments
1694 // that are not anonymous functions, then we typecheck the anonymous
1695 // functions. This is so that we have more information about the types
1696 // of arguments when we typecheck the functions. This isn't really the
1697 // right way to do this.
1698 let xs = [false, true];
1699 for check_blocks in xs.iter() {
1700 let check_blocks = *check_blocks;
1701 debug!("check_blocks={}", check_blocks);
1703 // More awful hacks: before we check the blocks, try to do
1704 // an "opportunistic" vtable resolution of any trait
1705 // bounds on the call.
1707 vtable::early_resolve_expr(callee_expr, fcx, true);
1710 // For variadic functions, we don't have a declared type for all of
1711 // the arguments hence we only do our usual type checking with
1712 // the arguments who's types we do know.
1713 let t = if variadic {
1718 for (i, arg) in args.iter().take(t).enumerate() {
1719 let is_block = match arg.node {
1720 ast::ExprFnBlock(..) |
1721 ast::ExprProc(..) => true,
1725 if is_block == check_blocks {
1726 debug!("checking the argument");
1727 let mut formal_ty = formal_tys[i];
1731 match ty::get(formal_ty).sty {
1732 ty::ty_rptr(_, mt) => formal_ty = mt.ty,
1735 // So we hit this case when one implements the
1736 // operator traits but leaves an argument as
1737 // just T instead of &T. We'll catch it in the
1738 // mismatch impl/trait method phase no need to
1741 formal_ty = ty::mk_err();
1748 check_expr_coercable_to_type(fcx, *arg, formal_ty);
1754 // We also need to make sure we at least write the ty of the other
1755 // arguments which we skipped above.
1757 for arg in args.iter().skip(expected_arg_count) {
1758 check_expr(fcx, *arg);
1760 // There are a few types which get autopromoted when passed via varargs
1761 // in C but we just error out instead and require explicit casts.
1762 let arg_ty = structurally_resolved_type(fcx, arg.span, fcx.expr_ty(*arg));
1763 match ty::get(arg_ty).sty {
1764 ty::ty_float(ast::TyF32) => {
1765 fcx.type_error_message(arg.span,
1766 |t| format!("can't pass an {} to variadic function, \
1767 cast to c_double", t), arg_ty, None);
1769 ty::ty_int(ast::TyI8) | ty::ty_int(ast::TyI16) | ty::ty_bool => {
1770 fcx.type_error_message(arg.span,
1771 |t| format!("can't pass {} to variadic function, cast to c_int",
1774 ty::ty_uint(ast::TyU8) | ty::ty_uint(ast::TyU16) => {
1775 fcx.type_error_message(arg.span,
1776 |t| format!("can't pass {} to variadic function, cast to c_uint",
1785 fn err_args(len: uint) -> ~[ty::t] {
1786 vec::from_fn(len, |_| ty::mk_err())
1789 // A generic function for checking assignment expressions
1790 fn check_assignment(fcx: @FnCtxt,
1794 check_expr(fcx, lhs);
1795 let lhs_type = fcx.expr_ty(lhs);
1796 check_expr_has_type(fcx, rhs, lhs_type);
1797 fcx.write_ty(id, ty::mk_nil());
1798 // The callee checks for bot / err, we don't need to
1801 fn write_call(fcx: @FnCtxt, call_expr: &ast::Expr, output: ty::t) {
1802 fcx.write_ty(call_expr.id, output);
1805 // A generic function for doing all of the checking for call expressions
1806 fn check_call(fcx: @FnCtxt,
1807 call_expr: &ast::Expr,
1809 args: &[@ast::Expr]) {
1810 // Index expressions need to be handled separately, to inform them
1811 // that they appear in call position.
1814 // Store the type of `f` as the type of the callee
1815 let fn_ty = fcx.expr_ty(f);
1817 // Extract the function signature from `in_fty`.
1818 let fn_sty = structure_of(fcx, f.span, fn_ty);
1820 // This is the "default" function signature, used in case of error.
1821 // In that case, we check each argument against "error" in order to
1822 // set up all the node type bindings.
1823 let error_fn_sig = FnSig {
1824 binder_id: ast::CRATE_NODE_ID,
1825 inputs: err_args(args.len()),
1826 output: ty::mk_err(),
1830 let fn_sig = match *fn_sty {
1831 ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, ..}) |
1832 ty::ty_closure(ty::ClosureTy {sig: ref sig, ..}) => sig,
1834 fcx.type_error_message(call_expr.span, |actual| {
1835 format!("expected function but \
1836 found `{}`", actual) }, fn_ty, None);
1841 // Replace any bound regions that appear in the function
1842 // signature with region variables
1843 let (_, fn_sig) = replace_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
1845 .next_region_var(infer::BoundRegionInFnCall(call_expr.span, br))
1848 // Call the generic checker.
1849 check_argument_types(fcx, call_expr.span, fn_sig.inputs, f,
1850 args, DontDerefArgs, fn_sig.variadic);
1852 write_call(fcx, call_expr, fn_sig.output);
1855 // Checks a method call.
1856 fn check_method_call(fcx: @FnCtxt,
1858 method_name: ast::Ident,
1859 args: &[@ast::Expr],
1860 tps: &[ast::P<ast::Ty>]) {
1862 check_expr(fcx, rcvr);
1864 // no need to check for bot/err -- callee does that
1865 let expr_t = structurally_resolved_type(fcx,
1869 let tps = tps.map(|&ast_ty| fcx.to_ty(ast_ty));
1870 let fn_ty = match method::lookup(fcx, expr, rcvr,
1874 CheckTraitsAndInherentMethods,
1875 AutoderefReceiver) {
1877 let method_ty = method.ty;
1878 fcx.inh.method_map.borrow_mut().get().insert(expr.id, method);
1882 debug!("(checking method call) failing expr is {}", expr.id);
1884 fcx.type_error_message(expr.span,
1886 format!("type `{}` does not implement any method in scope \
1888 actual, token::get_ident(method_name))
1893 // Add error type for the result
1894 fcx.write_error(expr.id);
1899 // Call the generic checker.
1900 let ret_ty = check_method_argument_types(fcx, expr.span,
1904 write_call(fcx, expr, ret_ty);
1907 // A generic function for checking the then and else in an if
1909 fn check_then_else(fcx: @FnCtxt,
1910 cond_expr: &ast::Expr,
1911 then_blk: &ast::Block,
1912 opt_else_expr: Option<@ast::Expr>,
1915 expected: Option<ty::t>) {
1916 check_expr_has_type(fcx, cond_expr, ty::mk_bool());
1918 let branches_ty = match opt_else_expr {
1919 Some(else_expr) => {
1920 check_block_with_expected(fcx, then_blk, expected);
1921 let then_ty = fcx.node_ty(then_blk.id);
1922 check_expr_with_opt_hint(fcx, else_expr, expected);
1923 let else_ty = fcx.expr_ty(else_expr);
1924 infer::common_supertype(fcx.infcx(),
1925 infer::IfExpression(sp),
1931 check_block_no_value(fcx, then_blk);
1936 let cond_ty = fcx.expr_ty(cond_expr);
1937 let if_ty = if ty::type_is_error(cond_ty) {
1939 } else if ty::type_is_bot(cond_ty) {
1945 fcx.write_ty(id, if_ty);
1948 fn lookup_op_method(fcx: @FnCtxt,
1952 trait_did: Option<ast::DefId>,
1953 args: &[@ast::Expr],
1954 autoderef_receiver: AutoderefReceiverFlag,
1955 unbound_method: ||) -> ty::t {
1956 let method = match trait_did {
1957 Some(trait_did) => {
1958 method::lookup_in_trait(fcx, op_ex, args[0], opname, trait_did,
1959 self_t, [], autoderef_receiver)
1965 let method_ty = method.ty;
1966 fcx.inh.method_map.borrow_mut().get().insert(op_ex.id, method);
1967 check_method_argument_types(fcx, op_ex.span,
1973 // Check the args anyway
1974 // so we get all the error messages
1975 let expected_ty = ty::mk_err();
1976 check_method_argument_types(fcx, op_ex.span,
1984 // could be either an expr_binop or an expr_assign_binop
1985 fn check_binop(fcx: @FnCtxt,
1990 is_binop_assignment: IsBinopAssignment) {
1991 let tcx = fcx.ccx.tcx;
1993 check_expr(fcx, lhs);
1994 // Callee does bot / err checking
1995 let lhs_t = structurally_resolved_type(fcx, lhs.span,
1998 if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) {
1999 // Shift is a special case: rhs can be any integral type
2000 check_expr(fcx, rhs);
2001 let rhs_t = fcx.expr_ty(rhs);
2002 require_integral(fcx, rhs.span, rhs_t);
2003 fcx.write_ty(expr.id, lhs_t);
2007 if ty::is_binopable(tcx, lhs_t, op) {
2008 let tvar = fcx.infcx().next_ty_var();
2009 demand::suptype(fcx, expr.span, tvar, lhs_t);
2010 check_expr_has_type(fcx, rhs, tvar);
2012 let result_t = match op {
2013 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGe |
2014 ast::BiGt => ty::mk_bool(),
2018 fcx.write_ty(expr.id, result_t);
2022 if op == ast::BiOr || op == ast::BiAnd {
2023 // This is an error; one of the operands must have the wrong
2025 fcx.write_error(expr.id);
2026 fcx.write_error(rhs.id);
2027 fcx.type_error_message(expr.span, |actual| {
2028 format!("binary operation `{}` cannot be applied \
2030 ast_util::binop_to_str(op), actual)},
2035 // Check for overloaded operators if not an assignment.
2036 let result_t = if is_binop_assignment == SimpleBinop {
2037 check_user_binop(fcx, expr, lhs, lhs_t, op, rhs)
2039 fcx.type_error_message(expr.span,
2041 format!("binary assignment operation \
2042 `{}=` cannot be applied to type `{}`",
2043 ast_util::binop_to_str(op),
2048 check_expr(fcx, rhs);
2052 fcx.write_ty(expr.id, result_t);
2053 if ty::type_is_error(result_t) {
2054 fcx.write_ty(rhs.id, result_t);
2058 fn check_user_binop(fcx: @FnCtxt,
2060 lhs_expr: @ast::Expr,
2061 lhs_resolved_t: ty::t,
2063 rhs: @ast::Expr) -> ty::t {
2064 let tcx = fcx.ccx.tcx;
2065 let lang = tcx.lang_items;
2066 let (name, trait_did) = match op {
2067 ast::BiAdd => ("add", lang.add_trait()),
2068 ast::BiSub => ("sub", lang.sub_trait()),
2069 ast::BiMul => ("mul", lang.mul_trait()),
2070 ast::BiDiv => ("div", lang.div_trait()),
2071 ast::BiRem => ("rem", lang.rem_trait()),
2072 ast::BiBitXor => ("bitxor", lang.bitxor_trait()),
2073 ast::BiBitAnd => ("bitand", lang.bitand_trait()),
2074 ast::BiBitOr => ("bitor", lang.bitor_trait()),
2075 ast::BiShl => ("shl", lang.shl_trait()),
2076 ast::BiShr => ("shr", lang.shr_trait()),
2077 ast::BiLt => ("lt", lang.ord_trait()),
2078 ast::BiLe => ("le", lang.ord_trait()),
2079 ast::BiGe => ("ge", lang.ord_trait()),
2080 ast::BiGt => ("gt", lang.ord_trait()),
2081 ast::BiEq => ("eq", lang.eq_trait()),
2082 ast::BiNe => ("ne", lang.eq_trait()),
2083 ast::BiAnd | ast::BiOr => {
2084 check_expr(fcx, rhs);
2085 return ty::mk_err();
2088 lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
2089 trait_did, [lhs_expr, rhs], DontAutoderefReceiver, || {
2090 fcx.type_error_message(ex.span, |actual| {
2091 format!("binary operation `{}` cannot be applied to type `{}`",
2092 ast_util::binop_to_str(op), actual)
2093 }, lhs_resolved_t, None)
2097 fn check_user_unop(fcx: @FnCtxt,
2100 trait_did: Option<ast::DefId>,
2102 rhs_expr: @ast::Expr,
2103 rhs_t: ty::t) -> ty::t {
2104 lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
2105 trait_did, [rhs_expr], DontAutoderefReceiver, || {
2106 fcx.type_error_message(ex.span, |actual| {
2107 format!("cannot apply unary operator `{}` to type `{}`", op_str, actual)
2112 // Resolves `expected` by a single level if it is a variable and passes it
2113 // through the `unpack` function. It there is no expected type or
2114 // resolution is not possible (e.g., no constraints yet present), just
2116 fn unpack_expected<O>(
2118 expected: Option<ty::t>,
2119 unpack: |&ty::sty| -> Option<O>)
2123 match resolve_type(fcx.infcx(), t, force_tvar) {
2124 Ok(t) => unpack(&ty::get(t).sty),
2132 fn check_expr_fn(fcx: @FnCtxt,
2134 ast_sigil_opt: Option<ast::Sigil>,
2136 body: ast::P<ast::Block>,
2138 expected: Option<ty::t>) {
2139 let tcx = fcx.ccx.tcx;
2141 // Find the expected input/output types (if any). Substitute
2142 // fresh bound regions for any bound regions we find in the
2143 // expected types so as to avoid capture.
2145 // Also try to pick up inferred purity and sigil, defaulting
2146 // to impure and block. Note that we only will use those for
2147 // block syntax lambdas; that is, lambdas without explicit
2149 let expected_sty = unpack_expected(fcx,
2151 |x| Some((*x).clone()));
2152 let error_happened = false;
2157 expected_bounds) = {
2158 match expected_sty {
2159 Some(ty::ty_closure(ref cenv)) => {
2161 replace_bound_regions_in_fn_sig(
2163 |_| fcx.inh.infcx.fresh_bound_region(expr.id));
2164 (Some(sig), cenv.purity, cenv.sigil,
2165 cenv.onceness, cenv.bounds)
2168 // Not an error! Means we're inferring the closure type
2169 let mut sigil = ast::BorrowedSigil;
2170 let mut onceness = ast::Many;
2171 let mut bounds = ty::EmptyBuiltinBounds();
2173 ast::ExprProc(..) => {
2174 sigil = ast::OwnedSigil;
2175 onceness = ast::Once;
2176 bounds.add(ty::BoundSend);
2180 (None, ast::ImpureFn, sigil,
2186 // If the proto is specified, use that, otherwise select a
2187 // proto based on inference.
2188 let (sigil, purity) = match ast_sigil_opt {
2189 Some(p) => (p, ast::ImpureFn),
2190 None => (expected_sigil, expected_purity)
2193 // construct the function type
2194 let fn_ty = astconv::ty_of_closure(fcx,
2207 let fty = if error_happened {
2209 binder_id: ast::CRATE_NODE_ID,
2210 inputs: fn_ty.sig.inputs.map(|_| ty::mk_err()),
2211 output: ty::mk_err(),
2216 let fn_ty_copy = fn_ty.clone();
2217 fty_sig = fn_ty.sig.clone();
2218 ty::mk_closure(tcx, fn_ty_copy)
2221 debug!("check_expr_fn_with_unifier fty={}",
2222 fcx.infcx().ty_to_str(fty));
2224 fcx.write_ty(expr.id, fty);
2226 let (inherited_purity, id) =
2227 ty::determine_inherited_purity((fcx.ps.get().purity,
2232 check_fn(fcx.ccx, inherited_purity, &fty_sig,
2233 decl, id, body, fn_kind, fcx.inh);
2237 // Check field access expressions
2238 fn check_field(fcx: @FnCtxt,
2242 tys: &[ast::P<ast::Ty>]) {
2243 let tcx = fcx.ccx.tcx;
2244 let bot = check_expr(fcx, base);
2245 let expr_t = structurally_resolved_type(fcx, expr.span,
2247 let (base_t, derefs) = do_autoderef(fcx, expr.span, expr_t);
2249 match *structure_of(fcx, expr.span, base_t) {
2250 ty::ty_struct(base_id, ref substs) => {
2251 // This is just for fields -- the same code handles
2252 // methods in both classes and traits
2254 // (1) verify that the class id actually has a field called
2256 debug!("class named {}", ppaux::ty_to_str(tcx, base_t));
2257 let cls_items = ty::lookup_struct_fields(tcx, base_id);
2258 match lookup_field_ty(tcx, base_id, cls_items,
2259 field, &(*substs)) {
2261 // (2) look up what field's type is, and return it
2262 fcx.write_ty(expr.id, field_ty);
2263 fcx.write_autoderef_adjustment(base.id, derefs);
2272 let tps : ~[ty::t] = tys.iter().map(|&ty| fcx.to_ty(ty)).collect();
2273 match method::lookup(fcx,
2280 CheckTraitsAndInherentMethods,
2281 AutoderefReceiver) {
2283 fcx.type_error_message(
2286 format!("attempted to take value of method `{}` on type `{}` \
2287 (try writing an anonymous function)",
2288 token::get_name(field), actual)
2294 fcx.type_error_message(
2297 format!("attempted access of field `{}` on type `{}`, \
2298 but no field with that name was found",
2299 token::get_name(field), actual)
2305 fcx.write_error(expr.id);
2308 fn check_struct_or_variant_fields(fcx: @FnCtxt,
2311 class_id: ast::DefId,
2312 node_id: ast::NodeId,
2313 substitutions: ty::substs,
2314 field_types: &[ty::field_ty],
2315 ast_fields: &[ast::Field],
2316 check_completeness: bool) {
2317 let tcx = fcx.ccx.tcx;
2319 let mut class_field_map = HashMap::new();
2320 let mut fields_found = 0;
2321 for field in field_types.iter() {
2322 class_field_map.insert(field.name, (field.id, false));
2325 let mut error_happened = false;
2327 // Typecheck each field.
2328 for field in ast_fields.iter() {
2329 let mut expected_field_type = ty::mk_err();
2331 let pair = class_field_map.find(&field.ident.node.name).map(|x| *x);
2334 fcx.type_error_message(
2337 format!("structure `{}` has no field named `{}`",
2338 actual, token::get_ident(field.ident.node))
2339 }, struct_ty, None);
2340 error_happened = true;
2342 Some((_, true)) => {
2345 format!("field `{}` specified more than once",
2346 token::get_ident(field.ident.node)));
2347 error_happened = true;
2349 Some((field_id, false)) => {
2350 expected_field_type =
2351 ty::lookup_field_type(
2352 tcx, class_id, field_id, &substitutions);
2353 class_field_map.insert(
2354 field.ident.node.name, (field_id, true));
2358 // Make sure to give a type to the field even if there's
2359 // an error, so we can continue typechecking
2360 check_expr_coercable_to_type(
2363 expected_field_type);
2367 fcx.write_error(node_id);
2370 if check_completeness && !error_happened {
2371 // Make sure the programmer specified all the fields.
2372 assert!(fields_found <= field_types.len());
2373 if fields_found < field_types.len() {
2374 let mut missing_fields = ~[];
2375 for class_field in field_types.iter() {
2376 let name = class_field.name;
2377 let (_, seen) = *class_field_map.get(&name);
2379 missing_fields.push(~"`" + token::get_name(name).get() + "`");
2383 tcx.sess.span_err(span,
2384 format!("missing field{}: {}",
2385 if missing_fields.len() == 1 {
2390 missing_fields.connect(", ")));
2394 if !error_happened {
2395 fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx,
2396 class_id, substitutions));
2400 fn check_struct_constructor(fcx: @FnCtxt,
2402 span: codemap::Span,
2403 class_id: ast::DefId,
2404 fields: &[ast::Field],
2405 base_expr: Option<@ast::Expr>) {
2406 let tcx = fcx.ccx.tcx;
2408 // Look up the number of type parameters and the raw type, and
2409 // determine whether the class is region-parameterized.
2410 let item_type = ty::lookup_item_type(tcx, class_id);
2411 let type_parameter_count = item_type.generics.type_param_defs().len();
2412 let region_parameter_count = item_type.generics.region_param_defs().len();
2413 let raw_type = item_type.ty;
2415 // Generate the struct type.
2416 let regions = fcx.infcx().next_region_vars(
2417 infer::BoundRegionInTypeOrImpl(span),
2418 region_parameter_count);
2419 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2420 let substitutions = substs {
2421 regions: ty::NonerasedRegions(opt_vec::from(regions)),
2423 tps: type_parameters
2426 let mut struct_type = ty::subst(tcx, &substitutions, raw_type);
2428 // Look up and check the fields.
2429 let class_fields = ty::lookup_struct_fields(tcx, class_id);
2430 check_struct_or_variant_fields(fcx,
2438 base_expr.is_none());
2439 if ty::type_is_error(fcx.node_ty(id)) {
2440 struct_type = ty::mk_err();
2443 // Check the base expression if necessary.
2446 Some(base_expr) => {
2447 check_expr_has_type(fcx, base_expr, struct_type);
2448 if ty::type_is_bot(fcx.node_ty(base_expr.id)) {
2449 struct_type = ty::mk_bot();
2454 // Write in the resulting type.
2455 fcx.write_ty(id, struct_type);
2458 fn check_struct_enum_variant(fcx: @FnCtxt,
2460 span: codemap::Span,
2461 enum_id: ast::DefId,
2462 variant_id: ast::DefId,
2463 fields: &[ast::Field]) {
2464 let tcx = fcx.ccx.tcx;
2466 // Look up the number of type parameters and the raw type, and
2467 // determine whether the enum is region-parameterized.
2468 let item_type = ty::lookup_item_type(tcx, enum_id);
2469 let type_parameter_count = item_type.generics.type_param_defs().len();
2470 let region_parameter_count = item_type.generics.region_param_defs().len();
2471 let raw_type = item_type.ty;
2473 // Generate the enum type.
2474 let regions = fcx.infcx().next_region_vars(
2475 infer::BoundRegionInTypeOrImpl(span),
2476 region_parameter_count);
2477 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2478 let substitutions = substs {
2479 regions: ty::NonerasedRegions(opt_vec::from(regions)),
2481 tps: type_parameters
2484 let enum_type = ty::subst(tcx, &substitutions, raw_type);
2486 // Look up and check the enum variant fields.
2487 let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2488 check_struct_or_variant_fields(fcx,
2497 fcx.write_ty(id, enum_type);
2500 let tcx = fcx.ccx.tcx;
2503 ast::ExprVstore(ev, vst) => {
2504 let typ = match ev.node {
2505 ast::ExprLit(lit) if ast_util::lit_is_str(lit) => {
2506 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2509 ast::ExprVec(ref args, mutbl) => {
2510 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2511 let mut any_error = false;
2512 let mut any_bot = false;
2513 let mutability = match vst {
2514 ast::ExprVstoreMutSlice => ast::MutMutable,
2517 let t: ty::t = fcx.infcx().next_ty_var();
2518 for e in args.iter() {
2519 check_expr_has_type(fcx, *e, t);
2520 let arg_t = fcx.expr_ty(*e);
2521 if ty::type_is_error(arg_t) {
2524 else if ty::type_is_bot(arg_t) {
2533 ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2536 ast::ExprRepeat(element, count_expr, mutbl) => {
2537 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2538 let _ = ty::eval_repeat_count(fcx, count_expr);
2539 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2540 let mutability = match vst {
2541 ast::ExprVstoreMutSlice => ast::MutMutable,
2544 let t: ty::t = fcx.infcx().next_ty_var();
2545 check_expr_has_type(fcx, element, t);
2546 let arg_t = fcx.expr_ty(element);
2547 if ty::type_is_error(arg_t) {
2549 } else if ty::type_is_bot(arg_t) {
2552 ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2556 tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence")
2558 fcx.write_ty(ev.id, typ);
2559 fcx.write_ty(id, typ);
2562 ast::ExprBox(place, subexpr) => {
2563 check_expr(fcx, place);
2564 check_expr(fcx, subexpr);
2566 let mut checked = false;
2568 ast::ExprPath(ref path) => {
2569 // FIXME(pcwalton): For now we hardcode the two permissible
2570 // places: the exchange heap and the managed heap.
2571 let definition = lookup_def(fcx, path.span, place.id);
2572 let def_id = ast_util::def_id_of_def(definition);
2573 match tcx.lang_items.items[ExchangeHeapLangItem as uint] {
2574 Some(item_def_id) if def_id == item_def_id => {
2575 fcx.write_ty(id, ty::mk_uniq(tcx,
2576 fcx.expr_ty(subexpr)));
2579 Some(_) | None => {}
2582 match tcx.lang_items
2583 .items[ManagedHeapLangItem as uint] {
2584 Some(item_def_id) if def_id == item_def_id => {
2585 // Assign the magic `Gc<T>` struct.
2587 match tcx.lang_items
2588 .require(GcLangItem) {
2591 tcx.sess.span_err(expr.span, msg);
2593 krate: ast::CRATE_NODE_ID,
2594 node: ast::DUMMY_NODE_ID,
2599 ty::NonerasedRegions(opt_vec::Empty);
2600 let sty = ty::mk_struct(tcx,
2610 fcx.write_ty(id, sty);
2613 Some(_) | None => {}
2621 tcx.sess.span_err(expr.span,
2622 "only the managed heap and exchange heap are \
2623 currently supported")
2627 ast::ExprLit(lit) => {
2628 let typ = check_lit(fcx, lit);
2629 fcx.write_ty(id, typ);
2631 ast::ExprBinary(op, lhs, rhs) => {
2632 check_binop(fcx, expr, op, lhs, rhs, SimpleBinop);
2634 let lhs_ty = fcx.expr_ty(lhs);
2635 let rhs_ty = fcx.expr_ty(rhs);
2636 if ty::type_is_error(lhs_ty) ||
2637 ty::type_is_error(rhs_ty) {
2638 fcx.write_error(id);
2640 else if ty::type_is_bot(lhs_ty) ||
2641 (ty::type_is_bot(rhs_ty) && !ast_util::lazy_binop(op)) {
2645 ast::ExprAssignOp(op, lhs, rhs) => {
2646 check_binop(fcx, expr, op, lhs, rhs, BinopAssignment);
2648 let lhs_t = fcx.expr_ty(lhs);
2649 let result_t = fcx.expr_ty(expr);
2650 demand::suptype(fcx, expr.span, result_t, lhs_t);
2652 let tcx = fcx.tcx();
2653 if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
2654 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2657 // Overwrite result of check_binop...this preserves existing behavior
2658 // but seems quite dubious with regard to user-defined methods
2659 // and so forth. - Niko
2660 if !ty::type_is_error(result_t)
2661 && !ty::type_is_bot(result_t) {
2662 fcx.write_nil(expr.id);
2665 ast::ExprUnary(unop, oprnd) => {
2666 let exp_inner = unpack_expected(fcx, expected, |sty| {
2668 ast::UnBox | ast::UnUniq => match *sty {
2669 ty::ty_box(ty) | ty::ty_uniq(ty) => Some(ty),
2672 ast::UnNot | ast::UnNeg => expected,
2673 ast::UnDeref => None
2676 check_expr_with_opt_hint(fcx, oprnd, exp_inner);
2677 let mut oprnd_t = fcx.expr_ty(oprnd);
2678 if !ty::type_is_error(oprnd_t) &&
2679 !ty::type_is_bot(oprnd_t) {
2682 oprnd_t = ty::mk_box(tcx, oprnd_t)
2685 oprnd_t = ty::mk_uniq(tcx, oprnd_t);
2688 let sty = structure_of(fcx, expr.span, oprnd_t);
2689 let operand_ty = ty::deref_sty(sty, true);
2696 ty::ty_struct(did, ref substs) if {
2697 let fields = ty::struct_fields(fcx.tcx(), did, substs);
2699 && fields[0].ident == token::special_idents::unnamed_field
2701 // This is an obsolete struct deref
2704 "single-field tuple-structs can no longer be dereferenced");
2707 fcx.type_error_message(expr.span,
2709 format!("type `{}` cannot be dereferenced", actual)
2717 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2719 if !(ty::type_is_integral(oprnd_t) ||
2720 ty::get(oprnd_t).sty == ty::ty_bool) {
2721 oprnd_t = check_user_unop(fcx, "!", "not",
2722 tcx.lang_items.not_trait(),
2723 expr, oprnd, oprnd_t);
2727 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2729 if !(ty::type_is_integral(oprnd_t) ||
2730 ty::type_is_fp(oprnd_t)) {
2731 oprnd_t = check_user_unop(fcx, "-", "neg",
2732 tcx.lang_items.neg_trait(),
2733 expr, oprnd, oprnd_t);
2738 fcx.write_ty(id, oprnd_t);
2740 ast::ExprAddrOf(mutbl, oprnd) => {
2741 let hint = unpack_expected(
2743 |sty| match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty),
2745 check_expr_with_opt_hint(fcx, oprnd, hint);
2747 // Note: at this point, we cannot say what the best lifetime
2748 // is to use for resulting pointer. We want to use the
2749 // shortest lifetime possible so as to avoid spurious borrowck
2750 // errors. Moreover, the longest lifetime will depend on the
2751 // precise details of the value whose address is being taken
2752 // (and how long it is valid), which we don't know yet until type
2753 // inference is complete.
2755 // Therefore, here we simply generate a region variable. The
2756 // region inferencer will then select the ultimate value.
2757 // Finally, borrowck is charged with guaranteeing that the
2758 // value whose address was taken can actually be made to live
2759 // as long as it needs to live.
2760 let region = fcx.infcx().next_region_var(
2761 infer::AddrOfRegion(expr.span));
2763 let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
2764 let oprnd_t = if ty::type_is_error(tm.ty) {
2766 } else if ty::type_is_bot(tm.ty) {
2770 ty::mk_rptr(tcx, region, tm)
2772 fcx.write_ty(id, oprnd_t);
2774 ast::ExprPath(ref pth) => {
2775 let defn = lookup_def(fcx, pth.span, id);
2777 check_type_parameter_positions_in_path(fcx, pth, defn);
2778 let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2779 instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
2781 ast::ExprInlineAsm(ref ia) => {
2782 for &(_, input) in ia.inputs.iter() {
2783 check_expr(fcx, input);
2785 for &(_, out) in ia.outputs.iter() {
2786 check_expr(fcx, out);
2790 ast::ExprMac(_) => tcx.sess.bug("unexpanded macro"),
2791 ast::ExprBreak(_) => { fcx.write_bot(id); }
2792 ast::ExprAgain(_) => { fcx.write_bot(id); }
2793 ast::ExprRet(expr_opt) => {
2794 let ret_ty = fcx.ret_ty;
2796 None => match fcx.mk_eqty(false, infer::Misc(expr.span),
2797 ret_ty, ty::mk_nil()) {
2798 result::Ok(_) => { /* fall through */ }
2802 "`return;` in function returning non-nil");
2806 check_expr_has_type(fcx, e, ret_ty);
2811 ast::ExprLogLevel => {
2812 fcx.write_ty(id, ty::mk_u32())
2814 ast::ExprParen(a) => {
2815 check_expr_with_opt_hint(fcx, a, expected);
2816 fcx.write_ty(id, fcx.expr_ty(a));
2818 ast::ExprAssign(lhs, rhs) => {
2819 check_assignment(fcx, lhs, rhs, id);
2821 let tcx = fcx.tcx();
2822 if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
2823 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2826 let lhs_ty = fcx.expr_ty(lhs);
2827 let rhs_ty = fcx.expr_ty(rhs);
2828 if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
2829 fcx.write_error(id);
2831 else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
2838 ast::ExprIf(cond, then_blk, opt_else_expr) => {
2839 check_then_else(fcx, cond, then_blk, opt_else_expr,
2840 id, expr.span, expected);
2842 ast::ExprWhile(cond, body) => {
2843 check_expr_has_type(fcx, cond, ty::mk_bool());
2844 check_block_no_value(fcx, body);
2845 let cond_ty = fcx.expr_ty(cond);
2846 let body_ty = fcx.node_ty(body.id);
2847 if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) {
2848 fcx.write_error(id);
2850 else if ty::type_is_bot(cond_ty) {
2857 ast::ExprForLoop(..) =>
2858 fail!("non-desugared expr_for_loop"),
2859 ast::ExprLoop(body, _) => {
2860 check_block_no_value(fcx, (body));
2861 if !may_break(tcx, expr.id, body) {
2868 ast::ExprMatch(discrim, ref arms) => {
2869 _match::check_match(fcx, expr, discrim, *arms);
2871 ast::ExprFnBlock(decl, body) => {
2874 Some(ast::BorrowedSigil),
2880 ast::ExprProc(decl, body) => {
2883 Some(ast::OwnedSigil),
2889 ast::ExprBlock(b) => {
2890 check_block_with_expected(fcx, b, expected);
2891 fcx.write_ty(id, fcx.node_ty(b.id));
2893 ast::ExprCall(f, ref args) => {
2894 check_call(fcx, expr, f, *args);
2895 let f_ty = fcx.expr_ty(f);
2896 let (args_bot, args_err) = args.iter().fold((false, false),
2897 |(rest_bot, rest_err), a| {
2898 // is this not working?
2899 let a_ty = fcx.expr_ty(*a);
2900 (rest_bot || ty::type_is_bot(a_ty),
2901 rest_err || ty::type_is_error(a_ty))});
2902 if ty::type_is_error(f_ty) || args_err {
2903 fcx.write_error(id);
2905 else if ty::type_is_bot(f_ty) || args_bot {
2909 ast::ExprMethodCall(ident, ref tps, ref args) => {
2910 check_method_call(fcx, expr, ident, *args, *tps);
2911 let arg_tys = args.map(|a| fcx.expr_ty(*a));
2912 let (args_bot, args_err) = arg_tys.iter().fold((false, false),
2913 |(rest_bot, rest_err), a| {
2914 (rest_bot || ty::type_is_bot(*a),
2915 rest_err || ty::type_is_error(*a))});
2917 fcx.write_error(id);
2918 } else if args_bot {
2922 ast::ExprCast(e, t) => {
2924 let t_1 = fcx.to_ty(t);
2925 let t_e = fcx.expr_ty(e);
2927 debug!("t_1={}", fcx.infcx().ty_to_str(t_1));
2928 debug!("t_e={}", fcx.infcx().ty_to_str(t_e));
2930 if ty::type_is_error(t_e) {
2931 fcx.write_error(id);
2933 else if ty::type_is_bot(t_e) {
2937 match ty::get(t_1).sty {
2938 // This will be looked up later on
2939 ty::ty_trait(..) => (),
2942 if ty::type_is_nil(t_e) {
2943 fcx.type_error_message(expr.span, |actual| {
2944 format!("cast from nil: `{}` as `{}`", actual,
2945 fcx.infcx().ty_to_str(t_1))
2947 } else if ty::type_is_nil(t_1) {
2948 fcx.type_error_message(expr.span, |actual| {
2949 format!("cast to nil: `{}` as `{}`", actual,
2950 fcx.infcx().ty_to_str(t_1))
2954 let t1 = structurally_resolved_type(fcx, e.span, t_1);
2955 let te = structurally_resolved_type(fcx, e.span, t_e);
2956 let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
2957 let t_1_is_char = type_is_char(fcx, expr.span, t_1);
2958 let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1);
2960 // casts to scalars other than `char` and `bare fn` are trivial
2961 let t_1_is_trivial = t_1_is_scalar &&
2962 !t_1_is_char && !t_1_is_bare_fn;
2964 if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial {
2965 // casts from C-like enums are allowed
2966 } else if t_1_is_char {
2967 let te = fcx.infcx().resolve_type_vars_if_possible(te);
2968 if ty::get(te).sty != ty::ty_uint(ast::TyU8) {
2969 fcx.type_error_message(expr.span, |actual| {
2970 format!("only `u8` can be cast as `char`, not `{}`", actual)
2973 } else if ty::get(t1).sty == ty::ty_bool {
2974 fcx.tcx().sess.span_err(expr.span,
2975 "cannot cast as `bool`, compare with zero instead");
2976 } else if type_is_region_ptr(fcx, expr.span, t_e) &&
2977 type_is_unsafe_ptr(fcx, expr.span, t_1) {
2979 fn is_vec(t: ty::t) -> bool {
2980 match ty::get(t).sty {
2981 ty::ty_vec(..) => true,
2985 fn types_compatible(fcx: @FnCtxt, sp: Span,
2986 t1: ty::t, t2: ty::t) -> bool {
2990 let el = ty::sequence_element_type(fcx.tcx(),
2992 infer::mk_eqty(fcx.infcx(), false,
2993 infer::Misc(sp), el, t2).is_ok()
2997 // Due to the limitations of LLVM global constants,
2998 // region pointers end up pointing at copies of
2999 // vector elements instead of the original values.
3000 // To allow unsafe pointers to work correctly, we
3001 // need to special-case obtaining an unsafe pointer
3002 // from a region pointer to a vector.
3004 /* this cast is only allowed from &[T] to *T or
3006 match (&ty::get(te).sty, &ty::get(t_1).sty) {
3007 (&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
3008 if types_compatible(fcx, e.span,
3009 mt1.ty, mt2.ty) => {
3010 /* this case is allowed */
3013 demand::coerce(fcx, e.span, t_1, e);
3016 } else if !(type_is_scalar(fcx,expr.span,t_e)
3017 && t_1_is_trivial) {
3019 If more type combinations should be supported than are
3020 supported here, then file an enhancement issue and
3021 record the issue number in this comment.
3023 fcx.type_error_message(expr.span, |actual| {
3024 format!("non-scalar cast: `{}` as `{}`", actual,
3025 fcx.infcx().ty_to_str(t_1))
3030 fcx.write_ty(id, t_1);
3033 ast::ExprVec(ref args, mutbl) => {
3034 let t: ty::t = fcx.infcx().next_ty_var();
3035 for e in args.iter() {
3036 check_expr_has_type(fcx, *e, t);
3038 let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutbl},
3039 ty::vstore_fixed(args.len()));
3040 fcx.write_ty(id, typ);
3042 ast::ExprRepeat(element, count_expr, mutbl) => {
3043 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
3044 let count = ty::eval_repeat_count(fcx, count_expr);
3045 let t: ty::t = fcx.infcx().next_ty_var();
3046 check_expr_has_type(fcx, element, t);
3047 let element_ty = fcx.expr_ty(element);
3048 if ty::type_is_error(element_ty) {
3049 fcx.write_error(id);
3051 else if ty::type_is_bot(element_ty) {
3055 let t = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutbl},
3056 ty::vstore_fixed(count));
3057 fcx.write_ty(id, t);
3060 ast::ExprTup(ref elts) => {
3061 let flds = unpack_expected(fcx, expected, |sty| {
3063 ty::ty_tup(ref flds) => Some((*flds).clone()),
3067 let mut bot_field = false;
3068 let mut err_field = false;
3070 let elt_ts = elts.iter().enumerate().map(|(i, e)| {
3071 let opt_hint = match flds {
3072 Some(ref fs) if i < fs.len() => Some(fs[i]),
3075 check_expr_with_opt_hint(fcx, *e, opt_hint);
3076 let t = fcx.expr_ty(*e);
3077 err_field = err_field || ty::type_is_error(t);
3078 bot_field = bot_field || ty::type_is_bot(t);
3083 } else if err_field {
3084 fcx.write_error(id);
3086 let typ = ty::mk_tup(tcx, elt_ts);
3087 fcx.write_ty(id, typ);
3090 ast::ExprStruct(ref path, ref fields, base_expr) => {
3091 // Resolve the path.
3092 let def_map = tcx.def_map.borrow();
3093 match def_map.get().find(&id) {
3094 Some(&ast::DefStruct(type_def_id)) => {
3095 check_struct_constructor(fcx, id, expr.span, type_def_id,
3096 *fields, base_expr);
3098 Some(&ast::DefVariant(enum_id, variant_id, _)) => {
3099 check_struct_enum_variant(fcx, id, expr.span, enum_id,
3100 variant_id, *fields);
3103 tcx.sess.span_bug(path.span,
3104 "structure constructor does not name a structure type");
3108 ast::ExprField(base, field, ref tys) => {
3109 check_field(fcx, expr, base, field.name, *tys);
3111 ast::ExprIndex(base, idx) => {
3112 check_expr(fcx, base);
3113 check_expr(fcx, idx);
3114 let raw_base_t = fcx.expr_ty(base);
3115 let idx_t = fcx.expr_ty(idx);
3116 if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
3117 fcx.write_ty(id, raw_base_t);
3118 } else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
3119 fcx.write_ty(id, idx_t);
3121 let (base_t, derefs) = do_autoderef(fcx, expr.span, raw_base_t);
3122 let base_sty = structure_of(fcx, expr.span, base_t);
3123 match ty::index_sty(base_sty) {
3125 require_integral(fcx, idx.span, idx_t);
3126 fcx.write_ty(id, mt.ty);
3127 fcx.write_autoderef_adjustment(base.id, derefs);
3130 let resolved = structurally_resolved_type(fcx,
3133 let error_message = || {
3134 fcx.type_error_message(expr.span,
3136 format!("cannot index a value \
3143 let ret_ty = lookup_op_method(fcx,
3146 token::intern("index"),
3147 tcx.lang_items.index_trait(),
3151 fcx.write_ty(id, ret_ty);
3158 debug!("type of expr({}) {} is...", expr.id,
3159 syntax::print::pprust::expr_to_str(expr));
3160 debug!("... {}, expected is {}",
3161 ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
3163 Some(t) => ppaux::ty_to_str(tcx, t),
3170 pub fn require_integral(fcx: @FnCtxt, sp: Span, t: ty::t) {
3171 if !type_is_integral(fcx, sp, t) {
3172 fcx.type_error_message(sp, |actual| {
3173 format!("mismatched types: expected integral type but found `{}`",
3179 pub fn check_decl_initializer(fcx: @FnCtxt,
3183 let local_ty = fcx.local_ty(init.span, nid);
3184 check_expr_coercable_to_type(fcx, init, local_ty)
3187 pub fn check_decl_local(fcx: @FnCtxt, local: &ast::Local) {
3188 let tcx = fcx.ccx.tcx;
3190 let t = fcx.local_ty(local.span, local.id);
3191 fcx.write_ty(local.id, t);
3195 check_decl_initializer(fcx, local.id, init);
3196 let init_ty = fcx.expr_ty(init);
3197 if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
3198 fcx.write_ty(local.id, init_ty);
3204 let pcx = pat_ctxt {
3206 map: pat_id_map(tcx.def_map, local.pat),
3208 _match::check_pat(&pcx, local.pat, t);
3209 let pat_ty = fcx.node_ty(local.pat.id);
3210 if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
3211 fcx.write_ty(local.id, pat_ty);
3215 pub fn check_stmt(fcx: @FnCtxt, stmt: &ast::Stmt) {
3217 let mut saw_bot = false;
3218 let mut saw_err = false;
3220 ast::StmtDecl(decl, id) => {
3223 ast::DeclLocal(ref l) => {
3224 check_decl_local(fcx, *l);
3225 let l_t = fcx.node_ty(l.id);
3226 saw_bot = saw_bot || ty::type_is_bot(l_t);
3227 saw_err = saw_err || ty::type_is_error(l_t);
3229 ast::DeclItem(_) => {/* ignore for now */ }
3232 ast::StmtExpr(expr, id) => {
3234 // Check with expected type of ()
3235 check_expr_has_type(fcx, expr, ty::mk_nil());
3236 let expr_ty = fcx.expr_ty(expr);
3237 saw_bot = saw_bot || ty::type_is_bot(expr_ty);
3238 saw_err = saw_err || ty::type_is_error(expr_ty);
3240 ast::StmtSemi(expr, id) => {
3242 check_expr(fcx, expr);
3243 let expr_ty = fcx.expr_ty(expr);
3244 saw_bot |= ty::type_is_bot(expr_ty);
3245 saw_err |= ty::type_is_error(expr_ty);
3247 ast::StmtMac(..) => fcx.ccx.tcx.sess.bug("unexpanded macro")
3250 fcx.write_bot(node_id);
3253 fcx.write_error(node_id);
3256 fcx.write_nil(node_id)
3260 pub fn check_block_no_value(fcx: @FnCtxt, blk: &ast::Block) {
3261 check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
3262 let blkty = fcx.node_ty(blk.id);
3263 if ty::type_is_error(blkty) {
3264 fcx.write_error(blk.id);
3266 else if ty::type_is_bot(blkty) {
3267 fcx.write_bot(blk.id);
3270 let nilty = ty::mk_nil();
3271 demand::suptype(fcx, blk.span, nilty, blkty);
3275 pub fn check_block(fcx0: @FnCtxt, blk: &ast::Block) {
3276 check_block_with_expected(fcx0, blk, None)
3279 pub fn check_block_with_expected(fcx: @FnCtxt,
3281 expected: Option<ty::t>) {
3283 let mut fcx_ps = fcx.ps.borrow_mut();
3284 let purity_state = fcx_ps.get().recurse(blk);
3285 replace(fcx_ps.get(), purity_state)
3288 fcx.with_region_lb(blk.id, || {
3289 let mut warned = false;
3290 let mut last_was_bot = false;
3291 let mut any_bot = false;
3292 let mut any_err = false;
3293 for s in blk.stmts.iter() {
3294 check_stmt(fcx, *s);
3295 let s_id = ast_util::stmt_id(*s);
3296 let s_ty = fcx.node_ty(s_id);
3297 if last_was_bot && !warned && match s.node {
3298 ast::StmtDecl(decl, _) => {
3300 ast::DeclLocal(_) => true,
3304 ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true,
3307 fcx.ccx.tcx.sess.add_lint(UnreachableCode, s_id, s.span,
3308 ~"unreachable statement");
3311 if ty::type_is_bot(s_ty) {
3312 last_was_bot = true;
3314 any_bot = any_bot || ty::type_is_bot(s_ty);
3315 any_err = any_err || ty::type_is_error(s_ty);
3318 None => if any_err {
3319 fcx.write_error(blk.id);
3322 fcx.write_bot(blk.id);
3325 fcx.write_nil(blk.id);
3328 if any_bot && !warned {
3329 fcx.ccx.tcx.sess.add_lint(UnreachableCode, e.id, e.span,
3330 ~"unreachable expression");
3332 check_expr_with_opt_hint(fcx, e, expected);
3333 let ety = fcx.expr_ty(e);
3334 fcx.write_ty(blk.id, ety);
3336 fcx.write_error(blk.id);
3339 fcx.write_bot(blk.id);
3348 pub fn check_const(ccx: @CrateCtxt,
3352 let rty = ty::node_id_to_type(ccx.tcx, id);
3353 let fcx = blank_fn_ctxt(ccx, rty, e.id);
3355 let tcache = fcx.ccx.tcx.tcache.borrow();
3356 tcache.get().get(&local_def(id)).ty
3358 check_const_with_ty(fcx, sp, e, declty);
3361 pub fn check_const_with_ty(fcx: @FnCtxt,
3366 let cty = fcx.expr_ty(e);
3367 demand::suptype(fcx, e.span, declty, cty);
3368 regionck::regionck_expr(fcx, e);
3369 writeback::resolve_type_vars_in_expr(fcx, e);
3372 /// Checks whether a type can be represented in memory. In particular, it
3373 /// identifies types that contain themselves without indirection through a
3374 /// pointer, which would mean their size is unbounded. This is different from
3375 /// the question of whether a type can be instantiated. See the definition of
3376 /// `check_instantiable`.
3377 pub fn check_representable(tcx: ty::ctxt,
3379 item_id: ast::NodeId,
3380 designation: &str) {
3381 let rty = ty::node_id_to_type(tcx, item_id);
3383 // Check that it is possible to represent this type. This call identifies
3384 // (1) types that contain themselves and (2) types that contain a different
3385 // recursive type. It is only necessary to throw an error on those that
3386 // contain themselves. For case 2, there must be an inner type that will be
3387 // caught by case 1.
3388 match ty::is_type_representable(tcx, rty) {
3389 ty::SelfRecursive => {
3391 sp, format!("illegal recursive {} type; \
3392 wrap the inner value in a box to make it representable",
3395 ty::Representable | ty::ContainsRecursive => (),
3399 /// Checks whether a type can be created without an instance of itself.
3400 /// This is similar but different from the question of whether a type
3401 /// can be represented. For example, the following type:
3403 /// enum foo { None, Some(foo) }
3405 /// is instantiable but is not representable. Similarly, the type
3407 /// enum foo { Some(@foo) }
3409 /// is representable, but not instantiable.
3410 pub fn check_instantiable(tcx: ty::ctxt,
3412 item_id: ast::NodeId) {
3413 let item_ty = ty::node_id_to_type(tcx, item_id);
3414 if !ty::is_instantiable(tcx, item_ty) {
3415 tcx.sess.span_err(sp, format!("this type cannot be instantiated \
3416 without an instance of itself; \
3417 consider using `Option<{}>`",
3418 ppaux::ty_to_str(tcx, item_ty)));
3422 pub fn check_simd(tcx: ty::ctxt, sp: Span, id: ast::NodeId) {
3423 let t = ty::node_id_to_type(tcx, id);
3424 if ty::type_needs_subst(t) {
3425 tcx.sess.span_err(sp, "SIMD vector cannot be generic");
3428 match ty::get(t).sty {
3429 ty::ty_struct(did, ref substs) => {
3430 let fields = ty::lookup_struct_fields(tcx, did);
3431 if fields.is_empty() {
3432 tcx.sess.span_err(sp, "SIMD vector cannot be empty");
3435 let e = ty::lookup_field_type(tcx, did, fields[0].id, substs);
3436 if !fields.iter().all(
3437 |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
3438 tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
3441 if !ty::type_is_machine(e) {
3442 tcx.sess.span_err(sp, "SIMD vector element type should be \
3451 pub fn check_enum_variants(ccx: @CrateCtxt,
3453 vs: &[ast::P<ast::Variant>],
3456 fn disr_in_range(ccx: @CrateCtxt,
3458 disr: ty::Disr) -> bool {
3459 fn uint_in_range(ccx: @CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
3461 ast::TyU8 => disr as u8 as Disr == disr,
3462 ast::TyU16 => disr as u16 as Disr == disr,
3463 ast::TyU32 => disr as u32 as Disr == disr,
3464 ast::TyU64 => disr as u64 as Disr == disr,
3465 ast::TyU => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
3468 fn int_in_range(ccx: @CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
3470 ast::TyI8 => disr as i8 as Disr == disr,
3471 ast::TyI16 => disr as i16 as Disr == disr,
3472 ast::TyI32 => disr as i32 as Disr == disr,
3473 ast::TyI64 => disr as i64 as Disr == disr,
3474 ast::TyI => int_in_range(ccx, ccx.tcx.sess.targ_cfg.int_type, disr)
3478 attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
3479 attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
3483 fn do_check(ccx: @CrateCtxt,
3484 vs: &[ast::P<ast::Variant>],
3486 hint: attr::ReprAttr)
3487 -> ~[@ty::VariantInfo] {
3489 let rty = ty::node_id_to_type(ccx.tcx, id);
3490 let mut variants: ~[@ty::VariantInfo] = ~[];
3491 let mut disr_vals: ~[ty::Disr] = ~[];
3492 let mut prev_disr_val: Option<ty::Disr> = None;
3494 for &v in vs.iter() {
3496 // If the discriminant value is specified explicitly in the enum check whether the
3497 // initialization expression is valid, otherwise use the last value plus one.
3498 let mut current_disr_val = match prev_disr_val {
3499 Some(prev_disr_val) => prev_disr_val + 1,
3500 None => ty::INITIAL_DISCRIMINANT_VALUE
3503 match v.node.disr_expr {
3505 debug!("disr expr, checking {}", pprust::expr_to_str(e));
3507 let fcx = blank_fn_ctxt(ccx, rty, e.id);
3508 let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
3509 check_const_with_ty(fcx, e.span, e, declty);
3510 // check_expr (from check_const pass) doesn't guarantee
3511 // that the expression is in an form that eval_const_expr can
3512 // handle, so we may still get an internal compiler error
3514 match const_eval::eval_const_expr_partial(&ccx.tcx, e) {
3515 Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
3516 Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
3518 ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
3521 ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", *err));
3528 // Check for duplicate discriminant values
3529 if disr_vals.contains(¤t_disr_val) {
3530 ccx.tcx.sess.span_err(v.span, "discriminant value already exists");
3532 // Check for unrepresentable discriminant values
3534 attr::ReprAny | attr::ReprExtern => (),
3535 attr::ReprInt(sp, ity) => {
3536 if !disr_in_range(ccx, ity, current_disr_val) {
3537 ccx.tcx.sess.span_err(v.span,
3538 "discriminant value outside specified type");
3539 ccx.tcx.sess.span_note(sp, "discriminant type specified here");
3543 disr_vals.push(current_disr_val);
3545 let variant_info = @VariantInfo::from_ast_variant(ccx.tcx, v, current_disr_val);
3546 prev_disr_val = Some(current_disr_val);
3548 variants.push(variant_info);
3554 let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id });
3555 if hint != attr::ReprAny && vs.len() <= 1 {
3556 ccx.tcx.sess.span_err(sp, format!("unsupported representation for {}variant enum",
3557 if vs.len() == 1 { "uni" } else { "zero-" }))
3560 let variants = do_check(ccx, vs, id, hint);
3562 // cache so that ty::enum_variants won't repeat this work
3564 let mut enum_var_cache = ccx.tcx.enum_var_cache.borrow_mut();
3565 enum_var_cache.get().insert(local_def(id), @variants);
3568 // Check that it is possible to represent this enum.
3569 check_representable(ccx.tcx, sp, id, "enum");
3571 // Check that it is possible to instantiate this enum:
3573 // This *sounds* like the same that as representable, but it's
3574 // not. See def'n of `check_instantiable()` for details.
3575 check_instantiable(ccx.tcx, sp, id);
3578 pub fn lookup_def(fcx: @FnCtxt, sp: Span, id: ast::NodeId) -> ast::Def {
3579 lookup_def_ccx(fcx.ccx, sp, id)
3582 // Returns the type parameter count and the type for the given definition.
3583 pub fn ty_param_bounds_and_ty_for_def(fcx: @FnCtxt,
3586 -> ty_param_bounds_and_ty {
3588 ast::DefArg(nid, _) | ast::DefLocal(nid, _) |
3589 ast::DefBinding(nid, _) => {
3590 let typ = fcx.local_ty(sp, nid);
3591 return no_params(typ);
3593 ast::DefFn(id, _) | ast::DefStaticMethod(id, _, _) |
3594 ast::DefStatic(id, _) | ast::DefVariant(_, id, _) |
3595 ast::DefStruct(id) => {
3596 return ty::lookup_item_type(fcx.ccx.tcx, id);
3598 ast::DefUpvar(_, inner, _, _) => {
3599 return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
3604 ast::DefTyParam(..)=> {
3605 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type");
3607 ast::DefMod(..) | ast::DefForeignMod(..) => {
3608 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module");
3610 ast::DefUse(..) => {
3611 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use");
3613 ast::DefRegion(..) => {
3614 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region");
3616 ast::DefTyParamBinder(..) => {
3617 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter");
3619 ast::DefLabel(..) => {
3620 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label");
3622 ast::DefSelfTy(..) => {
3623 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty");
3625 ast::DefMethod(..) => {
3626 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method");
3631 // Instantiates the given path, which must refer to an item with the given
3632 // number of type parameters and type.
3633 pub fn instantiate_path(fcx: @FnCtxt,
3635 tpt: ty_param_bounds_and_ty,
3638 node_id: ast::NodeId) {
3639 debug!(">>> instantiate_path");
3641 let ty_param_count = tpt.generics.type_param_defs().len();
3642 let ty_param_req = tpt.generics.type_param_defs().iter()
3643 .take_while(|x| x.default.is_none())
3645 let mut ty_substs_len = 0;
3646 for segment in pth.segments.iter() {
3647 ty_substs_len += segment.types.len()
3650 debug!("tpt={} ty_param_count={:?} ty_substs_len={:?}",
3651 tpt.repr(fcx.tcx()),
3655 // determine the region parameters, using the value given by the user
3656 // (if any) and otherwise using a fresh region variable
3657 let num_expected_regions = tpt.generics.region_param_defs().len();
3658 let num_supplied_regions = pth.segments.last().unwrap().lifetimes.len();
3659 let regions = if num_expected_regions == num_supplied_regions {
3660 pth.segments.last().unwrap().lifetimes.map(
3661 |l| ast_region_to_region(fcx.tcx(), l))
3663 if num_supplied_regions != 0 {
3664 fcx.ccx.tcx.sess.span_err(
3666 format!("expected {} lifetime parameter(s), \
3667 found {} lifetime parameter(s)",
3668 num_expected_regions, num_supplied_regions));
3671 opt_vec::from(fcx.infcx().next_region_vars(
3672 infer::BoundRegionInTypeOrImpl(span),
3673 num_expected_regions))
3675 let regions = ty::NonerasedRegions(regions);
3677 // Special case: If there is a self parameter, omit it from the list of
3680 // Here we calculate the "user type parameter count", which is the number
3681 // of type parameters actually manifest in the AST. This will differ from
3682 // the internal type parameter count when there are self types involved.
3683 let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def {
3684 ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
3685 let generics = generics_of_static_method_container(fcx.ccx.tcx,
3687 (ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs().len()))
3689 _ => (ty_param_count, ty_param_req, None),
3692 // determine values for type parameters, using the values given by
3693 // the user (if any) and otherwise using fresh type variables
3694 let (tps, regions) = if ty_substs_len == 0 {
3695 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3696 } else if ty_param_count == 0 {
3697 fcx.ccx.tcx.sess.span_err
3698 (span, "this item does not take type parameters");
3699 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3700 } else if ty_substs_len > user_ty_param_count {
3701 let expected = if user_ty_param_req < user_ty_param_count {
3706 fcx.ccx.tcx.sess.span_err
3708 format!("too many type parameters provided: {} {}, found {}",
3709 expected, user_ty_param_count, ty_substs_len));
3710 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3711 } else if ty_substs_len < user_ty_param_req {
3712 let expected = if user_ty_param_req < user_ty_param_count {
3717 fcx.ccx.tcx.sess.span_err
3719 format!("not enough type parameters provided: {} {}, found {}",
3720 expected, user_ty_param_req, ty_substs_len));
3721 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3723 if ty_substs_len > user_ty_param_req
3724 && !fcx.tcx().sess.features.default_type_params.get() {
3725 fcx.tcx().sess.span_err(pth.span, "default type parameters are \
3726 experimental and possibly buggy");
3727 fcx.tcx().sess.span_note(pth.span, "add #[feature(default_type_params)] \
3728 to the crate attributes to enable");
3731 // Build up the list of type parameters, inserting the self parameter
3732 // at the appropriate position.
3734 let mut pushed = false;
3735 for (i, ty) in pth.segments.iter()
3736 .flat_map(|segment| segment.types.iter())
3737 .map(|&ast_type| fcx.to_ty(ast_type))
3739 match self_parameter_index {
3740 Some(index) if index == i => {
3741 tps.push(fcx.infcx().next_ty_vars(1)[0]);
3749 let mut substs = substs {
3755 let defaults = tpt.generics.type_param_defs().iter()
3756 .enumerate().filter_map(|(i, x)| {
3757 match self_parameter_index {
3758 Some(index) if index == i => None,
3759 _ => Some(x.default)
3762 for (i, default) in defaults.skip(ty_substs_len).enumerate() {
3763 match self_parameter_index {
3764 Some(index) if index == i + ty_substs_len => {
3765 substs.tps.push(fcx.infcx().next_ty_vars(1)[0]);
3772 let ty = default.subst_spanned(fcx.tcx(), &substs, Some(span));
3773 substs.tps.push(ty);
3776 fcx.tcx().sess.span_bug(span,
3777 "missing default for a not explicitely provided type param")
3782 // If the self parameter goes at the end, insert it there.
3783 if !pushed && self_parameter_index.is_some() {
3784 substs.tps.push(fcx.infcx().next_ty_vars(1)[0])
3787 assert_eq!(substs.tps.len(), ty_param_count)
3789 let substs {tps, regions, ..} = substs;
3793 fcx.write_ty_substs(node_id, tpt.ty, substs {
3802 // Resolves `typ` by a single level if `typ` is a type variable. If no
3803 // resolution is possible, then an error is reported.
3804 pub fn structurally_resolved_type(fcx: &FnCtxt, sp: Span, tp: ty::t) -> ty::t {
3805 match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
3806 Ok(t_s) if !ty::type_is_ty_var(t_s) => t_s,
3808 fcx.type_error_message(sp, |_actual| {
3809 ~"the type of this value must be known in this context"
3811 demand::suptype(fcx, sp, ty::mk_err(), tp);
3817 // Returns the one-level-deep structure of the given type.
3818 pub fn structure_of<'a>(fcx: @FnCtxt, sp: Span, typ: ty::t)
3820 &ty::get(structurally_resolved_type(fcx, sp, typ)).sty
3823 pub fn type_is_integral(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3824 let typ_s = structurally_resolved_type(fcx, sp, typ);
3825 return ty::type_is_integral(typ_s);
3828 pub fn type_is_scalar(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3829 let typ_s = structurally_resolved_type(fcx, sp, typ);
3830 return ty::type_is_scalar(typ_s);
3833 pub fn type_is_char(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3834 let typ_s = structurally_resolved_type(fcx, sp, typ);
3835 return ty::type_is_char(typ_s);
3838 pub fn type_is_bare_fn(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3839 let typ_s = structurally_resolved_type(fcx, sp, typ);
3840 return ty::type_is_bare_fn(typ_s);
3843 pub fn type_is_unsafe_ptr(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3844 let typ_s = structurally_resolved_type(fcx, sp, typ);
3845 return ty::type_is_unsafe_ptr(typ_s);
3848 pub fn type_is_region_ptr(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3849 let typ_s = structurally_resolved_type(fcx, sp, typ);
3850 return ty::type_is_region_ptr(typ_s);
3853 pub fn type_is_c_like_enum(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3854 let typ_s = structurally_resolved_type(fcx, sp, typ);
3855 return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
3858 pub fn ast_expr_vstore_to_vstore(fcx: @FnCtxt,
3863 ast::ExprVstoreUniq => ty::vstore_uniq,
3864 ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => {
3866 ast::ExprLit(..) => {
3867 // string literals and *empty slices* live in static memory
3868 ty::vstore_slice(ty::ReStatic)
3870 ast::ExprVec(ref elements, _) if elements.len() == 0 => {
3871 // string literals and *empty slices* live in static memory
3872 ty::vstore_slice(ty::ReStatic)
3874 ast::ExprRepeat(..) |
3875 ast::ExprVec(..) => {
3876 // vector literals are temporaries on the stack
3877 match fcx.tcx().region_maps.temporary_scope(e.id) {
3879 let r = ty::ReScope(scope);
3883 // this slice occurs in a static somewhere
3884 ty::vstore_slice(ty::ReStatic)
3889 fcx.ccx.tcx.sess.span_bug(
3890 e.span, format!("vstore with unexpected contents"))
3897 // Returns true if b contains a break that can exit from b
3898 pub fn may_break(cx: ty::ctxt, id: ast::NodeId, b: ast::P<ast::Block>) -> bool {
3899 // First: is there an unlabeled break immediately
3901 (loop_query(b, |e| {
3903 ast::ExprBreak(_) => true,
3907 // Second: is there a labeled break with label
3908 // <id> nested anywhere inside the loop?
3909 (block_query(b, |e| {
3911 ast::ExprBreak(Some(_)) => {
3912 let def_map = cx.def_map.borrow();
3913 match def_map.get().find(&e.id) {
3914 Some(&ast::DefLabel(loop_id)) if id == loop_id => true,
3922 pub fn check_bounds_are_used(ccx: @CrateCtxt,
3924 tps: &OptVec<ast::TyParam>,
3926 debug!("check_bounds_are_used(n_tps={}, ty={})",
3927 tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
3929 // make a vector of booleans initially false, set to true when used
3930 if tps.len() == 0u { return; }
3931 let mut tps_used = vec::from_elem(tps.len(), false);
3933 ty::walk_ty(ty, |t| {
3934 match ty::get(t).sty {
3935 ty::ty_param(param_ty {idx, ..}) => {
3936 debug!("Found use of ty param \\#{}", idx);
3937 tps_used[idx] = true;
3943 for (i, b) in tps_used.iter().enumerate() {
3945 ccx.tcx.sess.span_err(
3946 span, format!("type parameter `{}` is unused",
3947 token::get_ident(tps.get(i).ident)));
3952 pub fn check_intrinsic_type(ccx: @CrateCtxt, it: &ast::ForeignItem) {
3953 fn param(ccx: @CrateCtxt, n: uint) -> ty::t {
3954 ty::mk_param(ccx.tcx, n, local_def(0))
3958 let name = token::get_ident(it.ident);
3959 let (n_tps, inputs, output) = if name.get().starts_with("atomic_") {
3960 let split : ~[&str] = name.get().split('_').collect();
3961 assert!(split.len() >= 2, "Atomic intrinsic not correct format");
3963 //We only care about the operation here
3965 "cxchg" => (1, ~[ty::mk_mut_rptr(tcx,
3966 ty::ReLateBound(it.id, ty::BrAnon(0)),
3973 ty::mk_imm_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)),
3979 ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)),
3985 "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
3986 "min" | "umax" | "umin" => {
3987 (1, ~[ty::mk_mut_rptr(tcx,
3988 ty::ReLateBound(it.id, ty::BrAnon(0)),
3989 param(ccx, 0)), param(ccx, 0) ],
3993 (0, ~[], ty::mk_nil())
3996 tcx.sess.span_err(it.span,
3997 format!("unrecognized atomic operation function: `{}`",
4005 "abort" => (0, ~[], ty::mk_bot()),
4006 "breakpoint" => (0, ~[], ty::mk_nil()),
4008 "pref_align_of" | "min_align_of" => (1u, ~[], ty::mk_uint()),
4009 "init" => (1u, ~[], param(ccx, 0u)),
4010 "uninit" => (1u, ~[], param(ccx, 0u)),
4011 "forget" => (1u, ~[ param(ccx, 0) ], ty::mk_nil()),
4012 "transmute" => (2, ~[ param(ccx, 0) ], param(ccx, 1)),
4013 "move_val_init" => {
4016 ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), param(ccx, 0)),
4021 "needs_drop" => (1u, ~[], ty::mk_bool()),
4022 "owns_managed" => (1u, ~[], ty::mk_bool()),
4025 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4027 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4029 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4031 mutbl: ast::MutImmutable
4036 let langid = ccx.tcx.lang_items.require(TypeIdLangItem);
4038 Ok(did) => (1u, ~[], ty::mk_struct(ccx.tcx, did, substs {
4041 regions: ty::NonerasedRegions(opt_vec::Empty)
4043 Err(msg) => { tcx.sess.span_fatal(it.span, msg); }
4047 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4049 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4051 let region = ty::ReLateBound(it.id, ty::BrAnon(0));
4052 let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
4053 Ok((_, vot)) => vot,
4054 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4057 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4059 mutbl: ast::MutImmutable
4061 (0, ~[ td_ptr, visitor_object_ty ], ty::mk_nil())
4066 ty::mk_ptr(tcx, ty::mt {
4068 mutbl: ast::MutImmutable
4072 ty::mk_ptr(tcx, ty::mt {
4074 mutbl: ast::MutImmutable
4077 "copy_nonoverlapping_memory" => {
4080 ty::mk_ptr(tcx, ty::mt {
4082 mutbl: ast::MutMutable
4084 ty::mk_ptr(tcx, ty::mt {
4086 mutbl: ast::MutImmutable
4095 ty::mk_ptr(tcx, ty::mt {
4097 mutbl: ast::MutMutable
4099 ty::mk_ptr(tcx, ty::mt {
4101 mutbl: ast::MutImmutable
4110 ty::mk_ptr(tcx, ty::mt {
4112 mutbl: ast::MutMutable
4119 "sqrtf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4120 "sqrtf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4123 ~[ ty::mk_f32(), ty::mk_i32() ],
4128 ~[ ty::mk_f64(), ty::mk_i32() ],
4131 "sinf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4132 "sinf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4133 "cosf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4134 "cosf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4137 ~[ ty::mk_f32(), ty::mk_f32() ],
4142 ~[ ty::mk_f64(), ty::mk_f64() ],
4145 "expf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4146 "expf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4147 "exp2f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4148 "exp2f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4149 "logf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4150 "logf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4151 "log10f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4152 "log10f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4153 "log2f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4154 "log2f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4157 ~[ ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ],
4162 ~[ ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ],
4165 "fabsf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4166 "fabsf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4167 "copysignf32" => (0, ~[ ty::mk_f32(), ty::mk_f32() ], ty::mk_f32()),
4168 "copysignf64" => (0, ~[ ty::mk_f64(), ty::mk_f64() ], ty::mk_f64()),
4169 "floorf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4170 "floorf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4171 "ceilf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4172 "ceilf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4173 "truncf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4174 "truncf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4175 "rintf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4176 "rintf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4177 "nearbyintf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4178 "nearbyintf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4179 "roundf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
4180 "roundf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
4181 "ctpop8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()),
4182 "ctpop16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
4183 "ctpop32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
4184 "ctpop64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
4185 "ctlz8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()),
4186 "ctlz16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
4187 "ctlz32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
4188 "ctlz64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
4189 "cttz8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()),
4190 "cttz16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
4191 "cttz32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
4192 "cttz64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
4193 "bswap16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
4194 "bswap32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
4195 "bswap64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
4198 (1, ~[ ty::mk_imm_ptr(tcx, param(ccx, 0)) ], param(ccx, 0)),
4200 (1, ~[ ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ], ty::mk_nil()),
4202 "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
4203 (0, ~[ty::mk_i8(), ty::mk_i8()],
4204 ty::mk_tup(tcx, ~[ty::mk_i8(), ty::mk_bool()])),
4206 "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
4207 (0, ~[ty::mk_i16(), ty::mk_i16()],
4208 ty::mk_tup(tcx, ~[ty::mk_i16(), ty::mk_bool()])),
4210 "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
4211 (0, ~[ty::mk_i32(), ty::mk_i32()],
4212 ty::mk_tup(tcx, ~[ty::mk_i32(), ty::mk_bool()])),
4214 "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
4215 (0, ~[ty::mk_i64(), ty::mk_i64()],
4216 ty::mk_tup(tcx, ~[ty::mk_i64(), ty::mk_bool()])),
4218 "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
4219 (0, ~[ty::mk_u8(), ty::mk_u8()],
4220 ty::mk_tup(tcx, ~[ty::mk_u8(), ty::mk_bool()])),
4222 "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
4223 (0, ~[ty::mk_u16(), ty::mk_u16()],
4224 ty::mk_tup(tcx, ~[ty::mk_u16(), ty::mk_bool()])),
4226 "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
4227 (0, ~[ty::mk_u32(), ty::mk_u32()],
4228 ty::mk_tup(tcx, ~[ty::mk_u32(), ty::mk_bool()])),
4230 "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" =>
4231 (0, ~[ty::mk_u64(), ty::mk_u64()],
4232 ty::mk_tup(tcx, ~[ty::mk_u64(), ty::mk_bool()])),
4235 tcx.sess.span_err(it.span,
4236 format!("unrecognized intrinsic function: `{}`",
4242 let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
4243 purity: ast::UnsafeFn,
4244 abis: AbiSet::Intrinsic(),
4245 sig: FnSig {binder_id: it.id,
4250 let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
4251 let i_n_tps = i_ty.generics.type_param_defs().len();
4252 if i_n_tps != n_tps {
4253 tcx.sess.span_err(it.span, format!("intrinsic has wrong number \
4254 of type parameters: found {}, \
4255 expected {}", i_n_tps, n_tps));
4258 tcx, None, false, it.span, i_ty.ty, fty,
4259 || format!("intrinsic has wrong type: \
4261 ppaux::ty_to_str(ccx.tcx, fty)));