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_late_bound_regions_in_fn_sig;
101 use middle::typeck::check::regionmanip::relate_free_regions;
102 use middle::typeck::check::vtable::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, vtable_map};
110 use middle::typeck::{MethodCall, MethodMap};
111 use middle::lang_items::TypeIdLangItem;
112 use util::common::{block_query, indenter, loop_query};
114 use util::ppaux::{UserString, Repr};
115 use util::nodemap::{FnvHashMap, NodeMap};
117 use std::cell::{Cell, RefCell};
118 use collections::HashMap;
119 use std::mem::replace;
122 use std::vec_ng::Vec;
124 use syntax::abi::AbiSet;
125 use syntax::ast::{Provided, Required};
127 use syntax::ast_util::local_def;
128 use syntax::ast_util;
130 use syntax::codemap::Span;
132 use syntax::opt_vec::OptVec;
134 use syntax::parse::token;
135 use syntax::print::pprust;
137 use syntax::visit::Visitor;
148 /// Fields that are part of a `FnCtxt` which are inherited by
149 /// closures defined within the function. For example:
152 /// bar(proc() { ... })
155 /// Here, the function `foo()` and the closure passed to
156 /// `bar()` will each have their own `FnCtxt`, but they will
157 /// share the inherited fields.
158 pub struct Inherited {
159 infcx: infer::InferCtxt,
160 locals: @RefCell<NodeMap<ty::t>>,
161 param_env: ty::ParameterEnvironment,
164 node_types: RefCell<NodeMap<ty::t>>,
165 node_type_substs: RefCell<NodeMap<ty::substs>>,
166 adjustments: RefCell<NodeMap<@ty::AutoAdjustment>>,
167 method_map: MethodMap,
168 vtable_map: vtable_map,
169 upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
177 // A normal closure or fn item.
182 pub struct PurityState {
189 pub fn function(purity: ast::Purity, def: ast::NodeId) -> PurityState {
190 PurityState { def: def, purity: purity, from_fn: true }
193 pub fn recurse(&mut self, blk: &ast::Block) -> PurityState {
195 // If this unsafe, then if the outer function was already marked as
196 // unsafe we shouldn't attribute the unsafe'ness to the block. This
197 // way the block can be warned about instead of ignoring this
198 // extraneous block (functions are never warned about).
199 ast::UnsafeFn if self.from_fn => *self,
202 let (purity, def) = match blk.rules {
203 ast::UnsafeBlock(..) => (ast::UnsafeFn, blk.id),
204 ast::DefaultBlock => (purity, self.def),
206 PurityState{ def: def,
214 /// Whether `check_binop` is part of an assignment or not.
215 /// Used to know wether we allow user overloads and to print
216 /// better messages on error.
218 enum IsBinopAssignment{
225 // Number of errors that had been reported when we started
226 // checking this function. On exit, if we find that *more* errors
227 // have been reported, we will skip regionck and other work that
228 // expects the types within the function to be consistent.
229 err_count_on_creation: uint,
232 ps: RefCell<PurityState>,
234 // Sometimes we generate region pointers where the precise region
235 // to use is not known. For example, an expression like `&x.f`
236 // where `x` is of type `@T`: in this case, we will be rooting
237 // `x` onto the stack frame, and we could choose to root it until
238 // the end of (almost) any enclosing block or expression. We
239 // want to pick the narrowest block that encompasses all uses.
241 // What we do in such cases is to generate a region variable with
242 // `region_lb` as a lower bound. The regionck pass then adds
243 // other constriants based on how the variable is used and region
244 // inference selects the ultimate value. Finally, borrowck is
245 // charged with guaranteeing that the value whose address was taken
246 // can actually be made to live as long as it needs to live.
247 region_lb: Cell<ast::NodeId>,
249 // Says whether we're inside a for loop, in a do block
250 // or neither. Helps with error messages involving the
251 // function return type.
260 fn new(tcx: ty::ctxt,
261 param_env: ty::ParameterEnvironment)
264 infcx: infer::new_infer_ctxt(tcx),
265 locals: @RefCell::new(NodeMap::new()),
266 param_env: param_env,
267 node_types: RefCell::new(NodeMap::new()),
268 node_type_substs: RefCell::new(NodeMap::new()),
269 adjustments: RefCell::new(NodeMap::new()),
270 method_map: @RefCell::new(FnvHashMap::new()),
271 vtable_map: @RefCell::new(NodeMap::new()),
272 upvar_borrow_map: RefCell::new(HashMap::new()),
277 // Used by check_const and check_enum_variants
278 pub fn blank_fn_ctxt(ccx: @CrateCtxt,
280 region_bnd: ast::NodeId)
282 // It's kind of a kludge to manufacture a fake function context
283 // and statement context, but we might as well do write the code only once
284 let param_env = ty::ParameterEnvironment { free_substs: substs::empty(),
285 self_param_bound: None,
286 type_param_bounds: Vec::new() };
288 err_count_on_creation: ccx.tcx.sess.err_count(),
290 ps: RefCell::new(PurityState::function(ast::ImpureFn, 0)),
291 region_lb: Cell::new(region_bnd),
293 inh: @Inherited::new(ccx.tcx, param_env),
298 impl ExprTyProvider for FnCtxt {
299 fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
303 fn ty_ctxt(&self) -> ty::ctxt {
308 struct CheckItemTypesVisitor { ccx: @CrateCtxt }
310 impl Visitor<()> for CheckItemTypesVisitor {
311 fn visit_item(&mut self, i: &ast::Item, _: ()) {
312 check_item(self.ccx, i);
313 visit::walk_item(self, i, ());
317 pub fn check_item_types(ccx: @CrateCtxt, krate: &ast::Crate) {
318 let mut visit = CheckItemTypesVisitor { ccx: ccx };
319 visit::walk_crate(&mut visit, krate, ());
322 fn check_bare_fn(ccx: @CrateCtxt,
327 param_env: ty::ParameterEnvironment) {
328 match ty::get(fty).sty {
329 ty::ty_bare_fn(ref fn_ty) => {
331 check_fn(ccx, fn_ty.purity, &fn_ty.sig, decl, id, body,
332 Vanilla, @Inherited::new(ccx.tcx, param_env));
334 vtable::resolve_in_block(fcx, body);
335 regionck::regionck_fn(fcx, body);
336 writeback::resolve_type_vars_in_fn(fcx, decl, body);
338 _ => ccx.tcx.sess.impossible_case(body.span,
339 "check_bare_fn: function type expected")
343 struct GatherLocalsVisitor {
348 impl GatherLocalsVisitor {
349 fn assign(&mut self, nid: ast::NodeId, ty_opt: Option<ty::t>) {
352 // infer the variable's type
353 let var_id = self.fcx.infcx().next_ty_var_id();
354 let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
355 let mut locals = self.fcx.inh.locals.borrow_mut();
356 locals.get().insert(nid, var_ty);
359 // take type that the user specified
360 let mut locals = self.fcx.inh.locals.borrow_mut();
361 locals.get().insert(nid, typ);
367 impl Visitor<()> for GatherLocalsVisitor {
368 // Add explicitly-declared locals.
369 fn visit_local(&mut self, local: &ast::Local, _: ()) {
370 let o_ty = match local.ty.node {
371 ast::TyInfer => None,
372 _ => Some(self.fcx.to_ty(local.ty))
374 self.assign(local.id, o_ty);
376 let locals = self.fcx.inh.locals.borrow();
377 debug!("Local variable {} is assigned type {}",
378 self.fcx.pat_to_str(local.pat),
379 self.fcx.infcx().ty_to_str(
380 locals.get().get_copy(&local.id)));
382 visit::walk_local(self, local, ());
385 // Add pattern bindings.
386 fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
388 ast::PatIdent(_, ref path, _)
389 if pat_util::pat_is_binding(self.fcx.ccx.tcx.def_map, p) => {
390 self.assign(p.id, None);
392 let locals = self.fcx.inh.locals.borrow();
393 debug!("Pattern binding {} is assigned to {}",
394 token::get_ident(path.segments.get(0).identifier),
395 self.fcx.infcx().ty_to_str(
396 locals.get().get_copy(&p.id)));
401 visit::walk_pat(self, p, ());
405 fn visit_block(&mut self, b: &ast::Block, _: ()) {
406 // non-obvious: the `blk` variable maps to region lb, so
407 // we have to keep this up-to-date. This
408 // is... unfortunate. It'd be nice to not need this.
409 self.fcx.with_region_lb(b.id, || visit::walk_block(self, b, ()));
412 // Don't descend into fns and items
413 fn visit_fn(&mut self, _: &visit::FnKind, _: &ast::FnDecl,
414 _: &ast::Block, _: Span, _: ast::NodeId, _: ()) { }
415 fn visit_item(&mut self, _: &ast::Item, _: ()) { }
419 fn check_fn(ccx: @CrateCtxt,
426 inherited: @Inherited) -> @FnCtxt
429 * Helper used by check_bare_fn and check_expr_fn. Does the
430 * grungy work of checking a function body and returns the
431 * function context used for that purpose, since in the case of a
432 * fn item there is still a bit more to do.
435 * - inherited: other fields inherited from the enclosing fn (if any)
439 let err_count_on_creation = tcx.sess.err_count();
441 // First, we have to replace any bound regions in the fn type with free ones.
442 // The free region references will be bound the node_id of the body block.
443 let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(tcx, fn_sig, |br| {
444 ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
447 relate_free_regions(tcx, &fn_sig);
449 let arg_tys = fn_sig.inputs.as_slice();
450 let ret_ty = fn_sig.output;
452 debug!("check_fn(arg_tys={:?}, ret_ty={:?})",
453 arg_tys.map(|&a| ppaux::ty_to_str(tcx, a)),
454 ppaux::ty_to_str(tcx, ret_ty));
456 // Create the function context. This is either derived from scratch or,
457 // in the case of function expressions, based on the outer context.
459 err_count_on_creation: err_count_on_creation,
461 ps: RefCell::new(PurityState::function(purity, id)),
462 region_lb: Cell::new(body.id),
470 let mut visit = GatherLocalsVisitor { fcx: fcx, tcx: tcx, };
471 // Add formal parameters.
472 for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
473 // Create type variables for each argument.
474 pat_util::pat_bindings(tcx.def_map,
476 |_bm, pat_id, _sp, _path| {
477 visit.assign(pat_id, None);
480 // Check the pattern.
483 map: pat_id_map(tcx.def_map, input.pat),
485 _match::check_pat(&pcx, input.pat, *arg_ty);
488 visit.visit_block(body, ());
491 check_block_with_expected(fcx, body, Some(ret_ty));
493 // We unify the tail expr's type with the
494 // function result type, if there is a tail expr.
497 // Special case: we print a special error if there appears
498 // to be do-block/for-loop confusion
499 demand::suptype_with_fn(fcx, tail_expr.span, false,
500 fcx.ret_ty, fcx.expr_ty(tail_expr),
502 fcx.report_mismatched_return_types(sp, e, a, s);
508 for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
509 fcx.write_ty(input.id, *arg);
515 pub fn check_no_duplicate_fields(tcx: ty::ctxt,
516 fields: Vec<(ast::Ident, Span)> ) {
517 let mut field_names = HashMap::new();
519 for p in fields.iter() {
521 let orig_sp = field_names.find(&id).map(|x| *x);
524 tcx.sess.span_err(sp, format!("duplicate field name {} in record type declaration",
525 token::get_ident(id)));
526 tcx.sess.span_note(orig_sp, "first declaration of this field occurred here");
530 field_names.insert(id, sp);
536 pub fn check_struct(ccx: @CrateCtxt, id: ast::NodeId, span: Span) {
539 // Check that the struct is representable
540 check_representable(tcx, span, id, "struct");
542 // Check that the struct is instantiable
543 check_instantiable(tcx, span, id);
545 if ty::lookup_simd(tcx, local_def(id)) {
546 check_simd(tcx, span, id);
550 pub fn check_item(ccx: @CrateCtxt, it: &ast::Item) {
551 debug!("check_item(it.id={}, it.ident={})",
553 ty::item_path_str(ccx.tcx, local_def(it.id)));
554 let _indenter = indenter();
557 ast::ItemStatic(_, _, e) => check_const(ccx, it.span, e, it.id),
558 ast::ItemEnum(ref enum_definition, _) => {
559 check_enum_variants(ccx,
561 enum_definition.variants.as_slice(),
564 ast::ItemFn(decl, _, _, _, body) => {
565 let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
567 let param_env = ty::construct_parameter_environment(
570 fn_tpt.generics.type_param_defs(),
573 fn_tpt.generics.region_param_defs.deref().as_slice(),
576 check_bare_fn(ccx, decl, body, it.id, fn_tpt.ty, param_env);
578 ast::ItemImpl(_, ref opt_trait_ref, _, ref ms) => {
579 debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
581 let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
583 check_method_body(ccx, &impl_tpt.generics, None, *m);
586 match *opt_trait_ref {
587 Some(ref ast_trait_ref) => {
589 ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id);
590 check_impl_methods_against_trait(ccx,
596 vtable::resolve_impl(ccx.tcx, it, &impl_tpt.generics, impl_trait_ref);
602 ast::ItemTrait(_, _, ref trait_methods) => {
603 let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
604 for trait_method in (*trait_methods).iter() {
605 match *trait_method {
607 // Nothing to do, since required methods don't have
611 check_method_body(ccx, &trait_def.generics,
612 Some(trait_def.trait_ref), m);
617 ast::ItemStruct(..) => {
618 check_struct(ccx, it.id, it.span);
620 ast::ItemTy(ref t, ref generics) => {
621 let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id);
622 check_bounds_are_used(ccx, t.span, &generics.ty_params, tpt_ty);
624 ast::ItemForeignMod(ref m) => {
625 if m.abis.is_intrinsic() {
626 for item in m.items.iter() {
627 check_intrinsic_type(ccx, *item);
630 for item in m.items.iter() {
631 let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id));
632 if tpt.generics.has_type_params() {
633 ccx.tcx.sess.span_err(item.span, "foreign items may not have type parameters");
637 ast::ForeignItemFn(ref fn_decl, _) => {
638 if fn_decl.variadic && !m.abis.is_c() {
639 ccx.tcx.sess.span_err(
640 item.span, "variadic function must have C calling convention");
648 _ => {/* nothing to do */ }
652 fn check_method_body(ccx: @CrateCtxt,
653 item_generics: &ty::Generics,
654 self_bound: Option<@ty::TraitRef>,
655 method: &ast::Method) {
657 * Type checks a method body.
660 * - `item_generics`: generics defined on the impl/trait that contains
662 * - `self_bound`: bound for the `Self` type parameter, if any
663 * - `method`: the method definition
666 debug!("check_method_body(item_generics={}, \
669 item_generics.repr(ccx.tcx),
670 self_bound.repr(ccx.tcx),
672 let method_def_id = local_def(method.id);
673 let method_ty = ty::method(ccx.tcx, method_def_id);
674 let method_generics = &method_ty.generics;
677 ty::construct_parameter_environment(
680 item_generics.type_param_defs(),
681 method_generics.type_param_defs(),
682 item_generics.region_param_defs(),
683 method_generics.region_param_defs(),
686 // Compute the fty from point of view of inside fn
687 let fty = ty::node_id_to_type(ccx.tcx, method.id);
688 let fty = fty.subst(ccx.tcx, ¶m_env.free_substs);
690 check_bare_fn(ccx, method.decl, method.body, method.id, fty, param_env);
693 fn check_impl_methods_against_trait(ccx: @CrateCtxt,
695 impl_generics: &ty::Generics,
696 ast_trait_ref: &ast::TraitRef,
697 impl_trait_ref: &ty::TraitRef,
698 impl_methods: &[@ast::Method]) {
699 // Locate trait methods
701 let trait_methods = ty::trait_methods(tcx, impl_trait_ref.def_id);
703 // Check existing impl methods to see if they are both present in trait
704 // and compatible with trait signature
705 for impl_method in impl_methods.iter() {
706 let impl_method_def_id = local_def(impl_method.id);
707 let impl_method_ty = ty::method(ccx.tcx, impl_method_def_id);
709 // If this is an impl of a trait method, find the corresponding
710 // method definition in the trait.
711 let opt_trait_method_ty =
712 trait_methods.iter().
713 find(|tm| tm.ident.name == impl_method_ty.ident.name);
714 match opt_trait_method_ty {
715 Some(trait_method_ty) => {
716 compare_impl_method(ccx.tcx,
722 &impl_trait_ref.substs);
727 format!("method `{}` is not a member of trait `{}`",
728 token::get_ident(impl_method_ty.ident),
729 pprust::path_to_str(&ast_trait_ref.path)));
734 // Check for missing methods from trait
735 let provided_methods = ty::provided_trait_methods(tcx,
736 impl_trait_ref.def_id);
737 let mut missing_methods = Vec::new();
738 for trait_method in trait_methods.iter() {
740 impl_methods.iter().any(
741 |m| m.ident.name == trait_method.ident.name);
743 provided_methods.iter().any(
744 |m| m.ident.name == trait_method.ident.name);
745 if !is_implemented && !is_provided {
746 missing_methods.push(
747 format!("`{}`", token::get_ident(trait_method.ident)));
751 if !missing_methods.is_empty() {
754 format!("not all trait methods implemented, missing: {}",
755 missing_methods.connect(", ")));
760 * Checks that a method from an impl/class conforms to the signature of
761 * the same method as declared in the trait.
765 * - impl_generics: the generics declared on the impl itself (not the method!)
766 * - impl_m: type of the method we are checking
767 * - impl_m_span: span to use for reporting errors
768 * - impl_m_body_id: id of the method body
769 * - trait_m: the method in the trait
770 * - trait_substs: the substitutions used on the type of the trait
772 fn compare_impl_method(tcx: ty::ctxt,
773 impl_generics: &ty::Generics,
776 impl_m_body_id: ast::NodeId,
777 trait_m: &ty::Method,
778 trait_substs: &ty::substs) {
779 debug!("compare_impl_method()");
780 let infcx = infer::new_infer_ctxt(tcx);
782 let impl_tps = impl_generics.type_param_defs().len();
784 // Try to give more informative error messages about self typing
785 // mismatches. Note that any mismatch will also be detected
786 // below, where we construct a canonical function type that
787 // includes the self parameter as a normal parameter. It's just
788 // that the error messages you get out of this code are a bit more
789 // inscrutable, particularly for cases where one method has no
791 match (&trait_m.explicit_self, &impl_m.explicit_self) {
792 (&ast::SelfStatic, &ast::SelfStatic) => {}
793 (&ast::SelfStatic, _) => {
796 format!("method `{}` has a `{}` declaration in the impl, \
797 but not in the trait",
798 token::get_ident(trait_m.ident),
799 pprust::explicit_self_to_str(&impl_m.explicit_self)));
802 (_, &ast::SelfStatic) => {
805 format!("method `{}` has a `{}` declaration in the trait, \
806 but not in the impl",
807 token::get_ident(trait_m.ident),
808 pprust::explicit_self_to_str(&trait_m.explicit_self)));
812 // Let the type checker catch other errors below
816 let num_impl_m_type_params = impl_m.generics.type_param_defs().len();
817 let num_trait_m_type_params = trait_m.generics.type_param_defs().len();
818 if num_impl_m_type_params != num_trait_m_type_params {
821 format!("method `{method}` has {nimpl, plural, =1{# type parameter} \
822 other{# type parameters}}, \
823 but its trait declaration has {ntrait, plural, =1{# type parameter} \
824 other{# type parameters}}",
825 method = token::get_ident(trait_m.ident),
826 nimpl = num_impl_m_type_params,
827 ntrait = num_trait_m_type_params));
831 if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() {
834 format!("method `{method}` has {nimpl, plural, =1{# parameter} \
835 other{# parameters}} \
836 but the declaration in trait `{trait}` has {ntrait}",
837 method = token::get_ident(trait_m.ident),
838 nimpl = impl_m.fty.sig.inputs.len(),
839 trait = ty::item_path_str(tcx, trait_m.def_id),
840 ntrait = trait_m.fty.sig.inputs.len()));
844 let it = trait_m.generics.type_param_defs().iter()
845 .zip(impl_m.generics.type_param_defs().iter());
847 for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
848 // Check that the impl does not require any builtin-bounds
849 // that the trait does not guarantee:
851 impl_param_def.bounds.builtin_bounds -
852 trait_param_def.bounds.builtin_bounds;
853 if !extra_bounds.is_empty() {
856 format!("in method `{}`, \
857 type parameter {} requires `{}`, \
858 which is not required by \
859 the corresponding type parameter \
860 in the trait declaration",
861 token::get_ident(trait_m.ident),
863 extra_bounds.user_string(tcx)));
867 // FIXME(#2687)---we should be checking that the bounds of the
868 // trait imply the bounds of the subtype, but it appears we
869 // are...not checking this.
870 if impl_param_def.bounds.trait_bounds.len() !=
871 trait_param_def.bounds.trait_bounds.len()
875 format!("in method `{method}`, \
876 type parameter {typaram} has \
877 {nimpl, plural, =1{# trait bound} other{# trait bounds}}, \
878 but the corresponding type parameter in \
879 the trait declaration has \
880 {ntrait, plural, =1{# trait bound} other{# trait bounds}}",
881 method = token::get_ident(trait_m.ident),
883 nimpl = impl_param_def.bounds.trait_bounds.len(),
884 ntrait = trait_param_def.bounds.trait_bounds.len()));
889 // Create a substitution that maps the type parameters on the impl
890 // to themselves and which replace any references to bound regions
891 // in the self type with free regions. So, for example, if the
892 // impl type is "&'a str", then this would replace the self
893 // type with a free region `self`.
894 let dummy_impl_tps: Vec<ty::t> =
895 impl_generics.type_param_defs().iter().enumerate().
896 map(|(i,t)| ty::mk_param(tcx, i, t.def_id)).
898 let dummy_method_tps: Vec<ty::t> =
899 impl_m.generics.type_param_defs().iter().enumerate().
900 map(|(i,t)| ty::mk_param(tcx, i + impl_tps, t.def_id)).
902 let dummy_impl_regions: OptVec<ty::Region> =
903 impl_generics.region_param_defs().iter().
904 map(|l| ty::ReFree(ty::FreeRegion {
905 scope_id: impl_m_body_id,
906 bound_region: ty::BrNamed(l.def_id, l.name)})).
908 let dummy_substs = ty::substs {
909 tps: vec_ng::append(dummy_impl_tps, dummy_method_tps.as_slice()),
910 regions: ty::NonerasedRegions(dummy_impl_regions),
913 // Create a bare fn type for trait/impl
914 // It'd be nice to refactor so as to provide the bare fn types instead.
915 let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
916 let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
918 // Perform substitutions so that the trait/impl methods are expressed
919 // in terms of the same set of type/region parameters:
920 // - replace trait type parameters with those from `trait_substs`,
921 // except with any reference to bound self replaced with `dummy_self_r`
922 // - replace method parameters on the trait with fresh, dummy parameters
923 // that correspond to the parameters we will find on the impl
924 // - replace self region with a fresh, dummy region
926 debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
927 impl_fty.subst(tcx, &dummy_substs)
929 debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
931 let substs { regions: trait_regions,
933 self_ty: self_ty } = trait_substs.subst(tcx, &dummy_substs);
934 let substs = substs {
935 regions: trait_regions,
936 tps: vec_ng::append(trait_tps, dummy_method_tps.as_slice()),
939 debug!("trait_fty (pre-subst): {} substs={}",
940 trait_fty.repr(tcx), substs.repr(tcx));
941 trait_fty.subst(tcx, &substs)
943 debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx));
945 match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span),
946 impl_fty, trait_fty) {
948 result::Err(ref terr) => {
951 format!("method `{}` has an incompatible type: {}",
952 token::get_ident(trait_m.ident),
953 ty::type_err_to_str(tcx, terr)));
954 ty::note_and_explain_type_err(tcx, terr);
959 impl AstConv for FnCtxt {
960 fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
962 fn get_item_ty(&self, id: ast::DefId) -> ty::ty_param_bounds_and_ty {
963 ty::lookup_item_type(self.tcx(), id)
966 fn get_trait_def(&self, id: ast::DefId) -> @ty::TraitDef {
967 ty::lookup_trait_def(self.tcx(), id)
970 fn ty_infer(&self, _span: Span) -> ty::t {
971 self.infcx().next_ty_var()
976 pub fn infcx<'a>(&'a self) -> &'a infer::InferCtxt {
980 pub fn err_count_since_creation(&self) -> uint {
981 self.ccx.tcx.sess.err_count() - self.err_count_on_creation
984 pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
987 param_env: &self.inh.param_env
992 impl RegionScope for infer::InferCtxt {
993 fn anon_regions(&self, span: Span, count: uint)
994 -> Result<Vec<ty::Region> , ()> {
995 Ok(Vec::from_fn(count, |_| {
996 self.next_region_var(infer::MiscVariable(span))
1002 pub fn tag(&self) -> ~str {
1003 format!("{}", self as *FnCtxt)
1006 pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t {
1007 let locals = self.inh.locals.borrow();
1008 match locals.get().find(&nid) {
1011 self.tcx().sess.span_bug(
1013 format!("no type for local variable {:?}", nid));
1018 pub fn block_region(&self) -> ty::Region {
1019 ty::ReScope(self.region_lb.get())
1023 pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
1024 debug!("write_ty({}, {}) in fcx {}",
1025 node_id, ppaux::ty_to_str(self.tcx(), ty), self.tag());
1026 let mut node_types = self.inh.node_types.borrow_mut();
1027 node_types.get().insert(node_id, ty);
1030 pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::substs) {
1031 if !ty::substs_is_noop(&substs) {
1032 debug!("write_substs({}, {}) in fcx {}",
1034 ty::substs_to_str(self.tcx(), &substs),
1037 let mut node_type_substs = self.inh.node_type_substs.borrow_mut();
1038 node_type_substs.get().insert(node_id, substs);
1042 pub fn write_ty_substs(&self,
1043 node_id: ast::NodeId,
1045 substs: ty::substs) {
1046 let ty = ty::subst(self.tcx(), &substs, ty);
1047 self.write_ty(node_id, ty);
1048 self.write_substs(node_id, substs);
1051 pub fn write_autoderef_adjustment(&self,
1052 node_id: ast::NodeId,
1054 if derefs == 0 { return; }
1055 self.write_adjustment(
1057 @ty::AutoDerefRef(ty::AutoDerefRef {
1063 pub fn write_adjustment(&self,
1064 node_id: ast::NodeId,
1065 adj: @ty::AutoAdjustment) {
1066 debug!("write_adjustment(node_id={:?}, adj={:?})", node_id, adj);
1067 let mut adjustments = self.inh.adjustments.borrow_mut();
1068 adjustments.get().insert(node_id, adj);
1071 pub fn write_nil(&self, node_id: ast::NodeId) {
1072 self.write_ty(node_id, ty::mk_nil());
1074 pub fn write_bot(&self, node_id: ast::NodeId) {
1075 self.write_ty(node_id, ty::mk_bot());
1077 pub fn write_error(&self, node_id: ast::NodeId) {
1078 self.write_ty(node_id, ty::mk_err());
1081 pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
1082 ast_ty_to_ty(self, self.infcx(), ast_t)
1085 pub fn pat_to_str(&self, pat: &ast::Pat) -> ~str {
1086 pat.repr(self.tcx())
1089 pub fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
1090 let node_types = self.inh.node_types.borrow();
1091 match node_types.get().find(&ex.id) {
1094 self.tcx().sess.bug(format!("no type for expr in fcx {}",
1100 pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
1101 match self.inh.node_types.borrow().get().find(&id) {
1104 self.tcx().sess.bug(
1105 format!("no type for node {}: {} in fcx {}",
1106 id, self.tcx().map.node_to_str(id),
1112 pub fn node_ty_substs(&self, id: ast::NodeId) -> ty::substs {
1113 match self.inh.node_type_substs.borrow().get().find(&id) {
1114 Some(ts) => (*ts).clone(),
1116 self.tcx().sess.bug(
1117 format!("no type substs for node {}: {} in fcx {}",
1118 id, self.tcx().map.node_to_str(id),
1124 pub fn method_ty_substs(&self, id: ast::NodeId) -> ty::substs {
1125 match self.inh.method_map.borrow().get().find(&MethodCall::expr(id)) {
1126 Some(method) => method.substs.clone(),
1128 self.tcx().sess.bug(
1129 format!("no method entry for node {}: {} in fcx {}",
1130 id, self.tcx().map.node_to_str(id),
1136 pub fn opt_node_ty_substs(&self,
1138 f: |&ty::substs| -> bool)
1140 let node_type_substs = self.inh.node_type_substs.borrow();
1141 match node_type_substs.get().find(&id) {
1147 pub fn mk_subty(&self,
1148 a_is_expected: bool,
1149 origin: infer::TypeOrigin,
1152 -> Result<(), ty::type_err> {
1153 infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
1156 pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t)
1157 -> Result<(), ty::type_err> {
1158 infer::can_mk_subty(self.infcx(), sub, sup)
1161 pub fn mk_assignty(&self,
1165 -> Result<(), ty::type_err> {
1166 match infer::mk_coercety(self.infcx(),
1168 infer::ExprAssignable(expr.span),
1171 Ok(None) => result::Ok(()),
1172 Err(ref e) => result::Err((*e)),
1173 Ok(Some(adjustment)) => {
1174 self.write_adjustment(expr.id, adjustment);
1180 pub fn can_mk_assignty(&self, sub: ty::t, sup: ty::t)
1181 -> Result<(), ty::type_err> {
1182 infer::can_mk_coercety(self.infcx(), sub, sup)
1185 pub fn mk_eqty(&self,
1186 a_is_expected: bool,
1187 origin: infer::TypeOrigin,
1190 -> Result<(), ty::type_err> {
1191 infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
1194 pub fn mk_subr(&self,
1195 a_is_expected: bool,
1196 origin: infer::SubregionOrigin,
1199 infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
1202 pub fn with_region_lb<R>(&self, lb: ast::NodeId, f: || -> R) -> R {
1203 let old_region_lb = self.region_lb.get();
1204 self.region_lb.set(lb);
1206 self.region_lb.set(old_region_lb);
1210 pub fn type_error_message(&self,
1212 mk_msg: |~str| -> ~str,
1214 err: Option<&ty::type_err>) {
1215 self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
1218 pub fn report_mismatched_return_types(&self,
1222 err: &ty::type_err) {
1224 if ty::type_is_error(e) || ty::type_is_error(a) {
1227 self.infcx().report_mismatched_types(sp, e, a, err)
1230 pub fn report_mismatched_types(&self,
1234 err: &ty::type_err) {
1235 self.infcx().report_mismatched_types(sp, e, a, err)
1239 pub enum LvaluePreference {
1244 pub fn autoderef<T>(fcx: @FnCtxt, sp: Span, base_ty: ty::t,
1245 expr_id: Option<ast::NodeId>,
1246 mut lvalue_pref: LvaluePreference,
1247 should_stop: |ty::t, uint| -> Option<T>)
1248 -> (ty::t, uint, Option<T>) {
1250 * Executes an autoderef loop for the type `t`. At each step, invokes
1251 * `should_stop` to decide whether to terminate the loop. Returns
1252 * the final type and number of derefs that it performed.
1254 * Note: this method does not modify the adjustments table. The caller is
1255 * responsible for inserting an AutoAdjustment record into the `fcx`
1256 * using one of the suitable methods.
1259 let mut t = base_ty;
1260 for autoderefs in range(0, fcx.tcx().sess.recursion_limit.get()) {
1261 let resolved_t = structurally_resolved_type(fcx, sp, t);
1263 match should_stop(resolved_t, autoderefs) {
1264 Some(x) => return (resolved_t, autoderefs, Some(x)),
1268 // Otherwise, deref if type is derefable:
1269 let mt = match ty::deref(resolved_t, false) {
1270 Some(mt) => Some(mt),
1273 expr_id.map(|id| MethodCall::autoderef(id, autoderefs as u32));
1274 try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
1280 if mt.mutbl == ast::MutImmutable {
1281 lvalue_pref = NoPreference;
1284 None => return (resolved_t, autoderefs, None)
1288 // We've reached the recursion limit, error gracefully.
1289 fcx.tcx().sess.span_err(sp,
1290 format!("reached the recursion limit while auto-dereferencing {}",
1291 base_ty.repr(fcx.tcx())));
1292 (ty::mk_err(), 0, None)
1295 fn try_overloaded_deref(fcx: @FnCtxt,
1297 method_call: Option<MethodCall>,
1298 base_expr: Option<&ast::Expr>,
1300 lvalue_pref: LvaluePreference)
1302 // Try DerefMut first, if preferred.
1303 let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
1304 (PreferMutLvalue, Some(trait_did)) => {
1305 method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
1306 token::intern("deref_mut"), trait_did,
1307 base_ty, [], DontAutoderefReceiver)
1312 // Otherwise, fall back to Deref.
1313 let method = match (method, fcx.tcx().lang_items.deref_trait()) {
1314 (None, Some(trait_did)) => {
1315 method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
1316 token::intern("deref"), trait_did,
1317 base_ty, [], DontAutoderefReceiver)
1319 (method, _) => method
1324 let ref_ty = ty::ty_fn_ret(method.ty);
1326 Some(method_call) => {
1327 fcx.inh.method_map.borrow_mut().get().insert(method_call, method);
1331 ty::deref(ref_ty, true)
1337 // AST fragment checking
1338 pub fn check_lit(fcx: @FnCtxt, lit: &ast::Lit) -> ty::t {
1339 let tcx = fcx.ccx.tcx;
1342 ast::LitStr(..) => ty::mk_str(tcx, ty::vstore_slice(ty::ReStatic)),
1343 ast::LitBinary(..) => {
1344 ty::mk_vec(tcx, ty::mt{ ty: ty::mk_u8(), mutbl: ast::MutImmutable },
1345 ty::vstore_slice(ty::ReStatic))
1347 ast::LitChar(_) => ty::mk_char(),
1348 ast::LitInt(_, t) => ty::mk_mach_int(t),
1349 ast::LitUint(_, t) => ty::mk_mach_uint(t),
1350 ast::LitIntUnsuffixed(_) => {
1351 // An unsuffixed integer literal could have any integral type,
1352 // so we create an integral type variable for it.
1353 ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
1355 ast::LitFloat(_, t) => ty::mk_mach_float(t),
1356 ast::LitFloatUnsuffixed(_) => {
1357 // An unsuffixed floating point literal could have any floating point
1358 // type, so we create a floating point type variable for it.
1359 ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())
1361 ast::LitNil => ty::mk_nil(),
1362 ast::LitBool(_) => ty::mk_bool()
1366 pub fn valid_range_bounds(ccx: @CrateCtxt,
1370 match const_eval::compare_lit_exprs(ccx.tcx, from, to) {
1371 Some(val) => Some(val <= 0),
1376 pub fn check_expr_has_type(
1377 fcx: @FnCtxt, expr: &ast::Expr,
1379 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1380 demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
1384 fn check_expr_coercable_to_type(fcx: @FnCtxt, expr: &ast::Expr, expected: ty::t) {
1385 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1386 demand::coerce(fcx, expr.span, expected, expr)
1390 fn check_expr_with_hint(fcx: @FnCtxt, expr: &ast::Expr, expected: ty::t) {
1391 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || ())
1394 fn check_expr_with_opt_hint(fcx: @FnCtxt, expr: &ast::Expr,
1395 expected: Option<ty::t>) {
1396 check_expr_with_unifier(fcx, expr, expected, NoPreference, || ())
1399 fn check_expr_with_opt_hint_and_lvalue_pref(fcx: @FnCtxt,
1401 expected: Option<ty::t>,
1402 lvalue_pref: LvaluePreference) {
1403 check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ())
1406 fn check_expr(fcx: @FnCtxt, expr: &ast::Expr) {
1407 check_expr_with_unifier(fcx, expr, None, NoPreference, || ())
1410 fn check_expr_with_lvalue_pref(fcx: @FnCtxt, expr: &ast::Expr,
1411 lvalue_pref: LvaluePreference) {
1412 check_expr_with_unifier(fcx, expr, None, lvalue_pref, || ())
1416 // determine the `self` type, using fresh variables for all variables
1417 // declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
1418 // would return ($0, $1) where $0 and $1 are freshly instantiated type
1420 pub fn impl_self_ty(vcx: &VtableContext,
1421 span: Span, // (potential) receiver for this impl
1423 -> ty_param_substs_and_ty {
1424 let tcx = vcx.tcx();
1426 let ity = ty::lookup_item_type(tcx, did);
1427 let (n_tps, rps, raw_ty) =
1428 (ity.generics.type_param_defs().len(),
1429 ity.generics.region_param_defs(),
1432 let rps = vcx.infcx.region_vars_for_defs(span, rps);
1433 let tps = vcx.infcx.next_ty_vars(n_tps);
1435 let substs = substs {
1436 regions: ty::NonerasedRegions(rps),
1440 let substd_ty = ty::subst(tcx, &substs, raw_ty);
1442 ty_param_substs_and_ty { substs: substs, ty: substd_ty }
1445 // Only for fields! Returns <none> for methods>
1446 // Indifferent to privacy flags
1447 pub fn lookup_field_ty(tcx: ty::ctxt,
1448 class_id: ast::DefId,
1449 items: &[ty::field_ty],
1450 fieldname: ast::Name,
1451 substs: &ty::substs) -> Option<ty::t> {
1453 let o_field = items.iter().find(|f| f.name == fieldname);
1454 o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
1457 // Controls whether the arguments are automatically referenced. This is useful
1458 // for overloaded binary and unary operators.
1459 pub enum DerefArgs {
1464 // Given the provenance of a static method, returns the generics of the static
1465 // method's container.
1466 fn generics_of_static_method_container(type_context: ty::ctxt,
1467 provenance: ast::MethodProvenance)
1470 ast::FromTrait(trait_def_id) => {
1471 ty::lookup_trait_def(type_context, trait_def_id).generics.clone()
1473 ast::FromImpl(impl_def_id) => {
1474 ty::lookup_item_type(type_context, impl_def_id).generics.clone()
1479 // Verifies that type parameters supplied in paths are in the right
1481 fn check_type_parameter_positions_in_path(function_context: @FnCtxt,
1484 // We only care about checking the case in which the path has two or
1486 if path.segments.len() < 2 {
1490 // Verify that no lifetimes or type parameters are present anywhere
1491 // except the final two elements of the path.
1492 for i in range(0, path.segments.len() - 2) {
1493 for lifetime in path.segments.get(i).lifetimes.iter() {
1494 function_context.tcx()
1496 .span_err(lifetime.span,
1497 "lifetime parameters may not \
1502 for typ in path.segments.get(i).types.iter() {
1503 function_context.tcx()
1506 "type parameters may not appear here");
1511 // If there are no parameters at all, there is nothing more to do; the
1512 // rest of typechecking will (attempt to) infer everything.
1515 .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) {
1520 // If this is a static method of a trait or implementation, then
1521 // ensure that the segment of the path which names the trait or
1522 // implementation (the penultimate segment) is annotated with the
1523 // right number of type parameters.
1524 ast::DefStaticMethod(_, provenance, _) => {
1526 generics_of_static_method_container(function_context.ccx.tcx,
1528 let name = match provenance {
1529 ast::FromTrait(_) => "trait",
1530 ast::FromImpl(_) => "impl",
1533 let trait_segment = &path.segments.get(path.segments.len() - 2);
1535 // Make sure lifetime parameterization agrees with the trait or
1536 // implementation type.
1537 let trait_region_parameter_count = generics.region_param_defs().len();
1538 let supplied_region_parameter_count = trait_segment.lifetimes.len();
1539 if trait_region_parameter_count != supplied_region_parameter_count
1540 && supplied_region_parameter_count != 0 {
1541 function_context.tcx()
1543 .span_err(path.span,
1544 format!("expected {nexpected, plural, =1{# lifetime parameter} \
1545 other{# lifetime parameters}}, \
1546 found {nsupplied, plural, =1{# lifetime parameter} \
1547 other{# lifetime parameters}}",
1548 nexpected = trait_region_parameter_count,
1549 nsupplied = supplied_region_parameter_count));
1552 // Make sure the number of type parameters supplied on the trait
1553 // or implementation segment equals the number of type parameters
1554 // on the trait or implementation definition.
1555 let formal_ty_param_count = generics.type_param_defs().len();
1556 let required_ty_param_count = generics.type_param_defs().iter()
1557 .take_while(|x| x.default.is_none())
1559 let supplied_ty_param_count = trait_segment.types.len();
1560 if supplied_ty_param_count < required_ty_param_count {
1561 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1562 format!("the {trait_or_impl} referenced by this path needs at least \
1563 {nexpected, plural, =1{# type parameter} \
1564 other{# type parameters}}, \
1565 but {nsupplied, plural, =1{# type parameter} \
1566 other{# type parameters}} were supplied",
1567 trait_or_impl = name,
1568 nexpected = required_ty_param_count,
1569 nsupplied = supplied_ty_param_count)
1571 format!("the {trait_or_impl} referenced by this path needs \
1572 {nexpected, plural, =1{# type parameter} \
1573 other{# type parameters}}, \
1574 but {nsupplied, plural, =1{# type parameter} \
1575 other{# type parameters}} were supplied",
1576 trait_or_impl = name,
1577 nexpected = required_ty_param_count,
1578 nsupplied = supplied_ty_param_count)
1580 function_context.tcx().sess.span_err(path.span, msg)
1581 } else if supplied_ty_param_count > formal_ty_param_count {
1582 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1583 format!("the {trait_or_impl} referenced by this path needs at most \
1584 {nexpected, plural, =1{# type parameter} \
1585 other{# type parameters}}, \
1586 but {nsupplied, plural, =1{# type parameter} \
1587 other{# type parameters}} were supplied",
1588 trait_or_impl = name,
1589 nexpected = formal_ty_param_count,
1590 nsupplied = supplied_ty_param_count)
1592 format!("the {trait_or_impl} referenced by this path needs \
1593 {nexpected, plural, =1{# type parameter} \
1594 other{# type parameters}}, \
1595 but {nsupplied, plural, =1{# type parameter} \
1596 other{# type parameters}} were supplied",
1597 trait_or_impl = name,
1598 nexpected = formal_ty_param_count,
1599 nsupplied = supplied_ty_param_count)
1601 function_context.tcx().sess.span_err(path.span, msg)
1605 // Verify that no lifetimes or type parameters are present on
1606 // the penultimate segment of the path.
1607 let segment = &path.segments.get(path.segments.len() - 2);
1608 for lifetime in segment.lifetimes.iter() {
1609 function_context.tcx()
1611 .span_err(lifetime.span,
1612 "lifetime parameters may not
1616 for typ in segment.types.iter() {
1617 function_context.tcx()
1620 "type parameters may not appear \
1629 /// If an expression has any sub-expressions that result in a type error,
1630 /// inspecting that expression's type with `ty::type_is_error` will return
1631 /// true. Likewise, if an expression is known to diverge, inspecting its
1632 /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
1633 /// strict, _|_ can appear in the type of an expression that does not,
1634 /// itself, diverge: for example, fn() -> _|_.)
1635 /// Note that inspecting a type's structure *directly* may expose the fact
1636 /// that there are actually multiple representations for both `ty_err` and
1637 /// `ty_bot`, so avoid that when err and bot need to be handled differently.
1638 fn check_expr_with_unifier(fcx: @FnCtxt,
1640 expected: Option<ty::t>,
1641 lvalue_pref: LvaluePreference,
1643 debug!(">> typechecking");
1645 fn check_method_argument_types(
1648 method_fn_ty: ty::t,
1649 callee_expr: &ast::Expr,
1650 args: &[@ast::Expr],
1651 deref_args: DerefArgs) -> ty::t {
1652 // HACK(eddyb) ignore provided self (it has special typeck rules).
1653 let args = args.slice_from(1);
1654 if ty::type_is_error(method_fn_ty) {
1655 let err_inputs = err_args(args.len());
1656 check_argument_types(fcx, sp, err_inputs.as_slice(), callee_expr,
1657 args, deref_args, false);
1660 match ty::get(method_fn_ty).sty {
1661 ty::ty_bare_fn(ref fty) => {
1662 // HACK(eddyb) ignore self in the definition (see above).
1663 check_argument_types(fcx, sp, fty.sig.inputs.slice_from(1),
1664 callee_expr, args, deref_args,
1669 fcx.tcx().sess.span_bug(
1671 format!("method without bare fn type"));
1677 fn check_argument_types(fcx: @FnCtxt,
1679 fn_inputs: &[ty::t],
1680 callee_expr: &ast::Expr,
1681 args: &[@ast::Expr],
1682 deref_args: DerefArgs,
1686 * Generic function that factors out common logic from
1687 * function calls, method calls and overloaded operators.
1690 let tcx = fcx.ccx.tcx;
1692 // Grab the argument types, supplying fresh type variables
1693 // if the wrong number of arguments were supplied
1694 let supplied_arg_count = args.len();
1695 let expected_arg_count = fn_inputs.len();
1696 let formal_tys = if expected_arg_count == supplied_arg_count {
1697 fn_inputs.iter().map(|a| *a).collect()
1698 } else if variadic {
1699 if supplied_arg_count >= expected_arg_count {
1700 fn_inputs.iter().map(|a| *a).collect()
1703 "this function takes at least {nexpected, plural, =1{# parameter} \
1704 other{# parameters}} \
1705 but {nsupplied, plural, =1{# parameter was} \
1706 other{# parameters were}} supplied",
1707 nexpected = expected_arg_count,
1708 nsupplied = supplied_arg_count);
1710 tcx.sess.span_err(sp, msg);
1712 err_args(supplied_arg_count)
1716 "this function takes {nexpected, plural, =1{# parameter} \
1717 other{# parameters}} \
1718 but {nsupplied, plural, =1{# parameter was} \
1719 other{# parameters were}} supplied",
1720 nexpected = expected_arg_count,
1721 nsupplied = supplied_arg_count);
1723 tcx.sess.span_err(sp, msg);
1725 err_args(supplied_arg_count)
1728 debug!("check_argument_types: formal_tys={:?}",
1729 formal_tys.map(|t| fcx.infcx().ty_to_str(*t)));
1731 // Check the arguments.
1732 // We do this in a pretty awful way: first we typecheck any arguments
1733 // that are not anonymous functions, then we typecheck the anonymous
1734 // functions. This is so that we have more information about the types
1735 // of arguments when we typecheck the functions. This isn't really the
1736 // right way to do this.
1737 let xs = [false, true];
1738 for check_blocks in xs.iter() {
1739 let check_blocks = *check_blocks;
1740 debug!("check_blocks={}", check_blocks);
1742 // More awful hacks: before we check the blocks, try to do
1743 // an "opportunistic" vtable resolution of any trait
1744 // bounds on the call.
1746 vtable::early_resolve_expr(callee_expr, fcx, true);
1749 // For variadic functions, we don't have a declared type for all of
1750 // the arguments hence we only do our usual type checking with
1751 // the arguments who's types we do know.
1752 let t = if variadic {
1757 for (i, arg) in args.iter().take(t).enumerate() {
1758 let is_block = match arg.node {
1759 ast::ExprFnBlock(..) |
1760 ast::ExprProc(..) => true,
1764 if is_block == check_blocks {
1765 debug!("checking the argument");
1766 let mut formal_ty = *formal_tys.get(i);
1770 match ty::get(formal_ty).sty {
1771 ty::ty_rptr(_, mt) => formal_ty = mt.ty,
1774 // So we hit this case when one implements the
1775 // operator traits but leaves an argument as
1776 // just T instead of &T. We'll catch it in the
1777 // mismatch impl/trait method phase no need to
1780 formal_ty = ty::mk_err();
1787 check_expr_coercable_to_type(fcx, *arg, formal_ty);
1793 // We also need to make sure we at least write the ty of the other
1794 // arguments which we skipped above.
1796 for arg in args.iter().skip(expected_arg_count) {
1797 check_expr(fcx, *arg);
1799 // There are a few types which get autopromoted when passed via varargs
1800 // in C but we just error out instead and require explicit casts.
1801 let arg_ty = structurally_resolved_type(fcx, arg.span, fcx.expr_ty(*arg));
1802 match ty::get(arg_ty).sty {
1803 ty::ty_float(ast::TyF32) => {
1804 fcx.type_error_message(arg.span,
1805 |t| format!("can't pass an {} to variadic function, \
1806 cast to c_double", t), arg_ty, None);
1808 ty::ty_int(ast::TyI8) | ty::ty_int(ast::TyI16) | ty::ty_bool => {
1809 fcx.type_error_message(arg.span,
1810 |t| format!("can't pass {} to variadic function, cast to c_int",
1813 ty::ty_uint(ast::TyU8) | ty::ty_uint(ast::TyU16) => {
1814 fcx.type_error_message(arg.span,
1815 |t| format!("can't pass {} to variadic function, cast to c_uint",
1824 fn err_args(len: uint) -> Vec<ty::t> {
1825 Vec::from_fn(len, |_| ty::mk_err())
1828 fn write_call(fcx: @FnCtxt, call_expr: &ast::Expr, output: ty::t) {
1829 fcx.write_ty(call_expr.id, output);
1832 // A generic function for doing all of the checking for call expressions
1833 fn check_call(fcx: @FnCtxt,
1834 call_expr: &ast::Expr,
1836 args: &[@ast::Expr]) {
1837 // Index expressions need to be handled separately, to inform them
1838 // that they appear in call position.
1841 // Store the type of `f` as the type of the callee
1842 let fn_ty = fcx.expr_ty(f);
1844 // Extract the function signature from `in_fty`.
1845 let fn_sty = structure_of(fcx, f.span, fn_ty);
1847 // This is the "default" function signature, used in case of error.
1848 // In that case, we check each argument against "error" in order to
1849 // set up all the node type bindings.
1850 let error_fn_sig = FnSig {
1851 binder_id: ast::CRATE_NODE_ID,
1852 inputs: err_args(args.len()),
1853 output: ty::mk_err(),
1857 let fn_sig = match *fn_sty {
1858 ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, ..}) |
1859 ty::ty_closure(ty::ClosureTy {sig: ref sig, ..}) => sig,
1861 fcx.type_error_message(call_expr.span, |actual| {
1862 format!("expected function but \
1863 found `{}`", actual) }, fn_ty, None);
1868 // Replace any bound regions that appear in the function
1869 // signature with region variables
1870 let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
1871 fcx.infcx().next_region_var(infer::LateBoundRegion(call_expr.span, br))
1874 // Call the generic checker.
1875 check_argument_types(fcx, call_expr.span, fn_sig.inputs.as_slice(), f,
1876 args, DontDerefArgs, fn_sig.variadic);
1878 write_call(fcx, call_expr, fn_sig.output);
1881 // Checks a method call.
1882 fn check_method_call(fcx: @FnCtxt,
1884 method_name: ast::Ident,
1885 args: &[@ast::Expr],
1886 tps: &[ast::P<ast::Ty>]) {
1888 // We can't know if we need &mut self before we look up the method,
1889 // so treat the receiver as mutable just in case - only explicit
1890 // overloaded dereferences care about the distinction.
1891 check_expr_with_lvalue_pref(fcx, rcvr, PreferMutLvalue);
1893 // no need to check for bot/err -- callee does that
1894 let expr_t = structurally_resolved_type(fcx,
1898 let tps = tps.map(|&ast_ty| fcx.to_ty(ast_ty));
1899 let fn_ty = match method::lookup(fcx, expr, rcvr,
1903 CheckTraitsAndInherentMethods,
1904 AutoderefReceiver) {
1906 let method_ty = method.ty;
1907 let method_call = MethodCall::expr(expr.id);
1908 fcx.inh.method_map.borrow_mut().get().insert(method_call, method);
1912 debug!("(checking method call) failing expr is {}", expr.id);
1914 fcx.type_error_message(expr.span,
1916 format!("type `{}` does not implement any method in scope \
1918 actual, token::get_ident(method_name))
1923 // Add error type for the result
1924 fcx.write_error(expr.id);
1929 // Call the generic checker.
1930 let ret_ty = check_method_argument_types(fcx, expr.span,
1934 write_call(fcx, expr, ret_ty);
1937 // A generic function for checking the then and else in an if
1939 fn check_then_else(fcx: @FnCtxt,
1940 cond_expr: &ast::Expr,
1941 then_blk: &ast::Block,
1942 opt_else_expr: Option<@ast::Expr>,
1945 expected: Option<ty::t>) {
1946 check_expr_has_type(fcx, cond_expr, ty::mk_bool());
1948 let branches_ty = match opt_else_expr {
1949 Some(else_expr) => {
1950 check_block_with_expected(fcx, then_blk, expected);
1951 let then_ty = fcx.node_ty(then_blk.id);
1952 check_expr_with_opt_hint(fcx, else_expr, expected);
1953 let else_ty = fcx.expr_ty(else_expr);
1954 infer::common_supertype(fcx.infcx(),
1955 infer::IfExpression(sp),
1961 check_block_no_value(fcx, then_blk);
1966 let cond_ty = fcx.expr_ty(cond_expr);
1967 let if_ty = if ty::type_is_error(cond_ty) {
1969 } else if ty::type_is_bot(cond_ty) {
1975 fcx.write_ty(id, if_ty);
1978 fn lookup_op_method(fcx: @FnCtxt,
1982 trait_did: Option<ast::DefId>,
1983 args: &[@ast::Expr],
1984 autoderef_receiver: AutoderefReceiverFlag,
1985 unbound_method: ||) -> ty::t {
1986 let method = match trait_did {
1987 Some(trait_did) => {
1988 method::lookup_in_trait(fcx, op_ex.span, Some(&*args[0]), opname,
1989 trait_did, self_t, [], autoderef_receiver)
1995 let method_ty = method.ty;
1996 // HACK(eddyb) Fully qualified path to work around a resolve bug.
1997 let method_call = ::middle::typeck::MethodCall::expr(op_ex.id);
1998 fcx.inh.method_map.borrow_mut().get().insert(method_call, method);
1999 check_method_argument_types(fcx, op_ex.span,
2005 // Check the args anyway
2006 // so we get all the error messages
2007 let expected_ty = ty::mk_err();
2008 check_method_argument_types(fcx, op_ex.span,
2016 // could be either an expr_binop or an expr_assign_binop
2017 fn check_binop(fcx: @FnCtxt,
2022 is_binop_assignment: IsBinopAssignment) {
2023 let tcx = fcx.ccx.tcx;
2025 let lvalue_pref = match is_binop_assignment {
2026 BinopAssignment => PreferMutLvalue,
2027 SimpleBinop => NoPreference
2029 check_expr_with_lvalue_pref(fcx, lhs, lvalue_pref);
2031 // Callee does bot / err checking
2032 let lhs_t = structurally_resolved_type(fcx, lhs.span,
2035 if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) {
2036 // Shift is a special case: rhs can be any integral type
2037 check_expr(fcx, rhs);
2038 let rhs_t = fcx.expr_ty(rhs);
2039 require_integral(fcx, rhs.span, rhs_t);
2040 fcx.write_ty(expr.id, lhs_t);
2044 if ty::is_binopable(tcx, lhs_t, op) {
2045 let tvar = fcx.infcx().next_ty_var();
2046 demand::suptype(fcx, expr.span, tvar, lhs_t);
2047 check_expr_has_type(fcx, rhs, tvar);
2049 let result_t = match op {
2050 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGe |
2051 ast::BiGt => ty::mk_bool(),
2055 fcx.write_ty(expr.id, result_t);
2059 if op == ast::BiOr || op == ast::BiAnd {
2060 // This is an error; one of the operands must have the wrong
2062 fcx.write_error(expr.id);
2063 fcx.write_error(rhs.id);
2064 fcx.type_error_message(expr.span, |actual| {
2065 format!("binary operation `{}` cannot be applied \
2067 ast_util::binop_to_str(op), actual)},
2072 // Check for overloaded operators if not an assignment.
2073 let result_t = if is_binop_assignment == SimpleBinop {
2074 check_user_binop(fcx, expr, lhs, lhs_t, op, rhs)
2076 fcx.type_error_message(expr.span,
2078 format!("binary assignment operation \
2079 `{}=` cannot be applied to type `{}`",
2080 ast_util::binop_to_str(op),
2085 check_expr(fcx, rhs);
2089 fcx.write_ty(expr.id, result_t);
2090 if ty::type_is_error(result_t) {
2091 fcx.write_ty(rhs.id, result_t);
2095 fn check_user_binop(fcx: @FnCtxt,
2097 lhs_expr: @ast::Expr,
2098 lhs_resolved_t: ty::t,
2100 rhs: @ast::Expr) -> ty::t {
2101 let tcx = fcx.ccx.tcx;
2102 let lang = tcx.lang_items;
2103 let (name, trait_did) = match op {
2104 ast::BiAdd => ("add", lang.add_trait()),
2105 ast::BiSub => ("sub", lang.sub_trait()),
2106 ast::BiMul => ("mul", lang.mul_trait()),
2107 ast::BiDiv => ("div", lang.div_trait()),
2108 ast::BiRem => ("rem", lang.rem_trait()),
2109 ast::BiBitXor => ("bitxor", lang.bitxor_trait()),
2110 ast::BiBitAnd => ("bitand", lang.bitand_trait()),
2111 ast::BiBitOr => ("bitor", lang.bitor_trait()),
2112 ast::BiShl => ("shl", lang.shl_trait()),
2113 ast::BiShr => ("shr", lang.shr_trait()),
2114 ast::BiLt => ("lt", lang.ord_trait()),
2115 ast::BiLe => ("le", lang.ord_trait()),
2116 ast::BiGe => ("ge", lang.ord_trait()),
2117 ast::BiGt => ("gt", lang.ord_trait()),
2118 ast::BiEq => ("eq", lang.eq_trait()),
2119 ast::BiNe => ("ne", lang.eq_trait()),
2120 ast::BiAnd | ast::BiOr => {
2121 check_expr(fcx, rhs);
2122 return ty::mk_err();
2125 lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
2126 trait_did, [lhs_expr, rhs], DontAutoderefReceiver, || {
2127 fcx.type_error_message(ex.span, |actual| {
2128 format!("binary operation `{}` cannot be applied to type `{}`",
2129 ast_util::binop_to_str(op), actual)
2130 }, lhs_resolved_t, None)
2134 fn check_user_unop(fcx: @FnCtxt,
2137 trait_did: Option<ast::DefId>,
2139 rhs_expr: @ast::Expr,
2140 rhs_t: ty::t) -> ty::t {
2141 lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
2142 trait_did, [rhs_expr], DontAutoderefReceiver, || {
2143 fcx.type_error_message(ex.span, |actual| {
2144 format!("cannot apply unary operator `{}` to type `{}`", op_str, actual)
2149 // Resolves `expected` by a single level if it is a variable and passes it
2150 // through the `unpack` function. It there is no expected type or
2151 // resolution is not possible (e.g., no constraints yet present), just
2153 fn unpack_expected<O>(
2155 expected: Option<ty::t>,
2156 unpack: |&ty::sty| -> Option<O>)
2160 match resolve_type(fcx.infcx(), t, force_tvar) {
2161 Ok(t) => unpack(&ty::get(t).sty),
2169 fn check_expr_fn(fcx: @FnCtxt,
2171 ast_sigil_opt: Option<ast::Sigil>,
2173 body: ast::P<ast::Block>,
2175 expected: Option<ty::t>) {
2176 let tcx = fcx.ccx.tcx;
2178 // Find the expected input/output types (if any). Substitute
2179 // fresh bound regions for any bound regions we find in the
2180 // expected types so as to avoid capture.
2182 // Also try to pick up inferred purity and sigil, defaulting
2183 // to impure and block. Note that we only will use those for
2184 // block syntax lambdas; that is, lambdas without explicit
2186 let expected_sty = unpack_expected(fcx,
2188 |x| Some((*x).clone()));
2189 let error_happened = false;
2194 expected_bounds) = {
2195 match expected_sty {
2196 Some(ty::ty_closure(ref cenv)) => {
2198 replace_late_bound_regions_in_fn_sig(
2200 |_| fcx.inh.infcx.fresh_bound_region(expr.id));
2201 (Some(sig), cenv.purity, cenv.sigil,
2202 cenv.onceness, cenv.bounds)
2205 // Not an error! Means we're inferring the closure type
2206 let mut sigil = ast::BorrowedSigil;
2207 let mut onceness = ast::Many;
2208 let mut bounds = ty::EmptyBuiltinBounds();
2210 ast::ExprProc(..) => {
2211 sigil = ast::OwnedSigil;
2212 onceness = ast::Once;
2213 bounds.add(ty::BoundSend);
2217 (None, ast::ImpureFn, sigil,
2223 // If the proto is specified, use that, otherwise select a
2224 // proto based on inference.
2225 let (sigil, purity) = match ast_sigil_opt {
2226 Some(p) => (p, ast::ImpureFn),
2227 None => (expected_sigil, expected_purity)
2230 // construct the function type
2231 let fn_ty = astconv::ty_of_closure(fcx,
2244 let fty = if error_happened {
2246 binder_id: ast::CRATE_NODE_ID,
2247 inputs: fn_ty.sig.inputs.map(|_| ty::mk_err()),
2248 output: ty::mk_err(),
2253 let fn_ty_copy = fn_ty.clone();
2254 fty_sig = fn_ty.sig.clone();
2255 ty::mk_closure(tcx, fn_ty_copy)
2258 debug!("check_expr_fn_with_unifier fty={}",
2259 fcx.infcx().ty_to_str(fty));
2261 fcx.write_ty(expr.id, fty);
2263 let (inherited_purity, id) =
2264 ty::determine_inherited_purity((fcx.ps.get().purity,
2269 check_fn(fcx.ccx, inherited_purity, &fty_sig,
2270 decl, id, body, fn_kind, fcx.inh);
2274 // Check field access expressions
2275 fn check_field(fcx: @FnCtxt,
2277 lvalue_pref: LvaluePreference,
2280 tys: &[ast::P<ast::Ty>]) {
2281 let tcx = fcx.ccx.tcx;
2282 check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
2283 let expr_t = structurally_resolved_type(fcx, expr.span,
2285 // FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
2286 let (_, autoderefs, field_ty) =
2287 autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
2288 match ty::get(base_t).sty {
2289 ty::ty_struct(base_id, ref substs) => {
2290 debug!("struct named {}", ppaux::ty_to_str(tcx, base_t));
2291 let fields = ty::lookup_struct_fields(tcx, base_id);
2292 lookup_field_ty(tcx, base_id, fields.as_slice(), field, &(*substs))
2299 fcx.write_ty(expr.id, field_ty);
2300 fcx.write_autoderef_adjustment(base.id, autoderefs);
2306 let tps: Vec<ty::t> = tys.iter().map(|&ty| fcx.to_ty(ty)).collect();
2307 match method::lookup(fcx,
2314 CheckTraitsAndInherentMethods,
2315 AutoderefReceiver) {
2317 fcx.type_error_message(
2320 format!("attempted to take value of method `{}` on type `{}`",
2321 token::get_name(field), actual)
2325 tcx.sess.span_note(expr.span,
2326 "maybe a missing `()` to call it? If not, try an anonymous function.");
2330 fcx.type_error_message(
2333 format!("attempted access of field `{}` on type `{}`, \
2334 but no field with that name was found",
2335 token::get_name(field), actual)
2341 fcx.write_error(expr.id);
2344 fn check_struct_or_variant_fields(fcx: @FnCtxt,
2347 class_id: ast::DefId,
2348 node_id: ast::NodeId,
2349 substitutions: ty::substs,
2350 field_types: &[ty::field_ty],
2351 ast_fields: &[ast::Field],
2352 check_completeness: bool) {
2353 let tcx = fcx.ccx.tcx;
2355 let mut class_field_map = HashMap::new();
2356 let mut fields_found = 0;
2357 for field in field_types.iter() {
2358 class_field_map.insert(field.name, (field.id, false));
2361 let mut error_happened = false;
2363 // Typecheck each field.
2364 for field in ast_fields.iter() {
2365 let mut expected_field_type = ty::mk_err();
2367 let pair = class_field_map.find(&field.ident.node.name).map(|x| *x);
2370 fcx.type_error_message(
2373 format!("structure `{}` has no field named `{}`",
2374 actual, token::get_ident(field.ident.node))
2375 }, struct_ty, None);
2376 error_happened = true;
2378 Some((_, true)) => {
2381 format!("field `{}` specified more than once",
2382 token::get_ident(field.ident.node)));
2383 error_happened = true;
2385 Some((field_id, false)) => {
2386 expected_field_type =
2387 ty::lookup_field_type(
2388 tcx, class_id, field_id, &substitutions);
2389 class_field_map.insert(
2390 field.ident.node.name, (field_id, true));
2394 // Make sure to give a type to the field even if there's
2395 // an error, so we can continue typechecking
2396 check_expr_coercable_to_type(
2399 expected_field_type);
2403 fcx.write_error(node_id);
2406 if check_completeness && !error_happened {
2407 // Make sure the programmer specified all the fields.
2408 assert!(fields_found <= field_types.len());
2409 if fields_found < field_types.len() {
2410 let mut missing_fields = Vec::new();
2411 for class_field in field_types.iter() {
2412 let name = class_field.name;
2413 let (_, seen) = *class_field_map.get(&name);
2415 missing_fields.push(~"`" + token::get_name(name).get() + "`");
2419 tcx.sess.span_err(span,
2420 format!("missing {nfields, plural, =1{field} other{fields}}: {fields}",
2421 nfields = missing_fields.len(),
2422 fields = missing_fields.connect(", ")));
2426 if !error_happened {
2427 fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx,
2428 class_id, substitutions));
2432 fn check_struct_constructor(fcx: @FnCtxt,
2434 span: codemap::Span,
2435 class_id: ast::DefId,
2436 fields: &[ast::Field],
2437 base_expr: Option<@ast::Expr>) {
2438 let tcx = fcx.ccx.tcx;
2440 // Look up the number of type parameters and the raw type, and
2441 // determine whether the class is region-parameterized.
2442 let item_type = ty::lookup_item_type(tcx, class_id);
2443 let type_parameter_count = item_type.generics.type_param_defs().len();
2444 let region_param_defs = item_type.generics.region_param_defs();
2445 let raw_type = item_type.ty;
2447 // Generate the struct type.
2448 let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs);
2449 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2450 let substitutions = substs {
2451 regions: ty::NonerasedRegions(regions),
2453 tps: type_parameters
2456 let mut struct_type = ty::subst(tcx, &substitutions, raw_type);
2458 // Look up and check the fields.
2459 let class_fields = ty::lookup_struct_fields(tcx, class_id);
2460 check_struct_or_variant_fields(fcx,
2466 class_fields.as_slice(),
2468 base_expr.is_none());
2469 if ty::type_is_error(fcx.node_ty(id)) {
2470 struct_type = ty::mk_err();
2473 // Check the base expression if necessary.
2476 Some(base_expr) => {
2477 check_expr_has_type(fcx, base_expr, struct_type);
2478 if ty::type_is_bot(fcx.node_ty(base_expr.id)) {
2479 struct_type = ty::mk_bot();
2484 // Write in the resulting type.
2485 fcx.write_ty(id, struct_type);
2488 fn check_struct_enum_variant(fcx: @FnCtxt,
2490 span: codemap::Span,
2491 enum_id: ast::DefId,
2492 variant_id: ast::DefId,
2493 fields: &[ast::Field]) {
2494 let tcx = fcx.ccx.tcx;
2496 // Look up the number of type parameters and the raw type, and
2497 // determine whether the enum is region-parameterized.
2498 let item_type = ty::lookup_item_type(tcx, enum_id);
2499 let type_parameter_count = item_type.generics.type_param_defs().len();
2500 let region_param_defs = item_type.generics.region_param_defs();
2501 let raw_type = item_type.ty;
2503 // Generate the enum type.
2504 let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs);
2505 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2506 let substitutions = substs {
2507 regions: ty::NonerasedRegions(regions),
2509 tps: type_parameters
2512 let enum_type = ty::subst(tcx, &substitutions, raw_type);
2514 // Look up and check the enum variant fields.
2515 let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2516 check_struct_or_variant_fields(fcx,
2522 variant_fields.as_slice(),
2525 fcx.write_ty(id, enum_type);
2528 let tcx = fcx.ccx.tcx;
2531 ast::ExprVstore(ev, vst) => {
2532 let typ = match ev.node {
2533 ast::ExprLit(lit) if ast_util::lit_is_str(lit) => {
2534 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2537 ast::ExprVec(ref args, mutbl) => {
2538 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2539 let mut any_error = false;
2540 let mut any_bot = false;
2541 let mutability = match vst {
2542 ast::ExprVstoreMutSlice => ast::MutMutable,
2545 let t: ty::t = fcx.infcx().next_ty_var();
2546 for e in args.iter() {
2547 check_expr_has_type(fcx, *e, t);
2548 let arg_t = fcx.expr_ty(*e);
2549 if ty::type_is_error(arg_t) {
2552 else if ty::type_is_bot(arg_t) {
2561 ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2564 ast::ExprRepeat(element, count_expr, mutbl) => {
2565 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2566 let _ = ty::eval_repeat_count(fcx, count_expr);
2567 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2568 let mutability = match vst {
2569 ast::ExprVstoreMutSlice => ast::MutMutable,
2572 let t: ty::t = fcx.infcx().next_ty_var();
2573 check_expr_has_type(fcx, element, t);
2574 let arg_t = fcx.expr_ty(element);
2575 if ty::type_is_error(arg_t) {
2577 } else if ty::type_is_bot(arg_t) {
2580 ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2584 tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence")
2586 fcx.write_ty(ev.id, typ);
2587 fcx.write_ty(id, typ);
2590 ast::ExprBox(place, subexpr) => {
2591 check_expr(fcx, place);
2592 check_expr(fcx, subexpr);
2594 let mut checked = false;
2596 ast::ExprPath(ref path) => {
2597 // FIXME(pcwalton): For now we hardcode the two permissible
2598 // places: the exchange heap and the managed heap.
2599 let definition = lookup_def(fcx, path.span, place.id);
2600 let def_id = ast_util::def_id_of_def(definition);
2601 match tcx.lang_items
2603 .get(ExchangeHeapLangItem as uint) {
2604 &Some(item_def_id) if def_id == item_def_id => {
2605 fcx.write_ty(id, ty::mk_uniq(tcx,
2606 fcx.expr_ty(subexpr)));
2609 &Some(_) | &None => {}
2612 match tcx.lang_items
2614 .get(ManagedHeapLangItem as uint) {
2615 &Some(item_def_id) if def_id == item_def_id => {
2616 // Assign the magic `Gc<T>` struct.
2618 match tcx.lang_items
2619 .require(GcLangItem) {
2622 tcx.sess.span_err(expr.span, msg);
2624 krate: ast::CRATE_NODE_ID,
2625 node: ast::DUMMY_NODE_ID,
2630 ty::NonerasedRegions(opt_vec::Empty);
2631 let sty = ty::mk_struct(tcx,
2641 fcx.write_ty(id, sty);
2644 &Some(_) | &None => {}
2652 tcx.sess.span_err(expr.span,
2653 "only the managed heap and exchange heap are \
2654 currently supported")
2658 ast::ExprLit(lit) => {
2659 let typ = check_lit(fcx, lit);
2660 fcx.write_ty(id, typ);
2662 ast::ExprBinary(op, lhs, rhs) => {
2663 check_binop(fcx, expr, op, lhs, rhs, SimpleBinop);
2665 let lhs_ty = fcx.expr_ty(lhs);
2666 let rhs_ty = fcx.expr_ty(rhs);
2667 if ty::type_is_error(lhs_ty) ||
2668 ty::type_is_error(rhs_ty) {
2669 fcx.write_error(id);
2671 else if ty::type_is_bot(lhs_ty) ||
2672 (ty::type_is_bot(rhs_ty) && !ast_util::lazy_binop(op)) {
2676 ast::ExprAssignOp(op, lhs, rhs) => {
2677 check_binop(fcx, expr, op, lhs, rhs, BinopAssignment);
2679 let lhs_t = fcx.expr_ty(lhs);
2680 let result_t = fcx.expr_ty(expr);
2681 demand::suptype(fcx, expr.span, result_t, lhs_t);
2683 let tcx = fcx.tcx();
2684 if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
2685 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2688 // Overwrite result of check_binop...this preserves existing behavior
2689 // but seems quite dubious with regard to user-defined methods
2690 // and so forth. - Niko
2691 if !ty::type_is_error(result_t)
2692 && !ty::type_is_bot(result_t) {
2693 fcx.write_nil(expr.id);
2696 ast::ExprUnary(unop, oprnd) => {
2697 let exp_inner = unpack_expected(fcx, expected, |sty| {
2699 ast::UnBox | ast::UnUniq => match *sty {
2700 ty::ty_box(ty) | ty::ty_uniq(ty) => Some(ty),
2703 ast::UnNot | ast::UnNeg => expected,
2704 ast::UnDeref => None
2707 let lvalue_pref = match unop {
2708 ast::UnDeref => lvalue_pref,
2711 check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, exp_inner, lvalue_pref);
2712 let mut oprnd_t = fcx.expr_ty(oprnd);
2713 if !ty::type_is_error(oprnd_t) && !ty::type_is_bot(oprnd_t) {
2716 oprnd_t = ty::mk_box(tcx, oprnd_t)
2719 oprnd_t = ty::mk_uniq(tcx, oprnd_t);
2722 oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
2723 oprnd_t = match ty::deref(oprnd_t, true) {
2725 None => match try_overloaded_deref(fcx, expr.span,
2726 Some(MethodCall::expr(expr.id)),
2727 Some(&*oprnd), oprnd_t, lvalue_pref) {
2730 let is_newtype = match ty::get(oprnd_t).sty {
2731 ty::ty_struct(did, ref substs) => {
2732 let fields = ty::struct_fields(fcx.tcx(), did, substs);
2734 && fields.get(0).ident ==
2735 token::special_idents::unnamed_field
2740 // This is an obsolete struct deref
2741 tcx.sess.span_err(expr.span,
2742 "single-field tuple-structs can \
2743 no longer be dereferenced");
2745 fcx.type_error_message(expr.span, |actual| {
2746 format!("type `{}` cannot be dereferenced", actual)
2755 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2757 if !(ty::type_is_integral(oprnd_t) ||
2758 ty::get(oprnd_t).sty == ty::ty_bool) {
2759 oprnd_t = check_user_unop(fcx, "!", "not",
2760 tcx.lang_items.not_trait(),
2761 expr, oprnd, oprnd_t);
2765 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2767 if !(ty::type_is_integral(oprnd_t) ||
2768 ty::type_is_fp(oprnd_t)) {
2769 oprnd_t = check_user_unop(fcx, "-", "neg",
2770 tcx.lang_items.neg_trait(),
2771 expr, oprnd, oprnd_t);
2776 fcx.write_ty(id, oprnd_t);
2778 ast::ExprAddrOf(mutbl, oprnd) => {
2779 let hint = unpack_expected(
2781 |sty| match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty),
2783 let lvalue_pref = match mutbl {
2784 ast::MutMutable => PreferMutLvalue,
2785 ast::MutImmutable => NoPreference
2787 check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, hint, lvalue_pref);
2789 // Note: at this point, we cannot say what the best lifetime
2790 // is to use for resulting pointer. We want to use the
2791 // shortest lifetime possible so as to avoid spurious borrowck
2792 // errors. Moreover, the longest lifetime will depend on the
2793 // precise details of the value whose address is being taken
2794 // (and how long it is valid), which we don't know yet until type
2795 // inference is complete.
2797 // Therefore, here we simply generate a region variable. The
2798 // region inferencer will then select the ultimate value.
2799 // Finally, borrowck is charged with guaranteeing that the
2800 // value whose address was taken can actually be made to live
2801 // as long as it needs to live.
2802 let region = fcx.infcx().next_region_var(
2803 infer::AddrOfRegion(expr.span));
2805 let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
2806 let oprnd_t = if ty::type_is_error(tm.ty) {
2808 } else if ty::type_is_bot(tm.ty) {
2812 ty::mk_rptr(tcx, region, tm)
2814 fcx.write_ty(id, oprnd_t);
2816 ast::ExprPath(ref pth) => {
2817 let defn = lookup_def(fcx, pth.span, id);
2819 check_type_parameter_positions_in_path(fcx, pth, defn);
2820 let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2821 instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
2823 ast::ExprInlineAsm(ref ia) => {
2824 for &(_, input) in ia.inputs.iter() {
2825 check_expr(fcx, input);
2827 for &(_, out) in ia.outputs.iter() {
2828 check_expr(fcx, out);
2832 ast::ExprMac(_) => tcx.sess.bug("unexpanded macro"),
2833 ast::ExprBreak(_) => { fcx.write_bot(id); }
2834 ast::ExprAgain(_) => { fcx.write_bot(id); }
2835 ast::ExprRet(expr_opt) => {
2836 let ret_ty = fcx.ret_ty;
2838 None => match fcx.mk_eqty(false, infer::Misc(expr.span),
2839 ret_ty, ty::mk_nil()) {
2840 result::Ok(_) => { /* fall through */ }
2844 "`return;` in function returning non-nil");
2848 check_expr_has_type(fcx, e, ret_ty);
2853 ast::ExprParen(a) => {
2854 check_expr_with_opt_hint_and_lvalue_pref(fcx, a, expected, lvalue_pref);
2855 fcx.write_ty(id, fcx.expr_ty(a));
2857 ast::ExprAssign(lhs, rhs) => {
2858 check_expr_with_lvalue_pref(fcx, lhs, PreferMutLvalue);
2860 let tcx = fcx.tcx();
2861 if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
2862 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2865 let lhs_ty = fcx.expr_ty(lhs);
2866 check_expr_has_type(fcx, rhs, lhs_ty);
2867 let rhs_ty = fcx.expr_ty(rhs);
2869 if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
2870 fcx.write_error(id);
2871 } else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
2877 ast::ExprIf(cond, then_blk, opt_else_expr) => {
2878 check_then_else(fcx, cond, then_blk, opt_else_expr,
2879 id, expr.span, expected);
2881 ast::ExprWhile(cond, body) => {
2882 check_expr_has_type(fcx, cond, ty::mk_bool());
2883 check_block_no_value(fcx, body);
2884 let cond_ty = fcx.expr_ty(cond);
2885 let body_ty = fcx.node_ty(body.id);
2886 if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) {
2887 fcx.write_error(id);
2889 else if ty::type_is_bot(cond_ty) {
2896 ast::ExprForLoop(..) =>
2897 fail!("non-desugared expr_for_loop"),
2898 ast::ExprLoop(body, _) => {
2899 check_block_no_value(fcx, (body));
2900 if !may_break(tcx, expr.id, body) {
2907 ast::ExprMatch(discrim, ref arms) => {
2908 _match::check_match(fcx, expr, discrim, arms.as_slice());
2910 ast::ExprFnBlock(decl, body) => {
2913 Some(ast::BorrowedSigil),
2919 ast::ExprProc(decl, body) => {
2922 Some(ast::OwnedSigil),
2928 ast::ExprBlock(b) => {
2929 check_block_with_expected(fcx, b, expected);
2930 fcx.write_ty(id, fcx.node_ty(b.id));
2932 ast::ExprCall(f, ref args) => {
2933 check_call(fcx, expr, f, args.as_slice());
2934 let f_ty = fcx.expr_ty(f);
2935 let (args_bot, args_err) = args.iter().fold((false, false),
2936 |(rest_bot, rest_err), a| {
2937 // is this not working?
2938 let a_ty = fcx.expr_ty(*a);
2939 (rest_bot || ty::type_is_bot(a_ty),
2940 rest_err || ty::type_is_error(a_ty))});
2941 if ty::type_is_error(f_ty) || args_err {
2942 fcx.write_error(id);
2944 else if ty::type_is_bot(f_ty) || args_bot {
2948 ast::ExprMethodCall(ident, ref tps, ref args) => {
2949 check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice());
2950 let arg_tys = args.map(|a| fcx.expr_ty(*a));
2951 let (args_bot, args_err) = arg_tys.iter().fold((false, false),
2952 |(rest_bot, rest_err), a| {
2953 (rest_bot || ty::type_is_bot(*a),
2954 rest_err || ty::type_is_error(*a))});
2956 fcx.write_error(id);
2957 } else if args_bot {
2961 ast::ExprCast(e, t) => {
2963 let t_1 = fcx.to_ty(t);
2964 let t_e = fcx.expr_ty(e);
2966 debug!("t_1={}", fcx.infcx().ty_to_str(t_1));
2967 debug!("t_e={}", fcx.infcx().ty_to_str(t_e));
2969 if ty::type_is_error(t_e) {
2970 fcx.write_error(id);
2972 else if ty::type_is_bot(t_e) {
2976 match ty::get(t_1).sty {
2977 // This will be looked up later on
2978 ty::ty_trait(..) => (),
2981 if ty::type_is_nil(t_e) {
2982 fcx.type_error_message(expr.span, |actual| {
2983 format!("cast from nil: `{}` as `{}`", actual,
2984 fcx.infcx().ty_to_str(t_1))
2986 } else if ty::type_is_nil(t_1) {
2987 fcx.type_error_message(expr.span, |actual| {
2988 format!("cast to nil: `{}` as `{}`", actual,
2989 fcx.infcx().ty_to_str(t_1))
2993 let t1 = structurally_resolved_type(fcx, e.span, t_1);
2994 let te = structurally_resolved_type(fcx, e.span, t_e);
2995 let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
2996 let t_1_is_char = type_is_char(fcx, expr.span, t_1);
2997 let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1);
2999 // casts to scalars other than `char` and `bare fn` are trivial
3000 let t_1_is_trivial = t_1_is_scalar &&
3001 !t_1_is_char && !t_1_is_bare_fn;
3003 if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial {
3004 // casts from C-like enums are allowed
3005 } else if t_1_is_char {
3006 let te = fcx.infcx().resolve_type_vars_if_possible(te);
3007 if ty::get(te).sty != ty::ty_uint(ast::TyU8) {
3008 fcx.type_error_message(expr.span, |actual| {
3009 format!("only `u8` can be cast as `char`, not `{}`", actual)
3012 } else if ty::get(t1).sty == ty::ty_bool {
3013 fcx.tcx().sess.span_err(expr.span,
3014 "cannot cast as `bool`, compare with zero instead");
3015 } else if type_is_region_ptr(fcx, expr.span, t_e) &&
3016 type_is_unsafe_ptr(fcx, expr.span, t_1) {
3018 fn is_vec(t: ty::t) -> bool {
3019 match ty::get(t).sty {
3020 ty::ty_vec(..) => true,
3024 fn types_compatible(fcx: @FnCtxt, sp: Span,
3025 t1: ty::t, t2: ty::t) -> bool {
3029 let el = ty::sequence_element_type(fcx.tcx(),
3031 infer::mk_eqty(fcx.infcx(), false,
3032 infer::Misc(sp), el, t2).is_ok()
3036 // Due to the limitations of LLVM global constants,
3037 // region pointers end up pointing at copies of
3038 // vector elements instead of the original values.
3039 // To allow unsafe pointers to work correctly, we
3040 // need to special-case obtaining an unsafe pointer
3041 // from a region pointer to a vector.
3043 /* this cast is only allowed from &[T] to *T or
3045 match (&ty::get(te).sty, &ty::get(t_1).sty) {
3046 (&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
3047 if types_compatible(fcx, e.span,
3048 mt1.ty, mt2.ty) => {
3049 /* this case is allowed */
3052 demand::coerce(fcx, e.span, t_1, e);
3055 } else if !(type_is_scalar(fcx,expr.span,t_e)
3056 && t_1_is_trivial) {
3058 If more type combinations should be supported than are
3059 supported here, then file an enhancement issue and
3060 record the issue number in this comment.
3062 fcx.type_error_message(expr.span, |actual| {
3063 format!("non-scalar cast: `{}` as `{}`", actual,
3064 fcx.infcx().ty_to_str(t_1))
3069 fcx.write_ty(id, t_1);
3072 ast::ExprVec(ref args, mutbl) => {
3073 let t: ty::t = fcx.infcx().next_ty_var();
3074 for e in args.iter() {
3075 check_expr_has_type(fcx, *e, t);
3077 let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutbl},
3078 ty::vstore_fixed(args.len()));
3079 fcx.write_ty(id, typ);
3081 ast::ExprRepeat(element, count_expr, mutbl) => {
3082 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
3083 let count = ty::eval_repeat_count(fcx, count_expr);
3084 let t: ty::t = fcx.infcx().next_ty_var();
3085 check_expr_has_type(fcx, element, t);
3086 let element_ty = fcx.expr_ty(element);
3087 if ty::type_is_error(element_ty) {
3088 fcx.write_error(id);
3090 else if ty::type_is_bot(element_ty) {
3094 let t = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutbl},
3095 ty::vstore_fixed(count));
3096 fcx.write_ty(id, t);
3099 ast::ExprTup(ref elts) => {
3100 let flds = unpack_expected(fcx, expected, |sty| {
3102 ty::ty_tup(ref flds) => Some((*flds).clone()),
3106 let mut bot_field = false;
3107 let mut err_field = false;
3109 let elt_ts = elts.iter().enumerate().map(|(i, e)| {
3110 let opt_hint = match flds {
3111 Some(ref fs) if i < fs.len() => Some(*fs.get(i)),
3114 check_expr_with_opt_hint(fcx, *e, opt_hint);
3115 let t = fcx.expr_ty(*e);
3116 err_field = err_field || ty::type_is_error(t);
3117 bot_field = bot_field || ty::type_is_bot(t);
3122 } else if err_field {
3123 fcx.write_error(id);
3125 let typ = ty::mk_tup(tcx, elt_ts);
3126 fcx.write_ty(id, typ);
3129 ast::ExprStruct(ref path, ref fields, base_expr) => {
3130 // Resolve the path.
3131 let def_map = tcx.def_map.borrow();
3132 match def_map.get().find(&id) {
3133 Some(&ast::DefStruct(type_def_id)) => {
3134 check_struct_constructor(fcx, id, expr.span, type_def_id,
3135 fields.as_slice(), base_expr);
3137 Some(&ast::DefVariant(enum_id, variant_id, _)) => {
3138 check_struct_enum_variant(fcx, id, expr.span, enum_id,
3139 variant_id, fields.as_slice());
3142 tcx.sess.span_bug(path.span,
3143 "structure constructor does not name a structure type");
3147 ast::ExprField(base, field, ref tys) => {
3148 check_field(fcx, expr, lvalue_pref, base, field.name, tys.as_slice());
3150 ast::ExprIndex(base, idx) => {
3151 check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
3152 check_expr(fcx, idx);
3153 let raw_base_t = fcx.expr_ty(base);
3154 let idx_t = fcx.expr_ty(idx);
3155 if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
3156 fcx.write_ty(id, raw_base_t);
3157 } else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
3158 fcx.write_ty(id, idx_t);
3160 let (base_t, autoderefs, field_ty) =
3161 autoderef(fcx, expr.span, raw_base_t, Some(base.id),
3162 lvalue_pref, |base_t, _| ty::index(base_t));
3165 require_integral(fcx, idx.span, idx_t);
3166 fcx.write_ty(id, mt.ty);
3167 fcx.write_autoderef_adjustment(base.id, autoderefs);
3170 let resolved = structurally_resolved_type(fcx,
3173 let ret_ty = lookup_op_method(fcx,
3176 token::intern("index"),
3177 tcx.lang_items.index_trait(),
3181 fcx.type_error_message(expr.span,
3183 format!("cannot index a value \
3190 fcx.write_ty(id, ret_ty);
3197 debug!("type of expr({}) {} is...", expr.id,
3198 syntax::print::pprust::expr_to_str(expr));
3199 debug!("... {}, expected is {}",
3200 ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
3202 Some(t) => ppaux::ty_to_str(tcx, t),
3209 pub fn require_integral(fcx: @FnCtxt, sp: Span, t: ty::t) {
3210 if !type_is_integral(fcx, sp, t) {
3211 fcx.type_error_message(sp, |actual| {
3212 format!("mismatched types: expected integral type but found `{}`",
3218 pub fn check_decl_initializer(fcx: @FnCtxt,
3222 let local_ty = fcx.local_ty(init.span, nid);
3223 check_expr_coercable_to_type(fcx, init, local_ty)
3226 pub fn check_decl_local(fcx: @FnCtxt, local: &ast::Local) {
3227 let tcx = fcx.ccx.tcx;
3229 let t = fcx.local_ty(local.span, local.id);
3230 fcx.write_ty(local.id, t);
3234 check_decl_initializer(fcx, local.id, init);
3235 let init_ty = fcx.expr_ty(init);
3236 if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
3237 fcx.write_ty(local.id, init_ty);
3243 let pcx = pat_ctxt {
3245 map: pat_id_map(tcx.def_map, local.pat),
3247 _match::check_pat(&pcx, local.pat, t);
3248 let pat_ty = fcx.node_ty(local.pat.id);
3249 if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
3250 fcx.write_ty(local.id, pat_ty);
3254 pub fn check_stmt(fcx: @FnCtxt, stmt: &ast::Stmt) {
3256 let mut saw_bot = false;
3257 let mut saw_err = false;
3259 ast::StmtDecl(decl, id) => {
3262 ast::DeclLocal(ref l) => {
3263 check_decl_local(fcx, *l);
3264 let l_t = fcx.node_ty(l.id);
3265 saw_bot = saw_bot || ty::type_is_bot(l_t);
3266 saw_err = saw_err || ty::type_is_error(l_t);
3268 ast::DeclItem(_) => {/* ignore for now */ }
3271 ast::StmtExpr(expr, id) => {
3273 // Check with expected type of ()
3274 check_expr_has_type(fcx, expr, ty::mk_nil());
3275 let expr_ty = fcx.expr_ty(expr);
3276 saw_bot = saw_bot || ty::type_is_bot(expr_ty);
3277 saw_err = saw_err || ty::type_is_error(expr_ty);
3279 ast::StmtSemi(expr, id) => {
3281 check_expr(fcx, expr);
3282 let expr_ty = fcx.expr_ty(expr);
3283 saw_bot |= ty::type_is_bot(expr_ty);
3284 saw_err |= ty::type_is_error(expr_ty);
3286 ast::StmtMac(..) => fcx.ccx.tcx.sess.bug("unexpanded macro")
3289 fcx.write_bot(node_id);
3292 fcx.write_error(node_id);
3295 fcx.write_nil(node_id)
3299 pub fn check_block_no_value(fcx: @FnCtxt, blk: &ast::Block) {
3300 check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
3301 let blkty = fcx.node_ty(blk.id);
3302 if ty::type_is_error(blkty) {
3303 fcx.write_error(blk.id);
3305 else if ty::type_is_bot(blkty) {
3306 fcx.write_bot(blk.id);
3309 let nilty = ty::mk_nil();
3310 demand::suptype(fcx, blk.span, nilty, blkty);
3314 pub fn check_block(fcx0: @FnCtxt, blk: &ast::Block) {
3315 check_block_with_expected(fcx0, blk, None)
3318 pub fn check_block_with_expected(fcx: @FnCtxt,
3320 expected: Option<ty::t>) {
3322 let mut fcx_ps = fcx.ps.borrow_mut();
3323 let purity_state = fcx_ps.get().recurse(blk);
3324 replace(fcx_ps.get(), purity_state)
3327 fcx.with_region_lb(blk.id, || {
3328 let mut warned = false;
3329 let mut last_was_bot = false;
3330 let mut any_bot = false;
3331 let mut any_err = false;
3332 for s in blk.stmts.iter() {
3333 check_stmt(fcx, *s);
3334 let s_id = ast_util::stmt_id(*s);
3335 let s_ty = fcx.node_ty(s_id);
3336 if last_was_bot && !warned && match s.node {
3337 ast::StmtDecl(decl, _) => {
3339 ast::DeclLocal(_) => true,
3343 ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true,
3346 fcx.ccx.tcx.sess.add_lint(UnreachableCode, s_id, s.span,
3347 ~"unreachable statement");
3350 if ty::type_is_bot(s_ty) {
3351 last_was_bot = true;
3353 any_bot = any_bot || ty::type_is_bot(s_ty);
3354 any_err = any_err || ty::type_is_error(s_ty);
3357 None => if any_err {
3358 fcx.write_error(blk.id);
3361 fcx.write_bot(blk.id);
3364 fcx.write_nil(blk.id);
3367 if any_bot && !warned {
3368 fcx.ccx.tcx.sess.add_lint(UnreachableCode, e.id, e.span,
3369 ~"unreachable expression");
3371 check_expr_with_opt_hint(fcx, e, expected);
3372 let ety = fcx.expr_ty(e);
3373 fcx.write_ty(blk.id, ety);
3375 fcx.write_error(blk.id);
3378 fcx.write_bot(blk.id);
3387 pub fn check_const(ccx: @CrateCtxt,
3391 let rty = ty::node_id_to_type(ccx.tcx, id);
3392 let fcx = blank_fn_ctxt(ccx, rty, e.id);
3394 let tcache = fcx.ccx.tcx.tcache.borrow();
3395 tcache.get().get(&local_def(id)).ty
3397 check_const_with_ty(fcx, sp, e, declty);
3400 pub fn check_const_with_ty(fcx: @FnCtxt,
3405 let cty = fcx.expr_ty(e);
3406 demand::suptype(fcx, e.span, declty, cty);
3407 regionck::regionck_expr(fcx, e);
3408 writeback::resolve_type_vars_in_expr(fcx, e);
3411 /// Checks whether a type can be represented in memory. In particular, it
3412 /// identifies types that contain themselves without indirection through a
3413 /// pointer, which would mean their size is unbounded. This is different from
3414 /// the question of whether a type can be instantiated. See the definition of
3415 /// `check_instantiable`.
3416 pub fn check_representable(tcx: ty::ctxt,
3418 item_id: ast::NodeId,
3419 designation: &str) {
3420 let rty = ty::node_id_to_type(tcx, item_id);
3422 // Check that it is possible to represent this type. This call identifies
3423 // (1) types that contain themselves and (2) types that contain a different
3424 // recursive type. It is only necessary to throw an error on those that
3425 // contain themselves. For case 2, there must be an inner type that will be
3426 // caught by case 1.
3427 match ty::is_type_representable(tcx, rty) {
3428 ty::SelfRecursive => {
3430 sp, format!("illegal recursive {} type; \
3431 wrap the inner value in a box to make it representable",
3434 ty::Representable | ty::ContainsRecursive => (),
3438 /// Checks whether a type can be created without an instance of itself.
3439 /// This is similar but different from the question of whether a type
3440 /// can be represented. For example, the following type:
3442 /// enum foo { None, Some(foo) }
3444 /// is instantiable but is not representable. Similarly, the type
3446 /// enum foo { Some(@foo) }
3448 /// is representable, but not instantiable.
3449 pub fn check_instantiable(tcx: ty::ctxt,
3451 item_id: ast::NodeId) {
3452 let item_ty = ty::node_id_to_type(tcx, item_id);
3453 if !ty::is_instantiable(tcx, item_ty) {
3454 tcx.sess.span_err(sp, format!("this type cannot be instantiated \
3455 without an instance of itself; \
3456 consider using `Option<{}>`",
3457 ppaux::ty_to_str(tcx, item_ty)));
3461 pub fn check_simd(tcx: ty::ctxt, sp: Span, id: ast::NodeId) {
3462 let t = ty::node_id_to_type(tcx, id);
3463 if ty::type_needs_subst(t) {
3464 tcx.sess.span_err(sp, "SIMD vector cannot be generic");
3467 match ty::get(t).sty {
3468 ty::ty_struct(did, ref substs) => {
3469 let fields = ty::lookup_struct_fields(tcx, did);
3470 if fields.is_empty() {
3471 tcx.sess.span_err(sp, "SIMD vector cannot be empty");
3474 let e = ty::lookup_field_type(tcx, did, fields.get(0).id, substs);
3475 if !fields.iter().all(
3476 |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
3477 tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
3480 if !ty::type_is_machine(e) {
3481 tcx.sess.span_err(sp, "SIMD vector element type should be \
3490 pub fn check_enum_variants(ccx: @CrateCtxt,
3492 vs: &[ast::P<ast::Variant>],
3495 fn disr_in_range(ccx: @CrateCtxt,
3497 disr: ty::Disr) -> bool {
3498 fn uint_in_range(ccx: @CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
3500 ast::TyU8 => disr as u8 as Disr == disr,
3501 ast::TyU16 => disr as u16 as Disr == disr,
3502 ast::TyU32 => disr as u32 as Disr == disr,
3503 ast::TyU64 => disr as u64 as Disr == disr,
3504 ast::TyU => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
3507 fn int_in_range(ccx: @CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
3509 ast::TyI8 => disr as i8 as Disr == disr,
3510 ast::TyI16 => disr as i16 as Disr == disr,
3511 ast::TyI32 => disr as i32 as Disr == disr,
3512 ast::TyI64 => disr as i64 as Disr == disr,
3513 ast::TyI => int_in_range(ccx, ccx.tcx.sess.targ_cfg.int_type, disr)
3517 attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
3518 attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
3522 fn do_check(ccx: @CrateCtxt,
3523 vs: &[ast::P<ast::Variant>],
3525 hint: attr::ReprAttr)
3526 -> Vec<@ty::VariantInfo> {
3528 let rty = ty::node_id_to_type(ccx.tcx, id);
3529 let mut variants: Vec<@ty::VariantInfo> = Vec::new();
3530 let mut disr_vals: Vec<ty::Disr> = Vec::new();
3531 let mut prev_disr_val: Option<ty::Disr> = None;
3533 for &v in vs.iter() {
3535 // If the discriminant value is specified explicitly in the enum check whether the
3536 // initialization expression is valid, otherwise use the last value plus one.
3537 let mut current_disr_val = match prev_disr_val {
3538 Some(prev_disr_val) => prev_disr_val + 1,
3539 None => ty::INITIAL_DISCRIMINANT_VALUE
3542 match v.node.disr_expr {
3544 debug!("disr expr, checking {}", pprust::expr_to_str(e));
3546 let fcx = blank_fn_ctxt(ccx, rty, e.id);
3547 let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
3548 check_const_with_ty(fcx, e.span, e, declty);
3549 // check_expr (from check_const pass) doesn't guarantee
3550 // that the expression is in an form that eval_const_expr can
3551 // handle, so we may still get an internal compiler error
3553 match const_eval::eval_const_expr_partial(&ccx.tcx, e) {
3554 Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
3555 Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
3557 ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
3560 ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", *err));
3567 // Check for duplicate discriminant values
3568 if disr_vals.contains(¤t_disr_val) {
3569 ccx.tcx.sess.span_err(v.span, "discriminant value already exists");
3571 // Check for unrepresentable discriminant values
3573 attr::ReprAny | attr::ReprExtern => (),
3574 attr::ReprInt(sp, ity) => {
3575 if !disr_in_range(ccx, ity, current_disr_val) {
3576 ccx.tcx.sess.span_err(v.span,
3577 "discriminant value outside specified type");
3578 ccx.tcx.sess.span_note(sp, "discriminant type specified here");
3582 disr_vals.push(current_disr_val);
3584 let variant_info = @VariantInfo::from_ast_variant(ccx.tcx, v, current_disr_val);
3585 prev_disr_val = Some(current_disr_val);
3587 variants.push(variant_info);
3593 let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id });
3594 if hint != attr::ReprAny && vs.len() <= 1 {
3595 let msg = if vs.len() == 1 {
3596 "unsupported representation for univariant enum"
3598 "unsupported representation for zero-variant enum"
3600 ccx.tcx.sess.span_err(sp, msg)
3603 let variants = do_check(ccx, vs, id, hint);
3605 // cache so that ty::enum_variants won't repeat this work
3607 let mut enum_var_cache = ccx.tcx.enum_var_cache.borrow_mut();
3608 enum_var_cache.get().insert(local_def(id), @variants);
3611 // Check that it is possible to represent this enum.
3612 check_representable(ccx.tcx, sp, id, "enum");
3614 // Check that it is possible to instantiate this enum:
3616 // This *sounds* like the same that as representable, but it's
3617 // not. See def'n of `check_instantiable()` for details.
3618 check_instantiable(ccx.tcx, sp, id);
3621 pub fn lookup_def(fcx: @FnCtxt, sp: Span, id: ast::NodeId) -> ast::Def {
3622 lookup_def_ccx(fcx.ccx, sp, id)
3625 // Returns the type parameter count and the type for the given definition.
3626 pub fn ty_param_bounds_and_ty_for_def(fcx: @FnCtxt,
3629 -> ty_param_bounds_and_ty {
3631 ast::DefArg(nid, _) | ast::DefLocal(nid, _) |
3632 ast::DefBinding(nid, _) => {
3633 let typ = fcx.local_ty(sp, nid);
3634 return no_params(typ);
3636 ast::DefFn(id, _) | ast::DefStaticMethod(id, _, _) |
3637 ast::DefStatic(id, _) | ast::DefVariant(_, id, _) |
3638 ast::DefStruct(id) => {
3639 return ty::lookup_item_type(fcx.ccx.tcx, id);
3641 ast::DefUpvar(_, inner, _, _) => {
3642 return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
3647 ast::DefTyParam(..)=> {
3648 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type");
3650 ast::DefMod(..) | ast::DefForeignMod(..) => {
3651 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module");
3653 ast::DefUse(..) => {
3654 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use");
3656 ast::DefRegion(..) => {
3657 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region");
3659 ast::DefTyParamBinder(..) => {
3660 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter");
3662 ast::DefLabel(..) => {
3663 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label");
3665 ast::DefSelfTy(..) => {
3666 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty");
3668 ast::DefMethod(..) => {
3669 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method");
3674 // Instantiates the given path, which must refer to an item with the given
3675 // number of type parameters and type.
3676 pub fn instantiate_path(fcx: @FnCtxt,
3678 tpt: ty_param_bounds_and_ty,
3681 node_id: ast::NodeId) {
3682 debug!(">>> instantiate_path");
3684 let ty_param_count = tpt.generics.type_param_defs().len();
3685 let ty_param_req = tpt.generics.type_param_defs().iter()
3686 .take_while(|x| x.default.is_none())
3688 let mut ty_substs_len = 0;
3689 for segment in pth.segments.iter() {
3690 ty_substs_len += segment.types.len()
3693 debug!("tpt={} ty_param_count={:?} ty_substs_len={:?}",
3694 tpt.repr(fcx.tcx()),
3698 // determine the region parameters, using the value given by the user
3699 // (if any) and otherwise using a fresh region variable
3700 let num_expected_regions = tpt.generics.region_param_defs().len();
3701 let num_supplied_regions = pth.segments.last().unwrap().lifetimes.len();
3702 let regions = if num_expected_regions == num_supplied_regions {
3703 opt_vec::from(pth.segments.last().unwrap().lifetimes.map(
3704 |l| ast_region_to_region(fcx.tcx(), l)))
3706 if num_supplied_regions != 0 {
3707 fcx.ccx.tcx.sess.span_err(
3709 format!("expected {nexpected, plural, =1{# lifetime parameter} \
3710 other{# lifetime parameters}}, \
3711 found {nsupplied, plural, =1{# lifetime parameter} \
3712 other{# lifetime parameters}}",
3713 nexpected = num_expected_regions,
3714 nsupplied = num_supplied_regions));
3717 fcx.infcx().region_vars_for_defs(span, tpt.generics.region_param_defs.deref().as_slice())
3719 let regions = ty::NonerasedRegions(regions);
3721 // Special case: If there is a self parameter, omit it from the list of
3724 // Here we calculate the "user type parameter count", which is the number
3725 // of type parameters actually manifest in the AST. This will differ from
3726 // the internal type parameter count when there are self types involved.
3727 let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def {
3728 ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
3729 let generics = generics_of_static_method_container(fcx.ccx.tcx,
3731 (ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs().len()))
3733 _ => (ty_param_count, ty_param_req, None),
3736 // determine values for type parameters, using the values given by
3737 // the user (if any) and otherwise using fresh type variables
3738 let (tps, regions) = if ty_substs_len == 0 {
3739 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3740 } else if ty_param_count == 0 {
3741 fcx.ccx.tcx.sess.span_err
3742 (span, "this item does not take type parameters");
3743 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3744 } else if ty_substs_len > user_ty_param_count {
3745 let expected = if user_ty_param_req < user_ty_param_count {
3750 fcx.ccx.tcx.sess.span_err
3752 format!("too many type parameters provided: {} {}, found {}",
3753 expected, user_ty_param_count, ty_substs_len));
3754 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3755 } else if ty_substs_len < user_ty_param_req {
3756 let expected = if user_ty_param_req < user_ty_param_count {
3761 fcx.ccx.tcx.sess.span_err
3763 format!("not enough type parameters provided: {} {}, found {}",
3764 expected, user_ty_param_req, ty_substs_len));
3765 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3767 if ty_substs_len > user_ty_param_req
3768 && !fcx.tcx().sess.features.default_type_params.get() {
3769 fcx.tcx().sess.span_err(pth.span, "default type parameters are \
3770 experimental and possibly buggy");
3771 fcx.tcx().sess.span_note(pth.span, "add #[feature(default_type_params)] \
3772 to the crate attributes to enable");
3775 // Build up the list of type parameters, inserting the self parameter
3776 // at the appropriate position.
3777 let mut tps = Vec::new();
3778 let mut pushed = false;
3779 for (i, ty) in pth.segments.iter()
3780 .flat_map(|segment| segment.types.iter())
3781 .map(|&ast_type| fcx.to_ty(ast_type))
3783 match self_parameter_index {
3784 Some(index) if index == i => {
3785 tps.push(*fcx.infcx().next_ty_vars(1).get(0));
3793 let mut substs = substs {
3799 let defaults = tpt.generics.type_param_defs().iter()
3800 .enumerate().filter_map(|(i, x)| {
3801 match self_parameter_index {
3802 Some(index) if index == i => None,
3803 _ => Some(x.default)
3806 for (i, default) in defaults.skip(ty_substs_len).enumerate() {
3807 match self_parameter_index {
3808 Some(index) if index == i + ty_substs_len => {
3809 substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0));
3816 let ty = default.subst_spanned(fcx.tcx(), &substs, Some(span));
3817 substs.tps.push(ty);
3820 fcx.tcx().sess.span_bug(span,
3821 "missing default for a not explicitely provided type param")
3826 // If the self parameter goes at the end, insert it there.
3827 if !pushed && self_parameter_index.is_some() {
3828 substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0))
3831 assert_eq!(substs.tps.len(), ty_param_count)
3833 let substs {tps, regions, ..} = substs;
3837 fcx.write_ty_substs(node_id, tpt.ty, substs {
3846 // Resolves `typ` by a single level if `typ` is a type variable. If no
3847 // resolution is possible, then an error is reported.
3848 pub fn structurally_resolved_type(fcx: &FnCtxt, sp: Span, tp: ty::t) -> ty::t {
3849 match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
3850 Ok(t_s) if !ty::type_is_ty_var(t_s) => t_s,
3852 fcx.type_error_message(sp, |_actual| {
3853 ~"the type of this value must be known in this context"
3855 demand::suptype(fcx, sp, ty::mk_err(), tp);
3861 // Returns the one-level-deep structure of the given type.
3862 pub fn structure_of<'a>(fcx: @FnCtxt, sp: Span, typ: ty::t)
3864 &ty::get(structurally_resolved_type(fcx, sp, typ)).sty
3867 pub fn type_is_integral(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3868 let typ_s = structurally_resolved_type(fcx, sp, typ);
3869 return ty::type_is_integral(typ_s);
3872 pub fn type_is_scalar(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3873 let typ_s = structurally_resolved_type(fcx, sp, typ);
3874 return ty::type_is_scalar(typ_s);
3877 pub fn type_is_char(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3878 let typ_s = structurally_resolved_type(fcx, sp, typ);
3879 return ty::type_is_char(typ_s);
3882 pub fn type_is_bare_fn(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3883 let typ_s = structurally_resolved_type(fcx, sp, typ);
3884 return ty::type_is_bare_fn(typ_s);
3887 pub fn type_is_unsafe_ptr(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3888 let typ_s = structurally_resolved_type(fcx, sp, typ);
3889 return ty::type_is_unsafe_ptr(typ_s);
3892 pub fn type_is_region_ptr(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3893 let typ_s = structurally_resolved_type(fcx, sp, typ);
3894 return ty::type_is_region_ptr(typ_s);
3897 pub fn type_is_c_like_enum(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3898 let typ_s = structurally_resolved_type(fcx, sp, typ);
3899 return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
3902 pub fn ast_expr_vstore_to_vstore(fcx: @FnCtxt,
3907 ast::ExprVstoreUniq => ty::vstore_uniq,
3908 ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => {
3910 ast::ExprLit(..) => {
3911 // string literals and *empty slices* live in static memory
3912 ty::vstore_slice(ty::ReStatic)
3914 ast::ExprVec(ref elements, _) if elements.len() == 0 => {
3915 // string literals and *empty slices* live in static memory
3916 ty::vstore_slice(ty::ReStatic)
3918 ast::ExprRepeat(..) |
3919 ast::ExprVec(..) => {
3920 // vector literals are temporaries on the stack
3921 match fcx.tcx().region_maps.temporary_scope(e.id) {
3923 let r = ty::ReScope(scope);
3927 // this slice occurs in a static somewhere
3928 ty::vstore_slice(ty::ReStatic)
3933 fcx.ccx.tcx.sess.span_bug(
3934 e.span, format!("vstore with unexpected contents"))
3941 // Returns true if b contains a break that can exit from b
3942 pub fn may_break(cx: ty::ctxt, id: ast::NodeId, b: ast::P<ast::Block>) -> bool {
3943 // First: is there an unlabeled break immediately
3945 (loop_query(b, |e| {
3947 ast::ExprBreak(_) => true,
3951 // Second: is there a labeled break with label
3952 // <id> nested anywhere inside the loop?
3953 (block_query(b, |e| {
3955 ast::ExprBreak(Some(_)) => {
3956 let def_map = cx.def_map.borrow();
3957 match def_map.get().find(&e.id) {
3958 Some(&ast::DefLabel(loop_id)) if id == loop_id => true,
3966 pub fn check_bounds_are_used(ccx: @CrateCtxt,
3968 tps: &OptVec<ast::TyParam>,
3970 debug!("check_bounds_are_used(n_tps={}, ty={})",
3971 tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
3973 // make a vector of booleans initially false, set to true when used
3974 if tps.len() == 0u { return; }
3975 let mut tps_used = vec::from_elem(tps.len(), false);
3977 ty::walk_ty(ty, |t| {
3978 match ty::get(t).sty {
3979 ty::ty_param(param_ty {idx, ..}) => {
3980 debug!("Found use of ty param \\#{}", idx);
3981 tps_used[idx] = true;
3987 for (i, b) in tps_used.iter().enumerate() {
3989 ccx.tcx.sess.span_err(
3990 span, format!("type parameter `{}` is unused",
3991 token::get_ident(tps.get(i).ident)));
3996 pub fn check_intrinsic_type(ccx: @CrateCtxt, it: &ast::ForeignItem) {
3997 fn param(ccx: @CrateCtxt, n: uint) -> ty::t {
3998 ty::mk_param(ccx.tcx, n, local_def(0))
4002 let name = token::get_ident(it.ident);
4003 let (n_tps, inputs, output) = if name.get().starts_with("atomic_") {
4004 let split : Vec<&str> = name.get().split('_').collect();
4005 assert!(split.len() >= 2, "Atomic intrinsic not correct format");
4007 //We only care about the operation here
4008 match *split.get(1) {
4009 "cxchg" => (1, vec!(ty::mk_mut_rptr(tcx,
4010 ty::ReLateBound(it.id, ty::BrAnon(0)),
4013 param(ccx, 0)), param(ccx, 0)),
4016 ty::mk_imm_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)),
4022 ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)),
4028 "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
4029 "min" | "umax" | "umin" => {
4030 (1, vec!(ty::mk_mut_rptr(tcx,
4031 ty::ReLateBound(it.id, ty::BrAnon(0)),
4032 param(ccx, 0)), param(ccx, 0) ),
4036 (0, Vec::new(), ty::mk_nil())
4039 tcx.sess.span_err(it.span,
4040 format!("unrecognized atomic operation function: `{}`",
4048 "abort" => (0, Vec::new(), ty::mk_bot()),
4049 "breakpoint" => (0, Vec::new(), ty::mk_nil()),
4051 "pref_align_of" | "min_align_of" => (1u, Vec::new(), ty::mk_uint()),
4052 "init" => (1u, Vec::new(), param(ccx, 0u)),
4053 "uninit" => (1u, Vec::new(), param(ccx, 0u)),
4054 "forget" => (1u, vec!( param(ccx, 0) ), ty::mk_nil()),
4055 "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)),
4056 "move_val_init" => {
4059 ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), param(ccx, 0)),
4064 "needs_drop" => (1u, Vec::new(), ty::mk_bool()),
4065 "owns_managed" => (1u, Vec::new(), ty::mk_bool()),
4068 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4070 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4072 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4074 mutbl: ast::MutImmutable
4076 (1u, Vec::new(), td_ptr)
4079 let langid = ccx.tcx.lang_items.require(TypeIdLangItem);
4081 Ok(did) => (1u, Vec::new(), ty::mk_struct(ccx.tcx, did, substs {
4084 regions: ty::NonerasedRegions(opt_vec::Empty)
4086 Err(msg) => { tcx.sess.span_fatal(it.span, msg); }
4090 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4092 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4094 let region = ty::ReLateBound(it.id, ty::BrAnon(0));
4095 let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
4096 Ok((_, vot)) => vot,
4097 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4100 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4102 mutbl: ast::MutImmutable
4104 (0, vec!( td_ptr, visitor_object_ty ), ty::mk_nil())
4109 ty::mk_ptr(tcx, ty::mt {
4111 mutbl: ast::MutImmutable
4115 ty::mk_ptr(tcx, ty::mt {
4117 mutbl: ast::MutImmutable
4120 "copy_nonoverlapping_memory" => {
4123 ty::mk_ptr(tcx, ty::mt {
4125 mutbl: ast::MutMutable
4127 ty::mk_ptr(tcx, ty::mt {
4129 mutbl: ast::MutImmutable
4138 ty::mk_ptr(tcx, ty::mt {
4140 mutbl: ast::MutMutable
4142 ty::mk_ptr(tcx, ty::mt {
4144 mutbl: ast::MutImmutable
4153 ty::mk_ptr(tcx, ty::mt {
4155 mutbl: ast::MutMutable
4162 "sqrtf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4163 "sqrtf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4166 vec!( ty::mk_f32(), ty::mk_i32() ),
4171 vec!( ty::mk_f64(), ty::mk_i32() ),
4174 "sinf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4175 "sinf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4176 "cosf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4177 "cosf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4180 vec!( ty::mk_f32(), ty::mk_f32() ),
4185 vec!( ty::mk_f64(), ty::mk_f64() ),
4188 "expf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4189 "expf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4190 "exp2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4191 "exp2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4192 "logf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4193 "logf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4194 "log10f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4195 "log10f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4196 "log2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4197 "log2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4200 vec!( ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ),
4205 vec!( ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ),
4208 "fabsf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4209 "fabsf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4210 "copysignf32" => (0, vec!( ty::mk_f32(), ty::mk_f32() ), ty::mk_f32()),
4211 "copysignf64" => (0, vec!( ty::mk_f64(), ty::mk_f64() ), ty::mk_f64()),
4212 "floorf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4213 "floorf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4214 "ceilf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4215 "ceilf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4216 "truncf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4217 "truncf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4218 "rintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4219 "rintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4220 "nearbyintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4221 "nearbyintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4222 "roundf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4223 "roundf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4224 "ctpop8" => (0, vec!( ty::mk_i8() ), ty::mk_i8()),
4225 "ctpop16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
4226 "ctpop32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
4227 "ctpop64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
4228 "ctlz8" => (0, vec!( ty::mk_i8() ), ty::mk_i8()),
4229 "ctlz16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
4230 "ctlz32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
4231 "ctlz64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
4232 "cttz8" => (0, vec!( ty::mk_i8() ), ty::mk_i8()),
4233 "cttz16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
4234 "cttz32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
4235 "cttz64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
4236 "bswap16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
4237 "bswap32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
4238 "bswap64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
4241 (1, vec!( ty::mk_imm_ptr(tcx, param(ccx, 0)) ), param(ccx, 0)),
4243 (1, vec!( ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ), ty::mk_nil()),
4245 "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
4246 (0, vec!(ty::mk_i8(), ty::mk_i8()),
4247 ty::mk_tup(tcx, vec!(ty::mk_i8(), ty::mk_bool()))),
4249 "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
4250 (0, vec!(ty::mk_i16(), ty::mk_i16()),
4251 ty::mk_tup(tcx, vec!(ty::mk_i16(), ty::mk_bool()))),
4253 "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
4254 (0, vec!(ty::mk_i32(), ty::mk_i32()),
4255 ty::mk_tup(tcx, vec!(ty::mk_i32(), ty::mk_bool()))),
4257 "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
4258 (0, vec!(ty::mk_i64(), ty::mk_i64()),
4259 ty::mk_tup(tcx, vec!(ty::mk_i64(), ty::mk_bool()))),
4261 "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
4262 (0, vec!(ty::mk_u8(), ty::mk_u8()),
4263 ty::mk_tup(tcx, vec!(ty::mk_u8(), ty::mk_bool()))),
4265 "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
4266 (0, vec!(ty::mk_u16(), ty::mk_u16()),
4267 ty::mk_tup(tcx, vec!(ty::mk_u16(), ty::mk_bool()))),
4269 "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
4270 (0, vec!(ty::mk_u32(), ty::mk_u32()),
4271 ty::mk_tup(tcx, vec!(ty::mk_u32(), ty::mk_bool()))),
4273 "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" =>
4274 (0, vec!(ty::mk_u64(), ty::mk_u64()),
4275 ty::mk_tup(tcx, vec!(ty::mk_u64(), ty::mk_bool()))),
4278 tcx.sess.span_err(it.span,
4279 format!("unrecognized intrinsic function: `{}`",
4285 let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
4286 purity: ast::UnsafeFn,
4287 abis: AbiSet::Intrinsic(),
4288 sig: FnSig {binder_id: it.id,
4293 let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
4294 let i_n_tps = i_ty.generics.type_param_defs().len();
4295 if i_n_tps != n_tps {
4296 tcx.sess.span_err(it.span, format!("intrinsic has wrong number \
4297 of type parameters: found {}, \
4298 expected {}", i_n_tps, n_tps));
4301 tcx, None, false, it.span, i_ty.ty, fty,
4302 || format!("intrinsic has wrong type: \
4304 ppaux::ty_to_str(ccx.tcx, fty)));