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;
123 use syntax::ast::{Provided, Required};
125 use syntax::ast_util::local_def;
126 use syntax::ast_util;
128 use syntax::codemap::Span;
130 use syntax::owned_slice::OwnedSlice;
131 use syntax::parse::token;
132 use syntax::print::pprust;
134 use syntax::visit::Visitor;
145 /// Fields that are part of a `FnCtxt` which are inherited by
146 /// closures defined within the function. For example:
149 /// bar(proc() { ... })
152 /// Here, the function `foo()` and the closure passed to
153 /// `bar()` will each have their own `FnCtxt`, but they will
154 /// share the inherited fields.
155 pub struct Inherited<'a> {
156 infcx: infer::InferCtxt<'a>,
157 locals: @RefCell<NodeMap<ty::t>>,
158 param_env: ty::ParameterEnvironment,
161 node_types: RefCell<NodeMap<ty::t>>,
162 node_type_substs: RefCell<NodeMap<ty::substs>>,
163 adjustments: RefCell<NodeMap<@ty::AutoAdjustment>>,
164 method_map: MethodMap,
165 vtable_map: vtable_map,
166 upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
174 // A normal closure or fn item.
179 pub struct FnStyleState {
180 pub def: ast::NodeId,
181 pub fn_style: ast::FnStyle,
186 pub fn function(fn_style: ast::FnStyle, def: ast::NodeId) -> FnStyleState {
187 FnStyleState { def: def, fn_style: fn_style, from_fn: true }
190 pub fn recurse(&mut self, blk: &ast::Block) -> FnStyleState {
191 match self.fn_style {
192 // If this unsafe, then if the outer function was already marked as
193 // unsafe we shouldn't attribute the unsafe'ness to the block. This
194 // way the block can be warned about instead of ignoring this
195 // extraneous block (functions are never warned about).
196 ast::UnsafeFn if self.from_fn => *self,
199 let (fn_style, def) = match blk.rules {
200 ast::UnsafeBlock(..) => (ast::UnsafeFn, blk.id),
201 ast::DefaultBlock => (fn_style, self.def),
203 FnStyleState{ def: def,
211 /// Whether `check_binop` is part of an assignment or not.
212 /// Used to know wether we allow user overloads and to print
213 /// better messages on error.
215 enum IsBinopAssignment{
221 pub struct FnCtxt<'a> {
222 // Number of errors that had been reported when we started
223 // checking this function. On exit, if we find that *more* errors
224 // have been reported, we will skip regionck and other work that
225 // expects the types within the function to be consistent.
226 err_count_on_creation: uint,
229 ps: RefCell<FnStyleState>,
231 // Sometimes we generate region pointers where the precise region
232 // to use is not known. For example, an expression like `&x.f`
233 // where `x` is of type `@T`: in this case, we will be rooting
234 // `x` onto the stack frame, and we could choose to root it until
235 // the end of (almost) any enclosing block or expression. We
236 // want to pick the narrowest block that encompasses all uses.
238 // What we do in such cases is to generate a region variable with
239 // `region_lb` as a lower bound. The regionck pass then adds
240 // other constriants based on how the variable is used and region
241 // inference selects the ultimate value. Finally, borrowck is
242 // charged with guaranteeing that the value whose address was taken
243 // can actually be made to live as long as it needs to live.
244 region_lb: Cell<ast::NodeId>,
246 // Says whether we're inside a for loop, in a do block
247 // or neither. Helps with error messages involving the
248 // function return type.
251 inh: &'a Inherited<'a>,
253 ccx: &'a CrateCtxt<'a>,
256 impl<'a> Inherited<'a> {
257 fn new(tcx: &'a ty::ctxt,
258 param_env: ty::ParameterEnvironment)
261 infcx: infer::new_infer_ctxt(tcx),
262 locals: @RefCell::new(NodeMap::new()),
263 param_env: param_env,
264 node_types: RefCell::new(NodeMap::new()),
265 node_type_substs: RefCell::new(NodeMap::new()),
266 adjustments: RefCell::new(NodeMap::new()),
267 method_map: @RefCell::new(FnvHashMap::new()),
268 vtable_map: @RefCell::new(FnvHashMap::new()),
269 upvar_borrow_map: RefCell::new(HashMap::new()),
274 // Used by check_const and check_enum_variants
275 fn blank_fn_ctxt<'a>(ccx: &'a CrateCtxt<'a>,
276 inh: &'a Inherited<'a>,
278 region_bnd: ast::NodeId)
281 err_count_on_creation: ccx.tcx.sess.err_count(),
283 ps: RefCell::new(FnStyleState::function(ast::NormalFn, 0)),
284 region_lb: Cell::new(region_bnd),
291 fn blank_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> {
292 // It's kind of a kludge to manufacture a fake function context
293 // and statement context, but we might as well do write the code only once
294 let param_env = ty::ParameterEnvironment { free_substs: substs::empty(),
295 self_param_bound: None,
296 type_param_bounds: Vec::new() };
297 Inherited::new(ccx.tcx, param_env)
300 impl<'a> ExprTyProvider for FnCtxt<'a> {
301 fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
305 fn ty_ctxt<'a>(&'a self) -> &'a ty::ctxt {
310 struct CheckItemTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
312 impl<'a> Visitor<()> for CheckItemTypesVisitor<'a> {
313 fn visit_item(&mut self, i: &ast::Item, _: ()) {
314 check_item(self.ccx, i);
315 visit::walk_item(self, i, ());
319 pub fn check_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
320 let mut visit = CheckItemTypesVisitor { ccx: ccx };
321 visit::walk_crate(&mut visit, krate, ());
324 fn check_bare_fn(ccx: &CrateCtxt,
329 param_env: ty::ParameterEnvironment) {
330 // Compute the fty from point of view of inside fn
331 // (replace any type-scheme with a type)
332 let fty = fty.subst(ccx.tcx, ¶m_env.free_substs);
334 match ty::get(fty).sty {
335 ty::ty_bare_fn(ref fn_ty) => {
336 let inh = Inherited::new(ccx.tcx, param_env);
337 let fcx = check_fn(ccx, fn_ty.fn_style, &fn_ty.sig,
338 decl, id, body, Vanilla, &inh);
340 vtable::resolve_in_block(&fcx, body);
341 regionck::regionck_fn(&fcx, body);
342 writeback::resolve_type_vars_in_fn(&fcx, decl, body);
344 _ => ccx.tcx.sess.impossible_case(body.span,
345 "check_bare_fn: function type expected")
349 struct GatherLocalsVisitor<'a> {
353 impl<'a> GatherLocalsVisitor<'a> {
354 fn assign(&mut self, nid: ast::NodeId, ty_opt: Option<ty::t>) {
357 // infer the variable's type
358 let var_id = self.fcx.infcx().next_ty_var_id();
359 let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
360 self.fcx.inh.locals.borrow_mut().insert(nid, var_ty);
363 // take type that the user specified
364 self.fcx.inh.locals.borrow_mut().insert(nid, typ);
370 impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
371 // Add explicitly-declared locals.
372 fn visit_local(&mut self, local: &ast::Local, _: ()) {
373 let o_ty = match local.ty.node {
374 ast::TyInfer => None,
375 _ => Some(self.fcx.to_ty(local.ty))
377 self.assign(local.id, o_ty);
378 debug!("Local variable {} is assigned type {}",
379 self.fcx.pat_to_str(local.pat),
380 self.fcx.infcx().ty_to_str(
381 self.fcx.inh.locals.borrow().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);
391 debug!("Pattern binding {} is assigned to {}",
392 token::get_ident(path.segments.get(0).identifier),
393 self.fcx.infcx().ty_to_str(
394 self.fcx.inh.locals.borrow().get_copy(&p.id)));
398 visit::walk_pat(self, p, ());
402 fn visit_block(&mut self, b: &ast::Block, _: ()) {
403 // non-obvious: the `blk` variable maps to region lb, so
404 // we have to keep this up-to-date. This
405 // is... unfortunate. It'd be nice to not need this.
406 self.fcx.with_region_lb(b.id, || visit::walk_block(self, b, ()));
409 // Don't descend into fns and items
410 fn visit_fn(&mut self, _: &visit::FnKind, _: &ast::FnDecl,
411 _: &ast::Block, _: Span, _: ast::NodeId, _: ()) { }
412 fn visit_item(&mut self, _: &ast::Item, _: ()) { }
416 fn check_fn<'a>(ccx: &'a CrateCtxt<'a>,
417 fn_style: ast::FnStyle,
423 inherited: &'a Inherited<'a>) -> FnCtxt<'a>
426 * Helper used by check_bare_fn and check_expr_fn. Does the
427 * grungy work of checking a function body and returns the
428 * function context used for that purpose, since in the case of a
429 * fn item there is still a bit more to do.
432 * - inherited: other fields inherited from the enclosing fn (if any)
436 let err_count_on_creation = tcx.sess.err_count();
438 // First, we have to replace any bound regions in the fn type with free ones.
439 // The free region references will be bound the node_id of the body block.
440 let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(tcx, fn_sig, |br| {
441 ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
444 relate_free_regions(tcx, &fn_sig);
446 let arg_tys = fn_sig.inputs.as_slice();
447 let ret_ty = fn_sig.output;
449 debug!("check_fn(arg_tys={:?}, ret_ty={:?})",
450 arg_tys.iter().map(|&a| ppaux::ty_to_str(tcx, a)).collect::<Vec<~str>>(),
451 ppaux::ty_to_str(tcx, ret_ty));
453 // Create the function context. This is either derived from scratch or,
454 // in the case of function expressions, based on the outer context.
456 err_count_on_creation: err_count_on_creation,
458 ps: RefCell::new(FnStyleState::function(fn_style, id)),
459 region_lb: Cell::new(body.id),
467 let mut visit = GatherLocalsVisitor { fcx: &fcx, };
468 // Add formal parameters.
469 for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
470 // Create type variables for each argument.
471 pat_util::pat_bindings(tcx.def_map,
473 |_bm, pat_id, _sp, _path| {
474 visit.assign(pat_id, None);
477 // Check the pattern.
480 map: pat_id_map(tcx.def_map, input.pat),
482 _match::check_pat(&pcx, input.pat, *arg_ty);
485 visit.visit_block(body, ());
488 check_block_with_expected(&fcx, body, Some(ret_ty));
490 // We unify the tail expr's type with the
491 // function result type, if there is a tail expr.
494 // Special case: we print a special error if there appears
495 // to be do-block/for-loop confusion
496 demand::suptype_with_fn(&fcx, tail_expr.span, false,
497 fcx.ret_ty, fcx.expr_ty(tail_expr),
499 fcx.report_mismatched_return_types(sp, e, a, s);
505 for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
506 fcx.write_ty(input.id, *arg);
512 pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
515 // Check that the struct is representable
516 check_representable(tcx, span, id, "struct");
518 // Check that the struct is instantiable
519 check_instantiable(tcx, span, id);
521 if ty::lookup_simd(tcx, local_def(id)) {
522 check_simd(tcx, span, id);
526 pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
527 debug!("check_item(it.id={}, it.ident={})",
529 ty::item_path_str(ccx.tcx, local_def(it.id)));
530 let _indenter = indenter();
533 ast::ItemStatic(_, _, e) => check_const(ccx, it.span, e, it.id),
534 ast::ItemEnum(ref enum_definition, _) => {
535 check_enum_variants(ccx,
537 enum_definition.variants.as_slice(),
540 ast::ItemFn(decl, _, _, _, body) => {
541 let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
543 let param_env = ty::construct_parameter_environment(
546 fn_tpt.generics.type_param_defs(),
549 fn_tpt.generics.region_param_defs.as_slice(),
552 check_bare_fn(ccx, decl, body, it.id, fn_tpt.ty, param_env);
554 ast::ItemImpl(_, ref opt_trait_ref, _, ref ms) => {
555 debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
557 let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
559 check_method_body(ccx, &impl_tpt.generics, None, *m);
562 match *opt_trait_ref {
563 Some(ref ast_trait_ref) => {
565 ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id);
566 check_impl_methods_against_trait(ccx,
572 vtable::resolve_impl(ccx.tcx, it, &impl_tpt.generics, impl_trait_ref);
578 ast::ItemTrait(_, _, ref trait_methods) => {
579 let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
580 for trait_method in (*trait_methods).iter() {
581 match *trait_method {
583 // Nothing to do, since required methods don't have
587 check_method_body(ccx, &trait_def.generics,
588 Some(trait_def.trait_ref), m);
593 ast::ItemStruct(..) => {
594 check_struct(ccx, it.id, it.span);
596 ast::ItemTy(ref t, ref generics) => {
597 let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id);
598 check_bounds_are_used(ccx, t.span, &generics.ty_params, tpt_ty);
600 ast::ItemForeignMod(ref m) => {
601 if m.abi == abi::RustIntrinsic {
602 for item in m.items.iter() {
603 check_intrinsic_type(ccx, *item);
606 for item in m.items.iter() {
607 let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id));
608 if tpt.generics.has_type_params() {
609 ccx.tcx.sess.span_err(item.span, "foreign items may not have type parameters");
613 ast::ForeignItemFn(ref fn_decl, _) => {
614 if fn_decl.variadic && m.abi != abi::C {
615 ccx.tcx.sess.span_err(
616 item.span, "variadic function must have C calling convention");
624 _ => {/* nothing to do */ }
628 fn check_method_body(ccx: &CrateCtxt,
629 item_generics: &ty::Generics,
630 self_bound: Option<@ty::TraitRef>,
631 method: &ast::Method) {
633 * Type checks a method body.
636 * - `item_generics`: generics defined on the impl/trait that contains
638 * - `self_bound`: bound for the `Self` type parameter, if any
639 * - `method`: the method definition
642 debug!("check_method_body(item_generics={}, \
645 item_generics.repr(ccx.tcx),
646 self_bound.repr(ccx.tcx),
648 let method_def_id = local_def(method.id);
649 let method_ty = ty::method(ccx.tcx, method_def_id);
650 let method_generics = &method_ty.generics;
653 ty::construct_parameter_environment(
656 item_generics.type_param_defs(),
657 method_generics.type_param_defs(),
658 item_generics.region_param_defs(),
659 method_generics.region_param_defs(),
662 let fty = ty::node_id_to_type(ccx.tcx, method.id);
664 check_bare_fn(ccx, method.decl, method.body, method.id, fty, param_env);
667 fn check_impl_methods_against_trait(ccx: &CrateCtxt,
669 impl_generics: &ty::Generics,
670 ast_trait_ref: &ast::TraitRef,
671 impl_trait_ref: &ty::TraitRef,
672 impl_methods: &[@ast::Method]) {
673 // Locate trait methods
675 let trait_methods = ty::trait_methods(tcx, impl_trait_ref.def_id);
677 // Check existing impl methods to see if they are both present in trait
678 // and compatible with trait signature
679 for impl_method in impl_methods.iter() {
680 let impl_method_def_id = local_def(impl_method.id);
681 let impl_method_ty = ty::method(ccx.tcx, impl_method_def_id);
683 // If this is an impl of a trait method, find the corresponding
684 // method definition in the trait.
685 let opt_trait_method_ty =
686 trait_methods.iter().
687 find(|tm| tm.ident.name == impl_method_ty.ident.name);
688 match opt_trait_method_ty {
689 Some(trait_method_ty) => {
690 compare_impl_method(ccx.tcx,
696 &impl_trait_ref.substs);
701 format!("method `{}` is not a member of trait `{}`",
702 token::get_ident(impl_method_ty.ident),
703 pprust::path_to_str(&ast_trait_ref.path)));
708 // Check for missing methods from trait
709 let provided_methods = ty::provided_trait_methods(tcx,
710 impl_trait_ref.def_id);
711 let mut missing_methods = Vec::new();
712 for trait_method in trait_methods.iter() {
714 impl_methods.iter().any(
715 |m| m.ident.name == trait_method.ident.name);
717 provided_methods.iter().any(
718 |m| m.ident.name == trait_method.ident.name);
719 if !is_implemented && !is_provided {
720 missing_methods.push(
721 format!("`{}`", token::get_ident(trait_method.ident)));
725 if !missing_methods.is_empty() {
728 format!("not all trait methods implemented, missing: {}",
729 missing_methods.connect(", ")));
734 * Checks that a method from an impl/class conforms to the signature of
735 * the same method as declared in the trait.
739 * - impl_generics: the generics declared on the impl itself (not the method!)
740 * - impl_m: type of the method we are checking
741 * - impl_m_span: span to use for reporting errors
742 * - impl_m_body_id: id of the method body
743 * - trait_m: the method in the trait
744 * - trait_substs: the substitutions used on the type of the trait
746 fn compare_impl_method(tcx: &ty::ctxt,
747 impl_generics: &ty::Generics,
750 impl_m_body_id: ast::NodeId,
751 trait_m: &ty::Method,
752 trait_substs: &ty::substs) {
753 debug!("compare_impl_method()");
754 let infcx = infer::new_infer_ctxt(tcx);
756 let impl_tps = impl_generics.type_param_defs().len();
758 // Try to give more informative error messages about self typing
759 // mismatches. Note that any mismatch will also be detected
760 // below, where we construct a canonical function type that
761 // includes the self parameter as a normal parameter. It's just
762 // that the error messages you get out of this code are a bit more
763 // inscrutable, particularly for cases where one method has no
765 match (&trait_m.explicit_self, &impl_m.explicit_self) {
766 (&ast::SelfStatic, &ast::SelfStatic) => {}
767 (&ast::SelfStatic, _) => {
770 format!("method `{}` has a `{}` declaration in the impl, \
771 but not in the trait",
772 token::get_ident(trait_m.ident),
773 pprust::explicit_self_to_str(impl_m.explicit_self)));
776 (_, &ast::SelfStatic) => {
779 format!("method `{}` has a `{}` declaration in the trait, \
780 but not in the impl",
781 token::get_ident(trait_m.ident),
782 pprust::explicit_self_to_str(trait_m.explicit_self)));
786 // Let the type checker catch other errors below
790 let num_impl_m_type_params = impl_m.generics.type_param_defs().len();
791 let num_trait_m_type_params = trait_m.generics.type_param_defs().len();
792 if num_impl_m_type_params != num_trait_m_type_params {
795 format!("method `{method}` has {nimpl, plural, =1{# type parameter} \
796 other{# type parameters}}, \
797 but its trait declaration has {ntrait, plural, =1{# type parameter} \
798 other{# type parameters}}",
799 method = token::get_ident(trait_m.ident),
800 nimpl = num_impl_m_type_params,
801 ntrait = num_trait_m_type_params));
805 if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() {
808 format!("method `{method}` has {nimpl, plural, =1{# parameter} \
809 other{# parameters}} \
810 but the declaration in trait `{trait}` has {ntrait}",
811 method = token::get_ident(trait_m.ident),
812 nimpl = impl_m.fty.sig.inputs.len(),
813 trait = ty::item_path_str(tcx, trait_m.def_id),
814 ntrait = trait_m.fty.sig.inputs.len()));
818 let it = trait_m.generics.type_param_defs().iter()
819 .zip(impl_m.generics.type_param_defs().iter());
821 for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
822 // Check that the impl does not require any builtin-bounds
823 // that the trait does not guarantee:
825 impl_param_def.bounds.builtin_bounds -
826 trait_param_def.bounds.builtin_bounds;
827 if !extra_bounds.is_empty() {
830 format!("in method `{}`, \
831 type parameter {} requires `{}`, \
832 which is not required by \
833 the corresponding type parameter \
834 in the trait declaration",
835 token::get_ident(trait_m.ident),
837 extra_bounds.user_string(tcx)));
841 // FIXME(#2687)---we should be checking that the bounds of the
842 // trait imply the bounds of the subtype, but it appears we
843 // are...not checking this.
844 if impl_param_def.bounds.trait_bounds.len() !=
845 trait_param_def.bounds.trait_bounds.len()
849 format!("in method `{method}`, \
850 type parameter {typaram} has \
851 {nimpl, plural, =1{# trait bound} other{# trait bounds}}, \
852 but the corresponding type parameter in \
853 the trait declaration has \
854 {ntrait, plural, =1{# trait bound} other{# trait bounds}}",
855 method = token::get_ident(trait_m.ident),
857 nimpl = impl_param_def.bounds.trait_bounds.len(),
858 ntrait = trait_param_def.bounds.trait_bounds.len()));
863 // Create a substitution that maps the type parameters on the impl
864 // to themselves and which replace any references to bound regions
865 // in the self type with free regions. So, for example, if the
866 // impl type is "&'a str", then this would replace the self
867 // type with a free region `self`.
868 let dummy_impl_tps: Vec<ty::t> =
869 impl_generics.type_param_defs().iter().enumerate().
870 map(|(i,t)| ty::mk_param(tcx, i, t.def_id)).
872 let dummy_method_tps: Vec<ty::t> =
873 impl_m.generics.type_param_defs().iter().enumerate().
874 map(|(i,t)| ty::mk_param(tcx, i + impl_tps, t.def_id)).
876 let dummy_impl_regions: OwnedSlice<ty::Region> =
877 impl_generics.region_param_defs().iter().
878 map(|l| ty::ReFree(ty::FreeRegion {
879 scope_id: impl_m_body_id,
880 bound_region: ty::BrNamed(l.def_id, l.name)})).
882 let dummy_substs = ty::substs {
883 tps: dummy_impl_tps.append(dummy_method_tps.as_slice()),
884 regions: ty::NonerasedRegions(dummy_impl_regions),
887 // Create a bare fn type for trait/impl
888 // It'd be nice to refactor so as to provide the bare fn types instead.
889 let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
890 let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
892 // Perform substitutions so that the trait/impl methods are expressed
893 // in terms of the same set of type/region parameters:
894 // - replace trait type parameters with those from `trait_substs`,
895 // except with any reference to bound self replaced with `dummy_self_r`
896 // - replace method parameters on the trait with fresh, dummy parameters
897 // that correspond to the parameters we will find on the impl
898 // - replace self region with a fresh, dummy region
900 debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
901 impl_fty.subst(tcx, &dummy_substs)
903 debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
905 let substs { regions: trait_regions,
907 self_ty: self_ty } = trait_substs.subst(tcx, &dummy_substs);
908 let substs = substs {
909 regions: trait_regions,
910 tps: trait_tps.append(dummy_method_tps.as_slice()),
913 debug!("trait_fty (pre-subst): {} substs={}",
914 trait_fty.repr(tcx), substs.repr(tcx));
915 trait_fty.subst(tcx, &substs)
917 debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx));
919 match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span),
920 impl_fty, trait_fty) {
922 result::Err(ref terr) => {
925 format!("method `{}` has an incompatible type for trait: {}",
926 token::get_ident(trait_m.ident),
927 ty::type_err_to_str(tcx, terr)));
928 ty::note_and_explain_type_err(tcx, terr);
933 impl<'a> AstConv for FnCtxt<'a> {
934 fn tcx<'a>(&'a self) -> &'a ty::ctxt { self.ccx.tcx }
936 fn get_item_ty(&self, id: ast::DefId) -> ty::ty_param_bounds_and_ty {
937 ty::lookup_item_type(self.tcx(), id)
940 fn get_trait_def(&self, id: ast::DefId) -> @ty::TraitDef {
941 ty::lookup_trait_def(self.tcx(), id)
944 fn ty_infer(&self, _span: Span) -> ty::t {
945 self.infcx().next_ty_var()
949 impl<'a> FnCtxt<'a> {
950 pub fn infcx<'b>(&'b self) -> &'b infer::InferCtxt<'a> {
954 pub fn err_count_since_creation(&self) -> uint {
955 self.ccx.tcx.sess.err_count() - self.err_count_on_creation
958 pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
961 param_env: &self.inh.param_env
966 impl<'a> RegionScope for infer::InferCtxt<'a> {
967 fn anon_regions(&self, span: Span, count: uint)
968 -> Result<Vec<ty::Region> , ()> {
969 Ok(Vec::from_fn(count, |_| {
970 self.next_region_var(infer::MiscVariable(span))
975 impl<'a> FnCtxt<'a> {
976 pub fn tag(&self) -> ~str {
977 format!("{}", self as *FnCtxt)
980 pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t {
981 match self.inh.locals.borrow().find(&nid) {
984 self.tcx().sess.span_bug(
986 format!("no type for local variable {:?}", nid));
992 pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
993 debug!("write_ty({}, {}) in fcx {}",
994 node_id, ppaux::ty_to_str(self.tcx(), ty), self.tag());
995 self.inh.node_types.borrow_mut().insert(node_id, ty);
998 pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::substs) {
999 if !ty::substs_is_noop(&substs) {
1000 debug!("write_substs({}, {}) in fcx {}",
1002 ty::substs_to_str(self.tcx(), &substs),
1005 self.inh.node_type_substs.borrow_mut().insert(node_id, substs);
1009 pub fn write_ty_substs(&self,
1010 node_id: ast::NodeId,
1012 substs: ty::substs) {
1013 let ty = ty::subst(self.tcx(), &substs, ty);
1014 self.write_ty(node_id, ty);
1015 self.write_substs(node_id, substs);
1018 pub fn write_autoderef_adjustment(&self,
1019 node_id: ast::NodeId,
1021 if derefs == 0 { return; }
1022 self.write_adjustment(
1024 @ty::AutoDerefRef(ty::AutoDerefRef {
1030 pub fn write_adjustment(&self,
1031 node_id: ast::NodeId,
1032 adj: @ty::AutoAdjustment) {
1033 debug!("write_adjustment(node_id={:?}, adj={:?})", node_id, adj);
1034 self.inh.adjustments.borrow_mut().insert(node_id, adj);
1037 pub fn write_nil(&self, node_id: ast::NodeId) {
1038 self.write_ty(node_id, ty::mk_nil());
1040 pub fn write_bot(&self, node_id: ast::NodeId) {
1041 self.write_ty(node_id, ty::mk_bot());
1043 pub fn write_error(&self, node_id: ast::NodeId) {
1044 self.write_ty(node_id, ty::mk_err());
1047 pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
1048 ast_ty_to_ty(self, self.infcx(), ast_t)
1051 pub fn pat_to_str(&self, pat: &ast::Pat) -> ~str {
1052 pat.repr(self.tcx())
1055 pub fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
1056 match self.inh.node_types.borrow().find(&ex.id) {
1059 self.tcx().sess.bug(format!("no type for expr in fcx {}",
1065 pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
1066 match self.inh.node_types.borrow().find(&id) {
1069 self.tcx().sess.bug(
1070 format!("no type for node {}: {} in fcx {}",
1071 id, self.tcx().map.node_to_str(id),
1077 pub fn method_ty_substs(&self, id: ast::NodeId) -> ty::substs {
1078 match self.inh.method_map.borrow().find(&MethodCall::expr(id)) {
1079 Some(method) => method.substs.clone(),
1081 self.tcx().sess.bug(
1082 format!("no method entry for node {}: {} in fcx {}",
1083 id, self.tcx().map.node_to_str(id),
1089 pub fn opt_node_ty_substs(&self,
1091 f: |&ty::substs| -> bool)
1093 match self.inh.node_type_substs.borrow().find(&id) {
1099 pub fn mk_subty(&self,
1100 a_is_expected: bool,
1101 origin: infer::TypeOrigin,
1104 -> Result<(), ty::type_err> {
1105 infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
1108 pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t)
1109 -> Result<(), ty::type_err> {
1110 infer::can_mk_subty(self.infcx(), sub, sup)
1113 pub fn mk_assignty(&self,
1117 -> Result<(), ty::type_err> {
1118 match infer::mk_coercety(self.infcx(),
1120 infer::ExprAssignable(expr.span),
1123 Ok(None) => result::Ok(()),
1124 Err(ref e) => result::Err((*e)),
1125 Ok(Some(adjustment)) => {
1126 self.write_adjustment(expr.id, adjustment);
1132 pub fn mk_eqty(&self,
1133 a_is_expected: bool,
1134 origin: infer::TypeOrigin,
1137 -> Result<(), ty::type_err> {
1138 infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
1141 pub fn mk_subr(&self,
1142 a_is_expected: bool,
1143 origin: infer::SubregionOrigin,
1146 infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
1149 pub fn with_region_lb<R>(&self, lb: ast::NodeId, f: || -> R) -> R {
1150 let old_region_lb = self.region_lb.get();
1151 self.region_lb.set(lb);
1153 self.region_lb.set(old_region_lb);
1157 pub fn type_error_message(&self,
1159 mk_msg: |~str| -> ~str,
1161 err: Option<&ty::type_err>) {
1162 self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
1165 pub fn report_mismatched_return_types(&self,
1169 err: &ty::type_err) {
1171 if ty::type_is_error(e) || ty::type_is_error(a) {
1174 self.infcx().report_mismatched_types(sp, e, a, err)
1177 pub fn report_mismatched_types(&self,
1181 err: &ty::type_err) {
1182 self.infcx().report_mismatched_types(sp, e, a, err)
1186 pub enum LvaluePreference {
1191 pub fn autoderef<T>(fcx: &FnCtxt, sp: Span, base_ty: ty::t,
1192 expr_id: Option<ast::NodeId>,
1193 mut lvalue_pref: LvaluePreference,
1194 should_stop: |ty::t, uint| -> Option<T>)
1195 -> (ty::t, uint, Option<T>) {
1197 * Executes an autoderef loop for the type `t`. At each step, invokes
1198 * `should_stop` to decide whether to terminate the loop. Returns
1199 * the final type and number of derefs that it performed.
1201 * Note: this method does not modify the adjustments table. The caller is
1202 * responsible for inserting an AutoAdjustment record into the `fcx`
1203 * using one of the suitable methods.
1206 let mut t = base_ty;
1207 for autoderefs in range(0, fcx.tcx().sess.recursion_limit.get()) {
1208 let resolved_t = structurally_resolved_type(fcx, sp, t);
1210 match should_stop(resolved_t, autoderefs) {
1211 Some(x) => return (resolved_t, autoderefs, Some(x)),
1215 // Otherwise, deref if type is derefable:
1216 let mt = match ty::deref(resolved_t, false) {
1217 Some(mt) => Some(mt),
1220 expr_id.map(|id| MethodCall::autoderef(id, autoderefs as u32));
1221 try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
1227 if mt.mutbl == ast::MutImmutable {
1228 lvalue_pref = NoPreference;
1231 None => return (resolved_t, autoderefs, None)
1235 // We've reached the recursion limit, error gracefully.
1236 fcx.tcx().sess.span_err(sp,
1237 format!("reached the recursion limit while auto-dereferencing {}",
1238 base_ty.repr(fcx.tcx())));
1239 (ty::mk_err(), 0, None)
1242 fn try_overloaded_deref(fcx: &FnCtxt,
1244 method_call: Option<MethodCall>,
1245 base_expr: Option<&ast::Expr>,
1247 lvalue_pref: LvaluePreference)
1249 // Try DerefMut first, if preferred.
1250 let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
1251 (PreferMutLvalue, Some(trait_did)) => {
1252 method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
1253 token::intern("deref_mut"), trait_did,
1254 base_ty, [], DontAutoderefReceiver)
1259 // Otherwise, fall back to Deref.
1260 let method = match (method, fcx.tcx().lang_items.deref_trait()) {
1261 (None, Some(trait_did)) => {
1262 method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
1263 token::intern("deref"), trait_did,
1264 base_ty, [], DontAutoderefReceiver)
1266 (method, _) => method
1271 let ref_ty = ty::ty_fn_ret(method.ty);
1273 Some(method_call) => {
1274 fcx.inh.method_map.borrow_mut().insert(method_call, method);
1278 ty::deref(ref_ty, true)
1284 // AST fragment checking
1285 pub fn check_lit(fcx: &FnCtxt, lit: &ast::Lit) -> ty::t {
1286 let tcx = fcx.ccx.tcx;
1289 ast::LitStr(..) => ty::mk_str(tcx, ty::VstoreSlice(ty::ReStatic, ())),
1290 ast::LitBinary(..) => {
1291 ty::mk_vec(tcx, ty::mk_u8(),
1292 ty::VstoreSlice(ty::ReStatic, ast::MutImmutable))
1294 ast::LitChar(_) => ty::mk_char(),
1295 ast::LitInt(_, t) => ty::mk_mach_int(t),
1296 ast::LitUint(_, t) => ty::mk_mach_uint(t),
1297 ast::LitIntUnsuffixed(_) => {
1298 // An unsuffixed integer literal could have any integral type,
1299 // so we create an integral type variable for it.
1300 ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
1302 ast::LitFloat(_, t) => ty::mk_mach_float(t),
1303 ast::LitFloatUnsuffixed(_) => {
1304 // An unsuffixed floating point literal could have any floating point
1305 // type, so we create a floating point type variable for it.
1306 ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())
1308 ast::LitNil => ty::mk_nil(),
1309 ast::LitBool(_) => ty::mk_bool()
1313 pub fn valid_range_bounds(ccx: &CrateCtxt,
1317 match const_eval::compare_lit_exprs(ccx.tcx, from, to) {
1318 Some(val) => Some(val <= 0),
1323 pub fn check_expr_has_type(
1324 fcx: &FnCtxt, expr: &ast::Expr,
1326 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1327 demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
1331 fn check_expr_coercable_to_type(fcx: &FnCtxt, expr: &ast::Expr, expected: ty::t) {
1332 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1333 demand::coerce(fcx, expr.span, expected, expr)
1337 fn check_expr_with_hint(fcx: &FnCtxt, expr: &ast::Expr, expected: ty::t) {
1338 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || ())
1341 fn check_expr_with_opt_hint(fcx: &FnCtxt, expr: &ast::Expr,
1342 expected: Option<ty::t>) {
1343 check_expr_with_unifier(fcx, expr, expected, NoPreference, || ())
1346 fn check_expr_with_opt_hint_and_lvalue_pref(fcx: &FnCtxt,
1348 expected: Option<ty::t>,
1349 lvalue_pref: LvaluePreference) {
1350 check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ())
1353 fn check_expr(fcx: &FnCtxt, expr: &ast::Expr) {
1354 check_expr_with_unifier(fcx, expr, None, NoPreference, || ())
1357 fn check_expr_with_lvalue_pref(fcx: &FnCtxt, expr: &ast::Expr,
1358 lvalue_pref: LvaluePreference) {
1359 check_expr_with_unifier(fcx, expr, None, lvalue_pref, || ())
1363 // determine the `self` type, using fresh variables for all variables
1364 // declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
1365 // would return ($0, $1) where $0 and $1 are freshly instantiated type
1367 pub fn impl_self_ty(vcx: &VtableContext,
1368 span: Span, // (potential) receiver for this impl
1370 -> ty_param_substs_and_ty {
1371 let tcx = vcx.tcx();
1373 let ity = ty::lookup_item_type(tcx, did);
1374 let (n_tps, rps, raw_ty) =
1375 (ity.generics.type_param_defs().len(),
1376 ity.generics.region_param_defs(),
1379 let rps = vcx.infcx.region_vars_for_defs(span, rps);
1380 let tps = vcx.infcx.next_ty_vars(n_tps);
1382 let substs = substs {
1383 regions: ty::NonerasedRegions(rps),
1387 let substd_ty = ty::subst(tcx, &substs, raw_ty);
1389 ty_param_substs_and_ty { substs: substs, ty: substd_ty }
1392 // Only for fields! Returns <none> for methods>
1393 // Indifferent to privacy flags
1394 pub fn lookup_field_ty(tcx: &ty::ctxt,
1395 class_id: ast::DefId,
1396 items: &[ty::field_ty],
1397 fieldname: ast::Name,
1398 substs: &ty::substs) -> Option<ty::t> {
1400 let o_field = items.iter().find(|f| f.name == fieldname);
1401 o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
1404 // Controls whether the arguments are automatically referenced. This is useful
1405 // for overloaded binary and unary operators.
1406 pub enum DerefArgs {
1411 // Given the provenance of a static method, returns the generics of the static
1412 // method's container.
1413 fn generics_of_static_method_container(type_context: &ty::ctxt,
1414 provenance: ast::MethodProvenance)
1417 ast::FromTrait(trait_def_id) => {
1418 ty::lookup_trait_def(type_context, trait_def_id).generics.clone()
1420 ast::FromImpl(impl_def_id) => {
1421 ty::lookup_item_type(type_context, impl_def_id).generics.clone()
1426 // Verifies that type parameters supplied in paths are in the right
1428 fn check_type_parameter_positions_in_path(function_context: &FnCtxt,
1431 // We only care about checking the case in which the path has two or
1433 if path.segments.len() < 2 {
1437 // Verify that no lifetimes or type parameters are present anywhere
1438 // except the final two elements of the path.
1439 for i in range(0, path.segments.len() - 2) {
1440 for lifetime in path.segments.get(i).lifetimes.iter() {
1441 function_context.tcx()
1443 .span_err(lifetime.span,
1444 "lifetime parameters may not \
1449 for typ in path.segments.get(i).types.iter() {
1450 function_context.tcx()
1453 "type parameters may not appear here");
1458 // If there are no parameters at all, there is nothing more to do; the
1459 // rest of typechecking will (attempt to) infer everything.
1462 .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) {
1467 // If this is a static method of a trait or implementation, then
1468 // ensure that the segment of the path which names the trait or
1469 // implementation (the penultimate segment) is annotated with the
1470 // right number of type parameters.
1471 ast::DefStaticMethod(_, provenance, _) => {
1473 generics_of_static_method_container(function_context.ccx.tcx,
1475 let name = match provenance {
1476 ast::FromTrait(_) => "trait",
1477 ast::FromImpl(_) => "impl",
1480 let trait_segment = &path.segments.get(path.segments.len() - 2);
1482 // Make sure lifetime parameterization agrees with the trait or
1483 // implementation type.
1484 let trait_region_parameter_count = generics.region_param_defs().len();
1485 let supplied_region_parameter_count = trait_segment.lifetimes.len();
1486 if trait_region_parameter_count != supplied_region_parameter_count
1487 && supplied_region_parameter_count != 0 {
1488 function_context.tcx()
1490 .span_err(path.span,
1491 format!("expected {nexpected, plural, =1{# lifetime parameter} \
1492 other{# lifetime parameters}}, \
1493 found {nsupplied, plural, =1{# lifetime parameter} \
1494 other{# lifetime parameters}}",
1495 nexpected = trait_region_parameter_count,
1496 nsupplied = supplied_region_parameter_count));
1499 // Make sure the number of type parameters supplied on the trait
1500 // or implementation segment equals the number of type parameters
1501 // on the trait or implementation definition.
1502 let formal_ty_param_count = generics.type_param_defs().len();
1503 let required_ty_param_count = generics.type_param_defs().iter()
1504 .take_while(|x| x.default.is_none())
1506 let supplied_ty_param_count = trait_segment.types.len();
1507 if supplied_ty_param_count < required_ty_param_count {
1508 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1509 format!("the {trait_or_impl} referenced by this path needs at least \
1510 {nexpected, plural, =1{# type parameter} \
1511 other{# type parameters}}, \
1512 but {nsupplied, plural, =1{# type parameter} \
1513 other{# type parameters}} were supplied",
1514 trait_or_impl = name,
1515 nexpected = required_ty_param_count,
1516 nsupplied = supplied_ty_param_count)
1518 format!("the {trait_or_impl} referenced by this path needs \
1519 {nexpected, plural, =1{# type parameter} \
1520 other{# type parameters}}, \
1521 but {nsupplied, plural, =1{# type parameter} \
1522 other{# type parameters}} were supplied",
1523 trait_or_impl = name,
1524 nexpected = required_ty_param_count,
1525 nsupplied = supplied_ty_param_count)
1527 function_context.tcx().sess.span_err(path.span, msg)
1528 } else if supplied_ty_param_count > formal_ty_param_count {
1529 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1530 format!("the {trait_or_impl} referenced by this path needs at most \
1531 {nexpected, plural, =1{# type parameter} \
1532 other{# type parameters}}, \
1533 but {nsupplied, plural, =1{# type parameter} \
1534 other{# type parameters}} were supplied",
1535 trait_or_impl = name,
1536 nexpected = formal_ty_param_count,
1537 nsupplied = supplied_ty_param_count)
1539 format!("the {trait_or_impl} referenced by this path needs \
1540 {nexpected, plural, =1{# type parameter} \
1541 other{# type parameters}}, \
1542 but {nsupplied, plural, =1{# type parameter} \
1543 other{# type parameters}} were supplied",
1544 trait_or_impl = name,
1545 nexpected = formal_ty_param_count,
1546 nsupplied = supplied_ty_param_count)
1548 function_context.tcx().sess.span_err(path.span, msg)
1552 // Verify that no lifetimes or type parameters are present on
1553 // the penultimate segment of the path.
1554 let segment = &path.segments.get(path.segments.len() - 2);
1555 for lifetime in segment.lifetimes.iter() {
1556 function_context.tcx()
1558 .span_err(lifetime.span,
1559 "lifetime parameters may not
1563 for typ in segment.types.iter() {
1564 function_context.tcx()
1567 "type parameters may not appear \
1576 /// If an expression has any sub-expressions that result in a type error,
1577 /// inspecting that expression's type with `ty::type_is_error` will return
1578 /// true. Likewise, if an expression is known to diverge, inspecting its
1579 /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
1580 /// strict, _|_ can appear in the type of an expression that does not,
1581 /// itself, diverge: for example, fn() -> _|_.)
1582 /// Note that inspecting a type's structure *directly* may expose the fact
1583 /// that there are actually multiple representations for both `ty_err` and
1584 /// `ty_bot`, so avoid that when err and bot need to be handled differently.
1585 fn check_expr_with_unifier(fcx: &FnCtxt,
1587 expected: Option<ty::t>,
1588 lvalue_pref: LvaluePreference,
1590 debug!(">> typechecking");
1592 fn check_method_argument_types(
1595 method_fn_ty: ty::t,
1596 callee_expr: &ast::Expr,
1597 args: &[@ast::Expr],
1598 deref_args: DerefArgs) -> ty::t {
1599 // HACK(eddyb) ignore provided self (it has special typeck rules).
1600 let args = args.slice_from(1);
1601 if ty::type_is_error(method_fn_ty) {
1602 let err_inputs = err_args(args.len());
1603 check_argument_types(fcx, sp, err_inputs.as_slice(), callee_expr,
1604 args, deref_args, false);
1607 match ty::get(method_fn_ty).sty {
1608 ty::ty_bare_fn(ref fty) => {
1609 // HACK(eddyb) ignore self in the definition (see above).
1610 check_argument_types(fcx, sp, fty.sig.inputs.slice_from(1),
1611 callee_expr, args, deref_args,
1616 fcx.tcx().sess.span_bug(
1618 format!("method without bare fn type"));
1624 fn check_argument_types(fcx: &FnCtxt,
1626 fn_inputs: &[ty::t],
1627 callee_expr: &ast::Expr,
1628 args: &[@ast::Expr],
1629 deref_args: DerefArgs,
1633 * Generic function that factors out common logic from
1634 * function calls, method calls and overloaded operators.
1637 let tcx = fcx.ccx.tcx;
1639 // Grab the argument types, supplying fresh type variables
1640 // if the wrong number of arguments were supplied
1641 let supplied_arg_count = args.len();
1642 let expected_arg_count = fn_inputs.len();
1643 let formal_tys = if expected_arg_count == supplied_arg_count {
1644 fn_inputs.iter().map(|a| *a).collect()
1645 } else if variadic {
1646 if supplied_arg_count >= expected_arg_count {
1647 fn_inputs.iter().map(|a| *a).collect()
1650 "this function takes at least {nexpected, plural, =1{# parameter} \
1651 other{# parameters}} \
1652 but {nsupplied, plural, =1{# parameter was} \
1653 other{# parameters were}} supplied",
1654 nexpected = expected_arg_count,
1655 nsupplied = supplied_arg_count);
1657 tcx.sess.span_err(sp, msg);
1659 err_args(supplied_arg_count)
1663 "this function takes {nexpected, plural, =1{# parameter} \
1664 other{# parameters}} \
1665 but {nsupplied, plural, =1{# parameter was} \
1666 other{# parameters were}} supplied",
1667 nexpected = expected_arg_count,
1668 nsupplied = supplied_arg_count);
1670 tcx.sess.span_err(sp, msg);
1672 err_args(supplied_arg_count)
1675 debug!("check_argument_types: formal_tys={:?}",
1676 formal_tys.iter().map(|t| fcx.infcx().ty_to_str(*t)).collect::<Vec<~str>>());
1678 // Check the arguments.
1679 // We do this in a pretty awful way: first we typecheck any arguments
1680 // that are not anonymous functions, then we typecheck the anonymous
1681 // functions. This is so that we have more information about the types
1682 // of arguments when we typecheck the functions. This isn't really the
1683 // right way to do this.
1684 let xs = [false, true];
1685 for check_blocks in xs.iter() {
1686 let check_blocks = *check_blocks;
1687 debug!("check_blocks={}", check_blocks);
1689 // More awful hacks: before we check the blocks, try to do
1690 // an "opportunistic" vtable resolution of any trait
1691 // bounds on the call.
1693 vtable::early_resolve_expr(callee_expr, fcx, true);
1696 // For variadic functions, we don't have a declared type for all of
1697 // the arguments hence we only do our usual type checking with
1698 // the arguments who's types we do know.
1699 let t = if variadic {
1704 for (i, arg) in args.iter().take(t).enumerate() {
1705 let is_block = match arg.node {
1706 ast::ExprFnBlock(..) |
1707 ast::ExprProc(..) => true,
1711 if is_block == check_blocks {
1712 debug!("checking the argument");
1713 let mut formal_ty = *formal_tys.get(i);
1717 match ty::get(formal_ty).sty {
1718 ty::ty_rptr(_, mt) => formal_ty = mt.ty,
1721 // So we hit this case when one implements the
1722 // operator traits but leaves an argument as
1723 // just T instead of &T. We'll catch it in the
1724 // mismatch impl/trait method phase no need to
1727 formal_ty = ty::mk_err();
1734 check_expr_coercable_to_type(fcx, *arg, formal_ty);
1740 // We also need to make sure we at least write the ty of the other
1741 // arguments which we skipped above.
1743 for arg in args.iter().skip(expected_arg_count) {
1744 check_expr(fcx, *arg);
1746 // There are a few types which get autopromoted when passed via varargs
1747 // in C but we just error out instead and require explicit casts.
1748 let arg_ty = structurally_resolved_type(fcx, arg.span, fcx.expr_ty(*arg));
1749 match ty::get(arg_ty).sty {
1750 ty::ty_float(ast::TyF32) => {
1751 fcx.type_error_message(arg.span,
1752 |t| format!("can't pass an {} to variadic function, \
1753 cast to c_double", t), arg_ty, None);
1755 ty::ty_int(ast::TyI8) | ty::ty_int(ast::TyI16) | ty::ty_bool => {
1756 fcx.type_error_message(arg.span,
1757 |t| format!("can't pass {} to variadic function, cast to c_int",
1760 ty::ty_uint(ast::TyU8) | ty::ty_uint(ast::TyU16) => {
1761 fcx.type_error_message(arg.span,
1762 |t| format!("can't pass {} to variadic function, cast to c_uint",
1771 fn err_args(len: uint) -> Vec<ty::t> {
1772 Vec::from_fn(len, |_| ty::mk_err())
1775 fn write_call(fcx: &FnCtxt, call_expr: &ast::Expr, output: ty::t) {
1776 fcx.write_ty(call_expr.id, output);
1779 // A generic function for doing all of the checking for call expressions
1780 fn check_call(fcx: &FnCtxt,
1781 call_expr: &ast::Expr,
1783 args: &[@ast::Expr]) {
1784 // Index expressions need to be handled separately, to inform them
1785 // that they appear in call position.
1788 // Store the type of `f` as the type of the callee
1789 let fn_ty = fcx.expr_ty(f);
1791 // Extract the function signature from `in_fty`.
1792 let fn_sty = structure_of(fcx, f.span, fn_ty);
1794 // This is the "default" function signature, used in case of error.
1795 // In that case, we check each argument against "error" in order to
1796 // set up all the node type bindings.
1797 let error_fn_sig = FnSig {
1798 binder_id: ast::CRATE_NODE_ID,
1799 inputs: err_args(args.len()),
1800 output: ty::mk_err(),
1804 let fn_sig = match *fn_sty {
1805 ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, ..}) |
1806 ty::ty_closure(~ty::ClosureTy {sig: ref sig, ..}) => sig,
1808 fcx.type_error_message(call_expr.span, |actual| {
1809 format!("expected function but \
1810 found `{}`", actual) }, fn_ty, None);
1815 // Replace any bound regions that appear in the function
1816 // signature with region variables
1817 let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
1818 fcx.infcx().next_region_var(infer::LateBoundRegion(call_expr.span, br))
1821 // Call the generic checker.
1822 check_argument_types(fcx, call_expr.span, fn_sig.inputs.as_slice(), f,
1823 args, DontDerefArgs, fn_sig.variadic);
1825 write_call(fcx, call_expr, fn_sig.output);
1828 // Checks a method call.
1829 fn check_method_call(fcx: &FnCtxt,
1831 method_name: ast::Ident,
1832 args: &[@ast::Expr],
1833 tps: &[ast::P<ast::Ty>]) {
1835 // We can't know if we need &mut self before we look up the method,
1836 // so treat the receiver as mutable just in case - only explicit
1837 // overloaded dereferences care about the distinction.
1838 check_expr_with_lvalue_pref(fcx, rcvr, PreferMutLvalue);
1840 // no need to check for bot/err -- callee does that
1841 let expr_t = structurally_resolved_type(fcx,
1845 let tps = tps.iter().map(|&ast_ty| fcx.to_ty(ast_ty)).collect::<Vec<_>>();
1846 let fn_ty = match method::lookup(fcx, expr, rcvr,
1848 expr_t, tps.as_slice(),
1850 CheckTraitsAndInherentMethods,
1851 AutoderefReceiver) {
1853 let method_ty = method.ty;
1854 let method_call = MethodCall::expr(expr.id);
1855 fcx.inh.method_map.borrow_mut().insert(method_call, method);
1859 debug!("(checking method call) failing expr is {}", expr.id);
1861 fcx.type_error_message(expr.span,
1863 format!("type `{}` does not implement any method in scope \
1865 actual, token::get_ident(method_name))
1870 // Add error type for the result
1871 fcx.write_error(expr.id);
1876 // Call the generic checker.
1877 let ret_ty = check_method_argument_types(fcx, expr.span,
1881 write_call(fcx, expr, ret_ty);
1884 // A generic function for checking the then and else in an if
1886 fn check_then_else(fcx: &FnCtxt,
1887 cond_expr: &ast::Expr,
1888 then_blk: &ast::Block,
1889 opt_else_expr: Option<@ast::Expr>,
1892 expected: Option<ty::t>) {
1893 check_expr_has_type(fcx, cond_expr, ty::mk_bool());
1895 let branches_ty = match opt_else_expr {
1896 Some(else_expr) => {
1897 check_block_with_expected(fcx, then_blk, expected);
1898 let then_ty = fcx.node_ty(then_blk.id);
1899 check_expr_with_opt_hint(fcx, else_expr, expected);
1900 let else_ty = fcx.expr_ty(else_expr);
1901 infer::common_supertype(fcx.infcx(),
1902 infer::IfExpression(sp),
1908 check_block_no_value(fcx, then_blk);
1913 let cond_ty = fcx.expr_ty(cond_expr);
1914 let if_ty = if ty::type_is_error(cond_ty) {
1916 } else if ty::type_is_bot(cond_ty) {
1922 fcx.write_ty(id, if_ty);
1925 fn lookup_op_method(fcx: &FnCtxt,
1929 trait_did: Option<ast::DefId>,
1930 args: &[@ast::Expr],
1931 autoderef_receiver: AutoderefReceiverFlag,
1932 unbound_method: ||) -> ty::t {
1933 let method = match trait_did {
1934 Some(trait_did) => {
1935 method::lookup_in_trait(fcx, op_ex.span, Some(&*args[0]), opname,
1936 trait_did, self_t, [], autoderef_receiver)
1942 let method_ty = method.ty;
1943 // HACK(eddyb) Fully qualified path to work around a resolve bug.
1944 let method_call = ::middle::typeck::MethodCall::expr(op_ex.id);
1945 fcx.inh.method_map.borrow_mut().insert(method_call, method);
1946 check_method_argument_types(fcx, op_ex.span,
1952 // Check the args anyway
1953 // so we get all the error messages
1954 let expected_ty = ty::mk_err();
1955 check_method_argument_types(fcx, op_ex.span,
1963 // could be either an expr_binop or an expr_assign_binop
1964 fn check_binop(fcx: &FnCtxt,
1969 is_binop_assignment: IsBinopAssignment) {
1970 let tcx = fcx.ccx.tcx;
1972 let lvalue_pref = match is_binop_assignment {
1973 BinopAssignment => PreferMutLvalue,
1974 SimpleBinop => NoPreference
1976 check_expr_with_lvalue_pref(fcx, lhs, lvalue_pref);
1978 // Callee does bot / err checking
1979 let lhs_t = structurally_resolved_type(fcx, lhs.span,
1982 if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) {
1983 // Shift is a special case: rhs can be any integral type
1984 check_expr(fcx, rhs);
1985 let rhs_t = fcx.expr_ty(rhs);
1986 require_integral(fcx, rhs.span, rhs_t);
1987 fcx.write_ty(expr.id, lhs_t);
1991 if ty::is_binopable(tcx, lhs_t, op) {
1992 let tvar = fcx.infcx().next_ty_var();
1993 demand::suptype(fcx, expr.span, tvar, lhs_t);
1994 check_expr_has_type(fcx, rhs, tvar);
1996 let result_t = match op {
1997 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGe |
1998 ast::BiGt => ty::mk_bool(),
2002 fcx.write_ty(expr.id, result_t);
2006 if op == ast::BiOr || op == ast::BiAnd {
2007 // This is an error; one of the operands must have the wrong
2009 fcx.write_error(expr.id);
2010 fcx.write_error(rhs.id);
2011 fcx.type_error_message(expr.span, |actual| {
2012 format!("binary operation `{}` cannot be applied \
2014 ast_util::binop_to_str(op), actual)},
2019 // Check for overloaded operators if not an assignment.
2020 let result_t = if is_binop_assignment == SimpleBinop {
2021 check_user_binop(fcx, expr, lhs, lhs_t, op, rhs)
2023 fcx.type_error_message(expr.span,
2025 format!("binary assignment operation \
2026 `{}=` cannot be applied to type `{}`",
2027 ast_util::binop_to_str(op),
2032 check_expr(fcx, rhs);
2036 fcx.write_ty(expr.id, result_t);
2037 if ty::type_is_error(result_t) {
2038 fcx.write_ty(rhs.id, result_t);
2042 fn check_user_binop(fcx: &FnCtxt,
2044 lhs_expr: @ast::Expr,
2045 lhs_resolved_t: ty::t,
2047 rhs: @ast::Expr) -> ty::t {
2048 let tcx = fcx.ccx.tcx;
2049 let lang = tcx.lang_items;
2050 let (name, trait_did) = match op {
2051 ast::BiAdd => ("add", lang.add_trait()),
2052 ast::BiSub => ("sub", lang.sub_trait()),
2053 ast::BiMul => ("mul", lang.mul_trait()),
2054 ast::BiDiv => ("div", lang.div_trait()),
2055 ast::BiRem => ("rem", lang.rem_trait()),
2056 ast::BiBitXor => ("bitxor", lang.bitxor_trait()),
2057 ast::BiBitAnd => ("bitand", lang.bitand_trait()),
2058 ast::BiBitOr => ("bitor", lang.bitor_trait()),
2059 ast::BiShl => ("shl", lang.shl_trait()),
2060 ast::BiShr => ("shr", lang.shr_trait()),
2061 ast::BiLt => ("lt", lang.ord_trait()),
2062 ast::BiLe => ("le", lang.ord_trait()),
2063 ast::BiGe => ("ge", lang.ord_trait()),
2064 ast::BiGt => ("gt", lang.ord_trait()),
2065 ast::BiEq => ("eq", lang.eq_trait()),
2066 ast::BiNe => ("ne", lang.eq_trait()),
2067 ast::BiAnd | ast::BiOr => {
2068 check_expr(fcx, rhs);
2069 return ty::mk_err();
2072 lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
2073 trait_did, [lhs_expr, rhs], DontAutoderefReceiver, || {
2074 fcx.type_error_message(ex.span, |actual| {
2075 format!("binary operation `{}` cannot be applied to type `{}`",
2076 ast_util::binop_to_str(op), actual)
2077 }, lhs_resolved_t, None)
2081 fn check_user_unop(fcx: &FnCtxt,
2084 trait_did: Option<ast::DefId>,
2086 rhs_expr: @ast::Expr,
2087 rhs_t: ty::t) -> ty::t {
2088 lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
2089 trait_did, [rhs_expr], DontAutoderefReceiver, || {
2090 fcx.type_error_message(ex.span, |actual| {
2091 format!("cannot apply unary operator `{}` to type `{}`", op_str, actual)
2096 // Resolves `expected` by a single level if it is a variable and passes it
2097 // through the `unpack` function. It there is no expected type or
2098 // resolution is not possible (e.g., no constraints yet present), just
2100 fn unpack_expected<O>(
2102 expected: Option<ty::t>,
2103 unpack: |&ty::sty| -> Option<O>)
2107 match resolve_type(fcx.infcx(), t, force_tvar) {
2108 Ok(t) => unpack(&ty::get(t).sty),
2116 fn check_expr_fn(fcx: &FnCtxt,
2118 store: ty::TraitStore,
2120 body: ast::P<ast::Block>,
2122 expected: Option<ty::t>) {
2123 let tcx = fcx.ccx.tcx;
2125 // Find the expected input/output types (if any). Substitute
2126 // fresh bound regions for any bound regions we find in the
2127 // expected types so as to avoid capture.
2128 let expected_sty = unpack_expected(fcx,
2130 |x| Some((*x).clone()));
2131 let error_happened = false;
2134 expected_bounds) = {
2135 match expected_sty {
2136 Some(ty::ty_closure(ref cenv)) => {
2138 replace_late_bound_regions_in_fn_sig(
2140 |_| fcx.inh.infcx.fresh_bound_region(expr.id));
2141 (Some(sig), cenv.onceness, cenv.bounds)
2144 // Not an error! Means we're inferring the closure type
2145 let mut bounds = ty::EmptyBuiltinBounds();
2146 let onceness = match expr.node {
2147 ast::ExprProc(..) => {
2148 bounds.add(ty::BoundSend);
2153 (None, onceness, bounds)
2158 // construct the function type
2159 let fn_ty = astconv::ty_of_closure(fcx,
2169 let fty = if error_happened {
2171 binder_id: ast::CRATE_NODE_ID,
2172 inputs: fn_ty.sig.inputs.iter().map(|_| ty::mk_err()).collect(),
2173 output: ty::mk_err(),
2178 fty_sig = fn_ty.sig.clone();
2179 ty::mk_closure(tcx, fn_ty.clone())
2182 debug!("check_expr_fn_with_unifier fty={}",
2183 fcx.infcx().ty_to_str(fty));
2185 fcx.write_ty(expr.id, fty);
2187 // If the closure is a stack closure and hasn't had some non-standard
2188 // style inferred for it, then check it under its parent's style.
2189 // Otherwise, use its own
2190 let (inherited_style, id) = match store {
2191 ty::RegionTraitStore(..) => (fcx.ps.borrow().fn_style,
2192 fcx.ps.borrow().def),
2193 ty::UniqTraitStore => (ast::NormalFn, expr.id)
2196 check_fn(fcx.ccx, inherited_style, &fty_sig,
2197 decl, id, body, fn_kind, fcx.inh);
2201 // Check field access expressions
2202 fn check_field(fcx: &FnCtxt,
2204 lvalue_pref: LvaluePreference,
2207 tys: &[ast::P<ast::Ty>]) {
2208 let tcx = fcx.ccx.tcx;
2209 check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
2210 let expr_t = structurally_resolved_type(fcx, expr.span,
2212 // FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
2213 let (_, autoderefs, field_ty) =
2214 autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
2215 match ty::get(base_t).sty {
2216 ty::ty_struct(base_id, ref substs) => {
2217 debug!("struct named {}", ppaux::ty_to_str(tcx, base_t));
2218 let fields = ty::lookup_struct_fields(tcx, base_id);
2219 lookup_field_ty(tcx, base_id, fields.as_slice(), field, &(*substs))
2226 fcx.write_ty(expr.id, field_ty);
2227 fcx.write_autoderef_adjustment(base.id, autoderefs);
2233 let tps: Vec<ty::t> = tys.iter().map(|&ty| fcx.to_ty(ty)).collect();
2234 match method::lookup(fcx,
2241 CheckTraitsAndInherentMethods,
2242 AutoderefReceiver) {
2244 fcx.type_error_message(
2247 format!("attempted to take value of method `{}` on type `{}`",
2248 token::get_name(field), actual)
2252 tcx.sess.span_note(expr.span,
2253 "maybe a missing `()` to call it? If not, try an anonymous function.");
2257 fcx.type_error_message(
2260 format!("attempted access of field `{}` on type `{}`, \
2261 but no field with that name was found",
2262 token::get_name(field), actual)
2268 fcx.write_error(expr.id);
2271 fn check_struct_or_variant_fields(fcx: &FnCtxt,
2274 class_id: ast::DefId,
2275 node_id: ast::NodeId,
2276 substitutions: ty::substs,
2277 field_types: &[ty::field_ty],
2278 ast_fields: &[ast::Field],
2279 check_completeness: bool) {
2280 let tcx = fcx.ccx.tcx;
2282 let mut class_field_map = HashMap::new();
2283 let mut fields_found = 0;
2284 for field in field_types.iter() {
2285 class_field_map.insert(field.name, (field.id, false));
2288 let mut error_happened = false;
2290 // Typecheck each field.
2291 for field in ast_fields.iter() {
2292 let mut expected_field_type = ty::mk_err();
2294 let pair = class_field_map.find(&field.ident.node.name).map(|x| *x);
2297 fcx.type_error_message(
2300 format!("structure `{}` has no field named `{}`",
2301 actual, token::get_ident(field.ident.node))
2302 }, struct_ty, None);
2303 error_happened = true;
2305 Some((_, true)) => {
2308 format!("field `{}` specified more than once",
2309 token::get_ident(field.ident.node)));
2310 error_happened = true;
2312 Some((field_id, false)) => {
2313 expected_field_type =
2314 ty::lookup_field_type(
2315 tcx, class_id, field_id, &substitutions);
2316 class_field_map.insert(
2317 field.ident.node.name, (field_id, true));
2321 // Make sure to give a type to the field even if there's
2322 // an error, so we can continue typechecking
2323 check_expr_coercable_to_type(
2326 expected_field_type);
2330 fcx.write_error(node_id);
2333 if check_completeness && !error_happened {
2334 // Make sure the programmer specified all the fields.
2335 assert!(fields_found <= field_types.len());
2336 if fields_found < field_types.len() {
2337 let mut missing_fields = Vec::new();
2338 for class_field in field_types.iter() {
2339 let name = class_field.name;
2340 let (_, seen) = *class_field_map.get(&name);
2342 missing_fields.push(~"`" + token::get_name(name).get() + "`");
2346 tcx.sess.span_err(span,
2347 format!("missing {nfields, plural, =1{field} other{fields}}: {fields}",
2348 nfields = missing_fields.len(),
2349 fields = missing_fields.connect(", ")));
2353 if !error_happened {
2354 fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx,
2355 class_id, substitutions));
2359 fn check_struct_constructor(fcx: &FnCtxt,
2361 span: codemap::Span,
2362 class_id: ast::DefId,
2363 fields: &[ast::Field],
2364 base_expr: Option<@ast::Expr>) {
2365 let tcx = fcx.ccx.tcx;
2367 // Look up the number of type parameters and the raw type, and
2368 // determine whether the class is region-parameterized.
2369 let item_type = ty::lookup_item_type(tcx, class_id);
2370 let type_parameter_count = item_type.generics.type_param_defs().len();
2371 let region_param_defs = item_type.generics.region_param_defs();
2372 let raw_type = item_type.ty;
2374 // Generate the struct type.
2375 let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs);
2376 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2377 let substitutions = substs {
2378 regions: ty::NonerasedRegions(regions),
2380 tps: type_parameters
2383 let mut struct_type = ty::subst(tcx, &substitutions, raw_type);
2385 // Look up and check the fields.
2386 let class_fields = ty::lookup_struct_fields(tcx, class_id);
2387 check_struct_or_variant_fields(fcx,
2393 class_fields.as_slice(),
2395 base_expr.is_none());
2396 if ty::type_is_error(fcx.node_ty(id)) {
2397 struct_type = ty::mk_err();
2400 // Check the base expression if necessary.
2403 Some(base_expr) => {
2404 check_expr_has_type(fcx, base_expr, struct_type);
2405 if ty::type_is_bot(fcx.node_ty(base_expr.id)) {
2406 struct_type = ty::mk_bot();
2411 // Write in the resulting type.
2412 fcx.write_ty(id, struct_type);
2415 fn check_struct_enum_variant(fcx: &FnCtxt,
2417 span: codemap::Span,
2418 enum_id: ast::DefId,
2419 variant_id: ast::DefId,
2420 fields: &[ast::Field]) {
2421 let tcx = fcx.ccx.tcx;
2423 // Look up the number of type parameters and the raw type, and
2424 // determine whether the enum is region-parameterized.
2425 let item_type = ty::lookup_item_type(tcx, enum_id);
2426 let type_parameter_count = item_type.generics.type_param_defs().len();
2427 let region_param_defs = item_type.generics.region_param_defs();
2428 let raw_type = item_type.ty;
2430 // Generate the enum type.
2431 let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs);
2432 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2433 let substitutions = substs {
2434 regions: ty::NonerasedRegions(regions),
2436 tps: type_parameters
2439 let enum_type = ty::subst(tcx, &substitutions, raw_type);
2441 // Look up and check the enum variant fields.
2442 let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2443 check_struct_or_variant_fields(fcx,
2449 variant_fields.as_slice(),
2452 fcx.write_ty(id, enum_type);
2455 let tcx = fcx.ccx.tcx;
2458 ast::ExprVstore(ev, vst) => {
2459 let typ = match ev.node {
2460 ast::ExprLit(lit) if ast_util::lit_is_str(lit) => {
2461 let v = ast_expr_vstore_to_vstore(fcx, ev, vst, ());
2464 ast::ExprVec(ref args) => {
2465 let mutability = match vst {
2466 ast::ExprVstoreMutSlice => ast::MutMutable,
2467 _ => ast::MutImmutable,
2469 let v = ast_expr_vstore_to_vstore(fcx, ev, vst, mutability);
2470 let mut any_error = false;
2471 let mut any_bot = false;
2472 let t: ty::t = fcx.infcx().next_ty_var();
2473 for e in args.iter() {
2474 check_expr_has_type(fcx, *e, t);
2475 let arg_t = fcx.expr_ty(*e);
2476 if ty::type_is_error(arg_t) {
2479 else if ty::type_is_bot(arg_t) {
2488 ty::mk_vec(tcx, t, v)
2491 ast::ExprRepeat(element, count_expr) => {
2492 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2493 let _ = ty::eval_repeat_count(fcx, count_expr);
2494 let mutability = match vst {
2495 ast::ExprVstoreMutSlice => ast::MutMutable,
2496 _ => ast::MutImmutable,
2498 let v = ast_expr_vstore_to_vstore(fcx, ev, vst, mutability);
2499 let t = fcx.infcx().next_ty_var();
2500 check_expr_has_type(fcx, element, t);
2501 let arg_t = fcx.expr_ty(element);
2502 if ty::type_is_error(arg_t) {
2504 } else if ty::type_is_bot(arg_t) {
2507 ty::mk_vec(tcx, t, v)
2511 tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence")
2513 fcx.write_ty(ev.id, typ);
2514 fcx.write_ty(id, typ);
2517 ast::ExprBox(place, subexpr) => {
2518 check_expr(fcx, place);
2519 check_expr(fcx, subexpr);
2521 let mut checked = false;
2523 ast::ExprPath(ref path) => {
2524 // FIXME(pcwalton): For now we hardcode the two permissible
2525 // places: the exchange heap and the managed heap.
2526 let definition = lookup_def(fcx, path.span, place.id);
2527 let def_id = ast_util::def_id_of_def(definition);
2528 match tcx.lang_items
2530 .get(ExchangeHeapLangItem as uint) {
2531 &Some(item_def_id) if def_id == item_def_id => {
2532 fcx.write_ty(id, ty::mk_uniq(tcx,
2533 fcx.expr_ty(subexpr)));
2536 &Some(_) | &None => {}
2539 match tcx.lang_items
2541 .get(ManagedHeapLangItem as uint) {
2542 &Some(item_def_id) if def_id == item_def_id => {
2543 // Assign the magic `Gc<T>` struct.
2545 match tcx.lang_items
2546 .require(GcLangItem) {
2549 tcx.sess.span_err(expr.span, msg);
2551 krate: ast::CRATE_NODE_ID,
2552 node: ast::DUMMY_NODE_ID,
2557 ty::NonerasedRegions(OwnedSlice::empty());
2558 let sty = ty::mk_struct(tcx,
2568 fcx.write_ty(id, sty);
2571 &Some(_) | &None => {}
2579 tcx.sess.span_err(expr.span,
2580 "only the managed heap and exchange heap are \
2581 currently supported")
2585 ast::ExprLit(lit) => {
2586 let typ = check_lit(fcx, lit);
2587 fcx.write_ty(id, typ);
2589 ast::ExprBinary(op, lhs, rhs) => {
2590 check_binop(fcx, expr, op, lhs, rhs, SimpleBinop);
2592 let lhs_ty = fcx.expr_ty(lhs);
2593 let rhs_ty = fcx.expr_ty(rhs);
2594 if ty::type_is_error(lhs_ty) ||
2595 ty::type_is_error(rhs_ty) {
2596 fcx.write_error(id);
2598 else if ty::type_is_bot(lhs_ty) ||
2599 (ty::type_is_bot(rhs_ty) && !ast_util::lazy_binop(op)) {
2603 ast::ExprAssignOp(op, lhs, rhs) => {
2604 check_binop(fcx, expr, op, lhs, rhs, BinopAssignment);
2606 let lhs_t = fcx.expr_ty(lhs);
2607 let result_t = fcx.expr_ty(expr);
2608 demand::suptype(fcx, expr.span, result_t, lhs_t);
2610 let tcx = fcx.tcx();
2611 if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
2612 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2615 // Overwrite result of check_binop...this preserves existing behavior
2616 // but seems quite dubious with regard to user-defined methods
2617 // and so forth. - Niko
2618 if !ty::type_is_error(result_t)
2619 && !ty::type_is_bot(result_t) {
2620 fcx.write_nil(expr.id);
2623 ast::ExprUnary(unop, oprnd) => {
2624 let exp_inner = unpack_expected(fcx, expected, |sty| {
2626 ast::UnBox | ast::UnUniq => match *sty {
2627 ty::ty_box(ty) | ty::ty_uniq(ty) => Some(ty),
2630 ast::UnNot | ast::UnNeg => expected,
2631 ast::UnDeref => None
2634 let lvalue_pref = match unop {
2635 ast::UnDeref => lvalue_pref,
2638 check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, exp_inner, lvalue_pref);
2639 let mut oprnd_t = fcx.expr_ty(oprnd);
2640 if !ty::type_is_error(oprnd_t) && !ty::type_is_bot(oprnd_t) {
2643 oprnd_t = ty::mk_box(tcx, oprnd_t)
2646 oprnd_t = ty::mk_uniq(tcx, oprnd_t);
2649 oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
2650 oprnd_t = match ty::deref(oprnd_t, true) {
2652 None => match try_overloaded_deref(fcx, expr.span,
2653 Some(MethodCall::expr(expr.id)),
2654 Some(&*oprnd), oprnd_t, lvalue_pref) {
2657 let is_newtype = match ty::get(oprnd_t).sty {
2658 ty::ty_struct(did, ref substs) => {
2659 let fields = ty::struct_fields(fcx.tcx(), did, substs);
2661 && fields.get(0).ident ==
2662 token::special_idents::unnamed_field
2667 // This is an obsolete struct deref
2668 tcx.sess.span_err(expr.span,
2669 "single-field tuple-structs can \
2670 no longer be dereferenced");
2672 fcx.type_error_message(expr.span, |actual| {
2673 format!("type `{}` cannot be dereferenced", actual)
2682 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2684 if !(ty::type_is_integral(oprnd_t) ||
2685 ty::get(oprnd_t).sty == ty::ty_bool) {
2686 oprnd_t = check_user_unop(fcx, "!", "not",
2687 tcx.lang_items.not_trait(),
2688 expr, oprnd, oprnd_t);
2692 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2694 if !(ty::type_is_integral(oprnd_t) ||
2695 ty::type_is_fp(oprnd_t)) {
2696 oprnd_t = check_user_unop(fcx, "-", "neg",
2697 tcx.lang_items.neg_trait(),
2698 expr, oprnd, oprnd_t);
2703 fcx.write_ty(id, oprnd_t);
2705 ast::ExprAddrOf(mutbl, oprnd) => {
2706 let hint = unpack_expected(
2708 |sty| match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty),
2710 let lvalue_pref = match mutbl {
2711 ast::MutMutable => PreferMutLvalue,
2712 ast::MutImmutable => NoPreference
2714 check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, hint, lvalue_pref);
2716 // Note: at this point, we cannot say what the best lifetime
2717 // is to use for resulting pointer. We want to use the
2718 // shortest lifetime possible so as to avoid spurious borrowck
2719 // errors. Moreover, the longest lifetime will depend on the
2720 // precise details of the value whose address is being taken
2721 // (and how long it is valid), which we don't know yet until type
2722 // inference is complete.
2724 // Therefore, here we simply generate a region variable. The
2725 // region inferencer will then select the ultimate value.
2726 // Finally, borrowck is charged with guaranteeing that the
2727 // value whose address was taken can actually be made to live
2728 // as long as it needs to live.
2729 let region = fcx.infcx().next_region_var(
2730 infer::AddrOfRegion(expr.span));
2732 let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
2733 let oprnd_t = if ty::type_is_error(tm.ty) {
2735 } else if ty::type_is_bot(tm.ty) {
2739 ty::mk_rptr(tcx, region, tm)
2741 fcx.write_ty(id, oprnd_t);
2743 ast::ExprPath(ref pth) => {
2744 let defn = lookup_def(fcx, pth.span, id);
2746 check_type_parameter_positions_in_path(fcx, pth, defn);
2747 let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2748 instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
2750 ast::ExprInlineAsm(ref ia) => {
2751 for &(_, input) in ia.inputs.iter() {
2752 check_expr(fcx, input);
2754 for &(_, out) in ia.outputs.iter() {
2755 check_expr(fcx, out);
2759 ast::ExprMac(_) => tcx.sess.bug("unexpanded macro"),
2760 ast::ExprBreak(_) => { fcx.write_bot(id); }
2761 ast::ExprAgain(_) => { fcx.write_bot(id); }
2762 ast::ExprRet(expr_opt) => {
2763 let ret_ty = fcx.ret_ty;
2765 None => match fcx.mk_eqty(false, infer::Misc(expr.span),
2766 ret_ty, ty::mk_nil()) {
2767 result::Ok(_) => { /* fall through */ }
2771 "`return;` in function returning non-nil");
2775 check_expr_has_type(fcx, e, ret_ty);
2780 ast::ExprParen(a) => {
2781 check_expr_with_opt_hint_and_lvalue_pref(fcx, a, expected, lvalue_pref);
2782 fcx.write_ty(id, fcx.expr_ty(a));
2784 ast::ExprAssign(lhs, rhs) => {
2785 check_expr_with_lvalue_pref(fcx, lhs, PreferMutLvalue);
2787 let tcx = fcx.tcx();
2788 if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
2789 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2792 let lhs_ty = fcx.expr_ty(lhs);
2793 check_expr_has_type(fcx, rhs, lhs_ty);
2794 let rhs_ty = fcx.expr_ty(rhs);
2796 if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
2797 fcx.write_error(id);
2798 } else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
2804 ast::ExprIf(cond, then_blk, opt_else_expr) => {
2805 check_then_else(fcx, cond, then_blk, opt_else_expr,
2806 id, expr.span, expected);
2808 ast::ExprWhile(cond, body) => {
2809 check_expr_has_type(fcx, cond, ty::mk_bool());
2810 check_block_no_value(fcx, body);
2811 let cond_ty = fcx.expr_ty(cond);
2812 let body_ty = fcx.node_ty(body.id);
2813 if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) {
2814 fcx.write_error(id);
2816 else if ty::type_is_bot(cond_ty) {
2823 ast::ExprForLoop(..) =>
2824 fail!("non-desugared expr_for_loop"),
2825 ast::ExprLoop(body, _) => {
2826 check_block_no_value(fcx, (body));
2827 if !may_break(tcx, expr.id, body) {
2834 ast::ExprMatch(discrim, ref arms) => {
2835 _match::check_match(fcx, expr, discrim, arms.as_slice());
2837 ast::ExprFnBlock(decl, body) => {
2838 let region = astconv::opt_ast_region_to_region(fcx,
2844 ty::RegionTraitStore(region, ast::MutMutable),
2850 ast::ExprProc(decl, body) => {
2859 ast::ExprBlock(b) => {
2860 check_block_with_expected(fcx, b, expected);
2861 fcx.write_ty(id, fcx.node_ty(b.id));
2863 ast::ExprCall(f, ref args) => {
2864 check_call(fcx, expr, f, args.as_slice());
2865 let f_ty = fcx.expr_ty(f);
2866 let (args_bot, args_err) = args.iter().fold((false, false),
2867 |(rest_bot, rest_err), a| {
2868 // is this not working?
2869 let a_ty = fcx.expr_ty(*a);
2870 (rest_bot || ty::type_is_bot(a_ty),
2871 rest_err || ty::type_is_error(a_ty))});
2872 if ty::type_is_error(f_ty) || args_err {
2873 fcx.write_error(id);
2875 else if ty::type_is_bot(f_ty) || args_bot {
2879 ast::ExprMethodCall(ident, ref tps, ref args) => {
2880 check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice());
2881 let mut arg_tys = args.iter().map(|a| fcx.expr_ty(*a));
2882 let (args_bot, args_err) = arg_tys.fold((false, false),
2883 |(rest_bot, rest_err), a| {
2884 (rest_bot || ty::type_is_bot(a),
2885 rest_err || ty::type_is_error(a))});
2887 fcx.write_error(id);
2888 } else if args_bot {
2892 ast::ExprCast(e, t) => {
2894 let t_1 = fcx.to_ty(t);
2895 let t_e = fcx.expr_ty(e);
2897 debug!("t_1={}", fcx.infcx().ty_to_str(t_1));
2898 debug!("t_e={}", fcx.infcx().ty_to_str(t_e));
2900 if ty::type_is_error(t_e) {
2901 fcx.write_error(id);
2903 else if ty::type_is_bot(t_e) {
2907 match ty::get(t_1).sty {
2908 // This will be looked up later on
2909 ty::ty_trait(..) => (),
2912 if ty::type_is_nil(t_e) {
2913 fcx.type_error_message(expr.span, |actual| {
2914 format!("cast from nil: `{}` as `{}`", actual,
2915 fcx.infcx().ty_to_str(t_1))
2917 } else if ty::type_is_nil(t_1) {
2918 fcx.type_error_message(expr.span, |actual| {
2919 format!("cast to nil: `{}` as `{}`", actual,
2920 fcx.infcx().ty_to_str(t_1))
2924 let t1 = structurally_resolved_type(fcx, e.span, t_1);
2925 let te = structurally_resolved_type(fcx, e.span, t_e);
2926 let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
2927 let t_1_is_char = type_is_char(fcx, expr.span, t_1);
2928 let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1);
2930 // casts to scalars other than `char` and `bare fn` are trivial
2931 let t_1_is_trivial = t_1_is_scalar &&
2932 !t_1_is_char && !t_1_is_bare_fn;
2934 if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial {
2935 // casts from C-like enums are allowed
2936 } else if t_1_is_char {
2937 let te = fcx.infcx().resolve_type_vars_if_possible(te);
2938 if ty::get(te).sty != ty::ty_uint(ast::TyU8) {
2939 fcx.type_error_message(expr.span, |actual| {
2940 format!("only `u8` can be cast as `char`, not `{}`", actual)
2943 } else if ty::get(t1).sty == ty::ty_bool {
2944 fcx.tcx().sess.span_err(expr.span,
2945 "cannot cast as `bool`, compare with zero instead");
2946 } else if type_is_region_ptr(fcx, expr.span, t_e) &&
2947 type_is_unsafe_ptr(fcx, expr.span, t_1) {
2949 fn is_vec(t: ty::t) -> bool {
2950 match ty::get(t).sty {
2951 ty::ty_vec(..) => true,
2955 fn types_compatible(fcx: &FnCtxt, sp: Span,
2956 t1: ty::t, t2: ty::t) -> bool {
2960 let el = ty::sequence_element_type(fcx.tcx(),
2962 infer::mk_eqty(fcx.infcx(), false,
2963 infer::Misc(sp), el, t2).is_ok()
2967 // Due to the limitations of LLVM global constants,
2968 // region pointers end up pointing at copies of
2969 // vector elements instead of the original values.
2970 // To allow unsafe pointers to work correctly, we
2971 // need to special-case obtaining an unsafe pointer
2972 // from a region pointer to a vector.
2974 /* this cast is only allowed from &[T] to *T or
2976 match (&ty::get(te).sty, &ty::get(t_1).sty) {
2977 (&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
2978 if types_compatible(fcx, e.span,
2979 mt1.ty, mt2.ty) => {
2980 /* this case is allowed */
2983 demand::coerce(fcx, e.span, t_1, e);
2986 } else if !(type_is_scalar(fcx,expr.span,t_e)
2987 && t_1_is_trivial) {
2989 If more type combinations should be supported than are
2990 supported here, then file an enhancement issue and
2991 record the issue number in this comment.
2993 fcx.type_error_message(expr.span, |actual| {
2994 format!("non-scalar cast: `{}` as `{}`", actual,
2995 fcx.infcx().ty_to_str(t_1))
3000 fcx.write_ty(id, t_1);
3003 ast::ExprVec(ref args) => {
3004 let t: ty::t = fcx.infcx().next_ty_var();
3005 for e in args.iter() {
3006 check_expr_has_type(fcx, *e, t);
3008 let typ = ty::mk_vec(tcx, t, ty::VstoreFixed(args.len()));
3009 fcx.write_ty(id, typ);
3011 ast::ExprRepeat(element, count_expr) => {
3012 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
3013 let count = ty::eval_repeat_count(fcx, count_expr);
3014 let t: ty::t = fcx.infcx().next_ty_var();
3015 check_expr_has_type(fcx, element, t);
3016 let element_ty = fcx.expr_ty(element);
3017 if ty::type_is_error(element_ty) {
3018 fcx.write_error(id);
3020 else if ty::type_is_bot(element_ty) {
3024 let t = ty::mk_vec(tcx, t, ty::VstoreFixed(count));
3025 fcx.write_ty(id, t);
3028 ast::ExprTup(ref elts) => {
3029 let flds = unpack_expected(fcx, expected, |sty| {
3031 ty::ty_tup(ref flds) => Some((*flds).clone()),
3035 let mut bot_field = false;
3036 let mut err_field = false;
3038 let elt_ts = elts.iter().enumerate().map(|(i, e)| {
3039 let opt_hint = match flds {
3040 Some(ref fs) if i < fs.len() => Some(*fs.get(i)),
3043 check_expr_with_opt_hint(fcx, *e, opt_hint);
3044 let t = fcx.expr_ty(*e);
3045 err_field = err_field || ty::type_is_error(t);
3046 bot_field = bot_field || ty::type_is_bot(t);
3051 } else if err_field {
3052 fcx.write_error(id);
3054 let typ = ty::mk_tup(tcx, elt_ts);
3055 fcx.write_ty(id, typ);
3058 ast::ExprStruct(ref path, ref fields, base_expr) => {
3059 // Resolve the path.
3060 match tcx.def_map.borrow().find(&id) {
3061 Some(&ast::DefStruct(type_def_id)) => {
3062 check_struct_constructor(fcx, id, expr.span, type_def_id,
3063 fields.as_slice(), base_expr);
3065 Some(&ast::DefVariant(enum_id, variant_id, _)) => {
3066 check_struct_enum_variant(fcx, id, expr.span, enum_id,
3067 variant_id, fields.as_slice());
3070 tcx.sess.span_bug(path.span,
3071 "structure constructor does not name a structure type");
3075 ast::ExprField(base, field, ref tys) => {
3076 check_field(fcx, expr, lvalue_pref, base, field.name, tys.as_slice());
3078 ast::ExprIndex(base, idx) => {
3079 check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
3080 check_expr(fcx, idx);
3081 let raw_base_t = fcx.expr_ty(base);
3082 let idx_t = fcx.expr_ty(idx);
3083 if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
3084 fcx.write_ty(id, raw_base_t);
3085 } else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
3086 fcx.write_ty(id, idx_t);
3088 let (base_t, autoderefs, field_ty) =
3089 autoderef(fcx, expr.span, raw_base_t, Some(base.id),
3090 lvalue_pref, |base_t, _| ty::index(base_t));
3093 check_expr_has_type(fcx, idx, ty::mk_uint());
3094 fcx.write_ty(id, ty);
3095 fcx.write_autoderef_adjustment(base.id, autoderefs);
3098 let resolved = structurally_resolved_type(fcx,
3101 let ret_ty = lookup_op_method(fcx,
3104 token::intern("index"),
3105 tcx.lang_items.index_trait(),
3109 fcx.type_error_message(expr.span,
3111 format!("cannot index a value \
3118 fcx.write_ty(id, ret_ty);
3125 debug!("type of expr({}) {} is...", expr.id,
3126 syntax::print::pprust::expr_to_str(expr));
3127 debug!("... {}, expected is {}",
3128 ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
3130 Some(t) => ppaux::ty_to_str(tcx, t),
3137 pub fn require_uint(fcx: &FnCtxt, sp: Span, t: ty::t) {
3138 if !type_is_uint(fcx, sp, t) {
3139 fcx.type_error_message(sp, |actual| {
3140 format!("mismatched types: expected `uint` type but found `{}`",
3146 pub fn require_integral(fcx: &FnCtxt, sp: Span, t: ty::t) {
3147 if !type_is_integral(fcx, sp, t) {
3148 fcx.type_error_message(sp, |actual| {
3149 format!("mismatched types: expected integral type but found `{}`",
3155 pub fn check_decl_initializer(fcx: &FnCtxt,
3159 let local_ty = fcx.local_ty(init.span, nid);
3160 check_expr_coercable_to_type(fcx, init, local_ty)
3163 pub fn check_decl_local(fcx: &FnCtxt, local: &ast::Local) {
3164 let tcx = fcx.ccx.tcx;
3166 let t = fcx.local_ty(local.span, local.id);
3167 fcx.write_ty(local.id, t);
3171 check_decl_initializer(fcx, local.id, init);
3172 let init_ty = fcx.expr_ty(init);
3173 if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
3174 fcx.write_ty(local.id, init_ty);
3180 let pcx = pat_ctxt {
3182 map: pat_id_map(tcx.def_map, local.pat),
3184 _match::check_pat(&pcx, local.pat, t);
3185 let pat_ty = fcx.node_ty(local.pat.id);
3186 if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
3187 fcx.write_ty(local.id, pat_ty);
3191 pub fn check_stmt(fcx: &FnCtxt, stmt: &ast::Stmt) {
3193 let mut saw_bot = false;
3194 let mut saw_err = false;
3196 ast::StmtDecl(decl, id) => {
3199 ast::DeclLocal(ref l) => {
3200 check_decl_local(fcx, *l);
3201 let l_t = fcx.node_ty(l.id);
3202 saw_bot = saw_bot || ty::type_is_bot(l_t);
3203 saw_err = saw_err || ty::type_is_error(l_t);
3205 ast::DeclItem(_) => {/* ignore for now */ }
3208 ast::StmtExpr(expr, id) => {
3210 // Check with expected type of ()
3211 check_expr_has_type(fcx, expr, ty::mk_nil());
3212 let expr_ty = fcx.expr_ty(expr);
3213 saw_bot = saw_bot || ty::type_is_bot(expr_ty);
3214 saw_err = saw_err || ty::type_is_error(expr_ty);
3216 ast::StmtSemi(expr, id) => {
3218 check_expr(fcx, expr);
3219 let expr_ty = fcx.expr_ty(expr);
3220 saw_bot |= ty::type_is_bot(expr_ty);
3221 saw_err |= ty::type_is_error(expr_ty);
3223 ast::StmtMac(..) => fcx.ccx.tcx.sess.bug("unexpanded macro")
3226 fcx.write_bot(node_id);
3229 fcx.write_error(node_id);
3232 fcx.write_nil(node_id)
3236 pub fn check_block_no_value(fcx: &FnCtxt, blk: &ast::Block) {
3237 check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
3238 let blkty = fcx.node_ty(blk.id);
3239 if ty::type_is_error(blkty) {
3240 fcx.write_error(blk.id);
3242 else if ty::type_is_bot(blkty) {
3243 fcx.write_bot(blk.id);
3246 let nilty = ty::mk_nil();
3247 demand::suptype(fcx, blk.span, nilty, blkty);
3251 pub fn check_block_with_expected(fcx: &FnCtxt,
3253 expected: Option<ty::t>) {
3255 let mut fcx_ps = fcx.ps.borrow_mut();
3256 let fn_style_state = fcx_ps.recurse(blk);
3257 replace(&mut *fcx_ps, fn_style_state)
3260 fcx.with_region_lb(blk.id, || {
3261 let mut warned = false;
3262 let mut last_was_bot = false;
3263 let mut any_bot = false;
3264 let mut any_err = false;
3265 for s in blk.stmts.iter() {
3266 check_stmt(fcx, *s);
3267 let s_id = ast_util::stmt_id(*s);
3268 let s_ty = fcx.node_ty(s_id);
3269 if last_was_bot && !warned && match s.node {
3270 ast::StmtDecl(decl, _) => {
3272 ast::DeclLocal(_) => true,
3276 ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true,
3279 fcx.ccx.tcx.sess.add_lint(UnreachableCode, s_id, s.span,
3280 ~"unreachable statement");
3283 if ty::type_is_bot(s_ty) {
3284 last_was_bot = true;
3286 any_bot = any_bot || ty::type_is_bot(s_ty);
3287 any_err = any_err || ty::type_is_error(s_ty);
3290 None => if any_err {
3291 fcx.write_error(blk.id);
3294 fcx.write_bot(blk.id);
3297 fcx.write_nil(blk.id);
3300 if any_bot && !warned {
3301 fcx.ccx.tcx.sess.add_lint(UnreachableCode, e.id, e.span,
3302 ~"unreachable expression");
3304 check_expr_with_opt_hint(fcx, e, expected);
3305 let ety = fcx.expr_ty(e);
3306 fcx.write_ty(blk.id, ety);
3308 fcx.write_error(blk.id);
3311 fcx.write_bot(blk.id);
3317 *fcx.ps.borrow_mut() = prev;
3320 pub fn check_const(ccx: &CrateCtxt,
3324 let inh = blank_inherited_fields(ccx);
3325 let rty = ty::node_id_to_type(ccx.tcx, id);
3326 let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
3327 let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty;
3328 check_const_with_ty(&fcx, sp, e, declty);
3331 pub fn check_const_with_ty(fcx: &FnCtxt,
3336 let cty = fcx.expr_ty(e);
3337 demand::suptype(fcx, e.span, declty, cty);
3338 regionck::regionck_expr(fcx, e);
3339 writeback::resolve_type_vars_in_expr(fcx, e);
3342 /// Checks whether a type can be represented in memory. In particular, it
3343 /// identifies types that contain themselves without indirection through a
3344 /// pointer, which would mean their size is unbounded. This is different from
3345 /// the question of whether a type can be instantiated. See the definition of
3346 /// `check_instantiable`.
3347 pub fn check_representable(tcx: &ty::ctxt,
3349 item_id: ast::NodeId,
3350 designation: &str) {
3351 let rty = ty::node_id_to_type(tcx, item_id);
3353 // Check that it is possible to represent this type. This call identifies
3354 // (1) types that contain themselves and (2) types that contain a different
3355 // recursive type. It is only necessary to throw an error on those that
3356 // contain themselves. For case 2, there must be an inner type that will be
3357 // caught by case 1.
3358 match ty::is_type_representable(tcx, sp, rty) {
3359 ty::SelfRecursive => {
3361 sp, format!("illegal recursive {} type; \
3362 wrap the inner value in a box to make it representable",
3365 ty::Representable | ty::ContainsRecursive => (),
3369 /// Checks whether a type can be created without an instance of itself.
3370 /// This is similar but different from the question of whether a type
3371 /// can be represented. For example, the following type:
3373 /// enum foo { None, Some(foo) }
3375 /// is instantiable but is not representable. Similarly, the type
3377 /// enum foo { Some(@foo) }
3379 /// is representable, but not instantiable.
3380 pub fn check_instantiable(tcx: &ty::ctxt,
3382 item_id: ast::NodeId) {
3383 let item_ty = ty::node_id_to_type(tcx, item_id);
3384 if !ty::is_instantiable(tcx, item_ty) {
3385 tcx.sess.span_err(sp, format!("this type cannot be instantiated \
3386 without an instance of itself; \
3387 consider using `Option<{}>`",
3388 ppaux::ty_to_str(tcx, item_ty)));
3392 pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
3393 let t = ty::node_id_to_type(tcx, id);
3394 if ty::type_needs_subst(t) {
3395 tcx.sess.span_err(sp, "SIMD vector cannot be generic");
3398 match ty::get(t).sty {
3399 ty::ty_struct(did, ref substs) => {
3400 let fields = ty::lookup_struct_fields(tcx, did);
3401 if fields.is_empty() {
3402 tcx.sess.span_err(sp, "SIMD vector cannot be empty");
3405 let e = ty::lookup_field_type(tcx, did, fields.get(0).id, substs);
3406 if !fields.iter().all(
3407 |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
3408 tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
3411 if !ty::type_is_machine(e) {
3412 tcx.sess.span_err(sp, "SIMD vector element type should be \
3421 pub fn check_enum_variants(ccx: &CrateCtxt,
3423 vs: &[ast::P<ast::Variant>],
3426 fn disr_in_range(ccx: &CrateCtxt,
3428 disr: ty::Disr) -> bool {
3429 fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
3431 ast::TyU8 => disr as u8 as Disr == disr,
3432 ast::TyU16 => disr as u16 as Disr == disr,
3433 ast::TyU32 => disr as u32 as Disr == disr,
3434 ast::TyU64 => disr as u64 as Disr == disr,
3435 ast::TyU => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
3438 fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
3440 ast::TyI8 => disr as i8 as Disr == disr,
3441 ast::TyI16 => disr as i16 as Disr == disr,
3442 ast::TyI32 => disr as i32 as Disr == disr,
3443 ast::TyI64 => disr as i64 as Disr == disr,
3444 ast::TyI => int_in_range(ccx, ccx.tcx.sess.targ_cfg.int_type, disr)
3448 attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
3449 attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
3453 fn do_check(ccx: &CrateCtxt,
3454 vs: &[ast::P<ast::Variant>],
3456 hint: attr::ReprAttr)
3457 -> Vec<@ty::VariantInfo> {
3459 let rty = ty::node_id_to_type(ccx.tcx, id);
3460 let mut variants: Vec<@ty::VariantInfo> = Vec::new();
3461 let mut disr_vals: Vec<ty::Disr> = Vec::new();
3462 let mut prev_disr_val: Option<ty::Disr> = None;
3464 for &v in vs.iter() {
3466 // If the discriminant value is specified explicitly in the enum check whether the
3467 // initialization expression is valid, otherwise use the last value plus one.
3468 let mut current_disr_val = match prev_disr_val {
3469 Some(prev_disr_val) => prev_disr_val + 1,
3470 None => ty::INITIAL_DISCRIMINANT_VALUE
3473 match v.node.disr_expr {
3475 debug!("disr expr, checking {}", pprust::expr_to_str(e));
3477 let inh = blank_inherited_fields(ccx);
3478 let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
3479 let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
3480 check_const_with_ty(&fcx, e.span, e, declty);
3481 // check_expr (from check_const pass) doesn't guarantee
3482 // that the expression is in an form that eval_const_expr can
3483 // handle, so we may still get an internal compiler error
3485 match const_eval::eval_const_expr_partial(ccx.tcx, e) {
3486 Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
3487 Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
3489 ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
3492 ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", *err));
3499 // Check for duplicate discriminant values
3500 if disr_vals.contains(¤t_disr_val) {
3501 ccx.tcx.sess.span_err(v.span, "discriminant value already exists");
3503 // Check for unrepresentable discriminant values
3505 attr::ReprAny | attr::ReprExtern => (),
3506 attr::ReprInt(sp, ity) => {
3507 if !disr_in_range(ccx, ity, current_disr_val) {
3508 ccx.tcx.sess.span_err(v.span,
3509 "discriminant value outside specified type");
3510 ccx.tcx.sess.span_note(sp, "discriminant type specified here");
3514 disr_vals.push(current_disr_val);
3516 let variant_info = @VariantInfo::from_ast_variant(ccx.tcx, v, current_disr_val);
3517 prev_disr_val = Some(current_disr_val);
3519 variants.push(variant_info);
3525 let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id });
3526 if hint != attr::ReprAny && vs.len() <= 1 {
3527 let msg = if vs.len() == 1 {
3528 "unsupported representation for univariant enum"
3530 "unsupported representation for zero-variant enum"
3532 ccx.tcx.sess.span_err(sp, msg)
3535 let variants = do_check(ccx, vs, id, hint);
3537 // cache so that ty::enum_variants won't repeat this work
3538 ccx.tcx.enum_var_cache.borrow_mut().insert(local_def(id), @variants);
3540 // Check that it is possible to represent this enum.
3541 check_representable(ccx.tcx, sp, id, "enum");
3543 // Check that it is possible to instantiate this enum:
3545 // This *sounds* like the same that as representable, but it's
3546 // not. See def'n of `check_instantiable()` for details.
3547 check_instantiable(ccx.tcx, sp, id);
3550 pub fn lookup_def(fcx: &FnCtxt, sp: Span, id: ast::NodeId) -> ast::Def {
3551 lookup_def_ccx(fcx.ccx, sp, id)
3554 // Returns the type parameter count and the type for the given definition.
3555 pub fn ty_param_bounds_and_ty_for_def(fcx: &FnCtxt,
3558 -> ty_param_bounds_and_ty {
3560 ast::DefArg(nid, _) | ast::DefLocal(nid, _) |
3561 ast::DefBinding(nid, _) => {
3562 let typ = fcx.local_ty(sp, nid);
3563 return no_params(typ);
3565 ast::DefFn(id, _) | ast::DefStaticMethod(id, _, _) |
3566 ast::DefStatic(id, _) | ast::DefVariant(_, id, _) |
3567 ast::DefStruct(id) => {
3568 return ty::lookup_item_type(fcx.ccx.tcx, id);
3570 ast::DefUpvar(_, inner, _, _) => {
3571 return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
3576 ast::DefTyParam(..)=> {
3577 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type");
3579 ast::DefMod(..) | ast::DefForeignMod(..) => {
3580 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module");
3582 ast::DefUse(..) => {
3583 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use");
3585 ast::DefRegion(..) => {
3586 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region");
3588 ast::DefTyParamBinder(..) => {
3589 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter");
3591 ast::DefLabel(..) => {
3592 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label");
3594 ast::DefSelfTy(..) => {
3595 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty");
3597 ast::DefMethod(..) => {
3598 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method");
3603 // Instantiates the given path, which must refer to an item with the given
3604 // number of type parameters and type.
3605 pub fn instantiate_path(fcx: &FnCtxt,
3607 tpt: ty_param_bounds_and_ty,
3610 node_id: ast::NodeId) {
3611 debug!(">>> instantiate_path");
3613 let ty_param_count = tpt.generics.type_param_defs().len();
3614 let ty_param_req = tpt.generics.type_param_defs().iter()
3615 .take_while(|x| x.default.is_none())
3617 let mut ty_substs_len = 0;
3618 for segment in pth.segments.iter() {
3619 ty_substs_len += segment.types.len()
3622 debug!("tpt={} ty_param_count={:?} ty_substs_len={:?}",
3623 tpt.repr(fcx.tcx()),
3627 // determine the region parameters, using the value given by the user
3628 // (if any) and otherwise using a fresh region variable
3629 let num_expected_regions = tpt.generics.region_param_defs().len();
3630 let num_supplied_regions = pth.segments.last().unwrap().lifetimes.len();
3631 let regions = if num_expected_regions == num_supplied_regions {
3632 OwnedSlice::from_vec(pth.segments.last().unwrap().lifetimes.iter().map(
3633 |l| ast_region_to_region(fcx.tcx(), l)).collect())
3635 if num_supplied_regions != 0 {
3636 fcx.ccx.tcx.sess.span_err(
3638 format!("expected {nexpected, plural, =1{# lifetime parameter} \
3639 other{# lifetime parameters}}, \
3640 found {nsupplied, plural, =1{# lifetime parameter} \
3641 other{# lifetime parameters}}",
3642 nexpected = num_expected_regions,
3643 nsupplied = num_supplied_regions));
3646 fcx.infcx().region_vars_for_defs(span, tpt.generics.region_param_defs.as_slice())
3648 let regions = ty::NonerasedRegions(regions);
3650 // Special case: If there is a self parameter, omit it from the list of
3653 // Here we calculate the "user type parameter count", which is the number
3654 // of type parameters actually manifest in the AST. This will differ from
3655 // the internal type parameter count when there are self types involved.
3656 let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def {
3657 ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
3658 let generics = generics_of_static_method_container(fcx.ccx.tcx,
3660 (ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs().len()))
3662 _ => (ty_param_count, ty_param_req, None),
3665 // determine values for type parameters, using the values given by
3666 // the user (if any) and otherwise using fresh type variables
3667 let (tps, regions) = if ty_substs_len == 0 {
3668 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3669 } else if ty_param_count == 0 {
3670 fcx.ccx.tcx.sess.span_err
3671 (span, "this item does not take type parameters");
3672 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3673 } else if ty_substs_len > user_ty_param_count {
3674 let expected = if user_ty_param_req < user_ty_param_count {
3679 fcx.ccx.tcx.sess.span_err
3681 format!("too many type parameters provided: {} {}, found {}",
3682 expected, user_ty_param_count, ty_substs_len));
3683 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3684 } else if ty_substs_len < user_ty_param_req {
3685 let expected = if user_ty_param_req < user_ty_param_count {
3690 fcx.ccx.tcx.sess.span_err
3692 format!("not enough type parameters provided: {} {}, found {}",
3693 expected, user_ty_param_req, ty_substs_len));
3694 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3696 if ty_substs_len > user_ty_param_req
3697 && !fcx.tcx().sess.features.default_type_params.get() {
3698 fcx.tcx().sess.span_err(pth.span, "default type parameters are \
3699 experimental and possibly buggy");
3700 fcx.tcx().sess.span_note(pth.span, "add #![feature(default_type_params)] \
3701 to the crate attributes to enable");
3704 // Build up the list of type parameters, inserting the self parameter
3705 // at the appropriate position.
3706 let mut tps = Vec::new();
3707 let mut pushed = false;
3708 for (i, ty) in pth.segments.iter()
3709 .flat_map(|segment| segment.types.iter())
3710 .map(|&ast_type| fcx.to_ty(ast_type))
3712 match self_parameter_index {
3713 Some(index) if index == i => {
3714 tps.push(*fcx.infcx().next_ty_vars(1).get(0));
3722 let mut substs = substs {
3728 let defaults = tpt.generics.type_param_defs().iter()
3729 .enumerate().filter_map(|(i, x)| {
3730 match self_parameter_index {
3731 Some(index) if index == i => None,
3732 _ => Some(x.default)
3735 for (i, default) in defaults.skip(ty_substs_len).enumerate() {
3736 match self_parameter_index {
3737 Some(index) if index == i + ty_substs_len => {
3738 substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0));
3745 let ty = default.subst_spanned(fcx.tcx(), &substs, Some(span));
3746 substs.tps.push(ty);
3749 fcx.tcx().sess.span_bug(span,
3750 "missing default for a not explicitely provided type param")
3755 // If the self parameter goes at the end, insert it there.
3756 if !pushed && self_parameter_index.is_some() {
3757 substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0))
3760 assert_eq!(substs.tps.len(), ty_param_count)
3762 let substs {tps, regions, ..} = substs;
3766 fcx.write_ty_substs(node_id, tpt.ty, substs {
3775 // Resolves `typ` by a single level if `typ` is a type variable. If no
3776 // resolution is possible, then an error is reported.
3777 pub fn structurally_resolved_type(fcx: &FnCtxt, sp: Span, tp: ty::t) -> ty::t {
3778 match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
3779 Ok(t_s) if !ty::type_is_ty_var(t_s) => t_s,
3781 fcx.type_error_message(sp, |_actual| {
3782 ~"the type of this value must be known in this context"
3784 demand::suptype(fcx, sp, ty::mk_err(), tp);
3790 // Returns the one-level-deep structure of the given type.
3791 pub fn structure_of<'a>(fcx: &FnCtxt, sp: Span, typ: ty::t)
3793 &ty::get(structurally_resolved_type(fcx, sp, typ)).sty
3796 pub fn type_is_integral(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3797 let typ_s = structurally_resolved_type(fcx, sp, typ);
3798 return ty::type_is_integral(typ_s);
3801 pub fn type_is_uint(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3802 let typ_s = structurally_resolved_type(fcx, sp, typ);
3803 return ty::type_is_uint(typ_s);
3806 pub fn type_is_scalar(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3807 let typ_s = structurally_resolved_type(fcx, sp, typ);
3808 return ty::type_is_scalar(typ_s);
3811 pub fn type_is_char(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3812 let typ_s = structurally_resolved_type(fcx, sp, typ);
3813 return ty::type_is_char(typ_s);
3816 pub fn type_is_bare_fn(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3817 let typ_s = structurally_resolved_type(fcx, sp, typ);
3818 return ty::type_is_bare_fn(typ_s);
3821 pub fn type_is_unsafe_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3822 let typ_s = structurally_resolved_type(fcx, sp, typ);
3823 return ty::type_is_unsafe_ptr(typ_s);
3826 pub fn type_is_region_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3827 let typ_s = structurally_resolved_type(fcx, sp, typ);
3828 return ty::type_is_region_ptr(typ_s);
3831 pub fn type_is_c_like_enum(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3832 let typ_s = structurally_resolved_type(fcx, sp, typ);
3833 return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
3836 pub fn ast_expr_vstore_to_vstore<M>(fcx: &FnCtxt,
3842 ast::ExprVstoreUniq => ty::VstoreUniq,
3843 ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => {
3845 ast::ExprLit(..) => {
3846 // string literals and *empty slices* live in static memory
3847 ty::VstoreSlice(ty::ReStatic, m)
3849 ast::ExprVec(ref elements) if elements.len() == 0 => {
3850 // string literals and *empty slices* live in static memory
3851 ty::VstoreSlice(ty::ReStatic, m)
3853 ast::ExprRepeat(..) |
3854 ast::ExprVec(..) => {
3855 // vector literals are temporaries on the stack
3856 match fcx.tcx().region_maps.temporary_scope(e.id) {
3858 ty::VstoreSlice(ty::ReScope(scope), m)
3861 // this slice occurs in a static somewhere
3862 ty::VstoreSlice(ty::ReStatic, m)
3867 fcx.ccx.tcx.sess.span_bug(
3868 e.span, format!("vstore with unexpected contents"))
3875 // Returns true if b contains a break that can exit from b
3876 pub fn may_break(cx: &ty::ctxt, id: ast::NodeId, b: ast::P<ast::Block>) -> bool {
3877 // First: is there an unlabeled break immediately
3879 (loop_query(b, |e| {
3881 ast::ExprBreak(_) => true,
3885 // Second: is there a labeled break with label
3886 // <id> nested anywhere inside the loop?
3887 (block_query(b, |e| {
3889 ast::ExprBreak(Some(_)) => {
3890 match cx.def_map.borrow().find(&e.id) {
3891 Some(&ast::DefLabel(loop_id)) if id == loop_id => true,
3899 pub fn check_bounds_are_used(ccx: &CrateCtxt,
3901 tps: &OwnedSlice<ast::TyParam>,
3903 debug!("check_bounds_are_used(n_tps={}, ty={})",
3904 tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
3906 // make a vector of booleans initially false, set to true when used
3907 if tps.len() == 0u { return; }
3908 let mut tps_used = Vec::from_elem(tps.len(), false);
3910 ty::walk_ty(ty, |t| {
3911 match ty::get(t).sty {
3912 ty::ty_param(param_ty {idx, ..}) => {
3913 debug!("Found use of ty param \\#{}", idx);
3914 *tps_used.get_mut(idx) = true;
3920 for (i, b) in tps_used.iter().enumerate() {
3922 ccx.tcx.sess.span_err(
3923 span, format!("type parameter `{}` is unused",
3924 token::get_ident(tps.get(i).ident)));
3929 pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
3930 fn param(ccx: &CrateCtxt, n: uint) -> ty::t {
3931 ty::mk_param(ccx.tcx, n, local_def(0))
3935 let name = token::get_ident(it.ident);
3936 let (n_tps, inputs, output) = if name.get().starts_with("atomic_") {
3937 let split : Vec<&str> = name.get().split('_').collect();
3938 assert!(split.len() >= 2, "Atomic intrinsic not correct format");
3940 //We only care about the operation here
3941 match *split.get(1) {
3942 "cxchg" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)),
3946 "load" => (1, vec!(ty::mk_imm_ptr(tcx, param(ccx, 0))),
3948 "store" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)),
3951 "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
3952 "min" | "umax" | "umin" => {
3953 (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)),
3957 (0, Vec::new(), ty::mk_nil())
3960 tcx.sess.span_err(it.span,
3961 format!("unrecognized atomic operation function: `{}`",
3969 "abort" => (0, Vec::new(), ty::mk_bot()),
3970 "breakpoint" => (0, Vec::new(), ty::mk_nil()),
3972 "pref_align_of" | "min_align_of" => (1u, Vec::new(), ty::mk_uint()),
3973 "init" => (1u, Vec::new(), param(ccx, 0u)),
3974 "uninit" => (1u, Vec::new(), param(ccx, 0u)),
3975 "forget" => (1u, vec!( param(ccx, 0) ), ty::mk_nil()),
3976 "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)),
3977 "move_val_init" => {
3980 ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), param(ccx, 0)),
3985 "needs_drop" => (1u, Vec::new(), ty::mk_bool()),
3986 "owns_managed" => (1u, Vec::new(), ty::mk_bool()),
3989 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
3991 Err(s) => { tcx.sess.span_fatal(it.span, s); }
3993 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
3995 mutbl: ast::MutImmutable
3997 (1u, Vec::new(), td_ptr)
4000 let langid = ccx.tcx.lang_items.require(TypeIdLangItem);
4002 Ok(did) => (1u, Vec::new(), ty::mk_struct(ccx.tcx, did, substs {
4005 regions: ty::NonerasedRegions(OwnedSlice::empty())
4007 Err(msg) => { tcx.sess.span_fatal(it.span, msg); }
4011 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4013 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4015 let region = ty::ReLateBound(it.id, ty::BrAnon(0));
4016 let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
4017 Ok((_, vot)) => vot,
4018 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4021 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4023 mutbl: ast::MutImmutable
4025 (0, vec!( td_ptr, visitor_object_ty ), ty::mk_nil())
4030 ty::mk_ptr(tcx, ty::mt {
4032 mutbl: ast::MutImmutable
4036 ty::mk_ptr(tcx, ty::mt {
4038 mutbl: ast::MutImmutable
4041 "copy_nonoverlapping_memory" => {
4044 ty::mk_ptr(tcx, ty::mt {
4046 mutbl: ast::MutMutable
4048 ty::mk_ptr(tcx, ty::mt {
4050 mutbl: ast::MutImmutable
4059 ty::mk_ptr(tcx, ty::mt {
4061 mutbl: ast::MutMutable
4063 ty::mk_ptr(tcx, ty::mt {
4065 mutbl: ast::MutImmutable
4074 ty::mk_ptr(tcx, ty::mt {
4076 mutbl: ast::MutMutable
4083 "sqrtf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4084 "sqrtf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4087 vec!( ty::mk_f32(), ty::mk_i32() ),
4092 vec!( ty::mk_f64(), ty::mk_i32() ),
4095 "sinf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4096 "sinf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4097 "cosf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4098 "cosf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4101 vec!( ty::mk_f32(), ty::mk_f32() ),
4106 vec!( ty::mk_f64(), ty::mk_f64() ),
4109 "expf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4110 "expf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4111 "exp2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4112 "exp2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4113 "logf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4114 "logf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4115 "log10f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4116 "log10f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4117 "log2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4118 "log2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4121 vec!( ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ),
4126 vec!( ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ),
4129 "fabsf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4130 "fabsf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4131 "copysignf32" => (0, vec!( ty::mk_f32(), ty::mk_f32() ), ty::mk_f32()),
4132 "copysignf64" => (0, vec!( ty::mk_f64(), ty::mk_f64() ), ty::mk_f64()),
4133 "floorf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4134 "floorf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4135 "ceilf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4136 "ceilf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4137 "truncf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4138 "truncf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4139 "rintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4140 "rintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4141 "nearbyintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4142 "nearbyintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4143 "roundf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4144 "roundf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4145 "ctpop8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()),
4146 "ctpop16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4147 "ctpop32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4148 "ctpop64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4149 "ctlz8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()),
4150 "ctlz16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4151 "ctlz32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4152 "ctlz64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4153 "cttz8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()),
4154 "cttz16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4155 "cttz32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4156 "cttz64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4157 "bswap16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4158 "bswap32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4159 "bswap64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4162 (1, vec!( ty::mk_imm_ptr(tcx, param(ccx, 0)) ), param(ccx, 0)),
4164 (1, vec!( ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ), ty::mk_nil()),
4166 "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
4167 (0, vec!(ty::mk_i8(), ty::mk_i8()),
4168 ty::mk_tup(tcx, vec!(ty::mk_i8(), ty::mk_bool()))),
4170 "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
4171 (0, vec!(ty::mk_i16(), ty::mk_i16()),
4172 ty::mk_tup(tcx, vec!(ty::mk_i16(), ty::mk_bool()))),
4174 "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
4175 (0, vec!(ty::mk_i32(), ty::mk_i32()),
4176 ty::mk_tup(tcx, vec!(ty::mk_i32(), ty::mk_bool()))),
4178 "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
4179 (0, vec!(ty::mk_i64(), ty::mk_i64()),
4180 ty::mk_tup(tcx, vec!(ty::mk_i64(), ty::mk_bool()))),
4182 "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
4183 (0, vec!(ty::mk_u8(), ty::mk_u8()),
4184 ty::mk_tup(tcx, vec!(ty::mk_u8(), ty::mk_bool()))),
4186 "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
4187 (0, vec!(ty::mk_u16(), ty::mk_u16()),
4188 ty::mk_tup(tcx, vec!(ty::mk_u16(), ty::mk_bool()))),
4190 "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
4191 (0, vec!(ty::mk_u32(), ty::mk_u32()),
4192 ty::mk_tup(tcx, vec!(ty::mk_u32(), ty::mk_bool()))),
4194 "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" =>
4195 (0, vec!(ty::mk_u64(), ty::mk_u64()),
4196 ty::mk_tup(tcx, vec!(ty::mk_u64(), ty::mk_bool()))),
4199 tcx.sess.span_err(it.span,
4200 format!("unrecognized intrinsic function: `{}`",
4206 let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
4207 fn_style: ast::UnsafeFn,
4208 abi: abi::RustIntrinsic,
4209 sig: FnSig {binder_id: it.id,
4214 let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
4215 let i_n_tps = i_ty.generics.type_param_defs().len();
4216 if i_n_tps != n_tps {
4217 tcx.sess.span_err(it.span, format!("intrinsic has wrong number \
4218 of type parameters: found {}, \
4219 expected {}", i_n_tps, n_tps));
4222 tcx, None, false, it.span, i_ty.ty, fty,
4223 || format!("intrinsic has wrong type: \
4225 ppaux::ty_to_str(ccx.tcx, fty)));