1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
15 Within the check phase of type check, we check each item one at a time
16 (bodies of function expressions are checked as part of the containing
17 function). Inference is used to supply types wherever they are
20 By far the most complex case is checking the body of a function. This
21 can be broken down into several distinct phases:
23 - gather: creates type variables to represent the type of each local
24 variable and pattern binding.
26 - main: the main pass does the lion's share of the work: it
27 determines the types of all expressions, resolves
28 methods, checks for most invalid conditions, and so forth. In
29 some cases, where a type is unknown, it may create a type or region
30 variable and use that as the type of an expression.
32 In the process of checking, various constraints will be placed on
33 these type variables through the subtyping relationships requested
34 through the `demand` module. The `typeck::infer` module is in charge
35 of resolving those constraints.
37 - regionck: after main is complete, the regionck pass goes over all
38 types looking for regions and making sure that they did not escape
39 into places they are not in scope. This may also influence the
40 final assignments of the various region variables if there is some
43 - vtable: find and records the impls to use for each trait bound that
44 appears on a type parameter.
46 - writeback: writes the final types within a function body, replacing
47 type variables with their final inferred types. These final types
48 are written into the `tcx.node_types` table, which should *never* contain
49 any reference to a type variable.
53 While type checking a function, the intermediate types for the
54 expressions, blocks, and so forth contained within the function are
55 stored in `fcx.node_types` and `fcx.node_type_substs`. These types
56 may contain unresolved type variables. After type checking is
57 complete, the functions in the writeback module are used to take the
58 types from this table, resolve them, and then write them into their
59 permanent home in the type context `ccx.tcx`.
61 This means that during inferencing you should use `fcx.write_ty()`
62 and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of
63 nodes within the function.
65 The types of top-level items, which never contain unbound type
66 variables, are stored directly into the `tcx` tables.
68 n.b.: A type variable is not the same thing as a type parameter. A
69 type variable is rather an "instance" of a type parameter: that is,
70 given a generic function `fn foo<T>(t: T)`: while checking the
71 function `foo`, the type `ty_param(0)` refers to the type `T`, which
72 is treated in abstract. When `foo()` is called, however, `T` will be
73 substituted for a fresh type variable `N`. This variable will
74 eventually be resolved to some concrete type (which might itself be
80 use middle::const_eval;
81 use middle::lang_items::{ExchangeHeapLangItem, GcLangItem};
82 use middle::lang_items::{ManagedHeapLangItem};
83 use middle::lint::UnreachableCode;
84 use middle::pat_util::pat_id_map;
86 use middle::subst::Subst;
87 use middle::ty::{FnSig, VariantInfo};
88 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
89 use middle::ty::{substs, param_ty, Disr, ExprTyProvider};
91 use middle::ty_fold::TypeFolder;
92 use middle::typeck::astconv::AstConv;
93 use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
94 use middle::typeck::astconv;
95 use middle::typeck::check::_match::pat_ctxt;
96 use middle::typeck::check::method::{AutoderefReceiver};
97 use middle::typeck::check::method::{AutoderefReceiverFlag};
98 use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
99 use middle::typeck::check::method::{DontAutoderefReceiver};
100 use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
101 use middle::typeck::check::regionmanip::relate_free_regions;
102 use middle::typeck::check::vtable::{LocationInfo, VtableContext};
103 use middle::typeck::CrateCtxt;
104 use middle::typeck::infer::{resolve_type, force_tvar};
105 use middle::typeck::infer;
106 use middle::typeck::rscope::RegionScope;
107 use middle::typeck::{lookup_def_ccx};
108 use middle::typeck::no_params;
109 use middle::typeck::{require_same_types, MethodMap, vtable_map};
110 use middle::lang_items::TypeIdLangItem;
111 use util::common::{block_query, indenter, loop_query};
113 use util::ppaux::{UserString, Repr};
114 use util::nodemap::NodeMap;
116 use std::cell::{Cell, RefCell};
117 use collections::HashMap;
118 use std::mem::replace;
121 use syntax::abi::AbiSet;
122 use syntax::ast::{Provided, Required};
124 use syntax::ast_util::local_def;
125 use syntax::ast_util;
127 use syntax::codemap::Span;
129 use syntax::opt_vec::OptVec;
131 use syntax::parse::token;
132 use syntax::print::pprust;
134 use syntax::visit::Visitor;
145 /// Fields that are part of a `FnCtxt` which are inherited by
146 /// closures defined within the function. For example:
149 /// bar(proc() { ... })
152 /// Here, the function `foo()` and the closure passed to
153 /// `bar()` will each have their own `FnCtxt`, but they will
154 /// share the inherited fields.
155 pub struct Inherited {
156 infcx: infer::InferCtxt,
157 locals: @RefCell<NodeMap<ty::t>>,
158 param_env: ty::ParameterEnvironment,
161 node_types: RefCell<NodeMap<ty::t>>,
162 node_type_substs: RefCell<NodeMap<ty::substs>>,
163 adjustments: RefCell<NodeMap<@ty::AutoAdjustment>>,
164 method_map: MethodMap,
165 vtable_map: vtable_map,
166 upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
174 // A normal closure or fn item.
179 pub struct PurityState {
186 pub fn function(purity: ast::Purity, def: ast::NodeId) -> PurityState {
187 PurityState { def: def, purity: purity, from_fn: true }
190 pub fn recurse(&mut self, blk: &ast::Block) -> PurityState {
192 // If this unsafe, then if the outer function was already marked as
193 // unsafe we shouldn't attribute the unsafe'ness to the block. This
194 // way the block can be warned about instead of ignoring this
195 // extraneous block (functions are never warned about).
196 ast::UnsafeFn if self.from_fn => *self,
199 let (purity, def) = match blk.rules {
200 ast::UnsafeBlock(..) => (ast::UnsafeFn, blk.id),
201 ast::DefaultBlock => (purity, self.def),
203 PurityState{ def: def,
211 /// Whether `check_binop` is part of an assignment or not.
212 /// Used to know wether we allow user overloads and to print
213 /// better messages on error.
215 enum IsBinopAssignment{
222 // Number of errors that had been reported when we started
223 // checking this function. On exit, if we find that *more* errors
224 // have been reported, we will skip regionck and other work that
225 // expects the types within the function to be consistent.
226 err_count_on_creation: uint,
229 ps: RefCell<PurityState>,
231 // Sometimes we generate region pointers where the precise region
232 // to use is not known. For example, an expression like `&x.f`
233 // where `x` is of type `@T`: in this case, we will be rooting
234 // `x` onto the stack frame, and we could choose to root it until
235 // the end of (almost) any enclosing block or expression. We
236 // want to pick the narrowest block that encompasses all uses.
238 // What we do in such cases is to generate a region variable with
239 // `region_lb` as a lower bound. The regionck pass then adds
240 // other constriants based on how the variable is used and region
241 // inference selects the ultimate value. Finally, borrowck is
242 // charged with guaranteeing that the value whose address was taken
243 // can actually be made to live as long as it needs to live.
244 region_lb: Cell<ast::NodeId>,
246 // Says whether we're inside a for loop, in a do block
247 // or neither. Helps with error messages involving the
248 // function return type.
257 fn new(tcx: ty::ctxt,
258 param_env: ty::ParameterEnvironment)
261 infcx: infer::new_infer_ctxt(tcx),
262 locals: @RefCell::new(NodeMap::new()),
263 param_env: param_env,
264 node_types: RefCell::new(NodeMap::new()),
265 node_type_substs: RefCell::new(NodeMap::new()),
266 adjustments: RefCell::new(NodeMap::new()),
267 method_map: @RefCell::new(NodeMap::new()),
268 vtable_map: @RefCell::new(NodeMap::new()),
269 upvar_borrow_map: RefCell::new(HashMap::new()),
274 // Used by check_const and check_enum_variants
275 pub fn blank_fn_ctxt(ccx: @CrateCtxt,
277 region_bnd: ast::NodeId)
279 // It's kind of a kludge to manufacture a fake function context
280 // and statement context, but we might as well do write the code only once
281 let param_env = ty::ParameterEnvironment { free_substs: substs::empty(),
282 self_param_bound: None,
283 type_param_bounds: Vec::new() };
285 err_count_on_creation: ccx.tcx.sess.err_count(),
287 ps: RefCell::new(PurityState::function(ast::ImpureFn, 0)),
288 region_lb: Cell::new(region_bnd),
290 inh: @Inherited::new(ccx.tcx, param_env),
295 impl ExprTyProvider for FnCtxt {
296 fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
300 fn ty_ctxt(&self) -> ty::ctxt {
305 struct CheckItemTypesVisitor { ccx: @CrateCtxt }
307 impl Visitor<()> for CheckItemTypesVisitor {
308 fn visit_item(&mut self, i: &ast::Item, _: ()) {
309 check_item(self.ccx, i);
310 visit::walk_item(self, i, ());
314 pub fn check_item_types(ccx: @CrateCtxt, krate: &ast::Crate) {
315 let mut visit = CheckItemTypesVisitor { ccx: ccx };
316 visit::walk_crate(&mut visit, krate, ());
319 fn check_bare_fn(ccx: @CrateCtxt,
324 param_env: ty::ParameterEnvironment) {
325 match ty::get(fty).sty {
326 ty::ty_bare_fn(ref fn_ty) => {
328 check_fn(ccx, fn_ty.purity, &fn_ty.sig, decl, id, body,
329 Vanilla, @Inherited::new(ccx.tcx, param_env));
331 vtable::resolve_in_block(fcx, body);
332 regionck::regionck_fn(fcx, body);
333 writeback::resolve_type_vars_in_fn(fcx, decl, body);
335 _ => ccx.tcx.sess.impossible_case(body.span,
336 "check_bare_fn: function type expected")
340 struct GatherLocalsVisitor {
345 impl GatherLocalsVisitor {
346 fn assign(&mut self, nid: ast::NodeId, ty_opt: Option<ty::t>) {
349 // infer the variable's type
350 let var_id = self.fcx.infcx().next_ty_var_id();
351 let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
352 let mut locals = self.fcx.inh.locals.borrow_mut();
353 locals.get().insert(nid, var_ty);
356 // take type that the user specified
357 let mut locals = self.fcx.inh.locals.borrow_mut();
358 locals.get().insert(nid, typ);
364 impl Visitor<()> for GatherLocalsVisitor {
365 // Add explicitly-declared locals.
366 fn visit_local(&mut self, local: &ast::Local, _: ()) {
367 let o_ty = match local.ty.node {
368 ast::TyInfer => None,
369 _ => Some(self.fcx.to_ty(local.ty))
371 self.assign(local.id, o_ty);
373 let locals = self.fcx.inh.locals.borrow();
374 debug!("Local variable {} is assigned type {}",
375 self.fcx.pat_to_str(local.pat),
376 self.fcx.infcx().ty_to_str(
377 locals.get().get_copy(&local.id)));
379 visit::walk_local(self, local, ());
382 // Add pattern bindings.
383 fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
385 ast::PatIdent(_, ref path, _)
386 if pat_util::pat_is_binding(self.fcx.ccx.tcx.def_map, p) => {
387 self.assign(p.id, None);
389 let locals = self.fcx.inh.locals.borrow();
390 debug!("Pattern binding {} is assigned to {}",
391 token::get_ident(path.segments.get(0).identifier),
392 self.fcx.infcx().ty_to_str(
393 locals.get().get_copy(&p.id)));
398 visit::walk_pat(self, p, ());
402 fn visit_block(&mut self, b: &ast::Block, _: ()) {
403 // non-obvious: the `blk` variable maps to region lb, so
404 // we have to keep this up-to-date. This
405 // is... unfortunate. It'd be nice to not need this.
406 self.fcx.with_region_lb(b.id, || visit::walk_block(self, b, ()));
409 // Don't descend into fns and items
410 fn visit_fn(&mut self, _: &visit::FnKind, _: &ast::FnDecl,
411 _: &ast::Block, _: Span, _: ast::NodeId, _: ()) { }
412 fn visit_item(&mut self, _: &ast::Item, _: ()) { }
416 fn check_fn(ccx: @CrateCtxt,
423 inherited: @Inherited) -> @FnCtxt
426 * Helper used by check_bare_fn and check_expr_fn. Does the
427 * grungy work of checking a function body and returns the
428 * function context used for that purpose, since in the case of a
429 * fn item there is still a bit more to do.
432 * - inherited: other fields inherited from the enclosing fn (if any)
436 let err_count_on_creation = tcx.sess.err_count();
438 // First, we have to replace any bound regions in the fn type with free ones.
439 // The free region references will be bound the node_id of the body block.
440 let (_, fn_sig) = replace_bound_regions_in_fn_sig(tcx, fn_sig, |br| {
441 ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
444 relate_free_regions(tcx, &fn_sig);
446 let arg_tys = fn_sig.inputs.as_slice();
447 let ret_ty = fn_sig.output;
449 debug!("check_fn(arg_tys={:?}, ret_ty={:?})",
450 arg_tys.map(|&a| ppaux::ty_to_str(tcx, a)),
451 ppaux::ty_to_str(tcx, ret_ty));
453 // Create the function context. This is either derived from scratch or,
454 // in the case of function expressions, based on the outer context.
456 err_count_on_creation: err_count_on_creation,
458 ps: RefCell::new(PurityState::function(purity, id)),
459 region_lb: Cell::new(body.id),
467 let mut visit = GatherLocalsVisitor { fcx: fcx, tcx: tcx, };
468 // Add formal parameters.
469 for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
470 // Create type variables for each argument.
471 pat_util::pat_bindings(tcx.def_map,
473 |_bm, pat_id, _sp, _path| {
474 visit.assign(pat_id, None);
477 // Check the pattern.
480 map: pat_id_map(tcx.def_map, input.pat),
482 _match::check_pat(&pcx, input.pat, *arg_ty);
485 visit.visit_block(body, ());
488 check_block_with_expected(fcx, body, Some(ret_ty));
490 // We unify the tail expr's type with the
491 // function result type, if there is a tail expr.
494 // Special case: we print a special error if there appears
495 // to be do-block/for-loop confusion
496 demand::suptype_with_fn(fcx, tail_expr.span, false,
497 fcx.ret_ty, fcx.expr_ty(tail_expr),
499 fcx.report_mismatched_return_types(sp, e, a, s);
505 for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
506 fcx.write_ty(input.id, *arg);
512 pub fn check_no_duplicate_fields(tcx: ty::ctxt,
513 fields: Vec<(ast::Ident, Span)> ) {
514 let mut field_names = HashMap::new();
516 for p in fields.iter() {
518 let orig_sp = field_names.find(&id).map(|x| *x);
521 tcx.sess.span_err(sp, format!("duplicate field name {} in record type declaration",
522 token::get_ident(id)));
523 tcx.sess.span_note(orig_sp, "first declaration of this field occurred here");
527 field_names.insert(id, sp);
533 pub fn check_struct(ccx: @CrateCtxt, id: ast::NodeId, span: Span) {
536 // Check that the struct is representable
537 check_representable(tcx, span, id, "struct");
539 // Check that the struct is instantiable
540 check_instantiable(tcx, span, id);
542 if ty::lookup_simd(tcx, local_def(id)) {
543 check_simd(tcx, span, id);
547 pub fn check_item(ccx: @CrateCtxt, it: &ast::Item) {
548 debug!("check_item(it.id={}, it.ident={})",
550 ty::item_path_str(ccx.tcx, local_def(it.id)));
551 let _indenter = indenter();
554 ast::ItemStatic(_, _, e) => check_const(ccx, it.span, e, it.id),
555 ast::ItemEnum(ref enum_definition, _) => {
556 check_enum_variants(ccx,
558 enum_definition.variants.as_slice(),
561 ast::ItemFn(decl, _, _, _, body) => {
562 let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
564 // FIXME(#5121) -- won't work for lifetimes that appear in type bounds
565 let param_env = ty::construct_parameter_environment(
568 fn_tpt.generics.type_param_defs(),
573 check_bare_fn(ccx, decl, body, it.id, fn_tpt.ty, param_env);
575 ast::ItemImpl(_, ref opt_trait_ref, _, ref ms) => {
576 debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
578 let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
580 check_method_body(ccx, &impl_tpt.generics, None, *m);
583 match *opt_trait_ref {
584 Some(ref ast_trait_ref) => {
586 ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id);
587 check_impl_methods_against_trait(ccx,
593 vtable::resolve_impl(ccx.tcx, it, &impl_tpt.generics, impl_trait_ref);
599 ast::ItemTrait(_, _, ref trait_methods) => {
600 let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
601 for trait_method in (*trait_methods).iter() {
602 match *trait_method {
604 // Nothing to do, since required methods don't have
608 check_method_body(ccx, &trait_def.generics,
609 Some(trait_def.trait_ref), m);
614 ast::ItemStruct(..) => {
615 check_struct(ccx, it.id, it.span);
617 ast::ItemTy(ref t, ref generics) => {
618 let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id);
619 check_bounds_are_used(ccx, t.span, &generics.ty_params, tpt_ty);
621 ast::ItemForeignMod(ref m) => {
622 if m.abis.is_intrinsic() {
623 for item in m.items.iter() {
624 check_intrinsic_type(ccx, *item);
627 for item in m.items.iter() {
628 let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id));
629 if tpt.generics.has_type_params() {
630 ccx.tcx.sess.span_err(item.span, "foreign items may not have type parameters");
634 ast::ForeignItemFn(ref fn_decl, _) => {
635 if fn_decl.variadic && !m.abis.is_c() {
636 ccx.tcx.sess.span_err(
637 item.span, "variadic function must have C calling convention");
645 _ => {/* nothing to do */ }
649 fn check_method_body(ccx: @CrateCtxt,
650 item_generics: &ty::Generics,
651 self_bound: Option<@ty::TraitRef>,
652 method: &ast::Method) {
654 * Type checks a method body.
657 * - `item_generics`: generics defined on the impl/trait that contains
659 * - `self_bound`: bound for the `Self` type parameter, if any
660 * - `method`: the method definition
663 debug!("check_method_body(item_generics={}, \
666 item_generics.repr(ccx.tcx),
667 self_bound.repr(ccx.tcx),
669 let method_def_id = local_def(method.id);
670 let method_ty = ty::method(ccx.tcx, method_def_id);
671 let method_generics = &method_ty.generics;
674 ty::construct_parameter_environment(
677 item_generics.type_param_defs(),
678 method_generics.type_param_defs(),
679 item_generics.region_param_defs(),
682 // Compute the fty from point of view of inside fn
683 let fty = ty::node_id_to_type(ccx.tcx, method.id);
684 let fty = fty.subst(ccx.tcx, ¶m_env.free_substs);
686 check_bare_fn(ccx, method.decl, method.body, method.id, fty, param_env);
689 fn check_impl_methods_against_trait(ccx: @CrateCtxt,
691 impl_generics: &ty::Generics,
692 ast_trait_ref: &ast::TraitRef,
693 impl_trait_ref: &ty::TraitRef,
694 impl_methods: &[@ast::Method]) {
695 // Locate trait methods
697 let trait_methods = ty::trait_methods(tcx, impl_trait_ref.def_id);
699 // Check existing impl methods to see if they are both present in trait
700 // and compatible with trait signature
701 for impl_method in impl_methods.iter() {
702 let impl_method_def_id = local_def(impl_method.id);
703 let impl_method_ty = ty::method(ccx.tcx, impl_method_def_id);
705 // If this is an impl of a trait method, find the corresponding
706 // method definition in the trait.
707 let opt_trait_method_ty =
708 trait_methods.iter().
709 find(|tm| tm.ident.name == impl_method_ty.ident.name);
710 match opt_trait_method_ty {
711 Some(trait_method_ty) => {
712 compare_impl_method(ccx.tcx,
718 &impl_trait_ref.substs);
723 format!("method `{}` is not a member of trait `{}`",
724 token::get_ident(impl_method_ty.ident),
725 pprust::path_to_str(&ast_trait_ref.path)));
730 // Check for missing methods from trait
731 let provided_methods = ty::provided_trait_methods(tcx,
732 impl_trait_ref.def_id);
733 let mut missing_methods = Vec::new();
734 for trait_method in trait_methods.iter() {
736 impl_methods.iter().any(
737 |m| m.ident.name == trait_method.ident.name);
739 provided_methods.iter().any(
740 |m| m.ident.name == trait_method.ident.name);
741 if !is_implemented && !is_provided {
742 missing_methods.push(
743 format!("`{}`", token::get_ident(trait_method.ident)));
747 if !missing_methods.is_empty() {
750 format!("not all trait methods implemented, missing: {}",
751 missing_methods.connect(", ")));
756 * Checks that a method from an impl/class conforms to the signature of
757 * the same method as declared in the trait.
761 * - impl_generics: the generics declared on the impl itself (not the method!)
762 * - impl_m: type of the method we are checking
763 * - impl_m_span: span to use for reporting errors
764 * - impl_m_body_id: id of the method body
765 * - trait_m: the method in the trait
766 * - trait_substs: the substitutions used on the type of the trait
768 fn compare_impl_method(tcx: ty::ctxt,
769 impl_generics: &ty::Generics,
772 impl_m_body_id: ast::NodeId,
773 trait_m: &ty::Method,
774 trait_substs: &ty::substs) {
775 debug!("compare_impl_method()");
776 let infcx = infer::new_infer_ctxt(tcx);
778 let impl_tps = impl_generics.type_param_defs().len();
780 // Try to give more informative error messages about self typing
781 // mismatches. Note that any mismatch will also be detected
782 // below, where we construct a canonical function type that
783 // includes the self parameter as a normal parameter. It's just
784 // that the error messages you get out of this code are a bit more
785 // inscrutable, particularly for cases where one method has no
787 match (&trait_m.explicit_self, &impl_m.explicit_self) {
788 (&ast::SelfStatic, &ast::SelfStatic) => {}
789 (&ast::SelfStatic, _) => {
792 format!("method `{}` has a `{}` declaration in the impl, \
793 but not in the trait",
794 token::get_ident(trait_m.ident),
795 pprust::explicit_self_to_str(&impl_m.explicit_self)));
798 (_, &ast::SelfStatic) => {
801 format!("method `{}` has a `{}` declaration in the trait, \
802 but not in the impl",
803 token::get_ident(trait_m.ident),
804 pprust::explicit_self_to_str(&trait_m.explicit_self)));
808 // Let the type checker catch other errors below
812 let num_impl_m_type_params = impl_m.generics.type_param_defs().len();
813 let num_trait_m_type_params = trait_m.generics.type_param_defs().len();
814 if num_impl_m_type_params != num_trait_m_type_params {
817 format!("method `{method}` has {nimpl, plural, =1{# type parameter} \
818 other{# type parameters}}, \
819 but its trait declaration has {ntrait, plural, =1{# type parameter} \
820 other{# type parameters}}",
821 method = token::get_ident(trait_m.ident),
822 nimpl = num_impl_m_type_params,
823 ntrait = num_trait_m_type_params));
827 if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() {
830 format!("method `{method}` has {nimpl, plural, =1{# parameter} \
831 other{# parameters}} \
832 but the declaration in trait `{trait}` has {ntrait}",
833 method = token::get_ident(trait_m.ident),
834 nimpl = impl_m.fty.sig.inputs.len(),
835 trait = ty::item_path_str(tcx, trait_m.def_id),
836 ntrait = trait_m.fty.sig.inputs.len()));
840 let it = trait_m.generics.type_param_defs().iter()
841 .zip(impl_m.generics.type_param_defs().iter());
843 for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
844 // Check that the impl does not require any builtin-bounds
845 // that the trait does not guarantee:
847 impl_param_def.bounds.builtin_bounds -
848 trait_param_def.bounds.builtin_bounds;
849 if !extra_bounds.is_empty() {
852 format!("in method `{}`, \
853 type parameter {} requires `{}`, \
854 which is not required by \
855 the corresponding type parameter \
856 in the trait declaration",
857 token::get_ident(trait_m.ident),
859 extra_bounds.user_string(tcx)));
863 // FIXME(#2687)---we should be checking that the bounds of the
864 // trait imply the bounds of the subtype, but it appears we
865 // are...not checking this.
866 if impl_param_def.bounds.trait_bounds.len() !=
867 trait_param_def.bounds.trait_bounds.len()
871 format!("in method `{method}`, \
872 type parameter {typaram} has \
873 {nimpl, plural, =1{# trait bound} other{# trait bounds}}, \
874 but the corresponding type parameter in \
875 the trait declaration has \
876 {ntrait, plural, =1{# trait bound} other{# trait bounds}}",
877 method = token::get_ident(trait_m.ident),
879 nimpl = impl_param_def.bounds.trait_bounds.len(),
880 ntrait = trait_param_def.bounds.trait_bounds.len()));
885 // Create a substitution that maps the type parameters on the impl
886 // to themselves and which replace any references to bound regions
887 // in the self type with free regions. So, for example, if the
888 // impl type is "&'a str", then this would replace the self
889 // type with a free region `self`.
890 let dummy_impl_tps: Vec<ty::t> =
891 impl_generics.type_param_defs().iter().enumerate().
892 map(|(i,t)| ty::mk_param(tcx, i, t.def_id)).
894 let dummy_method_tps: Vec<ty::t> =
895 impl_m.generics.type_param_defs().iter().enumerate().
896 map(|(i,t)| ty::mk_param(tcx, i + impl_tps, t.def_id)).
898 let dummy_impl_regions: OptVec<ty::Region> =
899 impl_generics.region_param_defs().iter().
900 map(|l| ty::ReFree(ty::FreeRegion {
901 scope_id: impl_m_body_id,
902 bound_region: ty::BrNamed(l.def_id, l.ident)})).
904 let dummy_substs = ty::substs {
905 tps: vec_ng::append(dummy_impl_tps, dummy_method_tps),
906 regions: ty::NonerasedRegions(dummy_impl_regions),
909 // Create a bare fn type for trait/impl
910 // It'd be nice to refactor so as to provide the bare fn types instead.
911 let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
912 let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
914 // Perform substitutions so that the trait/impl methods are expressed
915 // in terms of the same set of type/region parameters:
916 // - replace trait type parameters with those from `trait_substs`,
917 // except with any reference to bound self replaced with `dummy_self_r`
918 // - replace method parameters on the trait with fresh, dummy parameters
919 // that correspond to the parameters we will find on the impl
920 // - replace self region with a fresh, dummy region
922 debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
923 impl_fty.subst(tcx, &dummy_substs)
925 debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
927 let substs { regions: trait_regions,
929 self_ty: self_ty } = trait_substs.subst(tcx, &dummy_substs);
930 let substs = substs {
931 regions: trait_regions,
932 tps: vec_ng::append(trait_tps, dummy_method_tps),
935 debug!("trait_fty (pre-subst): {} substs={}",
936 trait_fty.repr(tcx), substs.repr(tcx));
937 trait_fty.subst(tcx, &substs)
939 debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx));
941 match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span),
942 impl_fty, trait_fty) {
944 result::Err(ref terr) => {
947 format!("method `{}` has an incompatible type: {}",
948 token::get_ident(trait_m.ident),
949 ty::type_err_to_str(tcx, terr)));
950 ty::note_and_explain_type_err(tcx, terr);
955 impl AstConv for FnCtxt {
956 fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
958 fn get_item_ty(&self, id: ast::DefId) -> ty::ty_param_bounds_and_ty {
959 ty::lookup_item_type(self.tcx(), id)
962 fn get_trait_def(&self, id: ast::DefId) -> @ty::TraitDef {
963 ty::lookup_trait_def(self.tcx(), id)
966 fn ty_infer(&self, _span: Span) -> ty::t {
967 self.infcx().next_ty_var()
972 pub fn infcx<'a>(&'a self) -> &'a infer::InferCtxt {
976 pub fn err_count_since_creation(&self) -> uint {
977 self.ccx.tcx.sess.err_count() - self.err_count_on_creation
980 pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
983 param_env: &self.inh.param_env
988 impl RegionScope for infer::InferCtxt {
989 fn anon_regions(&self, span: Span, count: uint)
990 -> Result<Vec<ty::Region> , ()> {
991 Ok(vec::from_fn(count, |_| {
992 self.next_region_var(infer::MiscVariable(span))
998 pub fn tag(&self) -> ~str {
999 format!("{}", self as *FnCtxt)
1002 pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t {
1003 let locals = self.inh.locals.borrow();
1004 match locals.get().find(&nid) {
1007 self.tcx().sess.span_bug(
1009 format!("no type for local variable {:?}", nid));
1014 pub fn block_region(&self) -> ty::Region {
1015 ty::ReScope(self.region_lb.get())
1019 pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
1020 debug!("write_ty({}, {}) in fcx {}",
1021 node_id, ppaux::ty_to_str(self.tcx(), ty), self.tag());
1022 let mut node_types = self.inh.node_types.borrow_mut();
1023 node_types.get().insert(node_id, ty);
1026 pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::substs) {
1027 if !ty::substs_is_noop(&substs) {
1028 debug!("write_substs({}, {}) in fcx {}",
1030 ty::substs_to_str(self.tcx(), &substs),
1033 let mut node_type_substs = self.inh.node_type_substs.borrow_mut();
1034 node_type_substs.get().insert(node_id, substs);
1038 pub fn write_ty_substs(&self,
1039 node_id: ast::NodeId,
1041 substs: ty::substs) {
1042 let ty = ty::subst(self.tcx(), &substs, ty);
1043 self.write_ty(node_id, ty);
1044 self.write_substs(node_id, substs);
1047 pub fn write_autoderef_adjustment(&self,
1048 node_id: ast::NodeId,
1050 if derefs == 0 { return; }
1051 self.write_adjustment(
1053 @ty::AutoDerefRef(ty::AutoDerefRef {
1059 pub fn write_adjustment(&self,
1060 node_id: ast::NodeId,
1061 adj: @ty::AutoAdjustment) {
1062 debug!("write_adjustment(node_id={:?}, adj={:?})", node_id, adj);
1063 let mut adjustments = self.inh.adjustments.borrow_mut();
1064 adjustments.get().insert(node_id, adj);
1067 pub fn write_nil(&self, node_id: ast::NodeId) {
1068 self.write_ty(node_id, ty::mk_nil());
1070 pub fn write_bot(&self, node_id: ast::NodeId) {
1071 self.write_ty(node_id, ty::mk_bot());
1073 pub fn write_error(&self, node_id: ast::NodeId) {
1074 self.write_ty(node_id, ty::mk_err());
1077 pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
1078 ast_ty_to_ty(self, self.infcx(), ast_t)
1081 pub fn pat_to_str(&self, pat: &ast::Pat) -> ~str {
1082 pat.repr(self.tcx())
1085 pub fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
1086 let node_types = self.inh.node_types.borrow();
1087 match node_types.get().find(&ex.id) {
1090 self.tcx().sess.bug(format!("no type for expr in fcx {}",
1096 pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
1097 match self.inh.node_types.borrow().get().find(&id) {
1100 self.tcx().sess.bug(
1101 format!("no type for node {}: {} in fcx {}",
1102 id, self.tcx().map.node_to_str(id),
1108 pub fn method_ty(&self, id: ast::NodeId) -> ty::t {
1109 match self.inh.method_map.borrow().get().find(&id) {
1110 Some(method) => method.ty,
1112 self.tcx().sess.bug(
1113 format!("no method entry for node {}: {} in fcx {}",
1114 id, self.tcx().map.node_to_str(id),
1120 pub fn node_ty_substs(&self, id: ast::NodeId) -> ty::substs {
1121 match self.inh.node_type_substs.borrow().get().find(&id) {
1122 Some(ts) => (*ts).clone(),
1124 self.tcx().sess.bug(
1125 format!("no type substs for node {}: {} in fcx {}",
1126 id, self.tcx().map.node_to_str(id),
1132 pub fn method_ty_substs(&self, id: ast::NodeId) -> ty::substs {
1133 match self.inh.method_map.borrow().get().find(&id) {
1134 Some(method) => method.substs.clone(),
1136 self.tcx().sess.bug(
1137 format!("no method entry for node {}: {} in fcx {}",
1138 id, self.tcx().map.node_to_str(id),
1144 pub fn opt_node_ty_substs(&self,
1146 f: |&ty::substs| -> bool)
1148 let node_type_substs = self.inh.node_type_substs.borrow();
1149 match node_type_substs.get().find(&id) {
1155 pub fn mk_subty(&self,
1156 a_is_expected: bool,
1157 origin: infer::TypeOrigin,
1160 -> Result<(), ty::type_err> {
1161 infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
1164 pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t)
1165 -> Result<(), ty::type_err> {
1166 infer::can_mk_subty(self.infcx(), sub, sup)
1169 pub fn mk_assignty(&self,
1173 -> Result<(), ty::type_err> {
1174 match infer::mk_coercety(self.infcx(),
1176 infer::ExprAssignable(expr.span),
1179 Ok(None) => result::Ok(()),
1180 Err(ref e) => result::Err((*e)),
1181 Ok(Some(adjustment)) => {
1182 self.write_adjustment(expr.id, adjustment);
1188 pub fn can_mk_assignty(&self, sub: ty::t, sup: ty::t)
1189 -> Result<(), ty::type_err> {
1190 infer::can_mk_coercety(self.infcx(), sub, sup)
1193 pub fn mk_eqty(&self,
1194 a_is_expected: bool,
1195 origin: infer::TypeOrigin,
1198 -> Result<(), ty::type_err> {
1199 infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
1202 pub fn mk_subr(&self,
1203 a_is_expected: bool,
1204 origin: infer::SubregionOrigin,
1207 infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
1210 pub fn with_region_lb<R>(&self, lb: ast::NodeId, f: || -> R) -> R {
1211 let old_region_lb = self.region_lb.get();
1212 self.region_lb.set(lb);
1214 self.region_lb.set(old_region_lb);
1218 pub fn type_error_message(&self,
1220 mk_msg: |~str| -> ~str,
1222 err: Option<&ty::type_err>) {
1223 self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
1226 pub fn report_mismatched_return_types(&self,
1230 err: &ty::type_err) {
1232 if ty::type_is_error(e) || ty::type_is_error(a) {
1235 self.infcx().report_mismatched_types(sp, e, a, err)
1238 pub fn report_mismatched_types(&self,
1242 err: &ty::type_err) {
1243 self.infcx().report_mismatched_types(sp, e, a, err)
1247 pub enum LvaluePreference {
1252 pub fn do_autoderef(fcx: @FnCtxt, sp: Span, t: ty::t) -> (ty::t, uint) {
1255 * Autoderefs the type `t` as many times as possible, returning
1256 * a new type and a counter for how many times the type was
1257 * deref'd. If the counter is non-zero, the receiver is responsible
1258 * for inserting an AutoAdjustment record into `tcx.adjustments`
1259 * so that trans/borrowck/etc know about this autoderef. */
1262 let mut enum_dids = Vec::new();
1263 let mut autoderefs = 0;
1265 let sty = structure_of(fcx, sp, t1);
1267 // Some extra checks to detect weird cycles and so forth:
1269 ty::ty_box(inner) | ty::ty_uniq(inner) => {
1270 match ty::get(t1).sty {
1271 ty::ty_infer(ty::TyVar(v1)) => {
1272 ty::occurs_check(fcx.ccx.tcx, sp, v1,
1273 ty::mk_box(fcx.ccx.tcx, inner));
1278 ty::ty_rptr(_, inner) => {
1279 match ty::get(t1).sty {
1280 ty::ty_infer(ty::TyVar(v1)) => {
1281 ty::occurs_check(fcx.ccx.tcx, sp, v1,
1282 ty::mk_box(fcx.ccx.tcx, inner.ty));
1287 ty::ty_enum(ref did, _) => {
1288 // Watch out for a type like `enum t = @t`. Such a
1289 // type would otherwise infinitely auto-deref. Only
1290 // autoderef loops during typeck (basically, this one
1291 // and the loops in typeck::check::method) need to be
1292 // concerned with this, as an error will be reported
1293 // on the enum definition as well because the enum is
1294 // not instantiable.
1295 if enum_dids.contains(did) {
1296 return (t1, autoderefs);
1298 enum_dids.push(*did);
1303 // Otherwise, deref if type is derefable:
1304 match ty::deref_sty(sty, false) {
1306 return (t1, autoderefs);
1316 fn try_overloaded_deref(fcx: @FnCtxt,
1318 base_expr: &ast::Expr,
1320 lvalue_pref: LvaluePreference)
1322 // Try DerefMut first, if preferred.
1323 let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
1324 (PreferMutLvalue, Some(trait_did)) => {
1325 method::lookup_in_trait(fcx, expr, base_expr, token::intern("deref_mut"),
1326 trait_did, base_ty, [], DontAutoderefReceiver)
1331 // Otherwise, fall back to Deref.
1332 let method = match (method, fcx.tcx().lang_items.deref_trait()) {
1333 (None, Some(trait_did)) => {
1334 method::lookup_in_trait(fcx, expr, base_expr, token::intern("deref"),
1335 trait_did, base_ty, [], DontAutoderefReceiver)
1337 (method, _) => method
1342 let ref_ty = ty::ty_fn_ret(method.ty);
1343 fcx.inh.method_map.borrow_mut().get().insert(expr.id, method);
1344 ty::deref(ref_ty, true)
1350 // AST fragment checking
1351 pub fn check_lit(fcx: @FnCtxt, lit: &ast::Lit) -> ty::t {
1352 let tcx = fcx.ccx.tcx;
1355 ast::LitStr(..) => ty::mk_str(tcx, ty::vstore_slice(ty::ReStatic)),
1356 ast::LitBinary(..) => {
1357 ty::mk_vec(tcx, ty::mt{ ty: ty::mk_u8(), mutbl: ast::MutImmutable },
1358 ty::vstore_slice(ty::ReStatic))
1360 ast::LitChar(_) => ty::mk_char(),
1361 ast::LitInt(_, t) => ty::mk_mach_int(t),
1362 ast::LitUint(_, t) => ty::mk_mach_uint(t),
1363 ast::LitIntUnsuffixed(_) => {
1364 // An unsuffixed integer literal could have any integral type,
1365 // so we create an integral type variable for it.
1366 ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
1368 ast::LitFloat(_, t) => ty::mk_mach_float(t),
1369 ast::LitFloatUnsuffixed(_) => {
1370 // An unsuffixed floating point literal could have any floating point
1371 // type, so we create a floating point type variable for it.
1372 ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())
1374 ast::LitNil => ty::mk_nil(),
1375 ast::LitBool(_) => ty::mk_bool()
1379 pub fn valid_range_bounds(ccx: @CrateCtxt,
1383 match const_eval::compare_lit_exprs(ccx.tcx, from, to) {
1384 Some(val) => Some(val <= 0),
1389 pub fn check_expr_has_type(
1390 fcx: @FnCtxt, expr: &ast::Expr,
1392 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1393 demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
1397 fn check_expr_coercable_to_type(fcx: @FnCtxt, expr: &ast::Expr, expected: ty::t) {
1398 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1399 demand::coerce(fcx, expr.span, expected, expr)
1403 fn check_expr_with_hint(fcx: @FnCtxt, expr: &ast::Expr, expected: ty::t) {
1404 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || ())
1407 fn check_expr_with_opt_hint(fcx: @FnCtxt, expr: &ast::Expr,
1408 expected: Option<ty::t>) {
1409 check_expr_with_unifier(fcx, expr, expected, NoPreference, || ())
1412 fn check_expr_with_opt_hint_and_lvalue_pref(fcx: @FnCtxt,
1414 expected: Option<ty::t>,
1415 lvalue_pref: LvaluePreference) {
1416 check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ())
1419 fn check_expr(fcx: @FnCtxt, expr: &ast::Expr) {
1420 check_expr_with_unifier(fcx, expr, None, NoPreference, || ())
1423 fn check_expr_with_lvalue_pref(fcx: @FnCtxt, expr: &ast::Expr,
1424 lvalue_pref: LvaluePreference) {
1425 check_expr_with_unifier(fcx, expr, None, lvalue_pref, || ())
1429 // determine the `self` type, using fresh variables for all variables
1430 // declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
1431 // would return ($0, $1) where $0 and $1 are freshly instantiated type
1433 pub fn impl_self_ty(vcx: &VtableContext,
1434 location_info: &LocationInfo, // (potential) receiver for
1437 -> ty_param_substs_and_ty {
1438 let tcx = vcx.tcx();
1440 let (n_tps, n_rps, raw_ty) = {
1441 let ity = ty::lookup_item_type(tcx, did);
1442 (ity.generics.type_param_defs().len(),
1443 ity.generics.region_param_defs().len(),
1448 vcx.infcx.next_region_vars(
1449 infer::BoundRegionInTypeOrImpl(location_info.span),
1451 let tps = vcx.infcx.next_ty_vars(n_tps);
1453 let substs = substs {
1454 regions: ty::NonerasedRegions(opt_vec::from(rps.move_iter()
1459 let substd_ty = ty::subst(tcx, &substs, raw_ty);
1461 ty_param_substs_and_ty { substs: substs, ty: substd_ty }
1464 // Only for fields! Returns <none> for methods>
1465 // Indifferent to privacy flags
1466 pub fn lookup_field_ty(tcx: ty::ctxt,
1467 class_id: ast::DefId,
1468 items: &[ty::field_ty],
1469 fieldname: ast::Name,
1470 substs: &ty::substs) -> Option<ty::t> {
1472 let o_field = items.iter().find(|f| f.name == fieldname);
1473 o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
1476 // Controls whether the arguments are automatically referenced. This is useful
1477 // for overloaded binary and unary operators.
1478 pub enum DerefArgs {
1483 // Given the provenance of a static method, returns the generics of the static
1484 // method's container.
1485 fn generics_of_static_method_container(type_context: ty::ctxt,
1486 provenance: ast::MethodProvenance)
1489 ast::FromTrait(trait_def_id) => {
1490 ty::lookup_trait_def(type_context, trait_def_id).generics.clone()
1492 ast::FromImpl(impl_def_id) => {
1493 ty::lookup_item_type(type_context, impl_def_id).generics.clone()
1498 // Verifies that type parameters supplied in paths are in the right
1500 fn check_type_parameter_positions_in_path(function_context: @FnCtxt,
1503 // We only care about checking the case in which the path has two or
1505 if path.segments.len() < 2 {
1509 // Verify that no lifetimes or type parameters are present anywhere
1510 // except the final two elements of the path.
1511 for i in range(0, path.segments.len() - 2) {
1512 for lifetime in path.segments.get(i).lifetimes.iter() {
1513 function_context.tcx()
1515 .span_err(lifetime.span,
1516 "lifetime parameters may not \
1521 for typ in path.segments.get(i).types.iter() {
1522 function_context.tcx()
1525 "type parameters may not appear here");
1530 // If there are no parameters at all, there is nothing more to do; the
1531 // rest of typechecking will (attempt to) infer everything.
1534 .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) {
1539 // If this is a static method of a trait or implementation, then
1540 // ensure that the segment of the path which names the trait or
1541 // implementation (the penultimate segment) is annotated with the
1542 // right number of type parameters.
1543 ast::DefStaticMethod(_, provenance, _) => {
1545 generics_of_static_method_container(function_context.ccx.tcx,
1547 let name = match provenance {
1548 ast::FromTrait(_) => "trait",
1549 ast::FromImpl(_) => "impl",
1552 let trait_segment = &path.segments.get(path.segments.len() - 2);
1554 // Make sure lifetime parameterization agrees with the trait or
1555 // implementation type.
1556 let trait_region_parameter_count = generics.region_param_defs().len();
1557 let supplied_region_parameter_count = trait_segment.lifetimes.len();
1558 if trait_region_parameter_count != supplied_region_parameter_count
1559 && supplied_region_parameter_count != 0 {
1560 function_context.tcx()
1562 .span_err(path.span,
1563 format!("expected {nexpected, plural, =1{# lifetime parameter} \
1564 other{# lifetime parameters}}, \
1565 found {nsupplied, plural, =1{# lifetime parameter} \
1566 other{# lifetime parameters}}",
1567 nexpected = trait_region_parameter_count,
1568 nsupplied = supplied_region_parameter_count));
1571 // Make sure the number of type parameters supplied on the trait
1572 // or implementation segment equals the number of type parameters
1573 // on the trait or implementation definition.
1574 let formal_ty_param_count = generics.type_param_defs().len();
1575 let required_ty_param_count = generics.type_param_defs().iter()
1576 .take_while(|x| x.default.is_none())
1578 let supplied_ty_param_count = trait_segment.types.len();
1579 if supplied_ty_param_count < required_ty_param_count {
1580 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1581 format!("the {trait_or_impl} referenced by this path needs at least \
1582 {nexpected, plural, =1{# type parameter} \
1583 other{# type parameters}}, \
1584 but {nsupplied, plural, =1{# type parameter} \
1585 other{# type parameters}} were supplied",
1586 trait_or_impl = name,
1587 nexpected = required_ty_param_count,
1588 nsupplied = supplied_ty_param_count)
1590 format!("the {trait_or_impl} referenced by this path needs \
1591 {nexpected, plural, =1{# type parameter} \
1592 other{# type parameters}}, \
1593 but {nsupplied, plural, =1{# type parameter} \
1594 other{# type parameters}} were supplied",
1595 trait_or_impl = name,
1596 nexpected = required_ty_param_count,
1597 nsupplied = supplied_ty_param_count)
1599 function_context.tcx().sess.span_err(path.span, msg)
1600 } else if supplied_ty_param_count > formal_ty_param_count {
1601 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1602 format!("the {trait_or_impl} referenced by this path needs at most \
1603 {nexpected, plural, =1{# type parameter} \
1604 other{# type parameters}}, \
1605 but {nsupplied, plural, =1{# type parameter} \
1606 other{# type parameters}} were supplied",
1607 trait_or_impl = name,
1608 nexpected = formal_ty_param_count,
1609 nsupplied = supplied_ty_param_count)
1611 format!("the {trait_or_impl} referenced by this path needs \
1612 {nexpected, plural, =1{# type parameter} \
1613 other{# type parameters}}, \
1614 but {nsupplied, plural, =1{# type parameter} \
1615 other{# type parameters}} were supplied",
1616 trait_or_impl = name,
1617 nexpected = formal_ty_param_count,
1618 nsupplied = supplied_ty_param_count)
1620 function_context.tcx().sess.span_err(path.span, msg)
1624 // Verify that no lifetimes or type parameters are present on
1625 // the penultimate segment of the path.
1626 let segment = &path.segments.get(path.segments.len() - 2);
1627 for lifetime in segment.lifetimes.iter() {
1628 function_context.tcx()
1630 .span_err(lifetime.span,
1631 "lifetime parameters may not
1635 for typ in segment.types.iter() {
1636 function_context.tcx()
1639 "type parameters may not appear \
1648 /// If an expression has any sub-expressions that result in a type error,
1649 /// inspecting that expression's type with `ty::type_is_error` will return
1650 /// true. Likewise, if an expression is known to diverge, inspecting its
1651 /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
1652 /// strict, _|_ can appear in the type of an expression that does not,
1653 /// itself, diverge: for example, fn() -> _|_.)
1654 /// Note that inspecting a type's structure *directly* may expose the fact
1655 /// that there are actually multiple representations for both `ty_err` and
1656 /// `ty_bot`, so avoid that when err and bot need to be handled differently.
1657 fn check_expr_with_unifier(fcx: @FnCtxt,
1659 expected: Option<ty::t>,
1660 lvalue_pref: LvaluePreference,
1662 debug!(">> typechecking");
1664 fn check_method_argument_types(
1667 method_fn_ty: ty::t,
1668 callee_expr: &ast::Expr,
1669 args: &[@ast::Expr],
1670 deref_args: DerefArgs) -> ty::t {
1671 // HACK(eddyb) ignore provided self (it has special typeck rules).
1672 let args = args.slice_from(1);
1673 if ty::type_is_error(method_fn_ty) {
1674 let err_inputs = err_args(args.len());
1675 check_argument_types(fcx, sp, err_inputs, callee_expr,
1676 args, deref_args, false);
1679 match ty::get(method_fn_ty).sty {
1680 ty::ty_bare_fn(ref fty) => {
1681 // HACK(eddyb) ignore self in the definition (see above).
1682 check_argument_types(fcx, sp, fty.sig.inputs.slice_from(1),
1683 callee_expr, args, deref_args,
1688 fcx.tcx().sess.span_bug(
1690 format!("method without bare fn type"));
1696 fn check_argument_types(fcx: @FnCtxt,
1698 fn_inputs: &[ty::t],
1699 callee_expr: &ast::Expr,
1700 args: &[@ast::Expr],
1701 deref_args: DerefArgs,
1705 * Generic function that factors out common logic from
1706 * function calls, method calls and overloaded operators.
1709 let tcx = fcx.ccx.tcx;
1711 // Grab the argument types, supplying fresh type variables
1712 // if the wrong number of arguments were supplied
1713 let supplied_arg_count = args.len();
1714 let expected_arg_count = fn_inputs.len();
1715 let formal_tys = if expected_arg_count == supplied_arg_count {
1716 fn_inputs.map(|a| *a)
1717 } else if variadic {
1718 if supplied_arg_count >= expected_arg_count {
1719 fn_inputs.map(|a| *a)
1722 "this function takes at least {nexpected, plural, =1{# parameter} \
1723 other{# parameters}} \
1724 but {nsupplied, plural, =1{# parameter was} \
1725 other{# parameters were}} supplied",
1726 nexpected = expected_arg_count,
1727 nsupplied = supplied_arg_count);
1729 tcx.sess.span_err(sp, msg);
1731 err_args(supplied_arg_count)
1735 "this function takes {nexpected, plural, =1{# parameter} \
1736 other{# parameters}} \
1737 but {nsupplied, plural, =1{# parameter was} \
1738 other{# parameters were}} supplied",
1739 nexpected = expected_arg_count,
1740 nsupplied = supplied_arg_count);
1742 tcx.sess.span_err(sp, msg);
1744 err_args(supplied_arg_count)
1747 debug!("check_argument_types: formal_tys={:?}",
1748 formal_tys.map(|t| fcx.infcx().ty_to_str(*t)));
1750 // Check the arguments.
1751 // We do this in a pretty awful way: first we typecheck any arguments
1752 // that are not anonymous functions, then we typecheck the anonymous
1753 // functions. This is so that we have more information about the types
1754 // of arguments when we typecheck the functions. This isn't really the
1755 // right way to do this.
1756 let xs = [false, true];
1757 for check_blocks in xs.iter() {
1758 let check_blocks = *check_blocks;
1759 debug!("check_blocks={}", check_blocks);
1761 // More awful hacks: before we check the blocks, try to do
1762 // an "opportunistic" vtable resolution of any trait
1763 // bounds on the call.
1765 vtable::early_resolve_expr(callee_expr, fcx, true);
1768 // For variadic functions, we don't have a declared type for all of
1769 // the arguments hence we only do our usual type checking with
1770 // the arguments who's types we do know.
1771 let t = if variadic {
1776 for (i, arg) in args.iter().take(t).enumerate() {
1777 let is_block = match arg.node {
1778 ast::ExprFnBlock(..) |
1779 ast::ExprProc(..) => true,
1783 if is_block == check_blocks {
1784 debug!("checking the argument");
1785 let mut formal_ty = formal_tys[i];
1789 match ty::get(formal_ty).sty {
1790 ty::ty_rptr(_, mt) => formal_ty = mt.ty,
1793 // So we hit this case when one implements the
1794 // operator traits but leaves an argument as
1795 // just T instead of &T. We'll catch it in the
1796 // mismatch impl/trait method phase no need to
1799 formal_ty = ty::mk_err();
1806 check_expr_coercable_to_type(fcx, *arg, formal_ty);
1812 // We also need to make sure we at least write the ty of the other
1813 // arguments which we skipped above.
1815 for arg in args.iter().skip(expected_arg_count) {
1816 check_expr(fcx, *arg);
1818 // There are a few types which get autopromoted when passed via varargs
1819 // in C but we just error out instead and require explicit casts.
1820 let arg_ty = structurally_resolved_type(fcx, arg.span, fcx.expr_ty(*arg));
1821 match ty::get(arg_ty).sty {
1822 ty::ty_float(ast::TyF32) => {
1823 fcx.type_error_message(arg.span,
1824 |t| format!("can't pass an {} to variadic function, \
1825 cast to c_double", t), arg_ty, None);
1827 ty::ty_int(ast::TyI8) | ty::ty_int(ast::TyI16) | ty::ty_bool => {
1828 fcx.type_error_message(arg.span,
1829 |t| format!("can't pass {} to variadic function, cast to c_int",
1832 ty::ty_uint(ast::TyU8) | ty::ty_uint(ast::TyU16) => {
1833 fcx.type_error_message(arg.span,
1834 |t| format!("can't pass {} to variadic function, cast to c_uint",
1843 fn err_args(len: uint) -> Vec<ty::t> {
1844 vec::from_fn(len, |_| ty::mk_err())
1847 fn write_call(fcx: @FnCtxt, call_expr: &ast::Expr, output: ty::t) {
1848 fcx.write_ty(call_expr.id, output);
1851 // A generic function for doing all of the checking for call expressions
1852 fn check_call(fcx: @FnCtxt,
1853 call_expr: &ast::Expr,
1855 args: &[@ast::Expr]) {
1856 // Index expressions need to be handled separately, to inform them
1857 // that they appear in call position.
1860 // Store the type of `f` as the type of the callee
1861 let fn_ty = fcx.expr_ty(f);
1863 // Extract the function signature from `in_fty`.
1864 let fn_sty = structure_of(fcx, f.span, fn_ty);
1866 // This is the "default" function signature, used in case of error.
1867 // In that case, we check each argument against "error" in order to
1868 // set up all the node type bindings.
1869 let error_fn_sig = FnSig {
1870 binder_id: ast::CRATE_NODE_ID,
1871 inputs: err_args(args.len()),
1872 output: ty::mk_err(),
1876 let fn_sig = match *fn_sty {
1877 ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, ..}) |
1878 ty::ty_closure(ty::ClosureTy {sig: ref sig, ..}) => sig,
1880 fcx.type_error_message(call_expr.span, |actual| {
1881 format!("expected function but \
1882 found `{}`", actual) }, fn_ty, None);
1887 // Replace any bound regions that appear in the function
1888 // signature with region variables
1889 let (_, fn_sig) = replace_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
1891 .next_region_var(infer::BoundRegionInFnCall(call_expr.span, br))
1894 // Call the generic checker.
1895 check_argument_types(fcx, call_expr.span, fn_sig.inputs, f,
1896 args, DontDerefArgs, fn_sig.variadic);
1898 write_call(fcx, call_expr, fn_sig.output);
1901 // Checks a method call.
1902 fn check_method_call(fcx: @FnCtxt,
1904 method_name: ast::Ident,
1905 args: &[@ast::Expr],
1906 tps: &[ast::P<ast::Ty>]) {
1908 // We can't know if we need &mut self before we look up the method,
1909 // so treat the receiver as mutable just in case - only explicit
1910 // overloaded dereferences care about the distinction.
1911 check_expr_with_lvalue_pref(fcx, rcvr, PreferMutLvalue);
1913 // no need to check for bot/err -- callee does that
1914 let expr_t = structurally_resolved_type(fcx,
1918 let tps = tps.map(|&ast_ty| fcx.to_ty(ast_ty));
1919 let fn_ty = match method::lookup(fcx, expr, rcvr,
1923 CheckTraitsAndInherentMethods,
1924 AutoderefReceiver) {
1926 let method_ty = method.ty;
1927 fcx.inh.method_map.borrow_mut().get().insert(expr.id, method);
1931 debug!("(checking method call) failing expr is {}", expr.id);
1933 fcx.type_error_message(expr.span,
1935 format!("type `{}` does not implement any method in scope \
1937 actual, token::get_ident(method_name))
1942 // Add error type for the result
1943 fcx.write_error(expr.id);
1948 // Call the generic checker.
1949 let ret_ty = check_method_argument_types(fcx, expr.span,
1953 write_call(fcx, expr, ret_ty);
1956 // A generic function for checking the then and else in an if
1958 fn check_then_else(fcx: @FnCtxt,
1959 cond_expr: &ast::Expr,
1960 then_blk: &ast::Block,
1961 opt_else_expr: Option<@ast::Expr>,
1964 expected: Option<ty::t>) {
1965 check_expr_has_type(fcx, cond_expr, ty::mk_bool());
1967 let branches_ty = match opt_else_expr {
1968 Some(else_expr) => {
1969 check_block_with_expected(fcx, then_blk, expected);
1970 let then_ty = fcx.node_ty(then_blk.id);
1971 check_expr_with_opt_hint(fcx, else_expr, expected);
1972 let else_ty = fcx.expr_ty(else_expr);
1973 infer::common_supertype(fcx.infcx(),
1974 infer::IfExpression(sp),
1980 check_block_no_value(fcx, then_blk);
1985 let cond_ty = fcx.expr_ty(cond_expr);
1986 let if_ty = if ty::type_is_error(cond_ty) {
1988 } else if ty::type_is_bot(cond_ty) {
1994 fcx.write_ty(id, if_ty);
1997 fn lookup_op_method(fcx: @FnCtxt,
2001 trait_did: Option<ast::DefId>,
2002 args: &[@ast::Expr],
2003 autoderef_receiver: AutoderefReceiverFlag,
2004 unbound_method: ||) -> ty::t {
2005 let method = match trait_did {
2006 Some(trait_did) => {
2007 method::lookup_in_trait(fcx, op_ex, args[0], opname, trait_did,
2008 self_t, [], autoderef_receiver)
2014 let method_ty = method.ty;
2015 fcx.inh.method_map.borrow_mut().get().insert(op_ex.id, method);
2016 check_method_argument_types(fcx, op_ex.span,
2022 // Check the args anyway
2023 // so we get all the error messages
2024 let expected_ty = ty::mk_err();
2025 check_method_argument_types(fcx, op_ex.span,
2033 // could be either an expr_binop or an expr_assign_binop
2034 fn check_binop(fcx: @FnCtxt,
2039 is_binop_assignment: IsBinopAssignment) {
2040 let tcx = fcx.ccx.tcx;
2042 let lvalue_pref = match is_binop_assignment {
2043 BinopAssignment => PreferMutLvalue,
2044 SimpleBinop => NoPreference
2046 check_expr_with_lvalue_pref(fcx, lhs, lvalue_pref);
2048 // Callee does bot / err checking
2049 let lhs_t = structurally_resolved_type(fcx, lhs.span,
2052 if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) {
2053 // Shift is a special case: rhs can be any integral type
2054 check_expr(fcx, rhs);
2055 let rhs_t = fcx.expr_ty(rhs);
2056 require_integral(fcx, rhs.span, rhs_t);
2057 fcx.write_ty(expr.id, lhs_t);
2061 if ty::is_binopable(tcx, lhs_t, op) {
2062 let tvar = fcx.infcx().next_ty_var();
2063 demand::suptype(fcx, expr.span, tvar, lhs_t);
2064 check_expr_has_type(fcx, rhs, tvar);
2066 let result_t = match op {
2067 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGe |
2068 ast::BiGt => ty::mk_bool(),
2072 fcx.write_ty(expr.id, result_t);
2076 if op == ast::BiOr || op == ast::BiAnd {
2077 // This is an error; one of the operands must have the wrong
2079 fcx.write_error(expr.id);
2080 fcx.write_error(rhs.id);
2081 fcx.type_error_message(expr.span, |actual| {
2082 format!("binary operation `{}` cannot be applied \
2084 ast_util::binop_to_str(op), actual)},
2089 // Check for overloaded operators if not an assignment.
2090 let result_t = if is_binop_assignment == SimpleBinop {
2091 check_user_binop(fcx, expr, lhs, lhs_t, op, rhs)
2093 fcx.type_error_message(expr.span,
2095 format!("binary assignment operation \
2096 `{}=` cannot be applied to type `{}`",
2097 ast_util::binop_to_str(op),
2102 check_expr(fcx, rhs);
2106 fcx.write_ty(expr.id, result_t);
2107 if ty::type_is_error(result_t) {
2108 fcx.write_ty(rhs.id, result_t);
2112 fn check_user_binop(fcx: @FnCtxt,
2114 lhs_expr: @ast::Expr,
2115 lhs_resolved_t: ty::t,
2117 rhs: @ast::Expr) -> ty::t {
2118 let tcx = fcx.ccx.tcx;
2119 let lang = tcx.lang_items;
2120 let (name, trait_did) = match op {
2121 ast::BiAdd => ("add", lang.add_trait()),
2122 ast::BiSub => ("sub", lang.sub_trait()),
2123 ast::BiMul => ("mul", lang.mul_trait()),
2124 ast::BiDiv => ("div", lang.div_trait()),
2125 ast::BiRem => ("rem", lang.rem_trait()),
2126 ast::BiBitXor => ("bitxor", lang.bitxor_trait()),
2127 ast::BiBitAnd => ("bitand", lang.bitand_trait()),
2128 ast::BiBitOr => ("bitor", lang.bitor_trait()),
2129 ast::BiShl => ("shl", lang.shl_trait()),
2130 ast::BiShr => ("shr", lang.shr_trait()),
2131 ast::BiLt => ("lt", lang.ord_trait()),
2132 ast::BiLe => ("le", lang.ord_trait()),
2133 ast::BiGe => ("ge", lang.ord_trait()),
2134 ast::BiGt => ("gt", lang.ord_trait()),
2135 ast::BiEq => ("eq", lang.eq_trait()),
2136 ast::BiNe => ("ne", lang.eq_trait()),
2137 ast::BiAnd | ast::BiOr => {
2138 check_expr(fcx, rhs);
2139 return ty::mk_err();
2142 lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
2143 trait_did, [lhs_expr, rhs], DontAutoderefReceiver, || {
2144 fcx.type_error_message(ex.span, |actual| {
2145 format!("binary operation `{}` cannot be applied to type `{}`",
2146 ast_util::binop_to_str(op), actual)
2147 }, lhs_resolved_t, None)
2151 fn check_user_unop(fcx: @FnCtxt,
2154 trait_did: Option<ast::DefId>,
2156 rhs_expr: @ast::Expr,
2157 rhs_t: ty::t) -> ty::t {
2158 lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
2159 trait_did, [rhs_expr], DontAutoderefReceiver, || {
2160 fcx.type_error_message(ex.span, |actual| {
2161 format!("cannot apply unary operator `{}` to type `{}`", op_str, actual)
2166 // Resolves `expected` by a single level if it is a variable and passes it
2167 // through the `unpack` function. It there is no expected type or
2168 // resolution is not possible (e.g., no constraints yet present), just
2170 fn unpack_expected<O>(
2172 expected: Option<ty::t>,
2173 unpack: |&ty::sty| -> Option<O>)
2177 match resolve_type(fcx.infcx(), t, force_tvar) {
2178 Ok(t) => unpack(&ty::get(t).sty),
2186 fn check_expr_fn(fcx: @FnCtxt,
2188 ast_sigil_opt: Option<ast::Sigil>,
2190 body: ast::P<ast::Block>,
2192 expected: Option<ty::t>) {
2193 let tcx = fcx.ccx.tcx;
2195 // Find the expected input/output types (if any). Substitute
2196 // fresh bound regions for any bound regions we find in the
2197 // expected types so as to avoid capture.
2199 // Also try to pick up inferred purity and sigil, defaulting
2200 // to impure and block. Note that we only will use those for
2201 // block syntax lambdas; that is, lambdas without explicit
2203 let expected_sty = unpack_expected(fcx,
2205 |x| Some((*x).clone()));
2206 let error_happened = false;
2211 expected_bounds) = {
2212 match expected_sty {
2213 Some(ty::ty_closure(ref cenv)) => {
2215 replace_bound_regions_in_fn_sig(
2217 |_| fcx.inh.infcx.fresh_bound_region(expr.id));
2218 (Some(sig), cenv.purity, cenv.sigil,
2219 cenv.onceness, cenv.bounds)
2222 // Not an error! Means we're inferring the closure type
2223 let mut sigil = ast::BorrowedSigil;
2224 let mut onceness = ast::Many;
2225 let mut bounds = ty::EmptyBuiltinBounds();
2227 ast::ExprProc(..) => {
2228 sigil = ast::OwnedSigil;
2229 onceness = ast::Once;
2230 bounds.add(ty::BoundSend);
2234 (None, ast::ImpureFn, sigil,
2240 // If the proto is specified, use that, otherwise select a
2241 // proto based on inference.
2242 let (sigil, purity) = match ast_sigil_opt {
2243 Some(p) => (p, ast::ImpureFn),
2244 None => (expected_sigil, expected_purity)
2247 // construct the function type
2248 let fn_ty = astconv::ty_of_closure(fcx,
2261 let fty = if error_happened {
2263 binder_id: ast::CRATE_NODE_ID,
2264 inputs: fn_ty.sig.inputs.map(|_| ty::mk_err()),
2265 output: ty::mk_err(),
2270 let fn_ty_copy = fn_ty.clone();
2271 fty_sig = fn_ty.sig.clone();
2272 ty::mk_closure(tcx, fn_ty_copy)
2275 debug!("check_expr_fn_with_unifier fty={}",
2276 fcx.infcx().ty_to_str(fty));
2278 fcx.write_ty(expr.id, fty);
2280 let (inherited_purity, id) =
2281 ty::determine_inherited_purity((fcx.ps.get().purity,
2286 check_fn(fcx.ccx, inherited_purity, &fty_sig,
2287 decl, id, body, fn_kind, fcx.inh);
2291 // Check field access expressions
2292 fn check_field(fcx: @FnCtxt,
2294 lvalue_pref: LvaluePreference,
2297 tys: &[ast::P<ast::Ty>]) {
2298 let tcx = fcx.ccx.tcx;
2299 let bot = check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
2300 let expr_t = structurally_resolved_type(fcx, expr.span,
2302 let (base_t, derefs) = do_autoderef(fcx, expr.span, expr_t);
2304 match *structure_of(fcx, expr.span, base_t) {
2305 ty::ty_struct(base_id, ref substs) => {
2306 // This is just for fields -- the same code handles
2307 // methods in both classes and traits
2309 // (1) verify that the class id actually has a field called
2311 debug!("class named {}", ppaux::ty_to_str(tcx, base_t));
2312 let cls_items = ty::lookup_struct_fields(tcx, base_id);
2313 match lookup_field_ty(tcx, base_id, cls_items,
2314 field, &(*substs)) {
2316 // (2) look up what field's type is, and return it
2317 fcx.write_ty(expr.id, field_ty);
2318 fcx.write_autoderef_adjustment(base.id, derefs);
2327 let tps: Vec<ty::t> = tys.iter().map(|&ty| fcx.to_ty(ty)).collect();
2328 match method::lookup(fcx,
2335 CheckTraitsAndInherentMethods,
2336 AutoderefReceiver) {
2338 fcx.type_error_message(
2341 format!("attempted to take value of method `{}` on type `{}` \
2342 (try writing an anonymous function)",
2343 token::get_name(field), actual)
2349 fcx.type_error_message(
2352 format!("attempted access of field `{}` on type `{}`, \
2353 but no field with that name was found",
2354 token::get_name(field), actual)
2360 fcx.write_error(expr.id);
2363 fn check_struct_or_variant_fields(fcx: @FnCtxt,
2366 class_id: ast::DefId,
2367 node_id: ast::NodeId,
2368 substitutions: ty::substs,
2369 field_types: &[ty::field_ty],
2370 ast_fields: &[ast::Field],
2371 check_completeness: bool) {
2372 let tcx = fcx.ccx.tcx;
2374 let mut class_field_map = HashMap::new();
2375 let mut fields_found = 0;
2376 for field in field_types.iter() {
2377 class_field_map.insert(field.name, (field.id, false));
2380 let mut error_happened = false;
2382 // Typecheck each field.
2383 for field in ast_fields.iter() {
2384 let mut expected_field_type = ty::mk_err();
2386 let pair = class_field_map.find(&field.ident.node.name).map(|x| *x);
2389 fcx.type_error_message(
2392 format!("structure `{}` has no field named `{}`",
2393 actual, token::get_ident(field.ident.node))
2394 }, struct_ty, None);
2395 error_happened = true;
2397 Some((_, true)) => {
2400 format!("field `{}` specified more than once",
2401 token::get_ident(field.ident.node)));
2402 error_happened = true;
2404 Some((field_id, false)) => {
2405 expected_field_type =
2406 ty::lookup_field_type(
2407 tcx, class_id, field_id, &substitutions);
2408 class_field_map.insert(
2409 field.ident.node.name, (field_id, true));
2413 // Make sure to give a type to the field even if there's
2414 // an error, so we can continue typechecking
2415 check_expr_coercable_to_type(
2418 expected_field_type);
2422 fcx.write_error(node_id);
2425 if check_completeness && !error_happened {
2426 // Make sure the programmer specified all the fields.
2427 assert!(fields_found <= field_types.len());
2428 if fields_found < field_types.len() {
2429 let mut missing_fields = Vec::new();
2430 for class_field in field_types.iter() {
2431 let name = class_field.name;
2432 let (_, seen) = *class_field_map.get(&name);
2434 missing_fields.push(~"`" + token::get_name(name).get() + "`");
2438 tcx.sess.span_err(span,
2439 format!("missing {nfields, plural, =1{field} other{fields}}: {fields}",
2440 nfields = missing_fields.len(),
2441 fields = missing_fields.connect(", ")));
2445 if !error_happened {
2446 fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx,
2447 class_id, substitutions));
2451 fn check_struct_constructor(fcx: @FnCtxt,
2453 span: codemap::Span,
2454 class_id: ast::DefId,
2455 fields: &[ast::Field],
2456 base_expr: Option<@ast::Expr>) {
2457 let tcx = fcx.ccx.tcx;
2459 // Look up the number of type parameters and the raw type, and
2460 // determine whether the class is region-parameterized.
2461 let item_type = ty::lookup_item_type(tcx, class_id);
2462 let type_parameter_count = item_type.generics.type_param_defs().len();
2463 let region_parameter_count = item_type.generics.region_param_defs().len();
2464 let raw_type = item_type.ty;
2466 // Generate the struct type.
2467 let regions = fcx.infcx().next_region_vars(
2468 infer::BoundRegionInTypeOrImpl(span),
2469 region_parameter_count).move_iter().collect();
2470 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2471 let substitutions = substs {
2472 regions: ty::NonerasedRegions(opt_vec::from(regions)),
2474 tps: type_parameters
2477 let mut struct_type = ty::subst(tcx, &substitutions, raw_type);
2479 // Look up and check the fields.
2480 let class_fields = ty::lookup_struct_fields(tcx, class_id);
2481 check_struct_or_variant_fields(fcx,
2489 base_expr.is_none());
2490 if ty::type_is_error(fcx.node_ty(id)) {
2491 struct_type = ty::mk_err();
2494 // Check the base expression if necessary.
2497 Some(base_expr) => {
2498 check_expr_has_type(fcx, base_expr, struct_type);
2499 if ty::type_is_bot(fcx.node_ty(base_expr.id)) {
2500 struct_type = ty::mk_bot();
2505 // Write in the resulting type.
2506 fcx.write_ty(id, struct_type);
2509 fn check_struct_enum_variant(fcx: @FnCtxt,
2511 span: codemap::Span,
2512 enum_id: ast::DefId,
2513 variant_id: ast::DefId,
2514 fields: &[ast::Field]) {
2515 let tcx = fcx.ccx.tcx;
2517 // Look up the number of type parameters and the raw type, and
2518 // determine whether the enum is region-parameterized.
2519 let item_type = ty::lookup_item_type(tcx, enum_id);
2520 let type_parameter_count = item_type.generics.type_param_defs().len();
2521 let region_parameter_count = item_type.generics.region_param_defs().len();
2522 let raw_type = item_type.ty;
2524 // Generate the enum type.
2525 let regions = fcx.infcx().next_region_vars(
2526 infer::BoundRegionInTypeOrImpl(span),
2527 region_parameter_count).move_iter().collect();
2528 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2529 let substitutions = substs {
2530 regions: ty::NonerasedRegions(opt_vec::from(regions)),
2532 tps: type_parameters
2535 let enum_type = ty::subst(tcx, &substitutions, raw_type);
2537 // Look up and check the enum variant fields.
2538 let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2539 check_struct_or_variant_fields(fcx,
2548 fcx.write_ty(id, enum_type);
2551 let tcx = fcx.ccx.tcx;
2554 ast::ExprVstore(ev, vst) => {
2555 let typ = match ev.node {
2556 ast::ExprLit(lit) if ast_util::lit_is_str(lit) => {
2557 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2560 ast::ExprVec(ref args, mutbl) => {
2561 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2562 let mut any_error = false;
2563 let mut any_bot = false;
2564 let mutability = match vst {
2565 ast::ExprVstoreMutSlice => ast::MutMutable,
2568 let t: ty::t = fcx.infcx().next_ty_var();
2569 for e in args.iter() {
2570 check_expr_has_type(fcx, *e, t);
2571 let arg_t = fcx.expr_ty(*e);
2572 if ty::type_is_error(arg_t) {
2575 else if ty::type_is_bot(arg_t) {
2584 ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2587 ast::ExprRepeat(element, count_expr, mutbl) => {
2588 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2589 let _ = ty::eval_repeat_count(fcx, count_expr);
2590 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2591 let mutability = match vst {
2592 ast::ExprVstoreMutSlice => ast::MutMutable,
2595 let t: ty::t = fcx.infcx().next_ty_var();
2596 check_expr_has_type(fcx, element, t);
2597 let arg_t = fcx.expr_ty(element);
2598 if ty::type_is_error(arg_t) {
2600 } else if ty::type_is_bot(arg_t) {
2603 ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2607 tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence")
2609 fcx.write_ty(ev.id, typ);
2610 fcx.write_ty(id, typ);
2613 ast::ExprBox(place, subexpr) => {
2614 check_expr(fcx, place);
2615 check_expr(fcx, subexpr);
2617 let mut checked = false;
2619 ast::ExprPath(ref path) => {
2620 // FIXME(pcwalton): For now we hardcode the two permissible
2621 // places: the exchange heap and the managed heap.
2622 let definition = lookup_def(fcx, path.span, place.id);
2623 let def_id = ast_util::def_id_of_def(definition);
2624 match tcx.lang_items.items[ExchangeHeapLangItem as uint] {
2625 Some(item_def_id) if def_id == item_def_id => {
2626 fcx.write_ty(id, ty::mk_uniq(tcx,
2627 fcx.expr_ty(subexpr)));
2630 Some(_) | None => {}
2633 match tcx.lang_items
2634 .items[ManagedHeapLangItem as uint] {
2635 Some(item_def_id) if def_id == item_def_id => {
2636 // Assign the magic `Gc<T>` struct.
2638 match tcx.lang_items
2639 .require(GcLangItem) {
2642 tcx.sess.span_err(expr.span, msg);
2644 krate: ast::CRATE_NODE_ID,
2645 node: ast::DUMMY_NODE_ID,
2650 ty::NonerasedRegions(opt_vec::Empty);
2651 let sty = ty::mk_struct(tcx,
2661 fcx.write_ty(id, sty);
2664 Some(_) | None => {}
2672 tcx.sess.span_err(expr.span,
2673 "only the managed heap and exchange heap are \
2674 currently supported")
2678 ast::ExprLit(lit) => {
2679 let typ = check_lit(fcx, lit);
2680 fcx.write_ty(id, typ);
2682 ast::ExprBinary(op, lhs, rhs) => {
2683 check_binop(fcx, expr, op, lhs, rhs, SimpleBinop);
2685 let lhs_ty = fcx.expr_ty(lhs);
2686 let rhs_ty = fcx.expr_ty(rhs);
2687 if ty::type_is_error(lhs_ty) ||
2688 ty::type_is_error(rhs_ty) {
2689 fcx.write_error(id);
2691 else if ty::type_is_bot(lhs_ty) ||
2692 (ty::type_is_bot(rhs_ty) && !ast_util::lazy_binop(op)) {
2696 ast::ExprAssignOp(op, lhs, rhs) => {
2697 check_binop(fcx, expr, op, lhs, rhs, BinopAssignment);
2699 let lhs_t = fcx.expr_ty(lhs);
2700 let result_t = fcx.expr_ty(expr);
2701 demand::suptype(fcx, expr.span, result_t, lhs_t);
2703 let tcx = fcx.tcx();
2704 if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
2705 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2708 // Overwrite result of check_binop...this preserves existing behavior
2709 // but seems quite dubious with regard to user-defined methods
2710 // and so forth. - Niko
2711 if !ty::type_is_error(result_t)
2712 && !ty::type_is_bot(result_t) {
2713 fcx.write_nil(expr.id);
2716 ast::ExprUnary(unop, oprnd) => {
2717 let exp_inner = unpack_expected(fcx, expected, |sty| {
2719 ast::UnBox | ast::UnUniq => match *sty {
2720 ty::ty_box(ty) | ty::ty_uniq(ty) => Some(ty),
2723 ast::UnNot | ast::UnNeg => expected,
2724 ast::UnDeref => None
2727 let lvalue_pref = match unop {
2728 ast::UnDeref => lvalue_pref,
2731 check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, exp_inner, lvalue_pref);
2732 let mut oprnd_t = fcx.expr_ty(oprnd);
2733 if !ty::type_is_error(oprnd_t) && !ty::type_is_bot(oprnd_t) {
2736 oprnd_t = ty::mk_box(tcx, oprnd_t)
2739 oprnd_t = ty::mk_uniq(tcx, oprnd_t);
2742 oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
2743 oprnd_t = match ty::deref(oprnd_t, true) {
2745 None => match try_overloaded_deref(fcx, expr, oprnd,
2746 oprnd_t, lvalue_pref) {
2749 let is_newtype = match ty::get(oprnd_t).sty {
2750 ty::ty_struct(did, ref substs) => {
2751 let fields = ty::struct_fields(fcx.tcx(), did, substs);
2753 && fields[0].ident == token::special_idents::unnamed_field
2758 // This is an obsolete struct deref
2759 tcx.sess.span_err(expr.span,
2760 "single-field tuple-structs can \
2761 no longer be dereferenced");
2763 fcx.type_error_message(expr.span, |actual| {
2764 format!("type `{}` cannot be dereferenced", actual)
2773 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2775 if !(ty::type_is_integral(oprnd_t) ||
2776 ty::get(oprnd_t).sty == ty::ty_bool) {
2777 oprnd_t = check_user_unop(fcx, "!", "not",
2778 tcx.lang_items.not_trait(),
2779 expr, oprnd, oprnd_t);
2783 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2785 if !(ty::type_is_integral(oprnd_t) ||
2786 ty::type_is_fp(oprnd_t)) {
2787 oprnd_t = check_user_unop(fcx, "-", "neg",
2788 tcx.lang_items.neg_trait(),
2789 expr, oprnd, oprnd_t);
2794 fcx.write_ty(id, oprnd_t);
2796 ast::ExprAddrOf(mutbl, oprnd) => {
2797 let hint = unpack_expected(
2799 |sty| match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty),
2801 let lvalue_pref = match mutbl {
2802 ast::MutMutable => PreferMutLvalue,
2803 ast::MutImmutable => NoPreference
2805 check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, hint, lvalue_pref);
2807 // Note: at this point, we cannot say what the best lifetime
2808 // is to use for resulting pointer. We want to use the
2809 // shortest lifetime possible so as to avoid spurious borrowck
2810 // errors. Moreover, the longest lifetime will depend on the
2811 // precise details of the value whose address is being taken
2812 // (and how long it is valid), which we don't know yet until type
2813 // inference is complete.
2815 // Therefore, here we simply generate a region variable. The
2816 // region inferencer will then select the ultimate value.
2817 // Finally, borrowck is charged with guaranteeing that the
2818 // value whose address was taken can actually be made to live
2819 // as long as it needs to live.
2820 let region = fcx.infcx().next_region_var(
2821 infer::AddrOfRegion(expr.span));
2823 let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
2824 let oprnd_t = if ty::type_is_error(tm.ty) {
2826 } else if ty::type_is_bot(tm.ty) {
2830 ty::mk_rptr(tcx, region, tm)
2832 fcx.write_ty(id, oprnd_t);
2834 ast::ExprPath(ref pth) => {
2835 let defn = lookup_def(fcx, pth.span, id);
2837 check_type_parameter_positions_in_path(fcx, pth, defn);
2838 let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2839 instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
2841 ast::ExprInlineAsm(ref ia) => {
2842 for &(_, input) in ia.inputs.iter() {
2843 check_expr(fcx, input);
2845 for &(_, out) in ia.outputs.iter() {
2846 check_expr(fcx, out);
2850 ast::ExprMac(_) => tcx.sess.bug("unexpanded macro"),
2851 ast::ExprBreak(_) => { fcx.write_bot(id); }
2852 ast::ExprAgain(_) => { fcx.write_bot(id); }
2853 ast::ExprRet(expr_opt) => {
2854 let ret_ty = fcx.ret_ty;
2856 None => match fcx.mk_eqty(false, infer::Misc(expr.span),
2857 ret_ty, ty::mk_nil()) {
2858 result::Ok(_) => { /* fall through */ }
2862 "`return;` in function returning non-nil");
2866 check_expr_has_type(fcx, e, ret_ty);
2871 ast::ExprLogLevel => {
2872 fcx.write_ty(id, ty::mk_u32())
2874 ast::ExprParen(a) => {
2875 check_expr_with_opt_hint_and_lvalue_pref(fcx, a, expected, lvalue_pref);
2876 fcx.write_ty(id, fcx.expr_ty(a));
2878 ast::ExprAssign(lhs, rhs) => {
2879 check_expr_with_lvalue_pref(fcx, lhs, PreferMutLvalue);
2881 let tcx = fcx.tcx();
2882 if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
2883 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2886 let lhs_ty = fcx.expr_ty(lhs);
2887 check_expr_has_type(fcx, rhs, lhs_ty);
2888 let rhs_ty = fcx.expr_ty(rhs);
2890 if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
2891 fcx.write_error(id);
2892 } else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
2898 ast::ExprIf(cond, then_blk, opt_else_expr) => {
2899 check_then_else(fcx, cond, then_blk, opt_else_expr,
2900 id, expr.span, expected);
2902 ast::ExprWhile(cond, body) => {
2903 check_expr_has_type(fcx, cond, ty::mk_bool());
2904 check_block_no_value(fcx, body);
2905 let cond_ty = fcx.expr_ty(cond);
2906 let body_ty = fcx.node_ty(body.id);
2907 if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) {
2908 fcx.write_error(id);
2910 else if ty::type_is_bot(cond_ty) {
2917 ast::ExprForLoop(..) =>
2918 fail!("non-desugared expr_for_loop"),
2919 ast::ExprLoop(body, _) => {
2920 check_block_no_value(fcx, (body));
2921 if !may_break(tcx, expr.id, body) {
2928 ast::ExprMatch(discrim, ref arms) => {
2929 _match::check_match(fcx, expr, discrim, arms.as_slice());
2931 ast::ExprFnBlock(decl, body) => {
2934 Some(ast::BorrowedSigil),
2940 ast::ExprProc(decl, body) => {
2943 Some(ast::OwnedSigil),
2949 ast::ExprBlock(b) => {
2950 check_block_with_expected(fcx, b, expected);
2951 fcx.write_ty(id, fcx.node_ty(b.id));
2953 ast::ExprCall(f, ref args) => {
2954 check_call(fcx, expr, f, args.as_slice());
2955 let f_ty = fcx.expr_ty(f);
2956 let (args_bot, args_err) = args.iter().fold((false, false),
2957 |(rest_bot, rest_err), a| {
2958 // is this not working?
2959 let a_ty = fcx.expr_ty(*a);
2960 (rest_bot || ty::type_is_bot(a_ty),
2961 rest_err || ty::type_is_error(a_ty))});
2962 if ty::type_is_error(f_ty) || args_err {
2963 fcx.write_error(id);
2965 else if ty::type_is_bot(f_ty) || args_bot {
2969 ast::ExprMethodCall(ident, ref tps, ref args) => {
2970 check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice());
2971 let arg_tys = args.map(|a| fcx.expr_ty(*a));
2972 let (args_bot, args_err) = arg_tys.iter().fold((false, false),
2973 |(rest_bot, rest_err), a| {
2974 (rest_bot || ty::type_is_bot(*a),
2975 rest_err || ty::type_is_error(*a))});
2977 fcx.write_error(id);
2978 } else if args_bot {
2982 ast::ExprCast(e, t) => {
2984 let t_1 = fcx.to_ty(t);
2985 let t_e = fcx.expr_ty(e);
2987 debug!("t_1={}", fcx.infcx().ty_to_str(t_1));
2988 debug!("t_e={}", fcx.infcx().ty_to_str(t_e));
2990 if ty::type_is_error(t_e) {
2991 fcx.write_error(id);
2993 else if ty::type_is_bot(t_e) {
2997 match ty::get(t_1).sty {
2998 // This will be looked up later on
2999 ty::ty_trait(..) => (),
3002 if ty::type_is_nil(t_e) {
3003 fcx.type_error_message(expr.span, |actual| {
3004 format!("cast from nil: `{}` as `{}`", actual,
3005 fcx.infcx().ty_to_str(t_1))
3007 } else if ty::type_is_nil(t_1) {
3008 fcx.type_error_message(expr.span, |actual| {
3009 format!("cast to nil: `{}` as `{}`", actual,
3010 fcx.infcx().ty_to_str(t_1))
3014 let t1 = structurally_resolved_type(fcx, e.span, t_1);
3015 let te = structurally_resolved_type(fcx, e.span, t_e);
3016 let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
3017 let t_1_is_char = type_is_char(fcx, expr.span, t_1);
3018 let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1);
3020 // casts to scalars other than `char` and `bare fn` are trivial
3021 let t_1_is_trivial = t_1_is_scalar &&
3022 !t_1_is_char && !t_1_is_bare_fn;
3024 if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial {
3025 // casts from C-like enums are allowed
3026 } else if t_1_is_char {
3027 let te = fcx.infcx().resolve_type_vars_if_possible(te);
3028 if ty::get(te).sty != ty::ty_uint(ast::TyU8) {
3029 fcx.type_error_message(expr.span, |actual| {
3030 format!("only `u8` can be cast as `char`, not `{}`", actual)
3033 } else if ty::get(t1).sty == ty::ty_bool {
3034 fcx.tcx().sess.span_err(expr.span,
3035 "cannot cast as `bool`, compare with zero instead");
3036 } else if type_is_region_ptr(fcx, expr.span, t_e) &&
3037 type_is_unsafe_ptr(fcx, expr.span, t_1) {
3039 fn is_vec(t: ty::t) -> bool {
3040 match ty::get(t).sty {
3041 ty::ty_vec(..) => true,
3045 fn types_compatible(fcx: @FnCtxt, sp: Span,
3046 t1: ty::t, t2: ty::t) -> bool {
3050 let el = ty::sequence_element_type(fcx.tcx(),
3052 infer::mk_eqty(fcx.infcx(), false,
3053 infer::Misc(sp), el, t2).is_ok()
3057 // Due to the limitations of LLVM global constants,
3058 // region pointers end up pointing at copies of
3059 // vector elements instead of the original values.
3060 // To allow unsafe pointers to work correctly, we
3061 // need to special-case obtaining an unsafe pointer
3062 // from a region pointer to a vector.
3064 /* this cast is only allowed from &[T] to *T or
3066 match (&ty::get(te).sty, &ty::get(t_1).sty) {
3067 (&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
3068 if types_compatible(fcx, e.span,
3069 mt1.ty, mt2.ty) => {
3070 /* this case is allowed */
3073 demand::coerce(fcx, e.span, t_1, e);
3076 } else if !(type_is_scalar(fcx,expr.span,t_e)
3077 && t_1_is_trivial) {
3079 If more type combinations should be supported than are
3080 supported here, then file an enhancement issue and
3081 record the issue number in this comment.
3083 fcx.type_error_message(expr.span, |actual| {
3084 format!("non-scalar cast: `{}` as `{}`", actual,
3085 fcx.infcx().ty_to_str(t_1))
3090 fcx.write_ty(id, t_1);
3093 ast::ExprVec(ref args, mutbl) => {
3094 let t: ty::t = fcx.infcx().next_ty_var();
3095 for e in args.iter() {
3096 check_expr_has_type(fcx, *e, t);
3098 let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutbl},
3099 ty::vstore_fixed(args.len()));
3100 fcx.write_ty(id, typ);
3102 ast::ExprRepeat(element, count_expr, mutbl) => {
3103 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
3104 let count = ty::eval_repeat_count(fcx, count_expr);
3105 let t: ty::t = fcx.infcx().next_ty_var();
3106 check_expr_has_type(fcx, element, t);
3107 let element_ty = fcx.expr_ty(element);
3108 if ty::type_is_error(element_ty) {
3109 fcx.write_error(id);
3111 else if ty::type_is_bot(element_ty) {
3115 let t = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: mutbl},
3116 ty::vstore_fixed(count));
3117 fcx.write_ty(id, t);
3120 ast::ExprTup(ref elts) => {
3121 let flds = unpack_expected(fcx, expected, |sty| {
3123 ty::ty_tup(ref flds) => Some((*flds).clone()),
3127 let mut bot_field = false;
3128 let mut err_field = false;
3130 let elt_ts = elts.iter().enumerate().map(|(i, e)| {
3131 let opt_hint = match flds {
3132 Some(ref fs) if i < fs.len() => Some(fs[i]),
3135 check_expr_with_opt_hint(fcx, *e, opt_hint);
3136 let t = fcx.expr_ty(*e);
3137 err_field = err_field || ty::type_is_error(t);
3138 bot_field = bot_field || ty::type_is_bot(t);
3143 } else if err_field {
3144 fcx.write_error(id);
3146 let typ = ty::mk_tup(tcx, elt_ts);
3147 fcx.write_ty(id, typ);
3150 ast::ExprStruct(ref path, ref fields, base_expr) => {
3151 // Resolve the path.
3152 let def_map = tcx.def_map.borrow();
3153 match def_map.get().find(&id) {
3154 Some(&ast::DefStruct(type_def_id)) => {
3155 check_struct_constructor(fcx, id, expr.span, type_def_id,
3156 fields.as_slice(), base_expr);
3158 Some(&ast::DefVariant(enum_id, variant_id, _)) => {
3159 check_struct_enum_variant(fcx, id, expr.span, enum_id,
3160 variant_id, fields.as_slice());
3163 tcx.sess.span_bug(path.span,
3164 "structure constructor does not name a structure type");
3168 ast::ExprField(base, field, ref tys) => {
3169 check_field(fcx, expr, lvalue_pref, base, field.name, tys.as_slice());
3171 ast::ExprIndex(base, idx) => {
3172 check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
3173 check_expr(fcx, idx);
3174 let raw_base_t = fcx.expr_ty(base);
3175 let idx_t = fcx.expr_ty(idx);
3176 if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
3177 fcx.write_ty(id, raw_base_t);
3178 } else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
3179 fcx.write_ty(id, idx_t);
3181 let (base_t, derefs) = do_autoderef(fcx, expr.span, raw_base_t);
3182 let base_sty = structure_of(fcx, expr.span, base_t);
3183 match ty::index_sty(base_sty) {
3185 require_integral(fcx, idx.span, idx_t);
3186 fcx.write_ty(id, mt.ty);
3187 fcx.write_autoderef_adjustment(base.id, derefs);
3190 let resolved = structurally_resolved_type(fcx,
3193 let error_message = || {
3194 fcx.type_error_message(expr.span,
3196 format!("cannot index a value \
3203 let ret_ty = lookup_op_method(fcx,
3206 token::intern("index"),
3207 tcx.lang_items.index_trait(),
3211 fcx.write_ty(id, ret_ty);
3218 debug!("type of expr({}) {} is...", expr.id,
3219 syntax::print::pprust::expr_to_str(expr));
3220 debug!("... {}, expected is {}",
3221 ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
3223 Some(t) => ppaux::ty_to_str(tcx, t),
3230 pub fn require_integral(fcx: @FnCtxt, sp: Span, t: ty::t) {
3231 if !type_is_integral(fcx, sp, t) {
3232 fcx.type_error_message(sp, |actual| {
3233 format!("mismatched types: expected integral type but found `{}`",
3239 pub fn check_decl_initializer(fcx: @FnCtxt,
3243 let local_ty = fcx.local_ty(init.span, nid);
3244 check_expr_coercable_to_type(fcx, init, local_ty)
3247 pub fn check_decl_local(fcx: @FnCtxt, local: &ast::Local) {
3248 let tcx = fcx.ccx.tcx;
3250 let t = fcx.local_ty(local.span, local.id);
3251 fcx.write_ty(local.id, t);
3255 check_decl_initializer(fcx, local.id, init);
3256 let init_ty = fcx.expr_ty(init);
3257 if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
3258 fcx.write_ty(local.id, init_ty);
3264 let pcx = pat_ctxt {
3266 map: pat_id_map(tcx.def_map, local.pat),
3268 _match::check_pat(&pcx, local.pat, t);
3269 let pat_ty = fcx.node_ty(local.pat.id);
3270 if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
3271 fcx.write_ty(local.id, pat_ty);
3275 pub fn check_stmt(fcx: @FnCtxt, stmt: &ast::Stmt) {
3277 let mut saw_bot = false;
3278 let mut saw_err = false;
3280 ast::StmtDecl(decl, id) => {
3283 ast::DeclLocal(ref l) => {
3284 check_decl_local(fcx, *l);
3285 let l_t = fcx.node_ty(l.id);
3286 saw_bot = saw_bot || ty::type_is_bot(l_t);
3287 saw_err = saw_err || ty::type_is_error(l_t);
3289 ast::DeclItem(_) => {/* ignore for now */ }
3292 ast::StmtExpr(expr, id) => {
3294 // Check with expected type of ()
3295 check_expr_has_type(fcx, expr, ty::mk_nil());
3296 let expr_ty = fcx.expr_ty(expr);
3297 saw_bot = saw_bot || ty::type_is_bot(expr_ty);
3298 saw_err = saw_err || ty::type_is_error(expr_ty);
3300 ast::StmtSemi(expr, id) => {
3302 check_expr(fcx, expr);
3303 let expr_ty = fcx.expr_ty(expr);
3304 saw_bot |= ty::type_is_bot(expr_ty);
3305 saw_err |= ty::type_is_error(expr_ty);
3307 ast::StmtMac(..) => fcx.ccx.tcx.sess.bug("unexpanded macro")
3310 fcx.write_bot(node_id);
3313 fcx.write_error(node_id);
3316 fcx.write_nil(node_id)
3320 pub fn check_block_no_value(fcx: @FnCtxt, blk: &ast::Block) {
3321 check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
3322 let blkty = fcx.node_ty(blk.id);
3323 if ty::type_is_error(blkty) {
3324 fcx.write_error(blk.id);
3326 else if ty::type_is_bot(blkty) {
3327 fcx.write_bot(blk.id);
3330 let nilty = ty::mk_nil();
3331 demand::suptype(fcx, blk.span, nilty, blkty);
3335 pub fn check_block(fcx0: @FnCtxt, blk: &ast::Block) {
3336 check_block_with_expected(fcx0, blk, None)
3339 pub fn check_block_with_expected(fcx: @FnCtxt,
3341 expected: Option<ty::t>) {
3343 let mut fcx_ps = fcx.ps.borrow_mut();
3344 let purity_state = fcx_ps.get().recurse(blk);
3345 replace(fcx_ps.get(), purity_state)
3348 fcx.with_region_lb(blk.id, || {
3349 let mut warned = false;
3350 let mut last_was_bot = false;
3351 let mut any_bot = false;
3352 let mut any_err = false;
3353 for s in blk.stmts.iter() {
3354 check_stmt(fcx, *s);
3355 let s_id = ast_util::stmt_id(*s);
3356 let s_ty = fcx.node_ty(s_id);
3357 if last_was_bot && !warned && match s.node {
3358 ast::StmtDecl(decl, _) => {
3360 ast::DeclLocal(_) => true,
3364 ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true,
3367 fcx.ccx.tcx.sess.add_lint(UnreachableCode, s_id, s.span,
3368 ~"unreachable statement");
3371 if ty::type_is_bot(s_ty) {
3372 last_was_bot = true;
3374 any_bot = any_bot || ty::type_is_bot(s_ty);
3375 any_err = any_err || ty::type_is_error(s_ty);
3378 None => if any_err {
3379 fcx.write_error(blk.id);
3382 fcx.write_bot(blk.id);
3385 fcx.write_nil(blk.id);
3388 if any_bot && !warned {
3389 fcx.ccx.tcx.sess.add_lint(UnreachableCode, e.id, e.span,
3390 ~"unreachable expression");
3392 check_expr_with_opt_hint(fcx, e, expected);
3393 let ety = fcx.expr_ty(e);
3394 fcx.write_ty(blk.id, ety);
3396 fcx.write_error(blk.id);
3399 fcx.write_bot(blk.id);
3408 pub fn check_const(ccx: @CrateCtxt,
3412 let rty = ty::node_id_to_type(ccx.tcx, id);
3413 let fcx = blank_fn_ctxt(ccx, rty, e.id);
3415 let tcache = fcx.ccx.tcx.tcache.borrow();
3416 tcache.get().get(&local_def(id)).ty
3418 check_const_with_ty(fcx, sp, e, declty);
3421 pub fn check_const_with_ty(fcx: @FnCtxt,
3426 let cty = fcx.expr_ty(e);
3427 demand::suptype(fcx, e.span, declty, cty);
3428 regionck::regionck_expr(fcx, e);
3429 writeback::resolve_type_vars_in_expr(fcx, e);
3432 /// Checks whether a type can be represented in memory. In particular, it
3433 /// identifies types that contain themselves without indirection through a
3434 /// pointer, which would mean their size is unbounded. This is different from
3435 /// the question of whether a type can be instantiated. See the definition of
3436 /// `check_instantiable`.
3437 pub fn check_representable(tcx: ty::ctxt,
3439 item_id: ast::NodeId,
3440 designation: &str) {
3441 let rty = ty::node_id_to_type(tcx, item_id);
3443 // Check that it is possible to represent this type. This call identifies
3444 // (1) types that contain themselves and (2) types that contain a different
3445 // recursive type. It is only necessary to throw an error on those that
3446 // contain themselves. For case 2, there must be an inner type that will be
3447 // caught by case 1.
3448 match ty::is_type_representable(tcx, rty) {
3449 ty::SelfRecursive => {
3451 sp, format!("illegal recursive {} type; \
3452 wrap the inner value in a box to make it representable",
3455 ty::Representable | ty::ContainsRecursive => (),
3459 /// Checks whether a type can be created without an instance of itself.
3460 /// This is similar but different from the question of whether a type
3461 /// can be represented. For example, the following type:
3463 /// enum foo { None, Some(foo) }
3465 /// is instantiable but is not representable. Similarly, the type
3467 /// enum foo { Some(@foo) }
3469 /// is representable, but not instantiable.
3470 pub fn check_instantiable(tcx: ty::ctxt,
3472 item_id: ast::NodeId) {
3473 let item_ty = ty::node_id_to_type(tcx, item_id);
3474 if !ty::is_instantiable(tcx, item_ty) {
3475 tcx.sess.span_err(sp, format!("this type cannot be instantiated \
3476 without an instance of itself; \
3477 consider using `Option<{}>`",
3478 ppaux::ty_to_str(tcx, item_ty)));
3482 pub fn check_simd(tcx: ty::ctxt, sp: Span, id: ast::NodeId) {
3483 let t = ty::node_id_to_type(tcx, id);
3484 if ty::type_needs_subst(t) {
3485 tcx.sess.span_err(sp, "SIMD vector cannot be generic");
3488 match ty::get(t).sty {
3489 ty::ty_struct(did, ref substs) => {
3490 let fields = ty::lookup_struct_fields(tcx, did);
3491 if fields.is_empty() {
3492 tcx.sess.span_err(sp, "SIMD vector cannot be empty");
3495 let e = ty::lookup_field_type(tcx, did, fields[0].id, substs);
3496 if !fields.iter().all(
3497 |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
3498 tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
3501 if !ty::type_is_machine(e) {
3502 tcx.sess.span_err(sp, "SIMD vector element type should be \
3511 pub fn check_enum_variants(ccx: @CrateCtxt,
3513 vs: &[ast::P<ast::Variant>],
3516 fn disr_in_range(ccx: @CrateCtxt,
3518 disr: ty::Disr) -> bool {
3519 fn uint_in_range(ccx: @CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
3521 ast::TyU8 => disr as u8 as Disr == disr,
3522 ast::TyU16 => disr as u16 as Disr == disr,
3523 ast::TyU32 => disr as u32 as Disr == disr,
3524 ast::TyU64 => disr as u64 as Disr == disr,
3525 ast::TyU => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
3528 fn int_in_range(ccx: @CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
3530 ast::TyI8 => disr as i8 as Disr == disr,
3531 ast::TyI16 => disr as i16 as Disr == disr,
3532 ast::TyI32 => disr as i32 as Disr == disr,
3533 ast::TyI64 => disr as i64 as Disr == disr,
3534 ast::TyI => int_in_range(ccx, ccx.tcx.sess.targ_cfg.int_type, disr)
3538 attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
3539 attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
3543 fn do_check(ccx: @CrateCtxt,
3544 vs: &[ast::P<ast::Variant>],
3546 hint: attr::ReprAttr)
3547 -> Vec<@ty::VariantInfo> {
3549 let rty = ty::node_id_to_type(ccx.tcx, id);
3550 let mut variants: Vec<@ty::VariantInfo> = Vec::new();
3551 let mut disr_vals: Vec<ty::Disr> = Vec::new();
3552 let mut prev_disr_val: Option<ty::Disr> = None;
3554 for &v in vs.iter() {
3556 // If the discriminant value is specified explicitly in the enum check whether the
3557 // initialization expression is valid, otherwise use the last value plus one.
3558 let mut current_disr_val = match prev_disr_val {
3559 Some(prev_disr_val) => prev_disr_val + 1,
3560 None => ty::INITIAL_DISCRIMINANT_VALUE
3563 match v.node.disr_expr {
3565 debug!("disr expr, checking {}", pprust::expr_to_str(e));
3567 let fcx = blank_fn_ctxt(ccx, rty, e.id);
3568 let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
3569 check_const_with_ty(fcx, e.span, e, declty);
3570 // check_expr (from check_const pass) doesn't guarantee
3571 // that the expression is in an form that eval_const_expr can
3572 // handle, so we may still get an internal compiler error
3574 match const_eval::eval_const_expr_partial(&ccx.tcx, e) {
3575 Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
3576 Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
3578 ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
3581 ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", *err));
3588 // Check for duplicate discriminant values
3589 if disr_vals.contains(¤t_disr_val) {
3590 ccx.tcx.sess.span_err(v.span, "discriminant value already exists");
3592 // Check for unrepresentable discriminant values
3594 attr::ReprAny | attr::ReprExtern => (),
3595 attr::ReprInt(sp, ity) => {
3596 if !disr_in_range(ccx, ity, current_disr_val) {
3597 ccx.tcx.sess.span_err(v.span,
3598 "discriminant value outside specified type");
3599 ccx.tcx.sess.span_note(sp, "discriminant type specified here");
3603 disr_vals.push(current_disr_val);
3605 let variant_info = @VariantInfo::from_ast_variant(ccx.tcx, v, current_disr_val);
3606 prev_disr_val = Some(current_disr_val);
3608 variants.push(variant_info);
3614 let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id });
3615 if hint != attr::ReprAny && vs.len() <= 1 {
3616 let msg = if vs.len() == 1 {
3617 "unsupported representation for univariant enum"
3619 "unsupported representation for zero-variant enum"
3621 ccx.tcx.sess.span_err(sp, msg)
3624 let variants = do_check(ccx, vs, id, hint);
3626 // cache so that ty::enum_variants won't repeat this work
3628 let mut enum_var_cache = ccx.tcx.enum_var_cache.borrow_mut();
3629 enum_var_cache.get().insert(local_def(id), @variants);
3632 // Check that it is possible to represent this enum.
3633 check_representable(ccx.tcx, sp, id, "enum");
3635 // Check that it is possible to instantiate this enum:
3637 // This *sounds* like the same that as representable, but it's
3638 // not. See def'n of `check_instantiable()` for details.
3639 check_instantiable(ccx.tcx, sp, id);
3642 pub fn lookup_def(fcx: @FnCtxt, sp: Span, id: ast::NodeId) -> ast::Def {
3643 lookup_def_ccx(fcx.ccx, sp, id)
3646 // Returns the type parameter count and the type for the given definition.
3647 pub fn ty_param_bounds_and_ty_for_def(fcx: @FnCtxt,
3650 -> ty_param_bounds_and_ty {
3652 ast::DefArg(nid, _) | ast::DefLocal(nid, _) |
3653 ast::DefBinding(nid, _) => {
3654 let typ = fcx.local_ty(sp, nid);
3655 return no_params(typ);
3657 ast::DefFn(id, _) | ast::DefStaticMethod(id, _, _) |
3658 ast::DefStatic(id, _) | ast::DefVariant(_, id, _) |
3659 ast::DefStruct(id) => {
3660 return ty::lookup_item_type(fcx.ccx.tcx, id);
3662 ast::DefUpvar(_, inner, _, _) => {
3663 return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
3668 ast::DefTyParam(..)=> {
3669 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type");
3671 ast::DefMod(..) | ast::DefForeignMod(..) => {
3672 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module");
3674 ast::DefUse(..) => {
3675 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use");
3677 ast::DefRegion(..) => {
3678 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region");
3680 ast::DefTyParamBinder(..) => {
3681 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter");
3683 ast::DefLabel(..) => {
3684 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label");
3686 ast::DefSelfTy(..) => {
3687 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty");
3689 ast::DefMethod(..) => {
3690 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method");
3695 // Instantiates the given path, which must refer to an item with the given
3696 // number of type parameters and type.
3697 pub fn instantiate_path(fcx: @FnCtxt,
3699 tpt: ty_param_bounds_and_ty,
3702 node_id: ast::NodeId) {
3703 debug!(">>> instantiate_path");
3705 let ty_param_count = tpt.generics.type_param_defs().len();
3706 let ty_param_req = tpt.generics.type_param_defs().iter()
3707 .take_while(|x| x.default.is_none())
3709 let mut ty_substs_len = 0;
3710 for segment in pth.segments.iter() {
3711 ty_substs_len += segment.types.len()
3714 debug!("tpt={} ty_param_count={:?} ty_substs_len={:?}",
3715 tpt.repr(fcx.tcx()),
3719 // determine the region parameters, using the value given by the user
3720 // (if any) and otherwise using a fresh region variable
3721 let num_expected_regions = tpt.generics.region_param_defs().len();
3722 let num_supplied_regions = pth.segments.last().unwrap().lifetimes.len();
3723 let regions = if num_expected_regions == num_supplied_regions {
3724 pth.segments.last().unwrap().lifetimes.map(
3725 |l| ast_region_to_region(fcx.tcx(), l))
3727 if num_supplied_regions != 0 {
3728 fcx.ccx.tcx.sess.span_err(
3730 format!("expected {nexpected, plural, =1{# lifetime parameter} \
3731 other{# lifetime parameters}}, \
3732 found {nsupplied, plural, =1{# lifetime parameter} \
3733 other{# lifetime parameters}}",
3734 nexpected = num_expected_regions,
3735 nsupplied = num_supplied_regions));
3738 opt_vec::from(fcx.infcx().next_region_vars(
3739 infer::BoundRegionInTypeOrImpl(span),
3740 num_expected_regions).move_iter().collect())
3742 let regions = ty::NonerasedRegions(regions);
3744 // Special case: If there is a self parameter, omit it from the list of
3747 // Here we calculate the "user type parameter count", which is the number
3748 // of type parameters actually manifest in the AST. This will differ from
3749 // the internal type parameter count when there are self types involved.
3750 let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def {
3751 ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
3752 let generics = generics_of_static_method_container(fcx.ccx.tcx,
3754 (ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs().len()))
3756 _ => (ty_param_count, ty_param_req, None),
3759 // determine values for type parameters, using the values given by
3760 // the user (if any) and otherwise using fresh type variables
3761 let (tps, regions) = if ty_substs_len == 0 {
3762 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3763 } else if ty_param_count == 0 {
3764 fcx.ccx.tcx.sess.span_err
3765 (span, "this item does not take type parameters");
3766 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3767 } else if ty_substs_len > user_ty_param_count {
3768 let expected = if user_ty_param_req < user_ty_param_count {
3773 fcx.ccx.tcx.sess.span_err
3775 format!("too many type parameters provided: {} {}, found {}",
3776 expected, user_ty_param_count, ty_substs_len));
3777 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3778 } else if ty_substs_len < user_ty_param_req {
3779 let expected = if user_ty_param_req < user_ty_param_count {
3784 fcx.ccx.tcx.sess.span_err
3786 format!("not enough type parameters provided: {} {}, found {}",
3787 expected, user_ty_param_req, ty_substs_len));
3788 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3790 if ty_substs_len > user_ty_param_req
3791 && !fcx.tcx().sess.features.default_type_params.get() {
3792 fcx.tcx().sess.span_err(pth.span, "default type parameters are \
3793 experimental and possibly buggy");
3794 fcx.tcx().sess.span_note(pth.span, "add #[feature(default_type_params)] \
3795 to the crate attributes to enable");
3798 // Build up the list of type parameters, inserting the self parameter
3799 // at the appropriate position.
3800 let mut tps = Vec::new();
3801 let mut pushed = false;
3802 for (i, ty) in pth.segments.iter()
3803 .flat_map(|segment| segment.types.iter())
3804 .map(|&ast_type| fcx.to_ty(ast_type))
3806 match self_parameter_index {
3807 Some(index) if index == i => {
3808 tps.push(fcx.infcx().next_ty_vars(1)[0]);
3816 let mut substs = substs {
3822 let defaults = tpt.generics.type_param_defs().iter()
3823 .enumerate().filter_map(|(i, x)| {
3824 match self_parameter_index {
3825 Some(index) if index == i => None,
3826 _ => Some(x.default)
3829 for (i, default) in defaults.skip(ty_substs_len).enumerate() {
3830 match self_parameter_index {
3831 Some(index) if index == i + ty_substs_len => {
3832 substs.tps.push(fcx.infcx().next_ty_vars(1)[0]);
3839 let ty = default.subst_spanned(fcx.tcx(), &substs, Some(span));
3840 substs.tps.push(ty);
3843 fcx.tcx().sess.span_bug(span,
3844 "missing default for a not explicitely provided type param")
3849 // If the self parameter goes at the end, insert it there.
3850 if !pushed && self_parameter_index.is_some() {
3851 substs.tps.push(fcx.infcx().next_ty_vars(1)[0])
3854 assert_eq!(substs.tps.len(), ty_param_count)
3856 let substs {tps, regions, ..} = substs;
3860 fcx.write_ty_substs(node_id, tpt.ty, substs {
3869 // Resolves `typ` by a single level if `typ` is a type variable. If no
3870 // resolution is possible, then an error is reported.
3871 pub fn structurally_resolved_type(fcx: &FnCtxt, sp: Span, tp: ty::t) -> ty::t {
3872 match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
3873 Ok(t_s) if !ty::type_is_ty_var(t_s) => t_s,
3875 fcx.type_error_message(sp, |_actual| {
3876 ~"the type of this value must be known in this context"
3878 demand::suptype(fcx, sp, ty::mk_err(), tp);
3884 // Returns the one-level-deep structure of the given type.
3885 pub fn structure_of<'a>(fcx: @FnCtxt, sp: Span, typ: ty::t)
3887 &ty::get(structurally_resolved_type(fcx, sp, typ)).sty
3890 pub fn type_is_integral(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3891 let typ_s = structurally_resolved_type(fcx, sp, typ);
3892 return ty::type_is_integral(typ_s);
3895 pub fn type_is_scalar(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3896 let typ_s = structurally_resolved_type(fcx, sp, typ);
3897 return ty::type_is_scalar(typ_s);
3900 pub fn type_is_char(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3901 let typ_s = structurally_resolved_type(fcx, sp, typ);
3902 return ty::type_is_char(typ_s);
3905 pub fn type_is_bare_fn(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3906 let typ_s = structurally_resolved_type(fcx, sp, typ);
3907 return ty::type_is_bare_fn(typ_s);
3910 pub fn type_is_unsafe_ptr(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3911 let typ_s = structurally_resolved_type(fcx, sp, typ);
3912 return ty::type_is_unsafe_ptr(typ_s);
3915 pub fn type_is_region_ptr(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3916 let typ_s = structurally_resolved_type(fcx, sp, typ);
3917 return ty::type_is_region_ptr(typ_s);
3920 pub fn type_is_c_like_enum(fcx: @FnCtxt, sp: Span, typ: ty::t) -> bool {
3921 let typ_s = structurally_resolved_type(fcx, sp, typ);
3922 return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
3925 pub fn ast_expr_vstore_to_vstore(fcx: @FnCtxt,
3930 ast::ExprVstoreUniq => ty::vstore_uniq,
3931 ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => {
3933 ast::ExprLit(..) => {
3934 // string literals and *empty slices* live in static memory
3935 ty::vstore_slice(ty::ReStatic)
3937 ast::ExprVec(ref elements, _) if elements.len() == 0 => {
3938 // string literals and *empty slices* live in static memory
3939 ty::vstore_slice(ty::ReStatic)
3941 ast::ExprRepeat(..) |
3942 ast::ExprVec(..) => {
3943 // vector literals are temporaries on the stack
3944 match fcx.tcx().region_maps.temporary_scope(e.id) {
3946 let r = ty::ReScope(scope);
3950 // this slice occurs in a static somewhere
3951 ty::vstore_slice(ty::ReStatic)
3956 fcx.ccx.tcx.sess.span_bug(
3957 e.span, format!("vstore with unexpected contents"))
3964 // Returns true if b contains a break that can exit from b
3965 pub fn may_break(cx: ty::ctxt, id: ast::NodeId, b: ast::P<ast::Block>) -> bool {
3966 // First: is there an unlabeled break immediately
3968 (loop_query(b, |e| {
3970 ast::ExprBreak(_) => true,
3974 // Second: is there a labeled break with label
3975 // <id> nested anywhere inside the loop?
3976 (block_query(b, |e| {
3978 ast::ExprBreak(Some(_)) => {
3979 let def_map = cx.def_map.borrow();
3980 match def_map.get().find(&e.id) {
3981 Some(&ast::DefLabel(loop_id)) if id == loop_id => true,
3989 pub fn check_bounds_are_used(ccx: @CrateCtxt,
3991 tps: &OptVec<ast::TyParam>,
3993 debug!("check_bounds_are_used(n_tps={}, ty={})",
3994 tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
3996 // make a vector of booleans initially false, set to true when used
3997 if tps.len() == 0u { return; }
3998 let mut tps_used = vec::from_elem(tps.len(), false);
4000 ty::walk_ty(ty, |t| {
4001 match ty::get(t).sty {
4002 ty::ty_param(param_ty {idx, ..}) => {
4003 debug!("Found use of ty param \\#{}", idx);
4004 tps_used[idx] = true;
4010 for (i, b) in tps_used.iter().enumerate() {
4012 ccx.tcx.sess.span_err(
4013 span, format!("type parameter `{}` is unused",
4014 token::get_ident(tps.get(i).ident)));
4019 pub fn check_intrinsic_type(ccx: @CrateCtxt, it: &ast::ForeignItem) {
4020 fn param(ccx: @CrateCtxt, n: uint) -> ty::t {
4021 ty::mk_param(ccx.tcx, n, local_def(0))
4025 let name = token::get_ident(it.ident);
4026 let (n_tps, inputs, output) = if name.get().starts_with("atomic_") {
4027 let split : Vec<&str> = name.get().split('_').collect();
4028 assert!(split.len() >= 2, "Atomic intrinsic not correct format");
4030 //We only care about the operation here
4032 "cxchg" => (1, vec!(ty::mk_mut_rptr(tcx,
4033 ty::ReLateBound(it.id, ty::BrAnon(0)),
4036 param(ccx, 0)), param(ccx, 0)),
4039 ty::mk_imm_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)),
4045 ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)),
4051 "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
4052 "min" | "umax" | "umin" => {
4053 (1, vec!(ty::mk_mut_rptr(tcx,
4054 ty::ReLateBound(it.id, ty::BrAnon(0)),
4055 param(ccx, 0)), param(ccx, 0) ),
4059 (0, Vec::new(), ty::mk_nil())
4062 tcx.sess.span_err(it.span,
4063 format!("unrecognized atomic operation function: `{}`",
4071 "abort" => (0, Vec::new(), ty::mk_bot()),
4072 "breakpoint" => (0, Vec::new(), ty::mk_nil()),
4074 "pref_align_of" | "min_align_of" => (1u, Vec::new(), ty::mk_uint()),
4075 "init" => (1u, Vec::new(), param(ccx, 0u)),
4076 "uninit" => (1u, Vec::new(), param(ccx, 0u)),
4077 "forget" => (1u, vec!( param(ccx, 0) ), ty::mk_nil()),
4078 "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)),
4079 "move_val_init" => {
4082 ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), param(ccx, 0)),
4087 "needs_drop" => (1u, Vec::new(), ty::mk_bool()),
4088 "owns_managed" => (1u, Vec::new(), ty::mk_bool()),
4091 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4093 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4095 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4097 mutbl: ast::MutImmutable
4099 (1u, Vec::new(), td_ptr)
4102 let langid = ccx.tcx.lang_items.require(TypeIdLangItem);
4104 Ok(did) => (1u, Vec::new(), ty::mk_struct(ccx.tcx, did, substs {
4107 regions: ty::NonerasedRegions(opt_vec::Empty)
4109 Err(msg) => { tcx.sess.span_fatal(it.span, msg); }
4113 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4115 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4117 let region = ty::ReLateBound(it.id, ty::BrAnon(0));
4118 let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
4119 Ok((_, vot)) => vot,
4120 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4123 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4125 mutbl: ast::MutImmutable
4127 (0, vec!( td_ptr, visitor_object_ty ), ty::mk_nil())
4132 ty::mk_ptr(tcx, ty::mt {
4134 mutbl: ast::MutImmutable
4138 ty::mk_ptr(tcx, ty::mt {
4140 mutbl: ast::MutImmutable
4143 "copy_nonoverlapping_memory" => {
4146 ty::mk_ptr(tcx, ty::mt {
4148 mutbl: ast::MutMutable
4150 ty::mk_ptr(tcx, ty::mt {
4152 mutbl: ast::MutImmutable
4161 ty::mk_ptr(tcx, ty::mt {
4163 mutbl: ast::MutMutable
4165 ty::mk_ptr(tcx, ty::mt {
4167 mutbl: ast::MutImmutable
4176 ty::mk_ptr(tcx, ty::mt {
4178 mutbl: ast::MutMutable
4185 "sqrtf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4186 "sqrtf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4189 vec!( ty::mk_f32(), ty::mk_i32() ),
4194 vec!( ty::mk_f64(), ty::mk_i32() ),
4197 "sinf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4198 "sinf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4199 "cosf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4200 "cosf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4203 vec!( ty::mk_f32(), ty::mk_f32() ),
4208 vec!( ty::mk_f64(), ty::mk_f64() ),
4211 "expf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4212 "expf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4213 "exp2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4214 "exp2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4215 "logf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4216 "logf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4217 "log10f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4218 "log10f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4219 "log2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4220 "log2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4223 vec!( ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ),
4228 vec!( ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ),
4231 "fabsf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4232 "fabsf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4233 "copysignf32" => (0, vec!( ty::mk_f32(), ty::mk_f32() ), ty::mk_f32()),
4234 "copysignf64" => (0, vec!( ty::mk_f64(), ty::mk_f64() ), ty::mk_f64()),
4235 "floorf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4236 "floorf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4237 "ceilf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4238 "ceilf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4239 "truncf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4240 "truncf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4241 "rintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4242 "rintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4243 "nearbyintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4244 "nearbyintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4245 "roundf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4246 "roundf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4247 "ctpop8" => (0, vec!( ty::mk_i8() ), ty::mk_i8()),
4248 "ctpop16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
4249 "ctpop32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
4250 "ctpop64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
4251 "ctlz8" => (0, vec!( ty::mk_i8() ), ty::mk_i8()),
4252 "ctlz16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
4253 "ctlz32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
4254 "ctlz64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
4255 "cttz8" => (0, vec!( ty::mk_i8() ), ty::mk_i8()),
4256 "cttz16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
4257 "cttz32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
4258 "cttz64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
4259 "bswap16" => (0, vec!( ty::mk_i16() ), ty::mk_i16()),
4260 "bswap32" => (0, vec!( ty::mk_i32() ), ty::mk_i32()),
4261 "bswap64" => (0, vec!( ty::mk_i64() ), ty::mk_i64()),
4264 (1, vec!( ty::mk_imm_ptr(tcx, param(ccx, 0)) ), param(ccx, 0)),
4266 (1, vec!( ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ), ty::mk_nil()),
4268 "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
4269 (0, vec!(ty::mk_i8(), ty::mk_i8()),
4270 ty::mk_tup(tcx, vec!(ty::mk_i8(), ty::mk_bool()))),
4272 "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
4273 (0, vec!(ty::mk_i16(), ty::mk_i16()),
4274 ty::mk_tup(tcx, vec!(ty::mk_i16(), ty::mk_bool()))),
4276 "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
4277 (0, vec!(ty::mk_i32(), ty::mk_i32()),
4278 ty::mk_tup(tcx, vec!(ty::mk_i32(), ty::mk_bool()))),
4280 "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
4281 (0, vec!(ty::mk_i64(), ty::mk_i64()),
4282 ty::mk_tup(tcx, vec!(ty::mk_i64(), ty::mk_bool()))),
4284 "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
4285 (0, vec!(ty::mk_u8(), ty::mk_u8()),
4286 ty::mk_tup(tcx, vec!(ty::mk_u8(), ty::mk_bool()))),
4288 "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
4289 (0, vec!(ty::mk_u16(), ty::mk_u16()),
4290 ty::mk_tup(tcx, vec!(ty::mk_u16(), ty::mk_bool()))),
4292 "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
4293 (0, vec!(ty::mk_u32(), ty::mk_u32()),
4294 ty::mk_tup(tcx, vec!(ty::mk_u32(), ty::mk_bool()))),
4296 "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" =>
4297 (0, vec!(ty::mk_u64(), ty::mk_u64()),
4298 ty::mk_tup(tcx, vec!(ty::mk_u64(), ty::mk_bool()))),
4301 tcx.sess.span_err(it.span,
4302 format!("unrecognized intrinsic function: `{}`",
4308 let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
4309 purity: ast::UnsafeFn,
4310 abis: AbiSet::Intrinsic(),
4311 sig: FnSig {binder_id: it.id,
4316 let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
4317 let i_n_tps = i_ty.generics.type_param_defs().len();
4318 if i_n_tps != n_tps {
4319 tcx.sess.span_err(it.span, format!("intrinsic has wrong number \
4320 of type parameters: found {}, \
4321 expected {}", i_n_tps, n_tps));
4324 tcx, None, false, it.span, i_ty.ty, fty,
4325 || format!("intrinsic has wrong type: \
4327 ppaux::ty_to_str(ccx.tcx, fty)));