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;
124 use syntax::ast::{Provided, Required};
126 use syntax::ast_util::local_def;
127 use syntax::ast_util;
129 use syntax::codemap::Span;
131 use syntax::owned_slice::OwnedSlice;
132 use syntax::parse::token;
133 use syntax::print::pprust;
135 use syntax::visit::Visitor;
146 /// Fields that are part of a `FnCtxt` which are inherited by
147 /// closures defined within the function. For example:
150 /// bar(proc() { ... })
153 /// Here, the function `foo()` and the closure passed to
154 /// `bar()` will each have their own `FnCtxt`, but they will
155 /// share the inherited fields.
156 pub struct Inherited<'a> {
157 infcx: infer::InferCtxt<'a>,
158 locals: @RefCell<NodeMap<ty::t>>,
159 param_env: ty::ParameterEnvironment,
162 node_types: RefCell<NodeMap<ty::t>>,
163 node_type_substs: RefCell<NodeMap<ty::substs>>,
164 adjustments: RefCell<NodeMap<@ty::AutoAdjustment>>,
165 method_map: MethodMap,
166 vtable_map: vtable_map,
167 upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
175 // A normal closure or fn item.
180 pub struct PurityState {
181 pub def: ast::NodeId,
182 pub purity: ast::Purity,
187 pub fn function(purity: ast::Purity, def: ast::NodeId) -> PurityState {
188 PurityState { def: def, purity: purity, from_fn: true }
191 pub fn recurse(&mut self, blk: &ast::Block) -> PurityState {
193 // If this unsafe, then if the outer function was already marked as
194 // unsafe we shouldn't attribute the unsafe'ness to the block. This
195 // way the block can be warned about instead of ignoring this
196 // extraneous block (functions are never warned about).
197 ast::UnsafeFn if self.from_fn => *self,
200 let (purity, def) = match blk.rules {
201 ast::UnsafeBlock(..) => (ast::UnsafeFn, blk.id),
202 ast::DefaultBlock => (purity, self.def),
204 PurityState{ def: def,
212 /// Whether `check_binop` is part of an assignment or not.
213 /// Used to know wether we allow user overloads and to print
214 /// better messages on error.
216 enum IsBinopAssignment{
222 pub struct FnCtxt<'a> {
223 // Number of errors that had been reported when we started
224 // checking this function. On exit, if we find that *more* errors
225 // have been reported, we will skip regionck and other work that
226 // expects the types within the function to be consistent.
227 err_count_on_creation: uint,
230 ps: RefCell<PurityState>,
232 // Sometimes we generate region pointers where the precise region
233 // to use is not known. For example, an expression like `&x.f`
234 // where `x` is of type `@T`: in this case, we will be rooting
235 // `x` onto the stack frame, and we could choose to root it until
236 // the end of (almost) any enclosing block or expression. We
237 // want to pick the narrowest block that encompasses all uses.
239 // What we do in such cases is to generate a region variable with
240 // `region_lb` as a lower bound. The regionck pass then adds
241 // other constriants based on how the variable is used and region
242 // inference selects the ultimate value. Finally, borrowck is
243 // charged with guaranteeing that the value whose address was taken
244 // can actually be made to live as long as it needs to live.
245 region_lb: Cell<ast::NodeId>,
247 // Says whether we're inside a for loop, in a do block
248 // or neither. Helps with error messages involving the
249 // function return type.
252 inh: &'a Inherited<'a>,
254 ccx: &'a CrateCtxt<'a>,
257 impl<'a> Inherited<'a> {
258 fn new(tcx: &'a ty::ctxt,
259 param_env: ty::ParameterEnvironment)
262 infcx: infer::new_infer_ctxt(tcx),
263 locals: @RefCell::new(NodeMap::new()),
264 param_env: param_env,
265 node_types: RefCell::new(NodeMap::new()),
266 node_type_substs: RefCell::new(NodeMap::new()),
267 adjustments: RefCell::new(NodeMap::new()),
268 method_map: @RefCell::new(FnvHashMap::new()),
269 vtable_map: @RefCell::new(FnvHashMap::new()),
270 upvar_borrow_map: RefCell::new(HashMap::new()),
275 // Used by check_const and check_enum_variants
276 fn blank_fn_ctxt<'a>(ccx: &'a CrateCtxt<'a>,
277 inh: &'a Inherited<'a>,
279 region_bnd: ast::NodeId)
282 err_count_on_creation: ccx.tcx.sess.err_count(),
284 ps: RefCell::new(PurityState::function(ast::ImpureFn, 0)),
285 region_lb: Cell::new(region_bnd),
292 fn blank_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> {
293 // It's kind of a kludge to manufacture a fake function context
294 // and statement context, but we might as well do write the code only once
295 let param_env = ty::ParameterEnvironment { free_substs: substs::empty(),
296 self_param_bound: None,
297 type_param_bounds: Vec::new() };
298 Inherited::new(ccx.tcx, param_env)
301 impl<'a> ExprTyProvider for FnCtxt<'a> {
302 fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
306 fn ty_ctxt<'a>(&'a self) -> &'a ty::ctxt {
311 struct CheckItemTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
313 impl<'a> Visitor<()> for CheckItemTypesVisitor<'a> {
314 fn visit_item(&mut self, i: &ast::Item, _: ()) {
315 check_item(self.ccx, i);
316 visit::walk_item(self, i, ());
320 pub fn check_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
321 let mut visit = CheckItemTypesVisitor { ccx: ccx };
322 visit::walk_crate(&mut visit, krate, ());
325 fn check_bare_fn(ccx: &CrateCtxt,
330 param_env: ty::ParameterEnvironment) {
331 // Compute the fty from point of view of inside fn
332 // (replace any type-scheme with a type)
333 let fty = fty.subst(ccx.tcx, ¶m_env.free_substs);
335 match ty::get(fty).sty {
336 ty::ty_bare_fn(ref fn_ty) => {
337 let inh = Inherited::new(ccx.tcx, param_env);
338 let fcx = check_fn(ccx, fn_ty.purity, &fn_ty.sig,
339 decl, id, body, Vanilla, &inh);
341 vtable::resolve_in_block(&fcx, body);
342 regionck::regionck_fn(&fcx, body);
343 writeback::resolve_type_vars_in_fn(&fcx, decl, body);
345 _ => ccx.tcx.sess.impossible_case(body.span,
346 "check_bare_fn: function type expected")
350 struct GatherLocalsVisitor<'a> {
354 impl<'a> GatherLocalsVisitor<'a> {
355 fn assign(&mut self, nid: ast::NodeId, ty_opt: Option<ty::t>) {
358 // infer the variable's type
359 let var_id = self.fcx.infcx().next_ty_var_id();
360 let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
361 self.fcx.inh.locals.borrow_mut().insert(nid, var_ty);
364 // take type that the user specified
365 self.fcx.inh.locals.borrow_mut().insert(nid, typ);
371 impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
372 // Add explicitly-declared locals.
373 fn visit_local(&mut self, local: &ast::Local, _: ()) {
374 let o_ty = match local.ty.node {
375 ast::TyInfer => None,
376 _ => Some(self.fcx.to_ty(local.ty))
378 self.assign(local.id, o_ty);
379 debug!("Local variable {} is assigned type {}",
380 self.fcx.pat_to_str(local.pat),
381 self.fcx.infcx().ty_to_str(
382 self.fcx.inh.locals.borrow().get_copy(&local.id)));
383 visit::walk_local(self, local, ());
386 // Add pattern bindings.
387 fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
389 ast::PatIdent(_, ref path, _)
390 if pat_util::pat_is_binding(self.fcx.ccx.tcx.def_map, p) => {
391 self.assign(p.id, None);
392 debug!("Pattern binding {} is assigned to {}",
393 token::get_ident(path.segments.get(0).identifier),
394 self.fcx.infcx().ty_to_str(
395 self.fcx.inh.locals.borrow().get_copy(&p.id)));
399 visit::walk_pat(self, p, ());
403 fn visit_block(&mut self, b: &ast::Block, _: ()) {
404 // non-obvious: the `blk` variable maps to region lb, so
405 // we have to keep this up-to-date. This
406 // is... unfortunate. It'd be nice to not need this.
407 self.fcx.with_region_lb(b.id, || visit::walk_block(self, b, ()));
410 // Don't descend into fns and items
411 fn visit_fn(&mut self, _: &visit::FnKind, _: &ast::FnDecl,
412 _: &ast::Block, _: Span, _: ast::NodeId, _: ()) { }
413 fn visit_item(&mut self, _: &ast::Item, _: ()) { }
417 fn check_fn<'a>(ccx: &'a CrateCtxt<'a>,
424 inherited: &'a Inherited<'a>) -> FnCtxt<'a>
427 * Helper used by check_bare_fn and check_expr_fn. Does the
428 * grungy work of checking a function body and returns the
429 * function context used for that purpose, since in the case of a
430 * fn item there is still a bit more to do.
433 * - inherited: other fields inherited from the enclosing fn (if any)
437 let err_count_on_creation = tcx.sess.err_count();
439 // First, we have to replace any bound regions in the fn type with free ones.
440 // The free region references will be bound the node_id of the body block.
441 let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(tcx, fn_sig, |br| {
442 ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
445 relate_free_regions(tcx, &fn_sig);
447 let arg_tys = fn_sig.inputs.as_slice();
448 let ret_ty = fn_sig.output;
450 debug!("check_fn(arg_tys={:?}, ret_ty={:?})",
451 arg_tys.iter().map(|&a| ppaux::ty_to_str(tcx, a)).collect::<Vec<~str>>(),
452 ppaux::ty_to_str(tcx, ret_ty));
454 // Create the function context. This is either derived from scratch or,
455 // in the case of function expressions, based on the outer context.
457 err_count_on_creation: err_count_on_creation,
459 ps: RefCell::new(PurityState::function(purity, id)),
460 region_lb: Cell::new(body.id),
468 let mut visit = GatherLocalsVisitor { fcx: &fcx, };
469 // Add formal parameters.
470 for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
471 // Create type variables for each argument.
472 pat_util::pat_bindings(tcx.def_map,
474 |_bm, pat_id, _sp, _path| {
475 visit.assign(pat_id, None);
478 // Check the pattern.
481 map: pat_id_map(tcx.def_map, input.pat),
483 _match::check_pat(&pcx, input.pat, *arg_ty);
486 visit.visit_block(body, ());
489 check_block_with_expected(&fcx, body, Some(ret_ty));
491 // We unify the tail expr's type with the
492 // function result type, if there is a tail expr.
495 // Special case: we print a special error if there appears
496 // to be do-block/for-loop confusion
497 demand::suptype_with_fn(&fcx, tail_expr.span, false,
498 fcx.ret_ty, fcx.expr_ty(tail_expr),
500 fcx.report_mismatched_return_types(sp, e, a, s);
506 for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
507 fcx.write_ty(input.id, *arg);
513 pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
516 // Check that the struct is representable
517 check_representable(tcx, span, id, "struct");
519 // Check that the struct is instantiable
520 check_instantiable(tcx, span, id);
522 if ty::lookup_simd(tcx, local_def(id)) {
523 check_simd(tcx, span, id);
527 pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
528 debug!("check_item(it.id={}, it.ident={})",
530 ty::item_path_str(ccx.tcx, local_def(it.id)));
531 let _indenter = indenter();
534 ast::ItemStatic(_, _, e) => check_const(ccx, it.span, e, it.id),
535 ast::ItemEnum(ref enum_definition, _) => {
536 check_enum_variants(ccx,
538 enum_definition.variants.as_slice(),
541 ast::ItemFn(decl, _, _, _, body) => {
542 let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
544 let param_env = ty::construct_parameter_environment(
547 fn_tpt.generics.type_param_defs(),
550 fn_tpt.generics.region_param_defs.as_slice(),
553 check_bare_fn(ccx, decl, body, it.id, fn_tpt.ty, param_env);
555 ast::ItemImpl(_, ref opt_trait_ref, _, ref ms) => {
556 debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
558 let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
560 check_method_body(ccx, &impl_tpt.generics, None, *m);
563 match *opt_trait_ref {
564 Some(ref ast_trait_ref) => {
566 ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id);
567 check_impl_methods_against_trait(ccx,
573 vtable::resolve_impl(ccx.tcx, it, &impl_tpt.generics, impl_trait_ref);
579 ast::ItemTrait(_, _, ref trait_methods) => {
580 let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
581 for trait_method in (*trait_methods).iter() {
582 match *trait_method {
584 // Nothing to do, since required methods don't have
588 check_method_body(ccx, &trait_def.generics,
589 Some(trait_def.trait_ref), m);
594 ast::ItemStruct(..) => {
595 check_struct(ccx, it.id, it.span);
597 ast::ItemTy(ref t, ref generics) => {
598 let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id);
599 check_bounds_are_used(ccx, t.span, &generics.ty_params, tpt_ty);
601 ast::ItemForeignMod(ref m) => {
602 if m.abi == abi::RustIntrinsic {
603 for item in m.items.iter() {
604 check_intrinsic_type(ccx, *item);
607 for item in m.items.iter() {
608 let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id));
609 if tpt.generics.has_type_params() {
610 ccx.tcx.sess.span_err(item.span, "foreign items may not have type parameters");
614 ast::ForeignItemFn(ref fn_decl, _) => {
615 if fn_decl.variadic && m.abi != abi::C {
616 ccx.tcx.sess.span_err(
617 item.span, "variadic function must have C calling convention");
625 _ => {/* nothing to do */ }
629 fn check_method_body(ccx: &CrateCtxt,
630 item_generics: &ty::Generics,
631 self_bound: Option<@ty::TraitRef>,
632 method: &ast::Method) {
634 * Type checks a method body.
637 * - `item_generics`: generics defined on the impl/trait that contains
639 * - `self_bound`: bound for the `Self` type parameter, if any
640 * - `method`: the method definition
643 debug!("check_method_body(item_generics={}, \
646 item_generics.repr(ccx.tcx),
647 self_bound.repr(ccx.tcx),
649 let method_def_id = local_def(method.id);
650 let method_ty = ty::method(ccx.tcx, method_def_id);
651 let method_generics = &method_ty.generics;
654 ty::construct_parameter_environment(
657 item_generics.type_param_defs(),
658 method_generics.type_param_defs(),
659 item_generics.region_param_defs(),
660 method_generics.region_param_defs(),
663 let fty = ty::node_id_to_type(ccx.tcx, method.id);
665 check_bare_fn(ccx, method.decl, method.body, method.id, fty, param_env);
668 fn check_impl_methods_against_trait(ccx: &CrateCtxt,
670 impl_generics: &ty::Generics,
671 ast_trait_ref: &ast::TraitRef,
672 impl_trait_ref: &ty::TraitRef,
673 impl_methods: &[@ast::Method]) {
674 // Locate trait methods
676 let trait_methods = ty::trait_methods(tcx, impl_trait_ref.def_id);
678 // Check existing impl methods to see if they are both present in trait
679 // and compatible with trait signature
680 for impl_method in impl_methods.iter() {
681 let impl_method_def_id = local_def(impl_method.id);
682 let impl_method_ty = ty::method(ccx.tcx, impl_method_def_id);
684 // If this is an impl of a trait method, find the corresponding
685 // method definition in the trait.
686 let opt_trait_method_ty =
687 trait_methods.iter().
688 find(|tm| tm.ident.name == impl_method_ty.ident.name);
689 match opt_trait_method_ty {
690 Some(trait_method_ty) => {
691 compare_impl_method(ccx.tcx,
697 &impl_trait_ref.substs);
702 format!("method `{}` is not a member of trait `{}`",
703 token::get_ident(impl_method_ty.ident),
704 pprust::path_to_str(&ast_trait_ref.path)));
709 // Check for missing methods from trait
710 let provided_methods = ty::provided_trait_methods(tcx,
711 impl_trait_ref.def_id);
712 let mut missing_methods = Vec::new();
713 for trait_method in trait_methods.iter() {
715 impl_methods.iter().any(
716 |m| m.ident.name == trait_method.ident.name);
718 provided_methods.iter().any(
719 |m| m.ident.name == trait_method.ident.name);
720 if !is_implemented && !is_provided {
721 missing_methods.push(
722 format!("`{}`", token::get_ident(trait_method.ident)));
726 if !missing_methods.is_empty() {
729 format!("not all trait methods implemented, missing: {}",
730 missing_methods.connect(", ")));
735 * Checks that a method from an impl/class conforms to the signature of
736 * the same method as declared in the trait.
740 * - impl_generics: the generics declared on the impl itself (not the method!)
741 * - impl_m: type of the method we are checking
742 * - impl_m_span: span to use for reporting errors
743 * - impl_m_body_id: id of the method body
744 * - trait_m: the method in the trait
745 * - trait_substs: the substitutions used on the type of the trait
747 fn compare_impl_method(tcx: &ty::ctxt,
748 impl_generics: &ty::Generics,
751 impl_m_body_id: ast::NodeId,
752 trait_m: &ty::Method,
753 trait_substs: &ty::substs) {
754 debug!("compare_impl_method()");
755 let infcx = infer::new_infer_ctxt(tcx);
757 let impl_tps = impl_generics.type_param_defs().len();
759 // Try to give more informative error messages about self typing
760 // mismatches. Note that any mismatch will also be detected
761 // below, where we construct a canonical function type that
762 // includes the self parameter as a normal parameter. It's just
763 // that the error messages you get out of this code are a bit more
764 // inscrutable, particularly for cases where one method has no
766 match (&trait_m.explicit_self, &impl_m.explicit_self) {
767 (&ast::SelfStatic, &ast::SelfStatic) => {}
768 (&ast::SelfStatic, _) => {
771 format!("method `{}` has a `{}` declaration in the impl, \
772 but not in the trait",
773 token::get_ident(trait_m.ident),
774 pprust::explicit_self_to_str(impl_m.explicit_self)));
777 (_, &ast::SelfStatic) => {
780 format!("method `{}` has a `{}` declaration in the trait, \
781 but not in the impl",
782 token::get_ident(trait_m.ident),
783 pprust::explicit_self_to_str(trait_m.explicit_self)));
787 // Let the type checker catch other errors below
791 let num_impl_m_type_params = impl_m.generics.type_param_defs().len();
792 let num_trait_m_type_params = trait_m.generics.type_param_defs().len();
793 if num_impl_m_type_params != num_trait_m_type_params {
796 format!("method `{method}` has {nimpl, plural, =1{# type parameter} \
797 other{# type parameters}}, \
798 but its trait declaration has {ntrait, plural, =1{# type parameter} \
799 other{# type parameters}}",
800 method = token::get_ident(trait_m.ident),
801 nimpl = num_impl_m_type_params,
802 ntrait = num_trait_m_type_params));
806 if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() {
809 format!("method `{method}` has {nimpl, plural, =1{# parameter} \
810 other{# parameters}} \
811 but the declaration in trait `{trait}` has {ntrait}",
812 method = token::get_ident(trait_m.ident),
813 nimpl = impl_m.fty.sig.inputs.len(),
814 trait = ty::item_path_str(tcx, trait_m.def_id),
815 ntrait = trait_m.fty.sig.inputs.len()));
819 let it = trait_m.generics.type_param_defs().iter()
820 .zip(impl_m.generics.type_param_defs().iter());
822 for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
823 // Check that the impl does not require any builtin-bounds
824 // that the trait does not guarantee:
826 impl_param_def.bounds.builtin_bounds -
827 trait_param_def.bounds.builtin_bounds;
828 if !extra_bounds.is_empty() {
831 format!("in method `{}`, \
832 type parameter {} requires `{}`, \
833 which is not required by \
834 the corresponding type parameter \
835 in the trait declaration",
836 token::get_ident(trait_m.ident),
838 extra_bounds.user_string(tcx)));
842 // FIXME(#2687)---we should be checking that the bounds of the
843 // trait imply the bounds of the subtype, but it appears we
844 // are...not checking this.
845 if impl_param_def.bounds.trait_bounds.len() !=
846 trait_param_def.bounds.trait_bounds.len()
850 format!("in method `{method}`, \
851 type parameter {typaram} has \
852 {nimpl, plural, =1{# trait bound} other{# trait bounds}}, \
853 but the corresponding type parameter in \
854 the trait declaration has \
855 {ntrait, plural, =1{# trait bound} other{# trait bounds}}",
856 method = token::get_ident(trait_m.ident),
858 nimpl = impl_param_def.bounds.trait_bounds.len(),
859 ntrait = trait_param_def.bounds.trait_bounds.len()));
864 // Create a substitution that maps the type parameters on the impl
865 // to themselves and which replace any references to bound regions
866 // in the self type with free regions. So, for example, if the
867 // impl type is "&'a str", then this would replace the self
868 // type with a free region `self`.
869 let dummy_impl_tps: Vec<ty::t> =
870 impl_generics.type_param_defs().iter().enumerate().
871 map(|(i,t)| ty::mk_param(tcx, i, t.def_id)).
873 let dummy_method_tps: Vec<ty::t> =
874 impl_m.generics.type_param_defs().iter().enumerate().
875 map(|(i,t)| ty::mk_param(tcx, i + impl_tps, t.def_id)).
877 let dummy_impl_regions: OwnedSlice<ty::Region> =
878 impl_generics.region_param_defs().iter().
879 map(|l| ty::ReFree(ty::FreeRegion {
880 scope_id: impl_m_body_id,
881 bound_region: ty::BrNamed(l.def_id, l.name)})).
883 let dummy_substs = ty::substs {
884 tps: dummy_impl_tps.append(dummy_method_tps.as_slice()),
885 regions: ty::NonerasedRegions(dummy_impl_regions),
888 // Create a bare fn type for trait/impl
889 // It'd be nice to refactor so as to provide the bare fn types instead.
890 let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
891 let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
893 // Perform substitutions so that the trait/impl methods are expressed
894 // in terms of the same set of type/region parameters:
895 // - replace trait type parameters with those from `trait_substs`,
896 // except with any reference to bound self replaced with `dummy_self_r`
897 // - replace method parameters on the trait with fresh, dummy parameters
898 // that correspond to the parameters we will find on the impl
899 // - replace self region with a fresh, dummy region
901 debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
902 impl_fty.subst(tcx, &dummy_substs)
904 debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
906 let substs { regions: trait_regions,
908 self_ty: self_ty } = trait_substs.subst(tcx, &dummy_substs);
909 let substs = substs {
910 regions: trait_regions,
911 tps: trait_tps.append(dummy_method_tps.as_slice()),
914 debug!("trait_fty (pre-subst): {} substs={}",
915 trait_fty.repr(tcx), substs.repr(tcx));
916 trait_fty.subst(tcx, &substs)
918 debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx));
920 match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span),
921 impl_fty, trait_fty) {
923 result::Err(ref terr) => {
926 format!("method `{}` has an incompatible type: {}",
927 token::get_ident(trait_m.ident),
928 ty::type_err_to_str(tcx, terr)));
929 ty::note_and_explain_type_err(tcx, terr);
934 impl<'a> AstConv for FnCtxt<'a> {
935 fn tcx<'a>(&'a self) -> &'a ty::ctxt { self.ccx.tcx }
937 fn get_item_ty(&self, id: ast::DefId) -> ty::ty_param_bounds_and_ty {
938 ty::lookup_item_type(self.tcx(), id)
941 fn get_trait_def(&self, id: ast::DefId) -> @ty::TraitDef {
942 ty::lookup_trait_def(self.tcx(), id)
945 fn ty_infer(&self, _span: Span) -> ty::t {
946 self.infcx().next_ty_var()
950 impl<'a> FnCtxt<'a> {
951 pub fn infcx<'b>(&'b self) -> &'b infer::InferCtxt<'a> {
955 pub fn err_count_since_creation(&self) -> uint {
956 self.ccx.tcx.sess.err_count() - self.err_count_on_creation
959 pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
962 param_env: &self.inh.param_env
967 impl<'a> RegionScope for infer::InferCtxt<'a> {
968 fn anon_regions(&self, span: Span, count: uint)
969 -> Result<Vec<ty::Region> , ()> {
970 Ok(Vec::from_fn(count, |_| {
971 self.next_region_var(infer::MiscVariable(span))
976 impl<'a> FnCtxt<'a> {
977 pub fn tag(&self) -> ~str {
978 format!("{}", self as *FnCtxt)
981 pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t {
982 match self.inh.locals.borrow().find(&nid) {
985 self.tcx().sess.span_bug(
987 format!("no type for local variable {:?}", nid));
993 pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
994 debug!("write_ty({}, {}) in fcx {}",
995 node_id, ppaux::ty_to_str(self.tcx(), ty), self.tag());
996 self.inh.node_types.borrow_mut().insert(node_id, ty);
999 pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::substs) {
1000 if !ty::substs_is_noop(&substs) {
1001 debug!("write_substs({}, {}) in fcx {}",
1003 ty::substs_to_str(self.tcx(), &substs),
1006 self.inh.node_type_substs.borrow_mut().insert(node_id, substs);
1010 pub fn write_ty_substs(&self,
1011 node_id: ast::NodeId,
1013 substs: ty::substs) {
1014 let ty = ty::subst(self.tcx(), &substs, ty);
1015 self.write_ty(node_id, ty);
1016 self.write_substs(node_id, substs);
1019 pub fn write_autoderef_adjustment(&self,
1020 node_id: ast::NodeId,
1022 if derefs == 0 { return; }
1023 self.write_adjustment(
1025 @ty::AutoDerefRef(ty::AutoDerefRef {
1031 pub fn write_adjustment(&self,
1032 node_id: ast::NodeId,
1033 adj: @ty::AutoAdjustment) {
1034 debug!("write_adjustment(node_id={:?}, adj={:?})", node_id, adj);
1035 self.inh.adjustments.borrow_mut().insert(node_id, adj);
1038 pub fn write_nil(&self, node_id: ast::NodeId) {
1039 self.write_ty(node_id, ty::mk_nil());
1041 pub fn write_bot(&self, node_id: ast::NodeId) {
1042 self.write_ty(node_id, ty::mk_bot());
1044 pub fn write_error(&self, node_id: ast::NodeId) {
1045 self.write_ty(node_id, ty::mk_err());
1048 pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
1049 ast_ty_to_ty(self, self.infcx(), ast_t)
1052 pub fn pat_to_str(&self, pat: &ast::Pat) -> ~str {
1053 pat.repr(self.tcx())
1056 pub fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
1057 match self.inh.node_types.borrow().find(&ex.id) {
1060 self.tcx().sess.bug(format!("no type for expr in fcx {}",
1066 pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
1067 match self.inh.node_types.borrow().find(&id) {
1070 self.tcx().sess.bug(
1071 format!("no type for node {}: {} in fcx {}",
1072 id, self.tcx().map.node_to_str(id),
1078 pub fn method_ty_substs(&self, id: ast::NodeId) -> ty::substs {
1079 match self.inh.method_map.borrow().find(&MethodCall::expr(id)) {
1080 Some(method) => method.substs.clone(),
1082 self.tcx().sess.bug(
1083 format!("no method entry for node {}: {} in fcx {}",
1084 id, self.tcx().map.node_to_str(id),
1090 pub fn opt_node_ty_substs(&self,
1092 f: |&ty::substs| -> bool)
1094 match self.inh.node_type_substs.borrow().find(&id) {
1100 pub fn mk_subty(&self,
1101 a_is_expected: bool,
1102 origin: infer::TypeOrigin,
1105 -> Result<(), ty::type_err> {
1106 infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
1109 pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t)
1110 -> Result<(), ty::type_err> {
1111 infer::can_mk_subty(self.infcx(), sub, sup)
1114 pub fn mk_assignty(&self,
1118 -> Result<(), ty::type_err> {
1119 match infer::mk_coercety(self.infcx(),
1121 infer::ExprAssignable(expr.span),
1124 Ok(None) => result::Ok(()),
1125 Err(ref e) => result::Err((*e)),
1126 Ok(Some(adjustment)) => {
1127 self.write_adjustment(expr.id, adjustment);
1133 pub fn mk_eqty(&self,
1134 a_is_expected: bool,
1135 origin: infer::TypeOrigin,
1138 -> Result<(), ty::type_err> {
1139 infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
1142 pub fn mk_subr(&self,
1143 a_is_expected: bool,
1144 origin: infer::SubregionOrigin,
1147 infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
1150 pub fn with_region_lb<R>(&self, lb: ast::NodeId, f: || -> R) -> R {
1151 let old_region_lb = self.region_lb.get();
1152 self.region_lb.set(lb);
1154 self.region_lb.set(old_region_lb);
1158 pub fn type_error_message(&self,
1160 mk_msg: |~str| -> ~str,
1162 err: Option<&ty::type_err>) {
1163 self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
1166 pub fn report_mismatched_return_types(&self,
1170 err: &ty::type_err) {
1172 if ty::type_is_error(e) || ty::type_is_error(a) {
1175 self.infcx().report_mismatched_types(sp, e, a, err)
1178 pub fn report_mismatched_types(&self,
1182 err: &ty::type_err) {
1183 self.infcx().report_mismatched_types(sp, e, a, err)
1187 pub enum LvaluePreference {
1192 pub fn autoderef<T>(fcx: &FnCtxt, sp: Span, base_ty: ty::t,
1193 expr_id: Option<ast::NodeId>,
1194 mut lvalue_pref: LvaluePreference,
1195 should_stop: |ty::t, uint| -> Option<T>)
1196 -> (ty::t, uint, Option<T>) {
1198 * Executes an autoderef loop for the type `t`. At each step, invokes
1199 * `should_stop` to decide whether to terminate the loop. Returns
1200 * the final type and number of derefs that it performed.
1202 * Note: this method does not modify the adjustments table. The caller is
1203 * responsible for inserting an AutoAdjustment record into the `fcx`
1204 * using one of the suitable methods.
1207 let mut t = base_ty;
1208 for autoderefs in range(0, fcx.tcx().sess.recursion_limit.get()) {
1209 let resolved_t = structurally_resolved_type(fcx, sp, t);
1211 match should_stop(resolved_t, autoderefs) {
1212 Some(x) => return (resolved_t, autoderefs, Some(x)),
1216 // Otherwise, deref if type is derefable:
1217 let mt = match ty::deref(resolved_t, false) {
1218 Some(mt) => Some(mt),
1221 expr_id.map(|id| MethodCall::autoderef(id, autoderefs as u32));
1222 try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
1228 if mt.mutbl == ast::MutImmutable {
1229 lvalue_pref = NoPreference;
1232 None => return (resolved_t, autoderefs, None)
1236 // We've reached the recursion limit, error gracefully.
1237 fcx.tcx().sess.span_err(sp,
1238 format!("reached the recursion limit while auto-dereferencing {}",
1239 base_ty.repr(fcx.tcx())));
1240 (ty::mk_err(), 0, None)
1243 fn try_overloaded_deref(fcx: &FnCtxt,
1245 method_call: Option<MethodCall>,
1246 base_expr: Option<&ast::Expr>,
1248 lvalue_pref: LvaluePreference)
1250 // Try DerefMut first, if preferred.
1251 let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
1252 (PreferMutLvalue, Some(trait_did)) => {
1253 method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
1254 token::intern("deref_mut"), trait_did,
1255 base_ty, [], DontAutoderefReceiver)
1260 // Otherwise, fall back to Deref.
1261 let method = match (method, fcx.tcx().lang_items.deref_trait()) {
1262 (None, Some(trait_did)) => {
1263 method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
1264 token::intern("deref"), trait_did,
1265 base_ty, [], DontAutoderefReceiver)
1267 (method, _) => method
1272 let ref_ty = ty::ty_fn_ret(method.ty);
1274 Some(method_call) => {
1275 fcx.inh.method_map.borrow_mut().insert(method_call, method);
1279 ty::deref(ref_ty, true)
1285 // AST fragment checking
1286 pub fn check_lit(fcx: &FnCtxt, lit: &ast::Lit) -> ty::t {
1287 let tcx = fcx.ccx.tcx;
1290 ast::LitStr(..) => ty::mk_str(tcx, ty::vstore_slice(ty::ReStatic)),
1291 ast::LitBinary(..) => {
1292 ty::mk_vec(tcx, ty::mt{ ty: ty::mk_u8(), mutbl: ast::MutImmutable },
1293 ty::vstore_slice(ty::ReStatic))
1295 ast::LitChar(_) => ty::mk_char(),
1296 ast::LitInt(_, t) => ty::mk_mach_int(t),
1297 ast::LitUint(_, t) => ty::mk_mach_uint(t),
1298 ast::LitIntUnsuffixed(_) => {
1299 // An unsuffixed integer literal could have any integral type,
1300 // so we create an integral type variable for it.
1301 ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
1303 ast::LitFloat(_, t) => ty::mk_mach_float(t),
1304 ast::LitFloatUnsuffixed(_) => {
1305 // An unsuffixed floating point literal could have any floating point
1306 // type, so we create a floating point type variable for it.
1307 ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())
1309 ast::LitNil => ty::mk_nil(),
1310 ast::LitBool(_) => ty::mk_bool()
1314 pub fn valid_range_bounds(ccx: &CrateCtxt,
1318 match const_eval::compare_lit_exprs(ccx.tcx, from, to) {
1319 Some(val) => Some(val <= 0),
1324 pub fn check_expr_has_type(
1325 fcx: &FnCtxt, expr: &ast::Expr,
1327 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1328 demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
1332 fn check_expr_coercable_to_type(fcx: &FnCtxt, expr: &ast::Expr, expected: ty::t) {
1333 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1334 demand::coerce(fcx, expr.span, expected, expr)
1338 fn check_expr_with_hint(fcx: &FnCtxt, expr: &ast::Expr, expected: ty::t) {
1339 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || ())
1342 fn check_expr_with_opt_hint(fcx: &FnCtxt, expr: &ast::Expr,
1343 expected: Option<ty::t>) {
1344 check_expr_with_unifier(fcx, expr, expected, NoPreference, || ())
1347 fn check_expr_with_opt_hint_and_lvalue_pref(fcx: &FnCtxt,
1349 expected: Option<ty::t>,
1350 lvalue_pref: LvaluePreference) {
1351 check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ())
1354 fn check_expr(fcx: &FnCtxt, expr: &ast::Expr) {
1355 check_expr_with_unifier(fcx, expr, None, NoPreference, || ())
1358 fn check_expr_with_lvalue_pref(fcx: &FnCtxt, expr: &ast::Expr,
1359 lvalue_pref: LvaluePreference) {
1360 check_expr_with_unifier(fcx, expr, None, lvalue_pref, || ())
1364 // determine the `self` type, using fresh variables for all variables
1365 // declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
1366 // would return ($0, $1) where $0 and $1 are freshly instantiated type
1368 pub fn impl_self_ty(vcx: &VtableContext,
1369 span: Span, // (potential) receiver for this impl
1371 -> ty_param_substs_and_ty {
1372 let tcx = vcx.tcx();
1374 let ity = ty::lookup_item_type(tcx, did);
1375 let (n_tps, rps, raw_ty) =
1376 (ity.generics.type_param_defs().len(),
1377 ity.generics.region_param_defs(),
1380 let rps = vcx.infcx.region_vars_for_defs(span, rps);
1381 let tps = vcx.infcx.next_ty_vars(n_tps);
1383 let substs = substs {
1384 regions: ty::NonerasedRegions(rps),
1388 let substd_ty = ty::subst(tcx, &substs, raw_ty);
1390 ty_param_substs_and_ty { substs: substs, ty: substd_ty }
1393 // Only for fields! Returns <none> for methods>
1394 // Indifferent to privacy flags
1395 pub fn lookup_field_ty(tcx: &ty::ctxt,
1396 class_id: ast::DefId,
1397 items: &[ty::field_ty],
1398 fieldname: ast::Name,
1399 substs: &ty::substs) -> Option<ty::t> {
1401 let o_field = items.iter().find(|f| f.name == fieldname);
1402 o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
1405 // Controls whether the arguments are automatically referenced. This is useful
1406 // for overloaded binary and unary operators.
1407 pub enum DerefArgs {
1412 // Given the provenance of a static method, returns the generics of the static
1413 // method's container.
1414 fn generics_of_static_method_container(type_context: &ty::ctxt,
1415 provenance: ast::MethodProvenance)
1418 ast::FromTrait(trait_def_id) => {
1419 ty::lookup_trait_def(type_context, trait_def_id).generics.clone()
1421 ast::FromImpl(impl_def_id) => {
1422 ty::lookup_item_type(type_context, impl_def_id).generics.clone()
1427 // Verifies that type parameters supplied in paths are in the right
1429 fn check_type_parameter_positions_in_path(function_context: &FnCtxt,
1432 // We only care about checking the case in which the path has two or
1434 if path.segments.len() < 2 {
1438 // Verify that no lifetimes or type parameters are present anywhere
1439 // except the final two elements of the path.
1440 for i in range(0, path.segments.len() - 2) {
1441 for lifetime in path.segments.get(i).lifetimes.iter() {
1442 function_context.tcx()
1444 .span_err(lifetime.span,
1445 "lifetime parameters may not \
1450 for typ in path.segments.get(i).types.iter() {
1451 function_context.tcx()
1454 "type parameters may not appear here");
1459 // If there are no parameters at all, there is nothing more to do; the
1460 // rest of typechecking will (attempt to) infer everything.
1463 .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) {
1468 // If this is a static method of a trait or implementation, then
1469 // ensure that the segment of the path which names the trait or
1470 // implementation (the penultimate segment) is annotated with the
1471 // right number of type parameters.
1472 ast::DefStaticMethod(_, provenance, _) => {
1474 generics_of_static_method_container(function_context.ccx.tcx,
1476 let name = match provenance {
1477 ast::FromTrait(_) => "trait",
1478 ast::FromImpl(_) => "impl",
1481 let trait_segment = &path.segments.get(path.segments.len() - 2);
1483 // Make sure lifetime parameterization agrees with the trait or
1484 // implementation type.
1485 let trait_region_parameter_count = generics.region_param_defs().len();
1486 let supplied_region_parameter_count = trait_segment.lifetimes.len();
1487 if trait_region_parameter_count != supplied_region_parameter_count
1488 && supplied_region_parameter_count != 0 {
1489 function_context.tcx()
1491 .span_err(path.span,
1492 format!("expected {nexpected, plural, =1{# lifetime parameter} \
1493 other{# lifetime parameters}}, \
1494 found {nsupplied, plural, =1{# lifetime parameter} \
1495 other{# lifetime parameters}}",
1496 nexpected = trait_region_parameter_count,
1497 nsupplied = supplied_region_parameter_count));
1500 // Make sure the number of type parameters supplied on the trait
1501 // or implementation segment equals the number of type parameters
1502 // on the trait or implementation definition.
1503 let formal_ty_param_count = generics.type_param_defs().len();
1504 let required_ty_param_count = generics.type_param_defs().iter()
1505 .take_while(|x| x.default.is_none())
1507 let supplied_ty_param_count = trait_segment.types.len();
1508 if supplied_ty_param_count < required_ty_param_count {
1509 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1510 format!("the {trait_or_impl} referenced by this path needs at least \
1511 {nexpected, plural, =1{# type parameter} \
1512 other{# type parameters}}, \
1513 but {nsupplied, plural, =1{# type parameter} \
1514 other{# type parameters}} were supplied",
1515 trait_or_impl = name,
1516 nexpected = required_ty_param_count,
1517 nsupplied = supplied_ty_param_count)
1519 format!("the {trait_or_impl} referenced by this path needs \
1520 {nexpected, plural, =1{# type parameter} \
1521 other{# type parameters}}, \
1522 but {nsupplied, plural, =1{# type parameter} \
1523 other{# type parameters}} were supplied",
1524 trait_or_impl = name,
1525 nexpected = required_ty_param_count,
1526 nsupplied = supplied_ty_param_count)
1528 function_context.tcx().sess.span_err(path.span, msg)
1529 } else if supplied_ty_param_count > formal_ty_param_count {
1530 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1531 format!("the {trait_or_impl} referenced by this path needs at most \
1532 {nexpected, plural, =1{# type parameter} \
1533 other{# type parameters}}, \
1534 but {nsupplied, plural, =1{# type parameter} \
1535 other{# type parameters}} were supplied",
1536 trait_or_impl = name,
1537 nexpected = formal_ty_param_count,
1538 nsupplied = supplied_ty_param_count)
1540 format!("the {trait_or_impl} referenced by this path needs \
1541 {nexpected, plural, =1{# type parameter} \
1542 other{# type parameters}}, \
1543 but {nsupplied, plural, =1{# type parameter} \
1544 other{# type parameters}} were supplied",
1545 trait_or_impl = name,
1546 nexpected = formal_ty_param_count,
1547 nsupplied = supplied_ty_param_count)
1549 function_context.tcx().sess.span_err(path.span, msg)
1553 // Verify that no lifetimes or type parameters are present on
1554 // the penultimate segment of the path.
1555 let segment = &path.segments.get(path.segments.len() - 2);
1556 for lifetime in segment.lifetimes.iter() {
1557 function_context.tcx()
1559 .span_err(lifetime.span,
1560 "lifetime parameters may not
1564 for typ in segment.types.iter() {
1565 function_context.tcx()
1568 "type parameters may not appear \
1577 /// If an expression has any sub-expressions that result in a type error,
1578 /// inspecting that expression's type with `ty::type_is_error` will return
1579 /// true. Likewise, if an expression is known to diverge, inspecting its
1580 /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
1581 /// strict, _|_ can appear in the type of an expression that does not,
1582 /// itself, diverge: for example, fn() -> _|_.)
1583 /// Note that inspecting a type's structure *directly* may expose the fact
1584 /// that there are actually multiple representations for both `ty_err` and
1585 /// `ty_bot`, so avoid that when err and bot need to be handled differently.
1586 fn check_expr_with_unifier(fcx: &FnCtxt,
1588 expected: Option<ty::t>,
1589 lvalue_pref: LvaluePreference,
1591 debug!(">> typechecking");
1593 fn check_method_argument_types(
1596 method_fn_ty: ty::t,
1597 callee_expr: &ast::Expr,
1598 args: &[@ast::Expr],
1599 deref_args: DerefArgs) -> ty::t {
1600 // HACK(eddyb) ignore provided self (it has special typeck rules).
1601 let args = args.slice_from(1);
1602 if ty::type_is_error(method_fn_ty) {
1603 let err_inputs = err_args(args.len());
1604 check_argument_types(fcx, sp, err_inputs.as_slice(), callee_expr,
1605 args, deref_args, false);
1608 match ty::get(method_fn_ty).sty {
1609 ty::ty_bare_fn(ref fty) => {
1610 // HACK(eddyb) ignore self in the definition (see above).
1611 check_argument_types(fcx, sp, fty.sig.inputs.slice_from(1),
1612 callee_expr, args, deref_args,
1617 fcx.tcx().sess.span_bug(
1619 format!("method without bare fn type"));
1625 fn check_argument_types(fcx: &FnCtxt,
1627 fn_inputs: &[ty::t],
1628 callee_expr: &ast::Expr,
1629 args: &[@ast::Expr],
1630 deref_args: DerefArgs,
1634 * Generic function that factors out common logic from
1635 * function calls, method calls and overloaded operators.
1638 let tcx = fcx.ccx.tcx;
1640 // Grab the argument types, supplying fresh type variables
1641 // if the wrong number of arguments were supplied
1642 let supplied_arg_count = args.len();
1643 let expected_arg_count = fn_inputs.len();
1644 let formal_tys = if expected_arg_count == supplied_arg_count {
1645 fn_inputs.iter().map(|a| *a).collect()
1646 } else if variadic {
1647 if supplied_arg_count >= expected_arg_count {
1648 fn_inputs.iter().map(|a| *a).collect()
1651 "this function takes at least {nexpected, plural, =1{# parameter} \
1652 other{# parameters}} \
1653 but {nsupplied, plural, =1{# parameter was} \
1654 other{# parameters were}} supplied",
1655 nexpected = expected_arg_count,
1656 nsupplied = supplied_arg_count);
1658 tcx.sess.span_err(sp, msg);
1660 err_args(supplied_arg_count)
1664 "this function takes {nexpected, plural, =1{# parameter} \
1665 other{# parameters}} \
1666 but {nsupplied, plural, =1{# parameter was} \
1667 other{# parameters were}} supplied",
1668 nexpected = expected_arg_count,
1669 nsupplied = supplied_arg_count);
1671 tcx.sess.span_err(sp, msg);
1673 err_args(supplied_arg_count)
1676 debug!("check_argument_types: formal_tys={:?}",
1677 formal_tys.iter().map(|t| fcx.infcx().ty_to_str(*t)).collect::<Vec<~str>>());
1679 // Check the arguments.
1680 // We do this in a pretty awful way: first we typecheck any arguments
1681 // that are not anonymous functions, then we typecheck the anonymous
1682 // functions. This is so that we have more information about the types
1683 // of arguments when we typecheck the functions. This isn't really the
1684 // right way to do this.
1685 let xs = [false, true];
1686 for check_blocks in xs.iter() {
1687 let check_blocks = *check_blocks;
1688 debug!("check_blocks={}", check_blocks);
1690 // More awful hacks: before we check the blocks, try to do
1691 // an "opportunistic" vtable resolution of any trait
1692 // bounds on the call.
1694 vtable::early_resolve_expr(callee_expr, fcx, true);
1697 // For variadic functions, we don't have a declared type for all of
1698 // the arguments hence we only do our usual type checking with
1699 // the arguments who's types we do know.
1700 let t = if variadic {
1705 for (i, arg) in args.iter().take(t).enumerate() {
1706 let is_block = match arg.node {
1707 ast::ExprFnBlock(..) |
1708 ast::ExprProc(..) => true,
1712 if is_block == check_blocks {
1713 debug!("checking the argument");
1714 let mut formal_ty = *formal_tys.get(i);
1718 match ty::get(formal_ty).sty {
1719 ty::ty_rptr(_, mt) => formal_ty = mt.ty,
1722 // So we hit this case when one implements the
1723 // operator traits but leaves an argument as
1724 // just T instead of &T. We'll catch it in the
1725 // mismatch impl/trait method phase no need to
1728 formal_ty = ty::mk_err();
1735 check_expr_coercable_to_type(fcx, *arg, formal_ty);
1741 // We also need to make sure we at least write the ty of the other
1742 // arguments which we skipped above.
1744 for arg in args.iter().skip(expected_arg_count) {
1745 check_expr(fcx, *arg);
1747 // There are a few types which get autopromoted when passed via varargs
1748 // in C but we just error out instead and require explicit casts.
1749 let arg_ty = structurally_resolved_type(fcx, arg.span, fcx.expr_ty(*arg));
1750 match ty::get(arg_ty).sty {
1751 ty::ty_float(ast::TyF32) => {
1752 fcx.type_error_message(arg.span,
1753 |t| format!("can't pass an {} to variadic function, \
1754 cast to c_double", t), arg_ty, None);
1756 ty::ty_int(ast::TyI8) | ty::ty_int(ast::TyI16) | ty::ty_bool => {
1757 fcx.type_error_message(arg.span,
1758 |t| format!("can't pass {} to variadic function, cast to c_int",
1761 ty::ty_uint(ast::TyU8) | ty::ty_uint(ast::TyU16) => {
1762 fcx.type_error_message(arg.span,
1763 |t| format!("can't pass {} to variadic function, cast to c_uint",
1772 fn err_args(len: uint) -> Vec<ty::t> {
1773 Vec::from_fn(len, |_| ty::mk_err())
1776 fn write_call(fcx: &FnCtxt, call_expr: &ast::Expr, output: ty::t) {
1777 fcx.write_ty(call_expr.id, output);
1780 // A generic function for doing all of the checking for call expressions
1781 fn check_call(fcx: &FnCtxt,
1782 call_expr: &ast::Expr,
1784 args: &[@ast::Expr]) {
1785 // Index expressions need to be handled separately, to inform them
1786 // that they appear in call position.
1789 // Store the type of `f` as the type of the callee
1790 let fn_ty = fcx.expr_ty(f);
1792 // Extract the function signature from `in_fty`.
1793 let fn_sty = structure_of(fcx, f.span, fn_ty);
1795 // This is the "default" function signature, used in case of error.
1796 // In that case, we check each argument against "error" in order to
1797 // set up all the node type bindings.
1798 let error_fn_sig = FnSig {
1799 binder_id: ast::CRATE_NODE_ID,
1800 inputs: err_args(args.len()),
1801 output: ty::mk_err(),
1805 let fn_sig = match *fn_sty {
1806 ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, ..}) |
1807 ty::ty_closure(~ty::ClosureTy {sig: ref sig, ..}) => sig,
1809 fcx.type_error_message(call_expr.span, |actual| {
1810 format!("expected function but \
1811 found `{}`", actual) }, fn_ty, None);
1816 // Replace any bound regions that appear in the function
1817 // signature with region variables
1818 let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
1819 fcx.infcx().next_region_var(infer::LateBoundRegion(call_expr.span, br))
1822 // Call the generic checker.
1823 check_argument_types(fcx, call_expr.span, fn_sig.inputs.as_slice(), f,
1824 args, DontDerefArgs, fn_sig.variadic);
1826 write_call(fcx, call_expr, fn_sig.output);
1829 // Checks a method call.
1830 fn check_method_call(fcx: &FnCtxt,
1832 method_name: ast::Ident,
1833 args: &[@ast::Expr],
1834 tps: &[ast::P<ast::Ty>]) {
1836 // We can't know if we need &mut self before we look up the method,
1837 // so treat the receiver as mutable just in case - only explicit
1838 // overloaded dereferences care about the distinction.
1839 check_expr_with_lvalue_pref(fcx, rcvr, PreferMutLvalue);
1841 // no need to check for bot/err -- callee does that
1842 let expr_t = structurally_resolved_type(fcx,
1846 let tps = tps.iter().map(|&ast_ty| fcx.to_ty(ast_ty)).collect::<Vec<_>>();
1847 let fn_ty = match method::lookup(fcx, expr, rcvr,
1849 expr_t, tps.as_slice(),
1851 CheckTraitsAndInherentMethods,
1852 AutoderefReceiver) {
1854 let method_ty = method.ty;
1855 let method_call = MethodCall::expr(expr.id);
1856 fcx.inh.method_map.borrow_mut().insert(method_call, method);
1860 debug!("(checking method call) failing expr is {}", expr.id);
1862 fcx.type_error_message(expr.span,
1864 format!("type `{}` does not implement any method in scope \
1866 actual, token::get_ident(method_name))
1871 // Add error type for the result
1872 fcx.write_error(expr.id);
1877 // Call the generic checker.
1878 let ret_ty = check_method_argument_types(fcx, expr.span,
1882 write_call(fcx, expr, ret_ty);
1885 // A generic function for checking the then and else in an if
1887 fn check_then_else(fcx: &FnCtxt,
1888 cond_expr: &ast::Expr,
1889 then_blk: &ast::Block,
1890 opt_else_expr: Option<@ast::Expr>,
1893 expected: Option<ty::t>) {
1894 check_expr_has_type(fcx, cond_expr, ty::mk_bool());
1896 let branches_ty = match opt_else_expr {
1897 Some(else_expr) => {
1898 check_block_with_expected(fcx, then_blk, expected);
1899 let then_ty = fcx.node_ty(then_blk.id);
1900 check_expr_with_opt_hint(fcx, else_expr, expected);
1901 let else_ty = fcx.expr_ty(else_expr);
1902 infer::common_supertype(fcx.infcx(),
1903 infer::IfExpression(sp),
1909 check_block_no_value(fcx, then_blk);
1914 let cond_ty = fcx.expr_ty(cond_expr);
1915 let if_ty = if ty::type_is_error(cond_ty) {
1917 } else if ty::type_is_bot(cond_ty) {
1923 fcx.write_ty(id, if_ty);
1926 fn lookup_op_method(fcx: &FnCtxt,
1930 trait_did: Option<ast::DefId>,
1931 args: &[@ast::Expr],
1932 autoderef_receiver: AutoderefReceiverFlag,
1933 unbound_method: ||) -> ty::t {
1934 let method = match trait_did {
1935 Some(trait_did) => {
1936 method::lookup_in_trait(fcx, op_ex.span, Some(&*args[0]), opname,
1937 trait_did, self_t, [], autoderef_receiver)
1943 let method_ty = method.ty;
1944 // HACK(eddyb) Fully qualified path to work around a resolve bug.
1945 let method_call = ::middle::typeck::MethodCall::expr(op_ex.id);
1946 fcx.inh.method_map.borrow_mut().insert(method_call, method);
1947 check_method_argument_types(fcx, op_ex.span,
1953 // Check the args anyway
1954 // so we get all the error messages
1955 let expected_ty = ty::mk_err();
1956 check_method_argument_types(fcx, op_ex.span,
1964 // could be either an expr_binop or an expr_assign_binop
1965 fn check_binop(fcx: &FnCtxt,
1970 is_binop_assignment: IsBinopAssignment) {
1971 let tcx = fcx.ccx.tcx;
1973 let lvalue_pref = match is_binop_assignment {
1974 BinopAssignment => PreferMutLvalue,
1975 SimpleBinop => NoPreference
1977 check_expr_with_lvalue_pref(fcx, lhs, lvalue_pref);
1979 // Callee does bot / err checking
1980 let lhs_t = structurally_resolved_type(fcx, lhs.span,
1983 if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) {
1984 // Shift is a special case: rhs can be any integral type
1985 check_expr(fcx, rhs);
1986 let rhs_t = fcx.expr_ty(rhs);
1987 require_integral(fcx, rhs.span, rhs_t);
1988 fcx.write_ty(expr.id, lhs_t);
1992 if ty::is_binopable(tcx, lhs_t, op) {
1993 let tvar = fcx.infcx().next_ty_var();
1994 demand::suptype(fcx, expr.span, tvar, lhs_t);
1995 check_expr_has_type(fcx, rhs, tvar);
1997 let result_t = match op {
1998 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGe |
1999 ast::BiGt => ty::mk_bool(),
2003 fcx.write_ty(expr.id, result_t);
2007 if op == ast::BiOr || op == ast::BiAnd {
2008 // This is an error; one of the operands must have the wrong
2010 fcx.write_error(expr.id);
2011 fcx.write_error(rhs.id);
2012 fcx.type_error_message(expr.span, |actual| {
2013 format!("binary operation `{}` cannot be applied \
2015 ast_util::binop_to_str(op), actual)},
2020 // Check for overloaded operators if not an assignment.
2021 let result_t = if is_binop_assignment == SimpleBinop {
2022 check_user_binop(fcx, expr, lhs, lhs_t, op, rhs)
2024 fcx.type_error_message(expr.span,
2026 format!("binary assignment operation \
2027 `{}=` cannot be applied to type `{}`",
2028 ast_util::binop_to_str(op),
2033 check_expr(fcx, rhs);
2037 fcx.write_ty(expr.id, result_t);
2038 if ty::type_is_error(result_t) {
2039 fcx.write_ty(rhs.id, result_t);
2043 fn check_user_binop(fcx: &FnCtxt,
2045 lhs_expr: @ast::Expr,
2046 lhs_resolved_t: ty::t,
2048 rhs: @ast::Expr) -> ty::t {
2049 let tcx = fcx.ccx.tcx;
2050 let lang = tcx.lang_items;
2051 let (name, trait_did) = match op {
2052 ast::BiAdd => ("add", lang.add_trait()),
2053 ast::BiSub => ("sub", lang.sub_trait()),
2054 ast::BiMul => ("mul", lang.mul_trait()),
2055 ast::BiDiv => ("div", lang.div_trait()),
2056 ast::BiRem => ("rem", lang.rem_trait()),
2057 ast::BiBitXor => ("bitxor", lang.bitxor_trait()),
2058 ast::BiBitAnd => ("bitand", lang.bitand_trait()),
2059 ast::BiBitOr => ("bitor", lang.bitor_trait()),
2060 ast::BiShl => ("shl", lang.shl_trait()),
2061 ast::BiShr => ("shr", lang.shr_trait()),
2062 ast::BiLt => ("lt", lang.ord_trait()),
2063 ast::BiLe => ("le", lang.ord_trait()),
2064 ast::BiGe => ("ge", lang.ord_trait()),
2065 ast::BiGt => ("gt", lang.ord_trait()),
2066 ast::BiEq => ("eq", lang.eq_trait()),
2067 ast::BiNe => ("ne", lang.eq_trait()),
2068 ast::BiAnd | ast::BiOr => {
2069 check_expr(fcx, rhs);
2070 return ty::mk_err();
2073 lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
2074 trait_did, [lhs_expr, rhs], DontAutoderefReceiver, || {
2075 fcx.type_error_message(ex.span, |actual| {
2076 format!("binary operation `{}` cannot be applied to type `{}`",
2077 ast_util::binop_to_str(op), actual)
2078 }, lhs_resolved_t, None)
2082 fn check_user_unop(fcx: &FnCtxt,
2085 trait_did: Option<ast::DefId>,
2087 rhs_expr: @ast::Expr,
2088 rhs_t: ty::t) -> ty::t {
2089 lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
2090 trait_did, [rhs_expr], DontAutoderefReceiver, || {
2091 fcx.type_error_message(ex.span, |actual| {
2092 format!("cannot apply unary operator `{}` to type `{}`", op_str, actual)
2097 // Resolves `expected` by a single level if it is a variable and passes it
2098 // through the `unpack` function. It there is no expected type or
2099 // resolution is not possible (e.g., no constraints yet present), just
2101 fn unpack_expected<O>(
2103 expected: Option<ty::t>,
2104 unpack: |&ty::sty| -> Option<O>)
2108 match resolve_type(fcx.infcx(), t, force_tvar) {
2109 Ok(t) => unpack(&ty::get(t).sty),
2117 fn check_expr_fn(fcx: &FnCtxt,
2119 ast_sigil_opt: Option<ast::Sigil>,
2121 body: ast::P<ast::Block>,
2123 expected: Option<ty::t>) {
2124 let tcx = fcx.ccx.tcx;
2126 // Find the expected input/output types (if any). Substitute
2127 // fresh bound regions for any bound regions we find in the
2128 // expected types so as to avoid capture.
2130 // Also try to pick up inferred purity and sigil, defaulting
2131 // to impure and block. Note that we only will use those for
2132 // block syntax lambdas; that is, lambdas without explicit
2134 let expected_sty = unpack_expected(fcx,
2136 |x| Some((*x).clone()));
2137 let error_happened = false;
2142 expected_bounds) = {
2143 match expected_sty {
2144 Some(ty::ty_closure(ref cenv)) => {
2146 replace_late_bound_regions_in_fn_sig(
2148 |_| fcx.inh.infcx.fresh_bound_region(expr.id));
2149 (Some(sig), cenv.purity, cenv.sigil,
2150 cenv.onceness, cenv.bounds)
2153 // Not an error! Means we're inferring the closure type
2154 let mut sigil = ast::BorrowedSigil;
2155 let mut onceness = ast::Many;
2156 let mut bounds = ty::EmptyBuiltinBounds();
2158 ast::ExprProc(..) => {
2159 sigil = ast::OwnedSigil;
2160 onceness = ast::Once;
2161 bounds.add(ty::BoundSend);
2165 (None, ast::ImpureFn, sigil,
2171 // If the proto is specified, use that, otherwise select a
2172 // proto based on inference.
2173 let (sigil, purity) = match ast_sigil_opt {
2174 Some(p) => (p, ast::ImpureFn),
2175 None => (expected_sigil, expected_purity)
2178 // construct the function type
2179 let fn_ty = astconv::ty_of_closure(fcx,
2192 let fty = if error_happened {
2194 binder_id: ast::CRATE_NODE_ID,
2195 inputs: fn_ty.sig.inputs.iter().map(|_| ty::mk_err()).collect(),
2196 output: ty::mk_err(),
2201 let fn_ty_copy = fn_ty.clone();
2202 fty_sig = fn_ty.sig.clone();
2203 ty::mk_closure(tcx, fn_ty_copy)
2206 debug!("check_expr_fn_with_unifier fty={}",
2207 fcx.infcx().ty_to_str(fty));
2209 fcx.write_ty(expr.id, fty);
2211 let (inherited_purity, id) =
2212 ty::determine_inherited_purity((fcx.ps.borrow().purity,
2213 fcx.ps.borrow().def),
2217 check_fn(fcx.ccx, inherited_purity, &fty_sig,
2218 decl, id, body, fn_kind, fcx.inh);
2222 // Check field access expressions
2223 fn check_field(fcx: &FnCtxt,
2225 lvalue_pref: LvaluePreference,
2228 tys: &[ast::P<ast::Ty>]) {
2229 let tcx = fcx.ccx.tcx;
2230 check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
2231 let expr_t = structurally_resolved_type(fcx, expr.span,
2233 // FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
2234 let (_, autoderefs, field_ty) =
2235 autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
2236 match ty::get(base_t).sty {
2237 ty::ty_struct(base_id, ref substs) => {
2238 debug!("struct named {}", ppaux::ty_to_str(tcx, base_t));
2239 let fields = ty::lookup_struct_fields(tcx, base_id);
2240 lookup_field_ty(tcx, base_id, fields.as_slice(), field, &(*substs))
2247 fcx.write_ty(expr.id, field_ty);
2248 fcx.write_autoderef_adjustment(base.id, autoderefs);
2254 let tps: Vec<ty::t> = tys.iter().map(|&ty| fcx.to_ty(ty)).collect();
2255 match method::lookup(fcx,
2262 CheckTraitsAndInherentMethods,
2263 AutoderefReceiver) {
2265 fcx.type_error_message(
2268 format!("attempted to take value of method `{}` on type `{}`",
2269 token::get_name(field), actual)
2273 tcx.sess.span_note(expr.span,
2274 "maybe a missing `()` to call it? If not, try an anonymous function.");
2278 fcx.type_error_message(
2281 format!("attempted access of field `{}` on type `{}`, \
2282 but no field with that name was found",
2283 token::get_name(field), actual)
2289 fcx.write_error(expr.id);
2292 fn check_struct_or_variant_fields(fcx: &FnCtxt,
2295 class_id: ast::DefId,
2296 node_id: ast::NodeId,
2297 substitutions: ty::substs,
2298 field_types: &[ty::field_ty],
2299 ast_fields: &[ast::Field],
2300 check_completeness: bool) {
2301 let tcx = fcx.ccx.tcx;
2303 let mut class_field_map = HashMap::new();
2304 let mut fields_found = 0;
2305 for field in field_types.iter() {
2306 class_field_map.insert(field.name, (field.id, false));
2309 let mut error_happened = false;
2311 // Typecheck each field.
2312 for field in ast_fields.iter() {
2313 let mut expected_field_type = ty::mk_err();
2315 let pair = class_field_map.find(&field.ident.node.name).map(|x| *x);
2318 fcx.type_error_message(
2321 format!("structure `{}` has no field named `{}`",
2322 actual, token::get_ident(field.ident.node))
2323 }, struct_ty, None);
2324 error_happened = true;
2326 Some((_, true)) => {
2329 format!("field `{}` specified more than once",
2330 token::get_ident(field.ident.node)));
2331 error_happened = true;
2333 Some((field_id, false)) => {
2334 expected_field_type =
2335 ty::lookup_field_type(
2336 tcx, class_id, field_id, &substitutions);
2337 class_field_map.insert(
2338 field.ident.node.name, (field_id, true));
2342 // Make sure to give a type to the field even if there's
2343 // an error, so we can continue typechecking
2344 check_expr_coercable_to_type(
2347 expected_field_type);
2351 fcx.write_error(node_id);
2354 if check_completeness && !error_happened {
2355 // Make sure the programmer specified all the fields.
2356 assert!(fields_found <= field_types.len());
2357 if fields_found < field_types.len() {
2358 let mut missing_fields = Vec::new();
2359 for class_field in field_types.iter() {
2360 let name = class_field.name;
2361 let (_, seen) = *class_field_map.get(&name);
2363 missing_fields.push(~"`" + token::get_name(name).get() + "`");
2367 tcx.sess.span_err(span,
2368 format!("missing {nfields, plural, =1{field} other{fields}}: {fields}",
2369 nfields = missing_fields.len(),
2370 fields = missing_fields.connect(", ")));
2374 if !error_happened {
2375 fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx,
2376 class_id, substitutions));
2380 fn check_struct_constructor(fcx: &FnCtxt,
2382 span: codemap::Span,
2383 class_id: ast::DefId,
2384 fields: &[ast::Field],
2385 base_expr: Option<@ast::Expr>) {
2386 let tcx = fcx.ccx.tcx;
2388 // Look up the number of type parameters and the raw type, and
2389 // determine whether the class is region-parameterized.
2390 let item_type = ty::lookup_item_type(tcx, class_id);
2391 let type_parameter_count = item_type.generics.type_param_defs().len();
2392 let region_param_defs = item_type.generics.region_param_defs();
2393 let raw_type = item_type.ty;
2395 // Generate the struct type.
2396 let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs);
2397 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2398 let substitutions = substs {
2399 regions: ty::NonerasedRegions(regions),
2401 tps: type_parameters
2404 let mut struct_type = ty::subst(tcx, &substitutions, raw_type);
2406 // Look up and check the fields.
2407 let class_fields = ty::lookup_struct_fields(tcx, class_id);
2408 check_struct_or_variant_fields(fcx,
2414 class_fields.as_slice(),
2416 base_expr.is_none());
2417 if ty::type_is_error(fcx.node_ty(id)) {
2418 struct_type = ty::mk_err();
2421 // Check the base expression if necessary.
2424 Some(base_expr) => {
2425 check_expr_has_type(fcx, base_expr, struct_type);
2426 if ty::type_is_bot(fcx.node_ty(base_expr.id)) {
2427 struct_type = ty::mk_bot();
2432 // Write in the resulting type.
2433 fcx.write_ty(id, struct_type);
2436 fn check_struct_enum_variant(fcx: &FnCtxt,
2438 span: codemap::Span,
2439 enum_id: ast::DefId,
2440 variant_id: ast::DefId,
2441 fields: &[ast::Field]) {
2442 let tcx = fcx.ccx.tcx;
2444 // Look up the number of type parameters and the raw type, and
2445 // determine whether the enum is region-parameterized.
2446 let item_type = ty::lookup_item_type(tcx, enum_id);
2447 let type_parameter_count = item_type.generics.type_param_defs().len();
2448 let region_param_defs = item_type.generics.region_param_defs();
2449 let raw_type = item_type.ty;
2451 // Generate the enum type.
2452 let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs);
2453 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2454 let substitutions = substs {
2455 regions: ty::NonerasedRegions(regions),
2457 tps: type_parameters
2460 let enum_type = ty::subst(tcx, &substitutions, raw_type);
2462 // Look up and check the enum variant fields.
2463 let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2464 check_struct_or_variant_fields(fcx,
2470 variant_fields.as_slice(),
2473 fcx.write_ty(id, enum_type);
2476 let tcx = fcx.ccx.tcx;
2479 ast::ExprVstore(ev, vst) => {
2480 let typ = match ev.node {
2481 ast::ExprLit(lit) if ast_util::lit_is_str(lit) => {
2482 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2485 ast::ExprVec(ref args, mutbl) => {
2486 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2487 let mut any_error = false;
2488 let mut any_bot = false;
2489 let mutability = match vst {
2490 ast::ExprVstoreMutSlice => ast::MutMutable,
2493 let t: ty::t = fcx.infcx().next_ty_var();
2494 for e in args.iter() {
2495 check_expr_has_type(fcx, *e, t);
2496 let arg_t = fcx.expr_ty(*e);
2497 if ty::type_is_error(arg_t) {
2500 else if ty::type_is_bot(arg_t) {
2509 ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2512 ast::ExprRepeat(element, count_expr, mutbl) => {
2513 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2514 let _ = ty::eval_repeat_count(fcx, count_expr);
2515 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2516 let mutability = match vst {
2517 ast::ExprVstoreMutSlice => ast::MutMutable,
2520 let t: ty::t = fcx.infcx().next_ty_var();
2521 check_expr_has_type(fcx, element, t);
2522 let arg_t = fcx.expr_ty(element);
2523 if ty::type_is_error(arg_t) {
2525 } else if ty::type_is_bot(arg_t) {
2528 ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2532 tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence")
2534 fcx.write_ty(ev.id, typ);
2535 fcx.write_ty(id, typ);
2538 ast::ExprBox(place, subexpr) => {
2539 check_expr(fcx, place);
2540 check_expr(fcx, subexpr);
2542 let mut checked = false;
2544 ast::ExprPath(ref path) => {
2545 // FIXME(pcwalton): For now we hardcode the two permissible
2546 // places: the exchange heap and the managed heap.
2547 let definition = lookup_def(fcx, path.span, place.id);
2548 let def_id = ast_util::def_id_of_def(definition);
2549 match tcx.lang_items
2551 .get(ExchangeHeapLangItem as uint) {
2552 &Some(item_def_id) if def_id == item_def_id => {
2553 fcx.write_ty(id, ty::mk_uniq(tcx,
2554 fcx.expr_ty(subexpr)));
2557 &Some(_) | &None => {}
2560 match tcx.lang_items
2562 .get(ManagedHeapLangItem as uint) {
2563 &Some(item_def_id) if def_id == item_def_id => {
2564 // Assign the magic `Gc<T>` struct.
2566 match tcx.lang_items
2567 .require(GcLangItem) {
2570 tcx.sess.span_err(expr.span, msg);
2572 krate: ast::CRATE_NODE_ID,
2573 node: ast::DUMMY_NODE_ID,
2578 ty::NonerasedRegions(OwnedSlice::empty());
2579 let sty = ty::mk_struct(tcx,
2589 fcx.write_ty(id, sty);
2592 &Some(_) | &None => {}
2600 tcx.sess.span_err(expr.span,
2601 "only the managed heap and exchange heap are \
2602 currently supported")
2606 ast::ExprLit(lit) => {
2607 let typ = check_lit(fcx, lit);
2608 fcx.write_ty(id, typ);
2610 ast::ExprBinary(op, lhs, rhs) => {
2611 check_binop(fcx, expr, op, lhs, rhs, SimpleBinop);
2613 let lhs_ty = fcx.expr_ty(lhs);
2614 let rhs_ty = fcx.expr_ty(rhs);
2615 if ty::type_is_error(lhs_ty) ||
2616 ty::type_is_error(rhs_ty) {
2617 fcx.write_error(id);
2619 else if ty::type_is_bot(lhs_ty) ||
2620 (ty::type_is_bot(rhs_ty) && !ast_util::lazy_binop(op)) {
2624 ast::ExprAssignOp(op, lhs, rhs) => {
2625 check_binop(fcx, expr, op, lhs, rhs, BinopAssignment);
2627 let lhs_t = fcx.expr_ty(lhs);
2628 let result_t = fcx.expr_ty(expr);
2629 demand::suptype(fcx, expr.span, result_t, lhs_t);
2631 let tcx = fcx.tcx();
2632 if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
2633 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2636 // Overwrite result of check_binop...this preserves existing behavior
2637 // but seems quite dubious with regard to user-defined methods
2638 // and so forth. - Niko
2639 if !ty::type_is_error(result_t)
2640 && !ty::type_is_bot(result_t) {
2641 fcx.write_nil(expr.id);
2644 ast::ExprUnary(unop, oprnd) => {
2645 let exp_inner = unpack_expected(fcx, expected, |sty| {
2647 ast::UnBox | ast::UnUniq => match *sty {
2648 ty::ty_box(ty) | ty::ty_uniq(ty) => Some(ty),
2651 ast::UnNot | ast::UnNeg => expected,
2652 ast::UnDeref => None
2655 let lvalue_pref = match unop {
2656 ast::UnDeref => lvalue_pref,
2659 check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, exp_inner, lvalue_pref);
2660 let mut oprnd_t = fcx.expr_ty(oprnd);
2661 if !ty::type_is_error(oprnd_t) && !ty::type_is_bot(oprnd_t) {
2664 oprnd_t = ty::mk_box(tcx, oprnd_t)
2667 oprnd_t = ty::mk_uniq(tcx, oprnd_t);
2670 oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
2671 oprnd_t = match ty::deref(oprnd_t, true) {
2673 None => match try_overloaded_deref(fcx, expr.span,
2674 Some(MethodCall::expr(expr.id)),
2675 Some(&*oprnd), oprnd_t, lvalue_pref) {
2678 let is_newtype = match ty::get(oprnd_t).sty {
2679 ty::ty_struct(did, ref substs) => {
2680 let fields = ty::struct_fields(fcx.tcx(), did, substs);
2682 && fields.get(0).ident ==
2683 token::special_idents::unnamed_field
2688 // This is an obsolete struct deref
2689 tcx.sess.span_err(expr.span,
2690 "single-field tuple-structs can \
2691 no longer be dereferenced");
2693 fcx.type_error_message(expr.span, |actual| {
2694 format!("type `{}` cannot be dereferenced", actual)
2703 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2705 if !(ty::type_is_integral(oprnd_t) ||
2706 ty::get(oprnd_t).sty == ty::ty_bool) {
2707 oprnd_t = check_user_unop(fcx, "!", "not",
2708 tcx.lang_items.not_trait(),
2709 expr, oprnd, oprnd_t);
2713 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2715 if !(ty::type_is_integral(oprnd_t) ||
2716 ty::type_is_fp(oprnd_t)) {
2717 oprnd_t = check_user_unop(fcx, "-", "neg",
2718 tcx.lang_items.neg_trait(),
2719 expr, oprnd, oprnd_t);
2724 fcx.write_ty(id, oprnd_t);
2726 ast::ExprAddrOf(mutbl, oprnd) => {
2727 let hint = unpack_expected(
2729 |sty| match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty),
2731 let lvalue_pref = match mutbl {
2732 ast::MutMutable => PreferMutLvalue,
2733 ast::MutImmutable => NoPreference
2735 check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, hint, lvalue_pref);
2737 // Note: at this point, we cannot say what the best lifetime
2738 // is to use for resulting pointer. We want to use the
2739 // shortest lifetime possible so as to avoid spurious borrowck
2740 // errors. Moreover, the longest lifetime will depend on the
2741 // precise details of the value whose address is being taken
2742 // (and how long it is valid), which we don't know yet until type
2743 // inference is complete.
2745 // Therefore, here we simply generate a region variable. The
2746 // region inferencer will then select the ultimate value.
2747 // Finally, borrowck is charged with guaranteeing that the
2748 // value whose address was taken can actually be made to live
2749 // as long as it needs to live.
2750 let region = fcx.infcx().next_region_var(
2751 infer::AddrOfRegion(expr.span));
2753 let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
2754 let oprnd_t = if ty::type_is_error(tm.ty) {
2756 } else if ty::type_is_bot(tm.ty) {
2760 ty::mk_rptr(tcx, region, tm)
2762 fcx.write_ty(id, oprnd_t);
2764 ast::ExprPath(ref pth) => {
2765 let defn = lookup_def(fcx, pth.span, id);
2767 check_type_parameter_positions_in_path(fcx, pth, defn);
2768 let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2769 instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
2771 ast::ExprInlineAsm(ref ia) => {
2772 for &(_, input) in ia.inputs.iter() {
2773 check_expr(fcx, input);
2775 for &(_, out) in ia.outputs.iter() {
2776 check_expr(fcx, out);
2780 ast::ExprMac(_) => tcx.sess.bug("unexpanded macro"),
2781 ast::ExprBreak(_) => { fcx.write_bot(id); }
2782 ast::ExprAgain(_) => { fcx.write_bot(id); }
2783 ast::ExprRet(expr_opt) => {
2784 let ret_ty = fcx.ret_ty;
2786 None => match fcx.mk_eqty(false, infer::Misc(expr.span),
2787 ret_ty, ty::mk_nil()) {
2788 result::Ok(_) => { /* fall through */ }
2792 "`return;` in function returning non-nil");
2796 check_expr_has_type(fcx, e, ret_ty);
2801 ast::ExprParen(a) => {
2802 check_expr_with_opt_hint_and_lvalue_pref(fcx, a, expected, lvalue_pref);
2803 fcx.write_ty(id, fcx.expr_ty(a));
2805 ast::ExprAssign(lhs, rhs) => {
2806 check_expr_with_lvalue_pref(fcx, lhs, PreferMutLvalue);
2808 let tcx = fcx.tcx();
2809 if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
2810 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2813 let lhs_ty = fcx.expr_ty(lhs);
2814 check_expr_has_type(fcx, rhs, lhs_ty);
2815 let rhs_ty = fcx.expr_ty(rhs);
2817 if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
2818 fcx.write_error(id);
2819 } else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
2825 ast::ExprIf(cond, then_blk, opt_else_expr) => {
2826 check_then_else(fcx, cond, then_blk, opt_else_expr,
2827 id, expr.span, expected);
2829 ast::ExprWhile(cond, body) => {
2830 check_expr_has_type(fcx, cond, ty::mk_bool());
2831 check_block_no_value(fcx, body);
2832 let cond_ty = fcx.expr_ty(cond);
2833 let body_ty = fcx.node_ty(body.id);
2834 if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) {
2835 fcx.write_error(id);
2837 else if ty::type_is_bot(cond_ty) {
2844 ast::ExprForLoop(..) =>
2845 fail!("non-desugared expr_for_loop"),
2846 ast::ExprLoop(body, _) => {
2847 check_block_no_value(fcx, (body));
2848 if !may_break(tcx, expr.id, body) {
2855 ast::ExprMatch(discrim, ref arms) => {
2856 _match::check_match(fcx, expr, discrim, arms.as_slice());
2858 ast::ExprFnBlock(decl, body) => {
2861 Some(ast::BorrowedSigil),
2867 ast::ExprProc(decl, body) => {
2870 Some(ast::OwnedSigil),
2876 ast::ExprBlock(b) => {
2877 check_block_with_expected(fcx, b, expected);
2878 fcx.write_ty(id, fcx.node_ty(b.id));
2880 ast::ExprCall(f, ref args) => {
2881 check_call(fcx, expr, f, args.as_slice());
2882 let f_ty = fcx.expr_ty(f);
2883 let (args_bot, args_err) = args.iter().fold((false, false),
2884 |(rest_bot, rest_err), a| {
2885 // is this not working?
2886 let a_ty = fcx.expr_ty(*a);
2887 (rest_bot || ty::type_is_bot(a_ty),
2888 rest_err || ty::type_is_error(a_ty))});
2889 if ty::type_is_error(f_ty) || args_err {
2890 fcx.write_error(id);
2892 else if ty::type_is_bot(f_ty) || args_bot {
2896 ast::ExprMethodCall(ident, ref tps, ref args) => {
2897 check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice());
2898 let mut arg_tys = args.iter().map(|a| fcx.expr_ty(*a));
2899 let (args_bot, args_err) = arg_tys.fold((false, false),
2900 |(rest_bot, rest_err), a| {
2901 (rest_bot || ty::type_is_bot(a),
2902 rest_err || ty::type_is_error(a))});
2904 fcx.write_error(id);
2905 } else if args_bot {
2909 ast::ExprCast(e, t) => {
2911 let t_1 = fcx.to_ty(t);
2912 let t_e = fcx.expr_ty(e);
2914 debug!("t_1={}", fcx.infcx().ty_to_str(t_1));
2915 debug!("t_e={}", fcx.infcx().ty_to_str(t_e));
2917 if ty::type_is_error(t_e) {
2918 fcx.write_error(id);
2920 else if ty::type_is_bot(t_e) {
2924 match ty::get(t_1).sty {
2925 // This will be looked up later on
2926 ty::ty_trait(..) => (),
2929 if ty::type_is_nil(t_e) {
2930 fcx.type_error_message(expr.span, |actual| {
2931 format!("cast from nil: `{}` as `{}`", actual,
2932 fcx.infcx().ty_to_str(t_1))
2934 } else if ty::type_is_nil(t_1) {
2935 fcx.type_error_message(expr.span, |actual| {
2936 format!("cast to nil: `{}` as `{}`", actual,
2937 fcx.infcx().ty_to_str(t_1))
2941 let t1 = structurally_resolved_type(fcx, e.span, t_1);
2942 let te = structurally_resolved_type(fcx, e.span, t_e);
2943 let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
2944 let t_1_is_char = type_is_char(fcx, expr.span, t_1);
2945 let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1);
2947 // casts to scalars other than `char` and `bare fn` are trivial
2948 let t_1_is_trivial = t_1_is_scalar &&
2949 !t_1_is_char && !t_1_is_bare_fn;
2951 if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial {
2952 // casts from C-like enums are allowed
2953 } else if t_1_is_char {
2954 let te = fcx.infcx().resolve_type_vars_if_possible(te);
2955 if ty::get(te).sty != ty::ty_uint(ast::TyU8) {
2956 fcx.type_error_message(expr.span, |actual| {
2957 format!("only `u8` can be cast as `char`, not `{}`", actual)
2960 } else if ty::get(t1).sty == ty::ty_bool {
2961 fcx.tcx().sess.span_err(expr.span,
2962 "cannot cast as `bool`, compare with zero instead");
2963 } else if type_is_region_ptr(fcx, expr.span, t_e) &&
2964 type_is_unsafe_ptr(fcx, expr.span, t_1) {
2966 fn is_vec(t: ty::t) -> bool {
2967 match ty::get(t).sty {
2968 ty::ty_vec(..) => true,
2972 fn types_compatible(fcx: &FnCtxt, sp: Span,
2973 t1: ty::t, t2: ty::t) -> bool {
2977 let el = ty::sequence_element_type(fcx.tcx(),
2979 infer::mk_eqty(fcx.infcx(), false,
2980 infer::Misc(sp), el, t2).is_ok()
2984 // Due to the limitations of LLVM global constants,
2985 // region pointers end up pointing at copies of
2986 // vector elements instead of the original values.
2987 // To allow unsafe pointers to work correctly, we
2988 // need to special-case obtaining an unsafe pointer
2989 // from a region pointer to a vector.
2991 /* this cast is only allowed from &[T] to *T or
2993 match (&ty::get(te).sty, &ty::get(t_1).sty) {
2994 (&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
2995 if types_compatible(fcx, e.span,
2996 mt1.ty, mt2.ty) => {
2997 /* this case is allowed */
3000 demand::coerce(fcx, e.span, t_1, e);
3003 } else if !(type_is_scalar(fcx,expr.span,t_e)
3004 && t_1_is_trivial) {
3006 If more type combinations should be supported than are
3007 supported here, then file an enhancement issue and
3008 record the issue number in this comment.
3010 fcx.type_error_message(expr.span, |actual| {
3011 format!("non-scalar cast: `{}` as `{}`", actual,
3012 fcx.infcx().ty_to_str(t_1))
3017 fcx.write_ty(id, t_1);
3020 ast::ExprVec(ref args, mutbl) => {
3021 let t: ty::t = fcx.infcx().next_ty_var();
3022 for e in args.iter() {
3023 check_expr_has_type(fcx, *e, t);
3025 let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutbl},
3026 ty::vstore_fixed(args.len()));
3027 fcx.write_ty(id, typ);
3029 ast::ExprRepeat(element, count_expr, mutbl) => {
3030 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
3031 let count = ty::eval_repeat_count(fcx, count_expr);
3032 let t: ty::t = fcx.infcx().next_ty_var();
3033 check_expr_has_type(fcx, element, t);
3034 let element_ty = fcx.expr_ty(element);
3035 if ty::type_is_error(element_ty) {
3036 fcx.write_error(id);
3038 else if ty::type_is_bot(element_ty) {
3042 let t = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutbl},
3043 ty::vstore_fixed(count));
3044 fcx.write_ty(id, t);
3047 ast::ExprTup(ref elts) => {
3048 let flds = unpack_expected(fcx, expected, |sty| {
3050 ty::ty_tup(ref flds) => Some((*flds).clone()),
3054 let mut bot_field = false;
3055 let mut err_field = false;
3057 let elt_ts = elts.iter().enumerate().map(|(i, e)| {
3058 let opt_hint = match flds {
3059 Some(ref fs) if i < fs.len() => Some(*fs.get(i)),
3062 check_expr_with_opt_hint(fcx, *e, opt_hint);
3063 let t = fcx.expr_ty(*e);
3064 err_field = err_field || ty::type_is_error(t);
3065 bot_field = bot_field || ty::type_is_bot(t);
3070 } else if err_field {
3071 fcx.write_error(id);
3073 let typ = ty::mk_tup(tcx, elt_ts);
3074 fcx.write_ty(id, typ);
3077 ast::ExprStruct(ref path, ref fields, base_expr) => {
3078 // Resolve the path.
3079 match tcx.def_map.borrow().find(&id) {
3080 Some(&ast::DefStruct(type_def_id)) => {
3081 check_struct_constructor(fcx, id, expr.span, type_def_id,
3082 fields.as_slice(), base_expr);
3084 Some(&ast::DefVariant(enum_id, variant_id, _)) => {
3085 check_struct_enum_variant(fcx, id, expr.span, enum_id,
3086 variant_id, fields.as_slice());
3089 tcx.sess.span_bug(path.span,
3090 "structure constructor does not name a structure type");
3094 ast::ExprField(base, field, ref tys) => {
3095 check_field(fcx, expr, lvalue_pref, base, field.name, tys.as_slice());
3097 ast::ExprIndex(base, idx) => {
3098 check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
3099 check_expr(fcx, idx);
3100 let raw_base_t = fcx.expr_ty(base);
3101 let idx_t = fcx.expr_ty(idx);
3102 if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
3103 fcx.write_ty(id, raw_base_t);
3104 } else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
3105 fcx.write_ty(id, idx_t);
3107 let (base_t, autoderefs, field_ty) =
3108 autoderef(fcx, expr.span, raw_base_t, Some(base.id),
3109 lvalue_pref, |base_t, _| ty::index(base_t));
3112 check_expr_has_type(fcx, idx, ty::mk_uint());
3113 fcx.write_ty(id, mt.ty);
3114 fcx.write_autoderef_adjustment(base.id, autoderefs);
3117 let resolved = structurally_resolved_type(fcx,
3120 let ret_ty = lookup_op_method(fcx,
3123 token::intern("index"),
3124 tcx.lang_items.index_trait(),
3128 fcx.type_error_message(expr.span,
3130 format!("cannot index a value \
3137 fcx.write_ty(id, ret_ty);
3144 debug!("type of expr({}) {} is...", expr.id,
3145 syntax::print::pprust::expr_to_str(expr));
3146 debug!("... {}, expected is {}",
3147 ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
3149 Some(t) => ppaux::ty_to_str(tcx, t),
3156 pub fn require_uint(fcx: &FnCtxt, sp: Span, t: ty::t) {
3157 if !type_is_uint(fcx, sp, t) {
3158 fcx.type_error_message(sp, |actual| {
3159 format!("mismatched types: expected `uint` type but found `{}`",
3165 pub fn require_integral(fcx: &FnCtxt, sp: Span, t: ty::t) {
3166 if !type_is_integral(fcx, sp, t) {
3167 fcx.type_error_message(sp, |actual| {
3168 format!("mismatched types: expected integral type but found `{}`",
3174 pub fn check_decl_initializer(fcx: &FnCtxt,
3178 let local_ty = fcx.local_ty(init.span, nid);
3179 check_expr_coercable_to_type(fcx, init, local_ty)
3182 pub fn check_decl_local(fcx: &FnCtxt, local: &ast::Local) {
3183 let tcx = fcx.ccx.tcx;
3185 let t = fcx.local_ty(local.span, local.id);
3186 fcx.write_ty(local.id, t);
3190 check_decl_initializer(fcx, local.id, init);
3191 let init_ty = fcx.expr_ty(init);
3192 if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
3193 fcx.write_ty(local.id, init_ty);
3199 let pcx = pat_ctxt {
3201 map: pat_id_map(tcx.def_map, local.pat),
3203 _match::check_pat(&pcx, local.pat, t);
3204 let pat_ty = fcx.node_ty(local.pat.id);
3205 if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
3206 fcx.write_ty(local.id, pat_ty);
3210 pub fn check_stmt(fcx: &FnCtxt, stmt: &ast::Stmt) {
3212 let mut saw_bot = false;
3213 let mut saw_err = false;
3215 ast::StmtDecl(decl, id) => {
3218 ast::DeclLocal(ref l) => {
3219 check_decl_local(fcx, *l);
3220 let l_t = fcx.node_ty(l.id);
3221 saw_bot = saw_bot || ty::type_is_bot(l_t);
3222 saw_err = saw_err || ty::type_is_error(l_t);
3224 ast::DeclItem(_) => {/* ignore for now */ }
3227 ast::StmtExpr(expr, id) => {
3229 // Check with expected type of ()
3230 check_expr_has_type(fcx, expr, ty::mk_nil());
3231 let expr_ty = fcx.expr_ty(expr);
3232 saw_bot = saw_bot || ty::type_is_bot(expr_ty);
3233 saw_err = saw_err || ty::type_is_error(expr_ty);
3235 ast::StmtSemi(expr, id) => {
3237 check_expr(fcx, expr);
3238 let expr_ty = fcx.expr_ty(expr);
3239 saw_bot |= ty::type_is_bot(expr_ty);
3240 saw_err |= ty::type_is_error(expr_ty);
3242 ast::StmtMac(..) => fcx.ccx.tcx.sess.bug("unexpanded macro")
3245 fcx.write_bot(node_id);
3248 fcx.write_error(node_id);
3251 fcx.write_nil(node_id)
3255 pub fn check_block_no_value(fcx: &FnCtxt, blk: &ast::Block) {
3256 check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
3257 let blkty = fcx.node_ty(blk.id);
3258 if ty::type_is_error(blkty) {
3259 fcx.write_error(blk.id);
3261 else if ty::type_is_bot(blkty) {
3262 fcx.write_bot(blk.id);
3265 let nilty = ty::mk_nil();
3266 demand::suptype(fcx, blk.span, nilty, blkty);
3270 pub fn check_block_with_expected(fcx: &FnCtxt,
3272 expected: Option<ty::t>) {
3274 let mut fcx_ps = fcx.ps.borrow_mut();
3275 let purity_state = fcx_ps.recurse(blk);
3276 replace(&mut *fcx_ps, purity_state)
3279 fcx.with_region_lb(blk.id, || {
3280 let mut warned = false;
3281 let mut last_was_bot = false;
3282 let mut any_bot = false;
3283 let mut any_err = false;
3284 for s in blk.stmts.iter() {
3285 check_stmt(fcx, *s);
3286 let s_id = ast_util::stmt_id(*s);
3287 let s_ty = fcx.node_ty(s_id);
3288 if last_was_bot && !warned && match s.node {
3289 ast::StmtDecl(decl, _) => {
3291 ast::DeclLocal(_) => true,
3295 ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true,
3298 fcx.ccx.tcx.sess.add_lint(UnreachableCode, s_id, s.span,
3299 ~"unreachable statement");
3302 if ty::type_is_bot(s_ty) {
3303 last_was_bot = true;
3305 any_bot = any_bot || ty::type_is_bot(s_ty);
3306 any_err = any_err || ty::type_is_error(s_ty);
3309 None => if any_err {
3310 fcx.write_error(blk.id);
3313 fcx.write_bot(blk.id);
3316 fcx.write_nil(blk.id);
3319 if any_bot && !warned {
3320 fcx.ccx.tcx.sess.add_lint(UnreachableCode, e.id, e.span,
3321 ~"unreachable expression");
3323 check_expr_with_opt_hint(fcx, e, expected);
3324 let ety = fcx.expr_ty(e);
3325 fcx.write_ty(blk.id, ety);
3327 fcx.write_error(blk.id);
3330 fcx.write_bot(blk.id);
3336 *fcx.ps.borrow_mut() = prev;
3339 pub fn check_const(ccx: &CrateCtxt,
3343 let inh = blank_inherited_fields(ccx);
3344 let rty = ty::node_id_to_type(ccx.tcx, id);
3345 let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
3346 let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty;
3347 check_const_with_ty(&fcx, sp, e, declty);
3350 pub fn check_const_with_ty(fcx: &FnCtxt,
3355 let cty = fcx.expr_ty(e);
3356 demand::suptype(fcx, e.span, declty, cty);
3357 regionck::regionck_expr(fcx, e);
3358 writeback::resolve_type_vars_in_expr(fcx, e);
3361 /// Checks whether a type can be represented in memory. In particular, it
3362 /// identifies types that contain themselves without indirection through a
3363 /// pointer, which would mean their size is unbounded. This is different from
3364 /// the question of whether a type can be instantiated. See the definition of
3365 /// `check_instantiable`.
3366 pub fn check_representable(tcx: &ty::ctxt,
3368 item_id: ast::NodeId,
3369 designation: &str) {
3370 let rty = ty::node_id_to_type(tcx, item_id);
3372 // Check that it is possible to represent this type. This call identifies
3373 // (1) types that contain themselves and (2) types that contain a different
3374 // recursive type. It is only necessary to throw an error on those that
3375 // contain themselves. For case 2, there must be an inner type that will be
3376 // caught by case 1.
3377 match ty::is_type_representable(tcx, rty) {
3378 ty::SelfRecursive => {
3380 sp, format!("illegal recursive {} type; \
3381 wrap the inner value in a box to make it representable",
3384 ty::Representable | ty::ContainsRecursive => (),
3388 /// Checks whether a type can be created without an instance of itself.
3389 /// This is similar but different from the question of whether a type
3390 /// can be represented. For example, the following type:
3392 /// enum foo { None, Some(foo) }
3394 /// is instantiable but is not representable. Similarly, the type
3396 /// enum foo { Some(@foo) }
3398 /// is representable, but not instantiable.
3399 pub fn check_instantiable(tcx: &ty::ctxt,
3401 item_id: ast::NodeId) {
3402 let item_ty = ty::node_id_to_type(tcx, item_id);
3403 if !ty::is_instantiable(tcx, item_ty) {
3404 tcx.sess.span_err(sp, format!("this type cannot be instantiated \
3405 without an instance of itself; \
3406 consider using `Option<{}>`",
3407 ppaux::ty_to_str(tcx, item_ty)));
3411 pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
3412 let t = ty::node_id_to_type(tcx, id);
3413 if ty::type_needs_subst(t) {
3414 tcx.sess.span_err(sp, "SIMD vector cannot be generic");
3417 match ty::get(t).sty {
3418 ty::ty_struct(did, ref substs) => {
3419 let fields = ty::lookup_struct_fields(tcx, did);
3420 if fields.is_empty() {
3421 tcx.sess.span_err(sp, "SIMD vector cannot be empty");
3424 let e = ty::lookup_field_type(tcx, did, fields.get(0).id, substs);
3425 if !fields.iter().all(
3426 |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
3427 tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
3430 if !ty::type_is_machine(e) {
3431 tcx.sess.span_err(sp, "SIMD vector element type should be \
3440 pub fn check_enum_variants(ccx: &CrateCtxt,
3442 vs: &[ast::P<ast::Variant>],
3445 fn disr_in_range(ccx: &CrateCtxt,
3447 disr: ty::Disr) -> bool {
3448 fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
3450 ast::TyU8 => disr as u8 as Disr == disr,
3451 ast::TyU16 => disr as u16 as Disr == disr,
3452 ast::TyU32 => disr as u32 as Disr == disr,
3453 ast::TyU64 => disr as u64 as Disr == disr,
3454 ast::TyU => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
3457 fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
3459 ast::TyI8 => disr as i8 as Disr == disr,
3460 ast::TyI16 => disr as i16 as Disr == disr,
3461 ast::TyI32 => disr as i32 as Disr == disr,
3462 ast::TyI64 => disr as i64 as Disr == disr,
3463 ast::TyI => int_in_range(ccx, ccx.tcx.sess.targ_cfg.int_type, disr)
3467 attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
3468 attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
3472 fn do_check(ccx: &CrateCtxt,
3473 vs: &[ast::P<ast::Variant>],
3475 hint: attr::ReprAttr)
3476 -> Vec<@ty::VariantInfo> {
3478 let rty = ty::node_id_to_type(ccx.tcx, id);
3479 let mut variants: Vec<@ty::VariantInfo> = Vec::new();
3480 let mut disr_vals: Vec<ty::Disr> = Vec::new();
3481 let mut prev_disr_val: Option<ty::Disr> = None;
3483 for &v in vs.iter() {
3485 // If the discriminant value is specified explicitly in the enum check whether the
3486 // initialization expression is valid, otherwise use the last value plus one.
3487 let mut current_disr_val = match prev_disr_val {
3488 Some(prev_disr_val) => prev_disr_val + 1,
3489 None => ty::INITIAL_DISCRIMINANT_VALUE
3492 match v.node.disr_expr {
3494 debug!("disr expr, checking {}", pprust::expr_to_str(e));
3496 let inh = blank_inherited_fields(ccx);
3497 let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
3498 let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
3499 check_const_with_ty(&fcx, e.span, e, declty);
3500 // check_expr (from check_const pass) doesn't guarantee
3501 // that the expression is in an form that eval_const_expr can
3502 // handle, so we may still get an internal compiler error
3504 match const_eval::eval_const_expr_partial(ccx.tcx, e) {
3505 Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
3506 Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
3508 ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
3511 ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", *err));
3518 // Check for duplicate discriminant values
3519 if disr_vals.contains(¤t_disr_val) {
3520 ccx.tcx.sess.span_err(v.span, "discriminant value already exists");
3522 // Check for unrepresentable discriminant values
3524 attr::ReprAny | attr::ReprExtern => (),
3525 attr::ReprInt(sp, ity) => {
3526 if !disr_in_range(ccx, ity, current_disr_val) {
3527 ccx.tcx.sess.span_err(v.span,
3528 "discriminant value outside specified type");
3529 ccx.tcx.sess.span_note(sp, "discriminant type specified here");
3533 disr_vals.push(current_disr_val);
3535 let variant_info = @VariantInfo::from_ast_variant(ccx.tcx, v, current_disr_val);
3536 prev_disr_val = Some(current_disr_val);
3538 variants.push(variant_info);
3544 let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id });
3545 if hint != attr::ReprAny && vs.len() <= 1 {
3546 let msg = if vs.len() == 1 {
3547 "unsupported representation for univariant enum"
3549 "unsupported representation for zero-variant enum"
3551 ccx.tcx.sess.span_err(sp, msg)
3554 let variants = do_check(ccx, vs, id, hint);
3556 // cache so that ty::enum_variants won't repeat this work
3557 ccx.tcx.enum_var_cache.borrow_mut().insert(local_def(id), @variants);
3559 // Check that it is possible to represent this enum.
3560 check_representable(ccx.tcx, sp, id, "enum");
3562 // Check that it is possible to instantiate this enum:
3564 // This *sounds* like the same that as representable, but it's
3565 // not. See def'n of `check_instantiable()` for details.
3566 check_instantiable(ccx.tcx, sp, id);
3569 pub fn lookup_def(fcx: &FnCtxt, sp: Span, id: ast::NodeId) -> ast::Def {
3570 lookup_def_ccx(fcx.ccx, sp, id)
3573 // Returns the type parameter count and the type for the given definition.
3574 pub fn ty_param_bounds_and_ty_for_def(fcx: &FnCtxt,
3577 -> ty_param_bounds_and_ty {
3579 ast::DefArg(nid, _) | ast::DefLocal(nid, _) |
3580 ast::DefBinding(nid, _) => {
3581 let typ = fcx.local_ty(sp, nid);
3582 return no_params(typ);
3584 ast::DefFn(id, _) | ast::DefStaticMethod(id, _, _) |
3585 ast::DefStatic(id, _) | ast::DefVariant(_, id, _) |
3586 ast::DefStruct(id) => {
3587 return ty::lookup_item_type(fcx.ccx.tcx, id);
3589 ast::DefUpvar(_, inner, _, _) => {
3590 return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
3595 ast::DefTyParam(..)=> {
3596 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type");
3598 ast::DefMod(..) | ast::DefForeignMod(..) => {
3599 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module");
3601 ast::DefUse(..) => {
3602 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use");
3604 ast::DefRegion(..) => {
3605 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region");
3607 ast::DefTyParamBinder(..) => {
3608 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter");
3610 ast::DefLabel(..) => {
3611 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label");
3613 ast::DefSelfTy(..) => {
3614 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty");
3616 ast::DefMethod(..) => {
3617 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method");
3622 // Instantiates the given path, which must refer to an item with the given
3623 // number of type parameters and type.
3624 pub fn instantiate_path(fcx: &FnCtxt,
3626 tpt: ty_param_bounds_and_ty,
3629 node_id: ast::NodeId) {
3630 debug!(">>> instantiate_path");
3632 let ty_param_count = tpt.generics.type_param_defs().len();
3633 let ty_param_req = tpt.generics.type_param_defs().iter()
3634 .take_while(|x| x.default.is_none())
3636 let mut ty_substs_len = 0;
3637 for segment in pth.segments.iter() {
3638 ty_substs_len += segment.types.len()
3641 debug!("tpt={} ty_param_count={:?} ty_substs_len={:?}",
3642 tpt.repr(fcx.tcx()),
3646 // determine the region parameters, using the value given by the user
3647 // (if any) and otherwise using a fresh region variable
3648 let num_expected_regions = tpt.generics.region_param_defs().len();
3649 let num_supplied_regions = pth.segments.last().unwrap().lifetimes.len();
3650 let regions = if num_expected_regions == num_supplied_regions {
3651 OwnedSlice::from_vec(pth.segments.last().unwrap().lifetimes.iter().map(
3652 |l| ast_region_to_region(fcx.tcx(), l)).collect())
3654 if num_supplied_regions != 0 {
3655 fcx.ccx.tcx.sess.span_err(
3657 format!("expected {nexpected, plural, =1{# lifetime parameter} \
3658 other{# lifetime parameters}}, \
3659 found {nsupplied, plural, =1{# lifetime parameter} \
3660 other{# lifetime parameters}}",
3661 nexpected = num_expected_regions,
3662 nsupplied = num_supplied_regions));
3665 fcx.infcx().region_vars_for_defs(span, tpt.generics.region_param_defs.as_slice())
3667 let regions = ty::NonerasedRegions(regions);
3669 // Special case: If there is a self parameter, omit it from the list of
3672 // Here we calculate the "user type parameter count", which is the number
3673 // of type parameters actually manifest in the AST. This will differ from
3674 // the internal type parameter count when there are self types involved.
3675 let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def {
3676 ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
3677 let generics = generics_of_static_method_container(fcx.ccx.tcx,
3679 (ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs().len()))
3681 _ => (ty_param_count, ty_param_req, None),
3684 // determine values for type parameters, using the values given by
3685 // the user (if any) and otherwise using fresh type variables
3686 let (tps, regions) = if ty_substs_len == 0 {
3687 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3688 } else if ty_param_count == 0 {
3689 fcx.ccx.tcx.sess.span_err
3690 (span, "this item does not take type parameters");
3691 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3692 } else if ty_substs_len > user_ty_param_count {
3693 let expected = if user_ty_param_req < user_ty_param_count {
3698 fcx.ccx.tcx.sess.span_err
3700 format!("too many type parameters provided: {} {}, found {}",
3701 expected, user_ty_param_count, ty_substs_len));
3702 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3703 } else if ty_substs_len < user_ty_param_req {
3704 let expected = if user_ty_param_req < user_ty_param_count {
3709 fcx.ccx.tcx.sess.span_err
3711 format!("not enough type parameters provided: {} {}, found {}",
3712 expected, user_ty_param_req, ty_substs_len));
3713 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3715 if ty_substs_len > user_ty_param_req
3716 && !fcx.tcx().sess.features.default_type_params.get() {
3717 fcx.tcx().sess.span_err(pth.span, "default type parameters are \
3718 experimental and possibly buggy");
3719 fcx.tcx().sess.span_note(pth.span, "add #[feature(default_type_params)] \
3720 to the crate attributes to enable");
3723 // Build up the list of type parameters, inserting the self parameter
3724 // at the appropriate position.
3725 let mut tps = Vec::new();
3726 let mut pushed = false;
3727 for (i, ty) in pth.segments.iter()
3728 .flat_map(|segment| segment.types.iter())
3729 .map(|&ast_type| fcx.to_ty(ast_type))
3731 match self_parameter_index {
3732 Some(index) if index == i => {
3733 tps.push(*fcx.infcx().next_ty_vars(1).get(0));
3741 let mut substs = substs {
3747 let defaults = tpt.generics.type_param_defs().iter()
3748 .enumerate().filter_map(|(i, x)| {
3749 match self_parameter_index {
3750 Some(index) if index == i => None,
3751 _ => Some(x.default)
3754 for (i, default) in defaults.skip(ty_substs_len).enumerate() {
3755 match self_parameter_index {
3756 Some(index) if index == i + ty_substs_len => {
3757 substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0));
3764 let ty = default.subst_spanned(fcx.tcx(), &substs, Some(span));
3765 substs.tps.push(ty);
3768 fcx.tcx().sess.span_bug(span,
3769 "missing default for a not explicitely provided type param")
3774 // If the self parameter goes at the end, insert it there.
3775 if !pushed && self_parameter_index.is_some() {
3776 substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0))
3779 assert_eq!(substs.tps.len(), ty_param_count)
3781 let substs {tps, regions, ..} = substs;
3785 fcx.write_ty_substs(node_id, tpt.ty, substs {
3794 // Resolves `typ` by a single level if `typ` is a type variable. If no
3795 // resolution is possible, then an error is reported.
3796 pub fn structurally_resolved_type(fcx: &FnCtxt, sp: Span, tp: ty::t) -> ty::t {
3797 match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
3798 Ok(t_s) if !ty::type_is_ty_var(t_s) => t_s,
3800 fcx.type_error_message(sp, |_actual| {
3801 ~"the type of this value must be known in this context"
3803 demand::suptype(fcx, sp, ty::mk_err(), tp);
3809 // Returns the one-level-deep structure of the given type.
3810 pub fn structure_of<'a>(fcx: &FnCtxt, sp: Span, typ: ty::t)
3812 &ty::get(structurally_resolved_type(fcx, sp, typ)).sty
3815 pub fn type_is_integral(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3816 let typ_s = structurally_resolved_type(fcx, sp, typ);
3817 return ty::type_is_integral(typ_s);
3820 pub fn type_is_uint(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3821 let typ_s = structurally_resolved_type(fcx, sp, typ);
3822 return ty::type_is_uint(typ_s);
3825 pub fn type_is_scalar(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3826 let typ_s = structurally_resolved_type(fcx, sp, typ);
3827 return ty::type_is_scalar(typ_s);
3830 pub fn type_is_char(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3831 let typ_s = structurally_resolved_type(fcx, sp, typ);
3832 return ty::type_is_char(typ_s);
3835 pub fn type_is_bare_fn(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3836 let typ_s = structurally_resolved_type(fcx, sp, typ);
3837 return ty::type_is_bare_fn(typ_s);
3840 pub fn type_is_unsafe_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3841 let typ_s = structurally_resolved_type(fcx, sp, typ);
3842 return ty::type_is_unsafe_ptr(typ_s);
3845 pub fn type_is_region_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3846 let typ_s = structurally_resolved_type(fcx, sp, typ);
3847 return ty::type_is_region_ptr(typ_s);
3850 pub fn type_is_c_like_enum(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3851 let typ_s = structurally_resolved_type(fcx, sp, typ);
3852 return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
3855 pub fn ast_expr_vstore_to_vstore(fcx: &FnCtxt,
3860 ast::ExprVstoreUniq => ty::vstore_uniq,
3861 ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => {
3863 ast::ExprLit(..) => {
3864 // string literals and *empty slices* live in static memory
3865 ty::vstore_slice(ty::ReStatic)
3867 ast::ExprVec(ref elements, _) if elements.len() == 0 => {
3868 // string literals and *empty slices* live in static memory
3869 ty::vstore_slice(ty::ReStatic)
3871 ast::ExprRepeat(..) |
3872 ast::ExprVec(..) => {
3873 // vector literals are temporaries on the stack
3874 match fcx.tcx().region_maps.temporary_scope(e.id) {
3876 let r = ty::ReScope(scope);
3880 // this slice occurs in a static somewhere
3881 ty::vstore_slice(ty::ReStatic)
3886 fcx.ccx.tcx.sess.span_bug(
3887 e.span, format!("vstore with unexpected contents"))
3894 // Returns true if b contains a break that can exit from b
3895 pub fn may_break(cx: &ty::ctxt, id: ast::NodeId, b: ast::P<ast::Block>) -> bool {
3896 // First: is there an unlabeled break immediately
3898 (loop_query(b, |e| {
3900 ast::ExprBreak(_) => true,
3904 // Second: is there a labeled break with label
3905 // <id> nested anywhere inside the loop?
3906 (block_query(b, |e| {
3908 ast::ExprBreak(Some(_)) => {
3909 match cx.def_map.borrow().find(&e.id) {
3910 Some(&ast::DefLabel(loop_id)) if id == loop_id => true,
3918 pub fn check_bounds_are_used(ccx: &CrateCtxt,
3920 tps: &OwnedSlice<ast::TyParam>,
3922 debug!("check_bounds_are_used(n_tps={}, ty={})",
3923 tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
3925 // make a vector of booleans initially false, set to true when used
3926 if tps.len() == 0u { return; }
3927 let mut tps_used = slice::from_elem(tps.len(), false);
3929 ty::walk_ty(ty, |t| {
3930 match ty::get(t).sty {
3931 ty::ty_param(param_ty {idx, ..}) => {
3932 debug!("Found use of ty param \\#{}", idx);
3933 tps_used[idx] = true;
3939 for (i, b) in tps_used.iter().enumerate() {
3941 ccx.tcx.sess.span_err(
3942 span, format!("type parameter `{}` is unused",
3943 token::get_ident(tps.get(i).ident)));
3948 pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
3949 fn param(ccx: &CrateCtxt, n: uint) -> ty::t {
3950 ty::mk_param(ccx.tcx, n, local_def(0))
3954 let name = token::get_ident(it.ident);
3955 let (n_tps, inputs, output) = if name.get().starts_with("atomic_") {
3956 let split : Vec<&str> = name.get().split('_').collect();
3957 assert!(split.len() >= 2, "Atomic intrinsic not correct format");
3959 //We only care about the operation here
3960 match *split.get(1) {
3961 "cxchg" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)),
3965 "load" => (1, vec!(ty::mk_imm_ptr(tcx, param(ccx, 0))),
3967 "store" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)),
3970 "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
3971 "min" | "umax" | "umin" => {
3972 (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)),
3976 (0, Vec::new(), ty::mk_nil())
3979 tcx.sess.span_err(it.span,
3980 format!("unrecognized atomic operation function: `{}`",
3988 "abort" => (0, Vec::new(), ty::mk_bot()),
3989 "breakpoint" => (0, Vec::new(), ty::mk_nil()),
3991 "pref_align_of" | "min_align_of" => (1u, Vec::new(), ty::mk_uint()),
3992 "init" => (1u, Vec::new(), param(ccx, 0u)),
3993 "uninit" => (1u, Vec::new(), param(ccx, 0u)),
3994 "forget" => (1u, vec!( param(ccx, 0) ), ty::mk_nil()),
3995 "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)),
3996 "move_val_init" => {
3999 ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), param(ccx, 0)),
4004 "needs_drop" => (1u, Vec::new(), ty::mk_bool()),
4005 "owns_managed" => (1u, Vec::new(), ty::mk_bool()),
4008 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4010 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4012 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4014 mutbl: ast::MutImmutable
4016 (1u, Vec::new(), td_ptr)
4019 let langid = ccx.tcx.lang_items.require(TypeIdLangItem);
4021 Ok(did) => (1u, Vec::new(), ty::mk_struct(ccx.tcx, did, substs {
4024 regions: ty::NonerasedRegions(OwnedSlice::empty())
4026 Err(msg) => { tcx.sess.span_fatal(it.span, msg); }
4030 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4032 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4034 let region = ty::ReLateBound(it.id, ty::BrAnon(0));
4035 let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
4036 Ok((_, vot)) => vot,
4037 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4040 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4042 mutbl: ast::MutImmutable
4044 (0, vec!( td_ptr, visitor_object_ty ), ty::mk_nil())
4049 ty::mk_ptr(tcx, ty::mt {
4051 mutbl: ast::MutImmutable
4055 ty::mk_ptr(tcx, ty::mt {
4057 mutbl: ast::MutImmutable
4060 "copy_nonoverlapping_memory" => {
4063 ty::mk_ptr(tcx, ty::mt {
4065 mutbl: ast::MutMutable
4067 ty::mk_ptr(tcx, ty::mt {
4069 mutbl: ast::MutImmutable
4078 ty::mk_ptr(tcx, ty::mt {
4080 mutbl: ast::MutMutable
4082 ty::mk_ptr(tcx, ty::mt {
4084 mutbl: ast::MutImmutable
4093 ty::mk_ptr(tcx, ty::mt {
4095 mutbl: ast::MutMutable
4102 "sqrtf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4103 "sqrtf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4106 vec!( ty::mk_f32(), ty::mk_i32() ),
4111 vec!( ty::mk_f64(), ty::mk_i32() ),
4114 "sinf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4115 "sinf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4116 "cosf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4117 "cosf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4120 vec!( ty::mk_f32(), ty::mk_f32() ),
4125 vec!( ty::mk_f64(), ty::mk_f64() ),
4128 "expf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4129 "expf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4130 "exp2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4131 "exp2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4132 "logf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4133 "logf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4134 "log10f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4135 "log10f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4136 "log2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4137 "log2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4140 vec!( ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ),
4145 vec!( ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ),
4148 "fabsf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4149 "fabsf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4150 "copysignf32" => (0, vec!( ty::mk_f32(), ty::mk_f32() ), ty::mk_f32()),
4151 "copysignf64" => (0, vec!( ty::mk_f64(), ty::mk_f64() ), ty::mk_f64()),
4152 "floorf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4153 "floorf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4154 "ceilf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4155 "ceilf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4156 "truncf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4157 "truncf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4158 "rintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4159 "rintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4160 "nearbyintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4161 "nearbyintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4162 "roundf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4163 "roundf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4164 "ctpop8" => (0, vec!( ty::mk_i8() ), ty::mk_i8()),
4165 "ctpop16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
4166 "ctpop32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
4167 "ctpop64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
4168 "ctlz8" => (0, vec!( ty::mk_i8() ), ty::mk_i8()),
4169 "ctlz16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
4170 "ctlz32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
4171 "ctlz64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
4172 "cttz8" => (0, vec!( ty::mk_i8() ), ty::mk_i8()),
4173 "cttz16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
4174 "cttz32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
4175 "cttz64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
4176 "bswap16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
4177 "bswap32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
4178 "bswap64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
4181 (1, vec!( ty::mk_imm_ptr(tcx, param(ccx, 0)) ), param(ccx, 0)),
4183 (1, vec!( ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ), ty::mk_nil()),
4185 "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
4186 (0, vec!(ty::mk_i8(), ty::mk_i8()),
4187 ty::mk_tup(tcx, vec!(ty::mk_i8(), ty::mk_bool()))),
4189 "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
4190 (0, vec!(ty::mk_i16(), ty::mk_i16()),
4191 ty::mk_tup(tcx, vec!(ty::mk_i16(), ty::mk_bool()))),
4193 "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
4194 (0, vec!(ty::mk_i32(), ty::mk_i32()),
4195 ty::mk_tup(tcx, vec!(ty::mk_i32(), ty::mk_bool()))),
4197 "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
4198 (0, vec!(ty::mk_i64(), ty::mk_i64()),
4199 ty::mk_tup(tcx, vec!(ty::mk_i64(), ty::mk_bool()))),
4201 "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
4202 (0, vec!(ty::mk_u8(), ty::mk_u8()),
4203 ty::mk_tup(tcx, vec!(ty::mk_u8(), ty::mk_bool()))),
4205 "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
4206 (0, vec!(ty::mk_u16(), ty::mk_u16()),
4207 ty::mk_tup(tcx, vec!(ty::mk_u16(), ty::mk_bool()))),
4209 "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
4210 (0, vec!(ty::mk_u32(), ty::mk_u32()),
4211 ty::mk_tup(tcx, vec!(ty::mk_u32(), ty::mk_bool()))),
4213 "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" =>
4214 (0, vec!(ty::mk_u64(), ty::mk_u64()),
4215 ty::mk_tup(tcx, vec!(ty::mk_u64(), ty::mk_bool()))),
4218 tcx.sess.span_err(it.span,
4219 format!("unrecognized intrinsic function: `{}`",
4225 let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
4226 purity: ast::UnsafeFn,
4227 abi: abi::RustIntrinsic,
4228 sig: FnSig {binder_id: it.id,
4233 let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
4234 let i_n_tps = i_ty.generics.type_param_defs().len();
4235 if i_n_tps != n_tps {
4236 tcx.sess.span_err(it.span, format!("intrinsic has wrong number \
4237 of type parameters: found {}, \
4238 expected {}", i_n_tps, n_tps));
4241 tcx, None, false, it.span, i_ty.ty, fty,
4242 || format!("intrinsic has wrong type: \
4244 ppaux::ty_to_str(ccx.tcx, fty)));