1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
15 Within the check phase of type check, we check each item one at a time
16 (bodies of function expressions are checked as part of the containing
17 function). Inference is used to supply types wherever they are
20 By far the most complex case is checking the body of a function. This
21 can be broken down into several distinct phases:
23 - gather: creates type variables to represent the type of each local
24 variable and pattern binding.
26 - main: the main pass does the lion's share of the work: it
27 determines the types of all expressions, resolves
28 methods, checks for most invalid conditions, and so forth. In
29 some cases, where a type is unknown, it may create a type or region
30 variable and use that as the type of an expression.
32 In the process of checking, various constraints will be placed on
33 these type variables through the subtyping relationships requested
34 through the `demand` module. The `typeck::infer` module is in charge
35 of resolving those constraints.
37 - regionck: after main is complete, the regionck pass goes over all
38 types looking for regions and making sure that they did not escape
39 into places they are not in scope. This may also influence the
40 final assignments of the various region variables if there is some
43 - vtable: find and records the impls to use for each trait bound that
44 appears on a type parameter.
46 - writeback: writes the final types within a function body, replacing
47 type variables with their final inferred types. These final types
48 are written into the `tcx.node_types` table, which should *never* contain
49 any reference to a type variable.
53 While type checking a function, the intermediate types for the
54 expressions, blocks, and so forth contained within the function are
55 stored in `fcx.node_types` and `fcx.node_type_substs`. These types
56 may contain unresolved type variables. After type checking is
57 complete, the functions in the writeback module are used to take the
58 types from this table, resolve them, and then write them into their
59 permanent home in the type context `ccx.tcx`.
61 This means that during inferencing you should use `fcx.write_ty()`
62 and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of
63 nodes within the function.
65 The types of top-level items, which never contain unbound type
66 variables, are stored directly into the `tcx` tables.
68 n.b.: A type variable is not the same thing as a type parameter. A
69 type variable is rather an "instance" of a type parameter: that is,
70 given a generic function `fn foo<T>(t: T)`: while checking the
71 function `foo`, the type `ty_param(0)` refers to the type `T`, which
72 is treated in abstract. When `foo()` is called, however, `T` will be
73 substituted for a fresh type variable `N`. This variable will
74 eventually be resolved to some concrete type (which might itself be
80 use middle::const_eval;
81 use middle::lang_items::{ExchangeHeapLangItem, GcLangItem};
82 use middle::lang_items::{ManagedHeapLangItem};
83 use middle::lint::UnreachableCode;
84 use middle::pat_util::pat_id_map;
86 use middle::subst::Subst;
87 use middle::ty::{FnSig, VariantInfo};
88 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
89 use middle::ty::{substs, param_ty, Disr, ExprTyProvider};
91 use middle::ty_fold::TypeFolder;
92 use middle::typeck::astconv::AstConv;
93 use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
94 use middle::typeck::astconv;
95 use middle::typeck::check::_match::pat_ctxt;
96 use middle::typeck::check::method::{AutoderefReceiver};
97 use middle::typeck::check::method::{AutoderefReceiverFlag};
98 use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
99 use middle::typeck::check::method::{DontAutoderefReceiver};
100 use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
101 use middle::typeck::check::regionmanip::relate_free_regions;
102 use middle::typeck::check::vtable::VtableContext;
103 use middle::typeck::CrateCtxt;
104 use middle::typeck::infer::{resolve_type, force_tvar};
105 use middle::typeck::infer;
106 use middle::typeck::rscope::RegionScope;
107 use middle::typeck::{lookup_def_ccx};
108 use middle::typeck::no_params;
109 use middle::typeck::{require_same_types, vtable_map};
110 use middle::typeck::{MethodCall, MethodMap};
111 use middle::lang_items::TypeIdLangItem;
112 use util::common::{block_query, indenter, loop_query};
114 use util::ppaux::{UserString, Repr};
115 use util::nodemap::{FnvHashMap, NodeMap};
117 use std::cell::{Cell, RefCell};
118 use collections::HashMap;
119 use std::mem::replace;
123 use syntax::ast::{Provided, Required};
126 use syntax::ast_util::local_def;
127 use syntax::ast_util;
129 use syntax::codemap::Span;
131 use syntax::owned_slice::OwnedSlice;
132 use syntax::parse::token;
133 use syntax::print::pprust;
135 use syntax::visit::Visitor;
146 /// Fields that are part of a `FnCtxt` which are inherited by
147 /// closures defined within the function. For example:
150 /// bar(proc() { ... })
153 /// Here, the function `foo()` and the closure passed to
154 /// `bar()` will each have their own `FnCtxt`, but they will
155 /// share the inherited fields.
156 pub struct Inherited<'a> {
157 infcx: infer::InferCtxt<'a>,
158 locals: RefCell<NodeMap<ty::t>>,
159 param_env: ty::ParameterEnvironment,
162 node_types: RefCell<NodeMap<ty::t>>,
163 node_type_substs: RefCell<NodeMap<ty::substs>>,
164 adjustments: RefCell<NodeMap<ty::AutoAdjustment>>,
165 method_map: MethodMap,
166 vtable_map: vtable_map,
167 upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
175 // A normal closure or fn item.
180 pub struct FnStyleState {
181 pub def: ast::NodeId,
182 pub fn_style: ast::FnStyle,
187 pub fn function(fn_style: ast::FnStyle, def: ast::NodeId) -> FnStyleState {
188 FnStyleState { def: def, fn_style: fn_style, from_fn: true }
191 pub fn recurse(&mut self, blk: &ast::Block) -> FnStyleState {
192 match self.fn_style {
193 // If this unsafe, then if the outer function was already marked as
194 // unsafe we shouldn't attribute the unsafe'ness to the block. This
195 // way the block can be warned about instead of ignoring this
196 // extraneous block (functions are never warned about).
197 ast::UnsafeFn if self.from_fn => *self,
200 let (fn_style, def) = match blk.rules {
201 ast::UnsafeBlock(..) => (ast::UnsafeFn, blk.id),
202 ast::DefaultBlock => (fn_style, self.def),
204 FnStyleState{ def: def,
212 /// Whether `check_binop` is part of an assignment or not.
213 /// Used to know wether we allow user overloads and to print
214 /// better messages on error.
216 enum IsBinopAssignment{
222 pub struct FnCtxt<'a> {
223 // Number of errors that had been reported when we started
224 // checking this function. On exit, if we find that *more* errors
225 // have been reported, we will skip regionck and other work that
226 // expects the types within the function to be consistent.
227 err_count_on_creation: uint,
230 ps: RefCell<FnStyleState>,
232 // Sometimes we generate region pointers where the precise region
233 // to use is not known. For example, an expression like `&x.f`
234 // where `x` is of type `@T`: in this case, we will be rooting
235 // `x` onto the stack frame, and we could choose to root it until
236 // the end of (almost) any enclosing block or expression. We
237 // want to pick the narrowest block that encompasses all uses.
239 // What we do in such cases is to generate a region variable with
240 // `region_lb` as a lower bound. The regionck pass then adds
241 // other constraints based on how the variable is used and region
242 // inference selects the ultimate value. Finally, borrowck is
243 // charged with guaranteeing that the value whose address was taken
244 // can actually be made to live as long as it needs to live.
245 region_lb: Cell<ast::NodeId>,
247 // Says whether we're inside a for loop, in a do block
248 // or neither. Helps with error messages involving the
249 // function return type.
252 inh: &'a Inherited<'a>,
254 ccx: &'a CrateCtxt<'a>,
257 impl<'a> Inherited<'a> {
258 fn new(tcx: &'a ty::ctxt,
259 param_env: ty::ParameterEnvironment)
262 infcx: infer::new_infer_ctxt(tcx),
263 locals: RefCell::new(NodeMap::new()),
264 param_env: param_env,
265 node_types: RefCell::new(NodeMap::new()),
266 node_type_substs: RefCell::new(NodeMap::new()),
267 adjustments: RefCell::new(NodeMap::new()),
268 method_map: RefCell::new(FnvHashMap::new()),
269 vtable_map: RefCell::new(FnvHashMap::new()),
270 upvar_borrow_map: RefCell::new(HashMap::new()),
275 // Used by check_const and check_enum_variants
276 fn blank_fn_ctxt<'a>(ccx: &'a CrateCtxt<'a>,
277 inh: &'a Inherited<'a>,
279 region_bnd: ast::NodeId)
282 err_count_on_creation: ccx.tcx.sess.err_count(),
284 ps: RefCell::new(FnStyleState::function(ast::NormalFn, 0)),
285 region_lb: Cell::new(region_bnd),
292 fn blank_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> {
293 // It's kind of a kludge to manufacture a fake function context
294 // and statement context, but we might as well do write the code only once
295 let param_env = ty::ParameterEnvironment { free_substs: substs::empty(),
296 self_param_bound: None,
297 type_param_bounds: Vec::new() };
298 Inherited::new(ccx.tcx, param_env)
301 impl<'a> ExprTyProvider for FnCtxt<'a> {
302 fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
306 fn ty_ctxt<'a>(&'a self) -> &'a ty::ctxt {
311 struct CheckItemTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
313 impl<'a> Visitor<()> for CheckItemTypesVisitor<'a> {
314 fn visit_item(&mut self, i: &ast::Item, _: ()) {
315 check_item(self.ccx, i);
316 visit::walk_item(self, i, ());
320 struct CheckItemSizedTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
322 impl<'a> Visitor<()> for CheckItemSizedTypesVisitor<'a> {
323 fn visit_item(&mut self, i: &ast::Item, _: ()) {
324 check_item_sized(self.ccx, i);
325 visit::walk_item(self, i, ());
329 pub fn check_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
330 let mut visit = CheckItemTypesVisitor { ccx: ccx };
331 visit::walk_crate(&mut visit, krate, ());
333 ccx.tcx.sess.abort_if_errors();
335 let mut visit = CheckItemSizedTypesVisitor { ccx: ccx };
336 visit::walk_crate(&mut visit, krate, ());
339 fn check_bare_fn(ccx: &CrateCtxt,
344 param_env: ty::ParameterEnvironment) {
345 // Compute the fty from point of view of inside fn
346 // (replace any type-scheme with a type)
347 let fty = fty.subst(ccx.tcx, ¶m_env.free_substs);
349 match ty::get(fty).sty {
350 ty::ty_bare_fn(ref fn_ty) => {
351 let inh = Inherited::new(ccx.tcx, param_env);
352 let fcx = check_fn(ccx, fn_ty.fn_style, &fn_ty.sig,
353 decl, id, body, Vanilla, &inh);
355 vtable::resolve_in_block(&fcx, body);
356 regionck::regionck_fn(&fcx, body);
357 writeback::resolve_type_vars_in_fn(&fcx, decl, body);
359 _ => ccx.tcx.sess.impossible_case(body.span,
360 "check_bare_fn: function type expected")
364 struct GatherLocalsVisitor<'a> {
368 impl<'a> GatherLocalsVisitor<'a> {
369 fn assign(&mut self, nid: ast::NodeId, ty_opt: Option<ty::t>) {
372 // infer the variable's type
373 let var_id = self.fcx.infcx().next_ty_var_id();
374 let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
375 self.fcx.inh.locals.borrow_mut().insert(nid, var_ty);
378 // take type that the user specified
379 self.fcx.inh.locals.borrow_mut().insert(nid, typ);
385 impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
386 // Add explicitly-declared locals.
387 fn visit_local(&mut self, local: &ast::Local, _: ()) {
388 let o_ty = match local.ty.node {
389 ast::TyInfer => None,
390 _ => Some(self.fcx.to_ty(local.ty))
392 self.assign(local.id, o_ty);
393 debug!("Local variable {} is assigned type {}",
394 self.fcx.pat_to_str(local.pat),
395 self.fcx.infcx().ty_to_str(
396 self.fcx.inh.locals.borrow().get_copy(&local.id)));
397 visit::walk_local(self, local, ());
400 // Add pattern bindings.
401 fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
403 ast::PatIdent(_, ref path, _)
404 if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) => {
405 self.assign(p.id, None);
406 debug!("Pattern binding {} is assigned to {}",
407 token::get_ident(path.segments.get(0).identifier),
408 self.fcx.infcx().ty_to_str(
409 self.fcx.inh.locals.borrow().get_copy(&p.id)));
413 visit::walk_pat(self, p, ());
417 fn visit_block(&mut self, b: &ast::Block, _: ()) {
418 // non-obvious: the `blk` variable maps to region lb, so
419 // we have to keep this up-to-date. This
420 // is... unfortunate. It'd be nice to not need this.
421 self.fcx.with_region_lb(b.id, || visit::walk_block(self, b, ()));
424 // Don't descend into fns and items
425 fn visit_fn(&mut self, _: &visit::FnKind, _: &ast::FnDecl,
426 _: &ast::Block, _: Span, _: ast::NodeId, _: ()) { }
427 fn visit_item(&mut self, _: &ast::Item, _: ()) { }
431 fn check_fn<'a>(ccx: &'a CrateCtxt<'a>,
432 fn_style: ast::FnStyle,
438 inherited: &'a Inherited<'a>) -> FnCtxt<'a>
441 * Helper used by check_bare_fn and check_expr_fn. Does the
442 * grungy work of checking a function body and returns the
443 * function context used for that purpose, since in the case of a
444 * fn item there is still a bit more to do.
447 * - inherited: other fields inherited from the enclosing fn (if any)
451 let err_count_on_creation = tcx.sess.err_count();
453 // First, we have to replace any bound regions in the fn type with free ones.
454 // The free region references will be bound the node_id of the body block.
455 let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(tcx, fn_sig, |br| {
456 ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
459 relate_free_regions(tcx, &fn_sig);
461 let arg_tys = fn_sig.inputs.as_slice();
462 let ret_ty = fn_sig.output;
464 debug!("check_fn(arg_tys={:?}, ret_ty={:?})",
465 arg_tys.iter().map(|&a| ppaux::ty_to_str(tcx, a)).collect::<Vec<~str>>(),
466 ppaux::ty_to_str(tcx, ret_ty));
468 // Create the function context. This is either derived from scratch or,
469 // in the case of function expressions, based on the outer context.
471 err_count_on_creation: err_count_on_creation,
473 ps: RefCell::new(FnStyleState::function(fn_style, id)),
474 region_lb: Cell::new(body.id),
482 let mut visit = GatherLocalsVisitor { fcx: &fcx, };
483 // Add formal parameters.
484 for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
485 // Create type variables for each argument.
486 pat_util::pat_bindings(&tcx.def_map,
488 |_bm, pat_id, _sp, _path| {
489 visit.assign(pat_id, None);
492 // Check the pattern.
495 map: pat_id_map(&tcx.def_map, input.pat),
497 _match::check_pat(&pcx, input.pat, *arg_ty);
500 visit.visit_block(body, ());
503 check_block_with_expected(&fcx, body, Some(ret_ty));
505 // We unify the tail expr's type with the
506 // function result type, if there is a tail expr.
509 // Special case: we print a special error if there appears
510 // to be do-block/for-loop confusion
511 demand::suptype_with_fn(&fcx, tail_expr.span, false,
512 fcx.ret_ty, fcx.expr_ty(tail_expr),
514 fcx.report_mismatched_return_types(sp, e, a, s);
520 for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
521 fcx.write_ty(input.id, *arg);
527 fn span_for_field(tcx: &ty::ctxt, field: &ty::field_ty, struct_id: ast::DefId) -> Span {
528 assert!(field.id.krate == ast::LOCAL_CRATE);
529 let item = match tcx.map.find(struct_id.node) {
530 Some(ast_map::NodeItem(item)) => item,
531 None => fail!("node not in ast map: {}", struct_id.node),
532 _ => fail!("expected item, found {}", tcx.map.node_to_str(struct_id.node))
536 ast::ItemStruct(struct_def, _) => {
537 match struct_def.fields.iter().find(|f| match f.node.kind {
538 ast::NamedField(ident, _) => ident.name == field.name,
542 None => tcx.sess.bug(format!("Could not find field {}",
543 token::get_name(field.name))),
546 _ => tcx.sess.bug("Field found outside of a struct?"),
550 // Check struct fields are uniquely named wrt parents.
551 fn check_for_field_shadowing(tcx: &ty::ctxt,
553 let struct_fields = tcx.struct_fields.borrow();
554 let fields = struct_fields.get(&id);
556 let superstructs = tcx.superstructs.borrow();
557 let super_struct = superstructs.get(&id);
558 match *super_struct {
560 let super_fields = ty::lookup_struct_fields(tcx, parent_id);
561 for f in fields.iter() {
562 match super_fields.iter().find(|sf| f.name == sf.name) {
563 Some(prev_field) => {
564 tcx.sess.span_err(span_for_field(tcx, f, id),
565 format!("field `{}` hides field declared in super-struct",
566 token::get_name(f.name)));
567 tcx.sess.span_note(span_for_field(tcx, prev_field, parent_id),
568 "previously declared here");
578 fn check_fields_sized(tcx: &ty::ctxt,
579 struct_def: &ast::StructDef) {
580 let len = struct_def.fields.len();
584 for f in struct_def.fields.slice_to(len - 1).iter() {
585 let t = ty::node_id_to_type(tcx, f.node.id);
586 if !ty::type_is_sized(tcx, t) {
588 ast::NamedField(ident, _) => {
589 tcx.sess.span_err(f.span, format!("type `{}` is dynamically sized. \
590 dynamically sized types may only \
591 appear as the type of the final \
593 token::get_ident(ident)));
595 ast::UnnamedField(_) => {
596 tcx.sess.span_err(f.span, "dynamically sized type in field");
603 pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
606 check_representable(tcx, span, id, "struct");
607 check_instantiable(tcx, span, id);
609 // Check there are no overlapping fields in super-structs
610 check_for_field_shadowing(tcx, local_def(id));
612 if ty::lookup_simd(tcx, local_def(id)) {
613 check_simd(tcx, span, id);
617 pub fn check_item_sized(ccx: &CrateCtxt, it: &ast::Item) {
618 debug!("check_item(it.id={}, it.ident={})",
620 ty::item_path_str(ccx.tcx, local_def(it.id)));
621 let _indenter = indenter();
624 ast::ItemEnum(ref enum_definition, _) => {
625 check_enum_variants_sized(ccx,
626 enum_definition.variants.as_slice());
628 ast::ItemStruct(..) => {
629 check_fields_sized(ccx.tcx, ccx.tcx.map.expect_struct(it.id));
635 pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
636 debug!("check_item(it.id={}, it.ident={})",
638 ty::item_path_str(ccx.tcx, local_def(it.id)));
639 let _indenter = indenter();
642 ast::ItemStatic(_, _, e) => check_const(ccx, it.span, e, it.id),
643 ast::ItemEnum(ref enum_definition, _) => {
644 check_enum_variants(ccx,
646 enum_definition.variants.as_slice(),
649 ast::ItemFn(decl, _, _, _, body) => {
650 let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
652 let param_env = ty::construct_parameter_environment(
655 fn_tpt.generics.type_param_defs(),
658 fn_tpt.generics.region_param_defs.as_slice(),
661 check_bare_fn(ccx, decl, body, it.id, fn_tpt.ty, param_env);
663 ast::ItemImpl(_, ref opt_trait_ref, _, ref ms) => {
664 debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
666 let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
668 check_method_body(ccx, &impl_tpt.generics, None, *m);
671 match *opt_trait_ref {
672 Some(ref ast_trait_ref) => {
674 ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id);
675 check_impl_methods_against_trait(ccx,
681 vtable::resolve_impl(ccx.tcx, it, &impl_tpt.generics, &*impl_trait_ref);
687 ast::ItemTrait(_, _, _, ref trait_methods) => {
688 let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
689 for trait_method in (*trait_methods).iter() {
690 match *trait_method {
692 // Nothing to do, since required methods don't have
696 check_method_body(ccx, &trait_def.generics,
697 Some(trait_def.trait_ref.clone()), m);
702 ast::ItemStruct(..) => {
703 check_struct(ccx, it.id, it.span);
705 ast::ItemTy(ref t, ref generics) => {
706 let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id);
707 check_bounds_are_used(ccx, t.span, &generics.ty_params, tpt_ty);
709 ast::ItemForeignMod(ref m) => {
710 if m.abi == abi::RustIntrinsic {
711 for item in m.items.iter() {
712 check_intrinsic_type(ccx, *item);
715 for item in m.items.iter() {
716 let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id));
717 if tpt.generics.has_type_params() {
718 ccx.tcx.sess.span_err(item.span, "foreign items may not have type parameters");
722 ast::ForeignItemFn(ref fn_decl, _) => {
723 if fn_decl.variadic && m.abi != abi::C {
724 ccx.tcx.sess.span_err(
725 item.span, "variadic function must have C calling convention");
733 _ => {/* nothing to do */ }
737 fn check_method_body(ccx: &CrateCtxt,
738 item_generics: &ty::Generics,
739 self_bound: Option<Rc<ty::TraitRef>>,
740 method: &ast::Method) {
742 * Type checks a method body.
745 * - `item_generics`: generics defined on the impl/trait that contains
747 * - `self_bound`: bound for the `Self` type parameter, if any
748 * - `method`: the method definition
751 debug!("check_method_body(item_generics={}, \
754 item_generics.repr(ccx.tcx),
755 self_bound.repr(ccx.tcx),
757 let method_def_id = local_def(method.id);
758 let method_ty = ty::method(ccx.tcx, method_def_id);
759 let method_generics = &method_ty.generics;
762 ty::construct_parameter_environment(
765 item_generics.type_param_defs(),
766 method_generics.type_param_defs(),
767 item_generics.region_param_defs(),
768 method_generics.region_param_defs(),
771 let fty = ty::node_id_to_type(ccx.tcx, method.id);
773 check_bare_fn(ccx, method.decl, method.body, method.id, fty, param_env);
776 fn check_impl_methods_against_trait(ccx: &CrateCtxt,
778 impl_generics: &ty::Generics,
779 ast_trait_ref: &ast::TraitRef,
780 impl_trait_ref: &ty::TraitRef,
781 impl_methods: &[@ast::Method]) {
782 // Locate trait methods
784 let trait_methods = ty::trait_methods(tcx, impl_trait_ref.def_id);
786 // Check existing impl methods to see if they are both present in trait
787 // and compatible with trait signature
788 for impl_method in impl_methods.iter() {
789 let impl_method_def_id = local_def(impl_method.id);
790 let impl_method_ty = ty::method(ccx.tcx, impl_method_def_id);
792 // If this is an impl of a trait method, find the corresponding
793 // method definition in the trait.
794 let opt_trait_method_ty =
795 trait_methods.iter().
796 find(|tm| tm.ident.name == impl_method_ty.ident.name);
797 match opt_trait_method_ty {
798 Some(trait_method_ty) => {
799 compare_impl_method(ccx.tcx,
805 &impl_trait_ref.substs);
810 format!("method `{}` is not a member of trait `{}`",
811 token::get_ident(impl_method_ty.ident),
812 pprust::path_to_str(&ast_trait_ref.path)));
817 // Check for missing methods from trait
818 let provided_methods = ty::provided_trait_methods(tcx,
819 impl_trait_ref.def_id);
820 let mut missing_methods = Vec::new();
821 for trait_method in trait_methods.iter() {
823 impl_methods.iter().any(
824 |m| m.ident.name == trait_method.ident.name);
826 provided_methods.iter().any(
827 |m| m.ident.name == trait_method.ident.name);
828 if !is_implemented && !is_provided {
829 missing_methods.push(
830 format!("`{}`", token::get_ident(trait_method.ident)));
834 if !missing_methods.is_empty() {
837 format!("not all trait methods implemented, missing: {}",
838 missing_methods.connect(", ")));
843 * Checks that a method from an impl/class conforms to the signature of
844 * the same method as declared in the trait.
848 * - impl_generics: the generics declared on the impl itself (not the method!)
849 * - impl_m: type of the method we are checking
850 * - impl_m_span: span to use for reporting errors
851 * - impl_m_body_id: id of the method body
852 * - trait_m: the method in the trait
853 * - trait_substs: the substitutions used on the type of the trait
855 fn compare_impl_method(tcx: &ty::ctxt,
856 impl_generics: &ty::Generics,
859 impl_m_body_id: ast::NodeId,
860 trait_m: &ty::Method,
861 trait_substs: &ty::substs) {
862 debug!("compare_impl_method()");
863 let infcx = infer::new_infer_ctxt(tcx);
865 let impl_tps = impl_generics.type_param_defs().len();
867 // Try to give more informative error messages about self typing
868 // mismatches. Note that any mismatch will also be detected
869 // below, where we construct a canonical function type that
870 // includes the self parameter as a normal parameter. It's just
871 // that the error messages you get out of this code are a bit more
872 // inscrutable, particularly for cases where one method has no
874 match (&trait_m.explicit_self, &impl_m.explicit_self) {
875 (&ast::SelfStatic, &ast::SelfStatic) => {}
876 (&ast::SelfStatic, _) => {
879 format!("method `{}` has a `{}` declaration in the impl, \
880 but not in the trait",
881 token::get_ident(trait_m.ident),
882 pprust::explicit_self_to_str(impl_m.explicit_self)));
885 (_, &ast::SelfStatic) => {
888 format!("method `{}` has a `{}` declaration in the trait, \
889 but not in the impl",
890 token::get_ident(trait_m.ident),
891 pprust::explicit_self_to_str(trait_m.explicit_self)));
895 // Let the type checker catch other errors below
899 let num_impl_m_type_params = impl_m.generics.type_param_defs().len();
900 let num_trait_m_type_params = trait_m.generics.type_param_defs().len();
901 if num_impl_m_type_params != num_trait_m_type_params {
904 format!("method `{method}` has {nimpl, plural, =1{# type parameter} \
905 other{# type parameters}}, \
906 but its trait declaration has {ntrait, plural, =1{# type parameter} \
907 other{# type parameters}}",
908 method = token::get_ident(trait_m.ident),
909 nimpl = num_impl_m_type_params,
910 ntrait = num_trait_m_type_params));
914 if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() {
917 format!("method `{method}` has {nimpl, plural, =1{# parameter} \
918 other{# parameters}} \
919 but the declaration in trait `{trait}` has {ntrait}",
920 method = token::get_ident(trait_m.ident),
921 nimpl = impl_m.fty.sig.inputs.len(),
922 trait = ty::item_path_str(tcx, trait_m.def_id),
923 ntrait = trait_m.fty.sig.inputs.len()));
927 let it = trait_m.generics.type_param_defs().iter()
928 .zip(impl_m.generics.type_param_defs().iter());
930 for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
931 // Check that the impl does not require any builtin-bounds
932 // that the trait does not guarantee:
934 impl_param_def.bounds.builtin_bounds -
935 trait_param_def.bounds.builtin_bounds;
936 if !extra_bounds.is_empty() {
939 format!("in method `{}`, \
940 type parameter {} requires `{}`, \
941 which is not required by \
942 the corresponding type parameter \
943 in the trait declaration",
944 token::get_ident(trait_m.ident),
946 extra_bounds.user_string(tcx)));
950 // FIXME(#2687)---we should be checking that the bounds of the
951 // trait imply the bounds of the subtype, but it appears we
952 // are...not checking this.
953 if impl_param_def.bounds.trait_bounds.len() !=
954 trait_param_def.bounds.trait_bounds.len()
958 format!("in method `{method}`, \
959 type parameter {typaram} has \
960 {nimpl, plural, =1{# trait bound} other{# trait bounds}}, \
961 but the corresponding type parameter in \
962 the trait declaration has \
963 {ntrait, plural, =1{# trait bound} other{# trait bounds}}",
964 method = token::get_ident(trait_m.ident),
966 nimpl = impl_param_def.bounds.trait_bounds.len(),
967 ntrait = trait_param_def.bounds.trait_bounds.len()));
972 // Create a substitution that maps the type parameters on the impl
973 // to themselves and which replace any references to bound regions
974 // in the self type with free regions. So, for example, if the
975 // impl type is "&'a str", then this would replace the self
976 // type with a free region `self`.
977 let dummy_impl_tps: Vec<ty::t> =
978 impl_generics.type_param_defs().iter().enumerate().
979 map(|(i,t)| ty::mk_param(tcx, i, t.def_id)).
981 let dummy_method_tps: Vec<ty::t> =
982 impl_m.generics.type_param_defs().iter().enumerate().
983 map(|(i,t)| ty::mk_param(tcx, i + impl_tps, t.def_id)).
985 let dummy_impl_regions: OwnedSlice<ty::Region> =
986 impl_generics.region_param_defs().iter().
987 map(|l| ty::ReFree(ty::FreeRegion {
988 scope_id: impl_m_body_id,
989 bound_region: ty::BrNamed(l.def_id, l.name)})).
991 let dummy_substs = ty::substs {
992 tps: dummy_impl_tps.append(dummy_method_tps.as_slice()),
993 regions: ty::NonerasedRegions(dummy_impl_regions),
996 // Create a bare fn type for trait/impl
997 // It'd be nice to refactor so as to provide the bare fn types instead.
998 let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
999 let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
1001 // Perform substitutions so that the trait/impl methods are expressed
1002 // in terms of the same set of type/region parameters:
1003 // - replace trait type parameters with those from `trait_substs`,
1004 // except with any reference to bound self replaced with `dummy_self_r`
1005 // - replace method parameters on the trait with fresh, dummy parameters
1006 // that correspond to the parameters we will find on the impl
1007 // - replace self region with a fresh, dummy region
1009 debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
1010 impl_fty.subst(tcx, &dummy_substs)
1012 debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
1014 let substs { regions: trait_regions,
1016 self_ty: self_ty } = trait_substs.subst(tcx, &dummy_substs);
1017 let substs = substs {
1018 regions: trait_regions,
1019 tps: trait_tps.append(dummy_method_tps.as_slice()),
1022 debug!("trait_fty (pre-subst): {} substs={}",
1023 trait_fty.repr(tcx), substs.repr(tcx));
1024 trait_fty.subst(tcx, &substs)
1026 debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx));
1028 match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span),
1029 impl_fty, trait_fty) {
1034 format!("method `{}` has an incompatible type for trait: {}",
1035 token::get_ident(trait_m.ident),
1036 ty::type_err_to_str(tcx, terr)));
1037 ty::note_and_explain_type_err(tcx, terr);
1042 impl<'a> AstConv for FnCtxt<'a> {
1043 fn tcx<'a>(&'a self) -> &'a ty::ctxt { self.ccx.tcx }
1045 fn get_item_ty(&self, id: ast::DefId) -> ty::ty_param_bounds_and_ty {
1046 ty::lookup_item_type(self.tcx(), id)
1049 fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef> {
1050 ty::lookup_trait_def(self.tcx(), id)
1053 fn ty_infer(&self, _span: Span) -> ty::t {
1054 self.infcx().next_ty_var()
1058 impl<'a> FnCtxt<'a> {
1059 pub fn infcx<'b>(&'b self) -> &'b infer::InferCtxt<'a> {
1063 pub fn err_count_since_creation(&self) -> uint {
1064 self.ccx.tcx.sess.err_count() - self.err_count_on_creation
1067 pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
1069 infcx: self.infcx(),
1070 param_env: &self.inh.param_env
1075 impl<'a> RegionScope for infer::InferCtxt<'a> {
1076 fn anon_regions(&self, span: Span, count: uint)
1077 -> Result<Vec<ty::Region> , ()> {
1078 Ok(Vec::from_fn(count, |_| {
1079 self.next_region_var(infer::MiscVariable(span))
1084 impl<'a> FnCtxt<'a> {
1085 pub fn tag(&self) -> ~str {
1086 format!("{}", self as *FnCtxt)
1089 pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t {
1090 match self.inh.locals.borrow().find(&nid) {
1093 self.tcx().sess.span_bug(
1095 format!("no type for local variable {:?}", nid));
1101 pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
1102 debug!("write_ty({}, {}) in fcx {}",
1103 node_id, ppaux::ty_to_str(self.tcx(), ty), self.tag());
1104 self.inh.node_types.borrow_mut().insert(node_id, ty);
1107 pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::substs) {
1108 if !ty::substs_is_noop(&substs) {
1109 debug!("write_substs({}, {}) in fcx {}",
1111 ty::substs_to_str(self.tcx(), &substs),
1114 self.inh.node_type_substs.borrow_mut().insert(node_id, substs);
1118 pub fn write_ty_substs(&self,
1119 node_id: ast::NodeId,
1121 substs: ty::substs) {
1122 let ty = ty::subst(self.tcx(), &substs, ty);
1123 self.write_ty(node_id, ty);
1124 self.write_substs(node_id, substs);
1127 pub fn write_autoderef_adjustment(&self,
1128 node_id: ast::NodeId,
1130 if derefs == 0 { return; }
1131 self.write_adjustment(
1133 ty::AutoDerefRef(ty::AutoDerefRef {
1139 pub fn write_adjustment(&self,
1140 node_id: ast::NodeId,
1141 adj: ty::AutoAdjustment) {
1142 debug!("write_adjustment(node_id={:?}, adj={:?})", node_id, adj);
1143 self.inh.adjustments.borrow_mut().insert(node_id, adj);
1146 pub fn write_nil(&self, node_id: ast::NodeId) {
1147 self.write_ty(node_id, ty::mk_nil());
1149 pub fn write_bot(&self, node_id: ast::NodeId) {
1150 self.write_ty(node_id, ty::mk_bot());
1152 pub fn write_error(&self, node_id: ast::NodeId) {
1153 self.write_ty(node_id, ty::mk_err());
1156 pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
1157 ast_ty_to_ty(self, self.infcx(), ast_t)
1160 pub fn pat_to_str(&self, pat: &ast::Pat) -> ~str {
1161 pat.repr(self.tcx())
1164 pub fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
1165 match self.inh.node_types.borrow().find(&ex.id) {
1168 self.tcx().sess.bug(format!("no type for expr in fcx {}",
1174 pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
1175 match self.inh.node_types.borrow().find(&id) {
1178 self.tcx().sess.bug(
1179 format!("no type for node {}: {} in fcx {}",
1180 id, self.tcx().map.node_to_str(id),
1186 pub fn method_ty_substs(&self, id: ast::NodeId) -> ty::substs {
1187 match self.inh.method_map.borrow().find(&MethodCall::expr(id)) {
1188 Some(method) => method.substs.clone(),
1190 self.tcx().sess.bug(
1191 format!("no method entry for node {}: {} in fcx {}",
1192 id, self.tcx().map.node_to_str(id),
1198 pub fn opt_node_ty_substs(&self,
1200 f: |&ty::substs| -> bool)
1202 match self.inh.node_type_substs.borrow().find(&id) {
1208 pub fn mk_subty(&self,
1209 a_is_expected: bool,
1210 origin: infer::TypeOrigin,
1213 -> Result<(), ty::type_err> {
1214 infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
1217 pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t)
1218 -> Result<(), ty::type_err> {
1219 infer::can_mk_subty(self.infcx(), sub, sup)
1222 pub fn mk_assignty(&self,
1226 -> Result<(), ty::type_err> {
1227 match infer::mk_coercety(self.infcx(),
1229 infer::ExprAssignable(expr.span),
1233 Err(ref e) => Err((*e)),
1234 Ok(Some(adjustment)) => {
1235 self.write_adjustment(expr.id, adjustment);
1241 pub fn mk_eqty(&self,
1242 a_is_expected: bool,
1243 origin: infer::TypeOrigin,
1246 -> Result<(), ty::type_err> {
1247 infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
1250 pub fn mk_subr(&self,
1251 a_is_expected: bool,
1252 origin: infer::SubregionOrigin,
1255 infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
1258 pub fn with_region_lb<R>(&self, lb: ast::NodeId, f: || -> R) -> R {
1259 let old_region_lb = self.region_lb.get();
1260 self.region_lb.set(lb);
1262 self.region_lb.set(old_region_lb);
1266 pub fn type_error_message(&self,
1268 mk_msg: |~str| -> ~str,
1270 err: Option<&ty::type_err>) {
1271 self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
1274 pub fn report_mismatched_return_types(&self,
1278 err: &ty::type_err) {
1280 if ty::type_is_error(e) || ty::type_is_error(a) {
1283 self.infcx().report_mismatched_types(sp, e, a, err)
1286 pub fn report_mismatched_types(&self,
1290 err: &ty::type_err) {
1291 self.infcx().report_mismatched_types(sp, e, a, err)
1295 pub enum LvaluePreference {
1300 pub fn autoderef<T>(fcx: &FnCtxt, sp: Span, base_ty: ty::t,
1301 expr_id: Option<ast::NodeId>,
1302 mut lvalue_pref: LvaluePreference,
1303 should_stop: |ty::t, uint| -> Option<T>)
1304 -> (ty::t, uint, Option<T>) {
1306 * Executes an autoderef loop for the type `t`. At each step, invokes
1307 * `should_stop` to decide whether to terminate the loop. Returns
1308 * the final type and number of derefs that it performed.
1310 * Note: this method does not modify the adjustments table. The caller is
1311 * responsible for inserting an AutoAdjustment record into the `fcx`
1312 * using one of the suitable methods.
1315 let mut t = base_ty;
1316 for autoderefs in range(0, fcx.tcx().sess.recursion_limit.get()) {
1317 let resolved_t = structurally_resolved_type(fcx, sp, t);
1319 match should_stop(resolved_t, autoderefs) {
1320 Some(x) => return (resolved_t, autoderefs, Some(x)),
1324 // Otherwise, deref if type is derefable:
1325 let mt = match ty::deref(resolved_t, false) {
1326 Some(mt) => Some(mt),
1329 expr_id.map(|id| MethodCall::autoderef(id, autoderefs as u32));
1330 try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
1336 if mt.mutbl == ast::MutImmutable {
1337 lvalue_pref = NoPreference;
1340 None => return (resolved_t, autoderefs, None)
1344 // We've reached the recursion limit, error gracefully.
1345 fcx.tcx().sess.span_err(sp,
1346 format!("reached the recursion limit while auto-dereferencing {}",
1347 base_ty.repr(fcx.tcx())));
1348 (ty::mk_err(), 0, None)
1351 fn try_overloaded_deref(fcx: &FnCtxt,
1353 method_call: Option<MethodCall>,
1354 base_expr: Option<&ast::Expr>,
1356 lvalue_pref: LvaluePreference)
1358 // Try DerefMut first, if preferred.
1359 let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
1360 (PreferMutLvalue, Some(trait_did)) => {
1361 method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
1362 token::intern("deref_mut"), trait_did,
1363 base_ty, [], DontAutoderefReceiver)
1368 // Otherwise, fall back to Deref.
1369 let method = match (method, fcx.tcx().lang_items.deref_trait()) {
1370 (None, Some(trait_did)) => {
1371 method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
1372 token::intern("deref"), trait_did,
1373 base_ty, [], DontAutoderefReceiver)
1375 (method, _) => method
1380 let ref_ty = ty::ty_fn_ret(method.ty);
1382 Some(method_call) => {
1383 fcx.inh.method_map.borrow_mut().insert(method_call, method);
1387 ty::deref(ref_ty, true)
1393 // AST fragment checking
1394 pub fn check_lit(fcx: &FnCtxt, lit: &ast::Lit) -> ty::t {
1395 let tcx = fcx.ccx.tcx;
1398 ast::LitStr(..) => ty::mk_str(tcx, ty::VstoreSlice(ty::ReStatic)),
1399 ast::LitBinary(..) => {
1400 ty::mk_slice(tcx, ty::ReStatic, ty::mt{ ty: ty::mk_u8(), mutbl: ast::MutImmutable })
1402 ast::LitChar(_) => ty::mk_char(),
1403 ast::LitInt(_, t) => ty::mk_mach_int(t),
1404 ast::LitUint(_, t) => ty::mk_mach_uint(t),
1405 ast::LitIntUnsuffixed(_) => {
1406 // An unsuffixed integer literal could have any integral type,
1407 // so we create an integral type variable for it.
1408 ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
1410 ast::LitFloat(_, t) => ty::mk_mach_float(t),
1411 ast::LitFloatUnsuffixed(_) => {
1412 // An unsuffixed floating point literal could have any floating point
1413 // type, so we create a floating point type variable for it.
1414 ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())
1416 ast::LitNil => ty::mk_nil(),
1417 ast::LitBool(_) => ty::mk_bool()
1421 pub fn valid_range_bounds(ccx: &CrateCtxt,
1425 match const_eval::compare_lit_exprs(ccx.tcx, from, to) {
1426 Some(val) => Some(val <= 0),
1431 pub fn check_expr_has_type(
1432 fcx: &FnCtxt, expr: &ast::Expr,
1434 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1435 demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
1439 fn check_expr_coercable_to_type(fcx: &FnCtxt, expr: &ast::Expr, expected: ty::t) {
1440 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1441 demand::coerce(fcx, expr.span, expected, expr)
1445 fn check_expr_with_hint(fcx: &FnCtxt, expr: &ast::Expr, expected: ty::t) {
1446 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || ())
1449 fn check_expr_with_opt_hint(fcx: &FnCtxt, expr: &ast::Expr,
1450 expected: Option<ty::t>) {
1451 check_expr_with_unifier(fcx, expr, expected, NoPreference, || ())
1454 fn check_expr_with_opt_hint_and_lvalue_pref(fcx: &FnCtxt,
1456 expected: Option<ty::t>,
1457 lvalue_pref: LvaluePreference) {
1458 check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ())
1461 fn check_expr(fcx: &FnCtxt, expr: &ast::Expr) {
1462 check_expr_with_unifier(fcx, expr, None, NoPreference, || ())
1465 fn check_expr_with_lvalue_pref(fcx: &FnCtxt, expr: &ast::Expr,
1466 lvalue_pref: LvaluePreference) {
1467 check_expr_with_unifier(fcx, expr, None, lvalue_pref, || ())
1471 // determine the `self` type, using fresh variables for all variables
1472 // declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
1473 // would return ($0, $1) where $0 and $1 are freshly instantiated type
1475 pub fn impl_self_ty(vcx: &VtableContext,
1476 span: Span, // (potential) receiver for this impl
1478 -> ty_param_substs_and_ty {
1479 let tcx = vcx.tcx();
1481 let ity = ty::lookup_item_type(tcx, did);
1482 let (n_tps, rps, raw_ty) =
1483 (ity.generics.type_param_defs().len(),
1484 ity.generics.region_param_defs(),
1487 let rps = vcx.infcx.region_vars_for_defs(span, rps);
1488 let tps = vcx.infcx.next_ty_vars(n_tps);
1490 let substs = substs {
1491 regions: ty::NonerasedRegions(rps),
1495 let substd_ty = ty::subst(tcx, &substs, raw_ty);
1497 ty_param_substs_and_ty { substs: substs, ty: substd_ty }
1500 // Only for fields! Returns <none> for methods>
1501 // Indifferent to privacy flags
1502 pub fn lookup_field_ty(tcx: &ty::ctxt,
1503 class_id: ast::DefId,
1504 items: &[ty::field_ty],
1505 fieldname: ast::Name,
1506 substs: &ty::substs) -> Option<ty::t> {
1508 let o_field = items.iter().find(|f| f.name == fieldname);
1509 o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
1512 // Controls whether the arguments are automatically referenced. This is useful
1513 // for overloaded binary and unary operators.
1514 pub enum DerefArgs {
1519 // Given the provenance of a static method, returns the generics of the static
1520 // method's container.
1521 fn generics_of_static_method_container(type_context: &ty::ctxt,
1522 provenance: ast::MethodProvenance)
1525 ast::FromTrait(trait_def_id) => {
1526 ty::lookup_trait_def(type_context, trait_def_id).generics.clone()
1528 ast::FromImpl(impl_def_id) => {
1529 ty::lookup_item_type(type_context, impl_def_id).generics.clone()
1534 // Verifies that type parameters supplied in paths are in the right
1536 fn check_type_parameter_positions_in_path(function_context: &FnCtxt,
1539 // We only care about checking the case in which the path has two or
1541 if path.segments.len() < 2 {
1545 // Verify that no lifetimes or type parameters are present anywhere
1546 // except the final two elements of the path.
1547 for i in range(0, path.segments.len() - 2) {
1548 for lifetime in path.segments.get(i).lifetimes.iter() {
1549 function_context.tcx()
1551 .span_err(lifetime.span,
1552 "lifetime parameters may not \
1557 for typ in path.segments.get(i).types.iter() {
1558 function_context.tcx()
1561 "type parameters may not appear here");
1566 // If there are no parameters at all, there is nothing more to do; the
1567 // rest of typechecking will (attempt to) infer everything.
1570 .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) {
1575 // If this is a static method of a trait or implementation, then
1576 // ensure that the segment of the path which names the trait or
1577 // implementation (the penultimate segment) is annotated with the
1578 // right number of type parameters.
1579 ast::DefStaticMethod(_, provenance, _) => {
1581 generics_of_static_method_container(function_context.ccx.tcx,
1583 let name = match provenance {
1584 ast::FromTrait(_) => "trait",
1585 ast::FromImpl(_) => "impl",
1588 let trait_segment = &path.segments.get(path.segments.len() - 2);
1590 // Make sure lifetime parameterization agrees with the trait or
1591 // implementation type.
1592 let trait_region_parameter_count = generics.region_param_defs().len();
1593 let supplied_region_parameter_count = trait_segment.lifetimes.len();
1594 if trait_region_parameter_count != supplied_region_parameter_count
1595 && supplied_region_parameter_count != 0 {
1596 function_context.tcx()
1598 .span_err(path.span,
1599 format!("expected {nexpected, plural, =1{# lifetime parameter} \
1600 other{# lifetime parameters}}, \
1601 found {nsupplied, plural, =1{# lifetime parameter} \
1602 other{# lifetime parameters}}",
1603 nexpected = trait_region_parameter_count,
1604 nsupplied = supplied_region_parameter_count));
1607 // Make sure the number of type parameters supplied on the trait
1608 // or implementation segment equals the number of type parameters
1609 // on the trait or implementation definition.
1610 let formal_ty_param_count = generics.type_param_defs().len();
1611 let required_ty_param_count = generics.type_param_defs().iter()
1612 .take_while(|x| x.default.is_none())
1614 let supplied_ty_param_count = trait_segment.types.len();
1615 if supplied_ty_param_count < required_ty_param_count {
1616 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1617 format!("the {trait_or_impl} referenced by this path needs at least \
1618 {nexpected, plural, =1{# type parameter} \
1619 other{# type parameters}}, \
1620 but {nsupplied, plural, =1{# type parameter} \
1621 other{# type parameters}} were supplied",
1622 trait_or_impl = name,
1623 nexpected = required_ty_param_count,
1624 nsupplied = supplied_ty_param_count)
1626 format!("the {trait_or_impl} referenced by this path needs \
1627 {nexpected, plural, =1{# type parameter} \
1628 other{# type parameters}}, \
1629 but {nsupplied, plural, =1{# type parameter} \
1630 other{# type parameters}} were supplied",
1631 trait_or_impl = name,
1632 nexpected = required_ty_param_count,
1633 nsupplied = supplied_ty_param_count)
1635 function_context.tcx().sess.span_err(path.span, msg)
1636 } else if supplied_ty_param_count > formal_ty_param_count {
1637 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1638 format!("the {trait_or_impl} referenced by this path needs at most \
1639 {nexpected, plural, =1{# type parameter} \
1640 other{# type parameters}}, \
1641 but {nsupplied, plural, =1{# type parameter} \
1642 other{# type parameters}} were supplied",
1643 trait_or_impl = name,
1644 nexpected = formal_ty_param_count,
1645 nsupplied = supplied_ty_param_count)
1647 format!("the {trait_or_impl} referenced by this path needs \
1648 {nexpected, plural, =1{# type parameter} \
1649 other{# type parameters}}, \
1650 but {nsupplied, plural, =1{# type parameter} \
1651 other{# type parameters}} were supplied",
1652 trait_or_impl = name,
1653 nexpected = formal_ty_param_count,
1654 nsupplied = supplied_ty_param_count)
1656 function_context.tcx().sess.span_err(path.span, msg)
1660 // Verify that no lifetimes or type parameters are present on
1661 // the penultimate segment of the path.
1662 let segment = &path.segments.get(path.segments.len() - 2);
1663 for lifetime in segment.lifetimes.iter() {
1664 function_context.tcx()
1666 .span_err(lifetime.span,
1667 "lifetime parameters may not
1671 for typ in segment.types.iter() {
1672 function_context.tcx()
1675 "type parameters may not appear \
1684 /// If an expression has any sub-expressions that result in a type error,
1685 /// inspecting that expression's type with `ty::type_is_error` will return
1686 /// true. Likewise, if an expression is known to diverge, inspecting its
1687 /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
1688 /// strict, _|_ can appear in the type of an expression that does not,
1689 /// itself, diverge: for example, fn() -> _|_.)
1690 /// Note that inspecting a type's structure *directly* may expose the fact
1691 /// that there are actually multiple representations for both `ty_err` and
1692 /// `ty_bot`, so avoid that when err and bot need to be handled differently.
1693 fn check_expr_with_unifier(fcx: &FnCtxt,
1695 expected: Option<ty::t>,
1696 lvalue_pref: LvaluePreference,
1698 debug!(">> typechecking");
1700 fn check_method_argument_types(
1703 method_fn_ty: ty::t,
1704 callee_expr: &ast::Expr,
1705 args: &[@ast::Expr],
1706 deref_args: DerefArgs) -> ty::t {
1707 // HACK(eddyb) ignore provided self (it has special typeck rules).
1708 let args = args.slice_from(1);
1709 if ty::type_is_error(method_fn_ty) {
1710 let err_inputs = err_args(args.len());
1711 check_argument_types(fcx, sp, err_inputs.as_slice(), callee_expr,
1712 args, deref_args, false);
1715 match ty::get(method_fn_ty).sty {
1716 ty::ty_bare_fn(ref fty) => {
1717 // HACK(eddyb) ignore self in the definition (see above).
1718 check_argument_types(fcx, sp, fty.sig.inputs.slice_from(1),
1719 callee_expr, args, deref_args,
1724 fcx.tcx().sess.span_bug(
1726 format!("method without bare fn type"));
1732 fn check_argument_types(fcx: &FnCtxt,
1734 fn_inputs: &[ty::t],
1735 callee_expr: &ast::Expr,
1736 args: &[@ast::Expr],
1737 deref_args: DerefArgs,
1741 * Generic function that factors out common logic from
1742 * function calls, method calls and overloaded operators.
1745 let tcx = fcx.ccx.tcx;
1747 // Grab the argument types, supplying fresh type variables
1748 // if the wrong number of arguments were supplied
1749 let supplied_arg_count = args.len();
1750 let expected_arg_count = fn_inputs.len();
1751 let formal_tys = if expected_arg_count == supplied_arg_count {
1752 fn_inputs.iter().map(|a| *a).collect()
1753 } else if variadic {
1754 if supplied_arg_count >= expected_arg_count {
1755 fn_inputs.iter().map(|a| *a).collect()
1758 "this function takes at least {nexpected, plural, =1{# parameter} \
1759 other{# parameters}} \
1760 but {nsupplied, plural, =1{# parameter was} \
1761 other{# parameters were}} supplied",
1762 nexpected = expected_arg_count,
1763 nsupplied = supplied_arg_count);
1765 tcx.sess.span_err(sp, msg);
1767 err_args(supplied_arg_count)
1771 "this function takes {nexpected, plural, =1{# parameter} \
1772 other{# parameters}} \
1773 but {nsupplied, plural, =1{# parameter was} \
1774 other{# parameters were}} supplied",
1775 nexpected = expected_arg_count,
1776 nsupplied = supplied_arg_count);
1778 tcx.sess.span_err(sp, msg);
1780 err_args(supplied_arg_count)
1783 debug!("check_argument_types: formal_tys={:?}",
1784 formal_tys.iter().map(|t| fcx.infcx().ty_to_str(*t)).collect::<Vec<~str>>());
1786 // Check the arguments.
1787 // We do this in a pretty awful way: first we typecheck any arguments
1788 // that are not anonymous functions, then we typecheck the anonymous
1789 // functions. This is so that we have more information about the types
1790 // of arguments when we typecheck the functions. This isn't really the
1791 // right way to do this.
1792 let xs = [false, true];
1793 for check_blocks in xs.iter() {
1794 let check_blocks = *check_blocks;
1795 debug!("check_blocks={}", check_blocks);
1797 // More awful hacks: before we check the blocks, try to do
1798 // an "opportunistic" vtable resolution of any trait
1799 // bounds on the call.
1801 vtable::early_resolve_expr(callee_expr, fcx, true);
1804 // For variadic functions, we don't have a declared type for all of
1805 // the arguments hence we only do our usual type checking with
1806 // the arguments who's types we do know.
1807 let t = if variadic {
1812 for (i, arg) in args.iter().take(t).enumerate() {
1813 let is_block = match arg.node {
1814 ast::ExprFnBlock(..) |
1815 ast::ExprProc(..) => true,
1819 if is_block == check_blocks {
1820 debug!("checking the argument");
1821 let mut formal_ty = *formal_tys.get(i);
1825 match ty::get(formal_ty).sty {
1826 ty::ty_rptr(_, mt) => formal_ty = mt.ty,
1829 // So we hit this case when one implements the
1830 // operator traits but leaves an argument as
1831 // just T instead of &T. We'll catch it in the
1832 // mismatch impl/trait method phase no need to
1835 formal_ty = ty::mk_err();
1842 check_expr_coercable_to_type(fcx, *arg, formal_ty);
1848 // We also need to make sure we at least write the ty of the other
1849 // arguments which we skipped above.
1851 for arg in args.iter().skip(expected_arg_count) {
1852 check_expr(fcx, *arg);
1854 // There are a few types which get autopromoted when passed via varargs
1855 // in C but we just error out instead and require explicit casts.
1856 let arg_ty = structurally_resolved_type(fcx, arg.span, fcx.expr_ty(*arg));
1857 match ty::get(arg_ty).sty {
1858 ty::ty_float(ast::TyF32) => {
1859 fcx.type_error_message(arg.span,
1860 |t| format!("can't pass an {} to variadic function, \
1861 cast to c_double", t), arg_ty, None);
1863 ty::ty_int(ast::TyI8) | ty::ty_int(ast::TyI16) | ty::ty_bool => {
1864 fcx.type_error_message(arg.span,
1865 |t| format!("can't pass {} to variadic function, cast to c_int",
1868 ty::ty_uint(ast::TyU8) | ty::ty_uint(ast::TyU16) => {
1869 fcx.type_error_message(arg.span,
1870 |t| format!("can't pass {} to variadic function, cast to c_uint",
1879 fn err_args(len: uint) -> Vec<ty::t> {
1880 Vec::from_fn(len, |_| ty::mk_err())
1883 fn write_call(fcx: &FnCtxt, call_expr: &ast::Expr, output: ty::t) {
1884 fcx.write_ty(call_expr.id, output);
1887 // A generic function for doing all of the checking for call expressions
1888 fn check_call(fcx: &FnCtxt,
1889 call_expr: &ast::Expr,
1891 args: &[@ast::Expr]) {
1892 // Index expressions need to be handled separately, to inform them
1893 // that they appear in call position.
1896 // Store the type of `f` as the type of the callee
1897 let fn_ty = fcx.expr_ty(f);
1899 // Extract the function signature from `in_fty`.
1900 let fn_sty = structure_of(fcx, f.span, fn_ty);
1902 // This is the "default" function signature, used in case of error.
1903 // In that case, we check each argument against "error" in order to
1904 // set up all the node type bindings.
1905 let error_fn_sig = FnSig {
1906 binder_id: ast::CRATE_NODE_ID,
1907 inputs: err_args(args.len()),
1908 output: ty::mk_err(),
1912 let fn_sig = match *fn_sty {
1913 ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, ..}) |
1914 ty::ty_closure(~ty::ClosureTy {sig: ref sig, ..}) => sig,
1916 fcx.type_error_message(call_expr.span, |actual| {
1917 format!("expected function but \
1918 found `{}`", actual) }, fn_ty, None);
1923 // Replace any bound regions that appear in the function
1924 // signature with region variables
1925 let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
1926 fcx.infcx().next_region_var(infer::LateBoundRegion(call_expr.span, br))
1929 // Call the generic checker.
1930 check_argument_types(fcx, call_expr.span, fn_sig.inputs.as_slice(), f,
1931 args, DontDerefArgs, fn_sig.variadic);
1933 write_call(fcx, call_expr, fn_sig.output);
1936 // Checks a method call.
1937 fn check_method_call(fcx: &FnCtxt,
1939 method_name: ast::Ident,
1940 args: &[@ast::Expr],
1941 tps: &[ast::P<ast::Ty>]) {
1943 // We can't know if we need &mut self before we look up the method,
1944 // so treat the receiver as mutable just in case - only explicit
1945 // overloaded dereferences care about the distinction.
1946 check_expr_with_lvalue_pref(fcx, rcvr, PreferMutLvalue);
1948 // no need to check for bot/err -- callee does that
1949 let expr_t = structurally_resolved_type(fcx,
1953 let tps = tps.iter().map(|&ast_ty| fcx.to_ty(ast_ty)).collect::<Vec<_>>();
1954 let fn_ty = match method::lookup(fcx, expr, rcvr,
1956 expr_t, tps.as_slice(),
1958 CheckTraitsAndInherentMethods,
1959 AutoderefReceiver) {
1961 let method_ty = method.ty;
1962 let method_call = MethodCall::expr(expr.id);
1963 fcx.inh.method_map.borrow_mut().insert(method_call, method);
1967 debug!("(checking method call) failing expr is {}", expr.id);
1969 fcx.type_error_message(expr.span,
1971 format!("type `{}` does not implement any method in scope \
1973 actual, token::get_ident(method_name))
1978 // Add error type for the result
1979 fcx.write_error(expr.id);
1984 // Call the generic checker.
1985 let ret_ty = check_method_argument_types(fcx, expr.span,
1989 write_call(fcx, expr, ret_ty);
1992 // A generic function for checking the then and else in an if
1994 fn check_then_else(fcx: &FnCtxt,
1995 cond_expr: &ast::Expr,
1996 then_blk: &ast::Block,
1997 opt_else_expr: Option<@ast::Expr>,
2000 expected: Option<ty::t>) {
2001 check_expr_has_type(fcx, cond_expr, ty::mk_bool());
2003 let branches_ty = match opt_else_expr {
2004 Some(else_expr) => {
2005 check_block_with_expected(fcx, then_blk, expected);
2006 let then_ty = fcx.node_ty(then_blk.id);
2007 check_expr_with_opt_hint(fcx, else_expr, expected);
2008 let else_ty = fcx.expr_ty(else_expr);
2009 infer::common_supertype(fcx.infcx(),
2010 infer::IfExpression(sp),
2016 check_block_no_value(fcx, then_blk);
2021 let cond_ty = fcx.expr_ty(cond_expr);
2022 let if_ty = if ty::type_is_error(cond_ty) {
2024 } else if ty::type_is_bot(cond_ty) {
2030 fcx.write_ty(id, if_ty);
2033 fn lookup_op_method(fcx: &FnCtxt,
2037 trait_did: Option<ast::DefId>,
2038 args: &[@ast::Expr],
2039 autoderef_receiver: AutoderefReceiverFlag,
2040 unbound_method: ||) -> ty::t {
2041 let method = match trait_did {
2042 Some(trait_did) => {
2043 method::lookup_in_trait(fcx, op_ex.span, Some(&*args[0]), opname,
2044 trait_did, self_t, [], autoderef_receiver)
2050 let method_ty = method.ty;
2051 // HACK(eddyb) Fully qualified path to work around a resolve bug.
2052 let method_call = ::middle::typeck::MethodCall::expr(op_ex.id);
2053 fcx.inh.method_map.borrow_mut().insert(method_call, method);
2054 check_method_argument_types(fcx, op_ex.span,
2060 // Check the args anyway
2061 // so we get all the error messages
2062 let expected_ty = ty::mk_err();
2063 check_method_argument_types(fcx, op_ex.span,
2071 // could be either an expr_binop or an expr_assign_binop
2072 fn check_binop(fcx: &FnCtxt,
2077 is_binop_assignment: IsBinopAssignment) {
2078 let tcx = fcx.ccx.tcx;
2080 let lvalue_pref = match is_binop_assignment {
2081 BinopAssignment => PreferMutLvalue,
2082 SimpleBinop => NoPreference
2084 check_expr_with_lvalue_pref(fcx, lhs, lvalue_pref);
2086 // Callee does bot / err checking
2087 let lhs_t = structurally_resolved_type(fcx, lhs.span,
2090 if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) {
2091 // Shift is a special case: rhs can be any integral type
2092 check_expr(fcx, rhs);
2093 let rhs_t = fcx.expr_ty(rhs);
2094 require_integral(fcx, rhs.span, rhs_t);
2095 fcx.write_ty(expr.id, lhs_t);
2099 if ty::is_binopable(tcx, lhs_t, op) {
2100 let tvar = fcx.infcx().next_ty_var();
2101 demand::suptype(fcx, expr.span, tvar, lhs_t);
2102 check_expr_has_type(fcx, rhs, tvar);
2104 let result_t = match op {
2105 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGe |
2106 ast::BiGt => ty::mk_bool(),
2110 fcx.write_ty(expr.id, result_t);
2114 if op == ast::BiOr || op == ast::BiAnd {
2115 // This is an error; one of the operands must have the wrong
2117 fcx.write_error(expr.id);
2118 fcx.write_error(rhs.id);
2119 fcx.type_error_message(expr.span, |actual| {
2120 format!("binary operation `{}` cannot be applied \
2122 ast_util::binop_to_str(op), actual)},
2127 // Check for overloaded operators if not an assignment.
2128 let result_t = if is_binop_assignment == SimpleBinop {
2129 check_user_binop(fcx, expr, lhs, lhs_t, op, rhs)
2131 fcx.type_error_message(expr.span,
2133 format!("binary assignment operation \
2134 `{}=` cannot be applied to type `{}`",
2135 ast_util::binop_to_str(op),
2140 check_expr(fcx, rhs);
2144 fcx.write_ty(expr.id, result_t);
2145 if ty::type_is_error(result_t) {
2146 fcx.write_ty(rhs.id, result_t);
2150 fn check_user_binop(fcx: &FnCtxt,
2152 lhs_expr: @ast::Expr,
2153 lhs_resolved_t: ty::t,
2155 rhs: @ast::Expr) -> ty::t {
2156 let tcx = fcx.ccx.tcx;
2157 let lang = &tcx.lang_items;
2158 let (name, trait_did) = match op {
2159 ast::BiAdd => ("add", lang.add_trait()),
2160 ast::BiSub => ("sub", lang.sub_trait()),
2161 ast::BiMul => ("mul", lang.mul_trait()),
2162 ast::BiDiv => ("div", lang.div_trait()),
2163 ast::BiRem => ("rem", lang.rem_trait()),
2164 ast::BiBitXor => ("bitxor", lang.bitxor_trait()),
2165 ast::BiBitAnd => ("bitand", lang.bitand_trait()),
2166 ast::BiBitOr => ("bitor", lang.bitor_trait()),
2167 ast::BiShl => ("shl", lang.shl_trait()),
2168 ast::BiShr => ("shr", lang.shr_trait()),
2169 ast::BiLt => ("lt", lang.ord_trait()),
2170 ast::BiLe => ("le", lang.ord_trait()),
2171 ast::BiGe => ("ge", lang.ord_trait()),
2172 ast::BiGt => ("gt", lang.ord_trait()),
2173 ast::BiEq => ("eq", lang.eq_trait()),
2174 ast::BiNe => ("ne", lang.eq_trait()),
2175 ast::BiAnd | ast::BiOr => {
2176 check_expr(fcx, rhs);
2177 return ty::mk_err();
2180 lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
2181 trait_did, [lhs_expr, rhs], DontAutoderefReceiver, || {
2182 fcx.type_error_message(ex.span, |actual| {
2183 format!("binary operation `{}` cannot be applied to type `{}`",
2184 ast_util::binop_to_str(op), actual)
2185 }, lhs_resolved_t, None)
2189 fn check_user_unop(fcx: &FnCtxt,
2192 trait_did: Option<ast::DefId>,
2194 rhs_expr: @ast::Expr,
2195 rhs_t: ty::t) -> ty::t {
2196 lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
2197 trait_did, [rhs_expr], DontAutoderefReceiver, || {
2198 fcx.type_error_message(ex.span, |actual| {
2199 format!("cannot apply unary operator `{}` to type `{}`", op_str, actual)
2204 // Resolves `expected` by a single level if it is a variable and passes it
2205 // through the `unpack` function. It there is no expected type or
2206 // resolution is not possible (e.g., no constraints yet present), just
2208 fn unpack_expected<O>(
2210 expected: Option<ty::t>,
2211 unpack: |&ty::sty| -> Option<O>)
2215 match resolve_type(fcx.infcx(), t, force_tvar) {
2216 Ok(t) => unpack(&ty::get(t).sty),
2224 fn check_expr_fn(fcx: &FnCtxt,
2226 store: ty::TraitStore,
2228 body: ast::P<ast::Block>,
2230 expected: Option<ty::t>) {
2231 let tcx = fcx.ccx.tcx;
2233 // Find the expected input/output types (if any). Substitute
2234 // fresh bound regions for any bound regions we find in the
2235 // expected types so as to avoid capture.
2236 let expected_sty = unpack_expected(fcx,
2238 |x| Some((*x).clone()));
2241 expected_bounds) = {
2242 match expected_sty {
2243 Some(ty::ty_closure(ref cenv)) => {
2245 replace_late_bound_regions_in_fn_sig(
2247 |_| fcx.inh.infcx.fresh_bound_region(expr.id));
2248 let onceness = match (&store, &cenv.store) {
2249 // As the closure type and onceness go, only three
2250 // combinations are legit:
2254 // If the actual and expected closure type disagree with
2255 // each other, set expected onceness to be always Once or
2256 // Many according to the actual type. Otherwise, it will
2257 // yield either an illegal "many proc" or a less known
2258 // "once closure" in the error message.
2259 (&ty::UniqTraitStore, &ty::UniqTraitStore) |
2260 (&ty::RegionTraitStore(..), &ty::RegionTraitStore(..)) =>
2262 (&ty::UniqTraitStore, _) => ast::Once,
2263 (&ty::RegionTraitStore(..), _) => ast::Many,
2265 (Some(sig), onceness, cenv.bounds)
2268 // Not an error! Means we're inferring the closure type
2269 let mut bounds = ty::EmptyBuiltinBounds();
2270 let onceness = match expr.node {
2271 ast::ExprProc(..) => {
2272 bounds.add(ty::BoundSend);
2277 (None, onceness, bounds)
2282 // construct the function type
2283 let fn_ty = astconv::ty_of_closure(fcx,
2291 let fty_sig = fn_ty.sig.clone();
2292 let fty = ty::mk_closure(tcx, fn_ty);
2293 debug!("check_expr_fn fty={}", fcx.infcx().ty_to_str(fty));
2295 fcx.write_ty(expr.id, fty);
2297 // If the closure is a stack closure and hasn't had some non-standard
2298 // style inferred for it, then check it under its parent's style.
2299 // Otherwise, use its own
2300 let (inherited_style, id) = match store {
2301 ty::RegionTraitStore(..) => (fcx.ps.borrow().fn_style,
2302 fcx.ps.borrow().def),
2303 ty::UniqTraitStore => (ast::NormalFn, expr.id)
2306 check_fn(fcx.ccx, inherited_style, &fty_sig,
2307 decl, id, body, fn_kind, fcx.inh);
2311 // Check field access expressions
2312 fn check_field(fcx: &FnCtxt,
2314 lvalue_pref: LvaluePreference,
2317 tys: &[ast::P<ast::Ty>]) {
2318 let tcx = fcx.ccx.tcx;
2319 check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
2320 let expr_t = structurally_resolved_type(fcx, expr.span,
2322 // FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
2323 let (_, autoderefs, field_ty) =
2324 autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
2325 match ty::get(base_t).sty {
2326 ty::ty_struct(base_id, ref substs) => {
2327 debug!("struct named {}", ppaux::ty_to_str(tcx, base_t));
2328 let fields = ty::lookup_struct_fields(tcx, base_id);
2329 lookup_field_ty(tcx, base_id, fields.as_slice(), field, &(*substs))
2336 fcx.write_ty(expr.id, field_ty);
2337 fcx.write_autoderef_adjustment(base.id, autoderefs);
2343 let tps: Vec<ty::t> = tys.iter().map(|&ty| fcx.to_ty(ty)).collect();
2344 match method::lookup(fcx,
2351 CheckTraitsAndInherentMethods,
2352 AutoderefReceiver) {
2354 fcx.type_error_message(
2357 format!("attempted to take value of method `{}` on type `{}`",
2358 token::get_name(field), actual)
2362 tcx.sess.span_note(expr.span,
2363 "maybe a missing `()` to call it? If not, try an anonymous function.");
2367 fcx.type_error_message(
2370 format!("attempted access of field `{}` on type `{}`, \
2371 but no field with that name was found",
2372 token::get_name(field), actual)
2378 fcx.write_error(expr.id);
2381 fn check_struct_or_variant_fields(fcx: &FnCtxt,
2384 class_id: ast::DefId,
2385 node_id: ast::NodeId,
2386 substitutions: ty::substs,
2387 field_types: &[ty::field_ty],
2388 ast_fields: &[ast::Field],
2389 check_completeness: bool) {
2390 let tcx = fcx.ccx.tcx;
2392 let mut class_field_map = HashMap::new();
2393 let mut fields_found = 0;
2394 for field in field_types.iter() {
2395 class_field_map.insert(field.name, (field.id, false));
2398 let mut error_happened = false;
2400 // Typecheck each field.
2401 for field in ast_fields.iter() {
2402 let mut expected_field_type = ty::mk_err();
2404 let pair = class_field_map.find(&field.ident.node.name).map(|x| *x);
2407 fcx.type_error_message(
2410 format!("structure `{}` has no field named `{}`",
2411 actual, token::get_ident(field.ident.node))
2412 }, struct_ty, None);
2413 error_happened = true;
2415 Some((_, true)) => {
2418 format!("field `{}` specified more than once",
2419 token::get_ident(field.ident.node)));
2420 error_happened = true;
2422 Some((field_id, false)) => {
2423 expected_field_type =
2424 ty::lookup_field_type(
2425 tcx, class_id, field_id, &substitutions);
2426 class_field_map.insert(
2427 field.ident.node.name, (field_id, true));
2431 // Make sure to give a type to the field even if there's
2432 // an error, so we can continue typechecking
2433 check_expr_coercable_to_type(
2436 expected_field_type);
2440 fcx.write_error(node_id);
2443 if check_completeness && !error_happened {
2444 // Make sure the programmer specified all the fields.
2445 assert!(fields_found <= field_types.len());
2446 if fields_found < field_types.len() {
2447 let mut missing_fields = Vec::new();
2448 for class_field in field_types.iter() {
2449 let name = class_field.name;
2450 let (_, seen) = *class_field_map.get(&name);
2452 missing_fields.push("`".to_owned() + token::get_name(name).get() + "`");
2456 tcx.sess.span_err(span,
2457 format!("missing {nfields, plural, =1{field} other{fields}}: {fields}",
2458 nfields = missing_fields.len(),
2459 fields = missing_fields.connect(", ")));
2463 if !error_happened {
2464 fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx,
2465 class_id, substitutions));
2469 fn check_struct_constructor(fcx: &FnCtxt,
2471 span: codemap::Span,
2472 class_id: ast::DefId,
2473 fields: &[ast::Field],
2474 base_expr: Option<@ast::Expr>) {
2475 let tcx = fcx.ccx.tcx;
2477 // Look up the number of type parameters and the raw type, and
2478 // determine whether the class is region-parameterized.
2479 let item_type = ty::lookup_item_type(tcx, class_id);
2480 let type_parameter_count = item_type.generics.type_param_defs().len();
2481 let region_param_defs = item_type.generics.region_param_defs();
2482 let raw_type = item_type.ty;
2484 // Generate the struct type.
2485 let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs);
2486 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2487 let substitutions = substs {
2488 regions: ty::NonerasedRegions(regions),
2490 tps: type_parameters
2493 let mut struct_type = ty::subst(tcx, &substitutions, raw_type);
2495 // Look up and check the fields.
2496 let class_fields = ty::lookup_struct_fields(tcx, class_id);
2497 check_struct_or_variant_fields(fcx,
2503 class_fields.as_slice(),
2505 base_expr.is_none());
2506 if ty::type_is_error(fcx.node_ty(id)) {
2507 struct_type = ty::mk_err();
2510 // Check the base expression if necessary.
2513 Some(base_expr) => {
2514 check_expr_has_type(fcx, base_expr, struct_type);
2515 if ty::type_is_bot(fcx.node_ty(base_expr.id)) {
2516 struct_type = ty::mk_bot();
2521 // Write in the resulting type.
2522 fcx.write_ty(id, struct_type);
2525 fn check_struct_enum_variant(fcx: &FnCtxt,
2527 span: codemap::Span,
2528 enum_id: ast::DefId,
2529 variant_id: ast::DefId,
2530 fields: &[ast::Field]) {
2531 let tcx = fcx.ccx.tcx;
2533 // Look up the number of type parameters and the raw type, and
2534 // determine whether the enum is region-parameterized.
2535 let item_type = ty::lookup_item_type(tcx, enum_id);
2536 let type_parameter_count = item_type.generics.type_param_defs().len();
2537 let region_param_defs = item_type.generics.region_param_defs();
2538 let raw_type = item_type.ty;
2540 // Generate the enum type.
2541 let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs);
2542 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2543 let substitutions = substs {
2544 regions: ty::NonerasedRegions(regions),
2546 tps: type_parameters
2549 let enum_type = ty::subst(tcx, &substitutions, raw_type);
2551 // Look up and check the enum variant fields.
2552 let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2553 check_struct_or_variant_fields(fcx,
2559 variant_fields.as_slice(),
2562 fcx.write_ty(id, enum_type);
2565 let tcx = fcx.ccx.tcx;
2568 ast::ExprVstore(ev, vst) => {
2569 let typ = match ev.node {
2570 ast::ExprLit(lit) if ast_util::lit_is_str(lit) => {
2571 let v = ast_expr_vstore_to_vstore(fcx, ev, vst);
2574 ast::ExprVec(ref args) => {
2575 let mutability = match vst {
2576 ast::ExprVstoreMutSlice => ast::MutMutable,
2577 _ => ast::MutImmutable,
2579 let v = ast_expr_vstore_to_vstore(fcx, ev, vst);
2580 let mut any_error = false;
2581 let mut any_bot = false;
2582 let t: ty::t = fcx.infcx().next_ty_var();
2583 for e in args.iter() {
2584 check_expr_has_type(fcx, *e, t);
2585 let arg_t = fcx.expr_ty(*e);
2586 if ty::type_is_error(arg_t) {
2589 else if ty::type_is_bot(arg_t) {
2599 ty::VstoreFixed(sz) => ty::mk_vec(tcx,
2600 ty::mt {ty: t, mutbl: mutability},
2602 ty::VstoreUniq => ty::mk_uniq(tcx,
2604 ty::mt {ty: t, mutbl: mutability},
2605 None)), // Sadly, we know the length
2606 // - Some(args.len()) - but
2607 // must throw it away or cause
2608 // confusion further down the
2609 // pipeline. Hopefully we can
2610 // remedy this later.
2611 // See below (x3) too.
2612 ty::VstoreSlice(r) => ty::mk_slice(tcx, r,
2613 ty::mt {ty: t, mutbl: mutability}),
2617 ast::ExprRepeat(element, count_expr) => {
2618 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2619 let _ = ty::eval_repeat_count(fcx, count_expr);
2620 let mutability = match vst {
2621 ast::ExprVstoreMutSlice => ast::MutMutable,
2622 _ => ast::MutImmutable,
2624 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2625 let t = fcx.infcx().next_ty_var();
2626 check_expr_has_type(fcx, element, t);
2627 let arg_t = fcx.expr_ty(element);
2628 if ty::type_is_error(arg_t) {
2630 } else if ty::type_is_bot(arg_t) {
2634 ty::VstoreFixed(sz) => ty::mk_vec(tcx,
2635 ty::mt {ty: t, mutbl: mutability},
2637 ty::VstoreUniq => ty::mk_uniq(tcx,
2639 ty::mt {ty: t, mutbl: mutability},
2641 ty::VstoreSlice(r) => ty::mk_slice(tcx, r,
2642 ty::mt {ty: t, mutbl: mutability}),
2647 tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence")
2649 fcx.write_ty(ev.id, typ);
2650 fcx.write_ty(id, typ);
2653 ast::ExprBox(place, subexpr) => {
2654 check_expr(fcx, place);
2655 check_expr(fcx, subexpr);
2657 let mut checked = false;
2659 ast::ExprPath(ref path) => {
2660 // FIXME(pcwalton): For now we hardcode the two permissible
2661 // places: the exchange heap and the managed heap.
2662 let definition = lookup_def(fcx, path.span, place.id);
2663 let def_id = ast_util::def_id_of_def(definition);
2664 match tcx.lang_items
2666 .get(ExchangeHeapLangItem as uint) {
2667 &Some(item_def_id) if def_id == item_def_id => {
2668 fcx.write_ty(id, ty::mk_uniq(tcx,
2669 fcx.expr_ty(subexpr)));
2672 &Some(_) | &None => {}
2675 match tcx.lang_items
2677 .get(ManagedHeapLangItem as uint) {
2678 &Some(item_def_id) if def_id == item_def_id => {
2679 // Assign the magic `Gc<T>` struct.
2681 match tcx.lang_items
2682 .require(GcLangItem) {
2685 tcx.sess.span_err(expr.span, msg);
2687 krate: ast::CRATE_NODE_ID,
2688 node: ast::DUMMY_NODE_ID,
2693 ty::NonerasedRegions(OwnedSlice::empty());
2694 let sty = ty::mk_struct(tcx,
2704 fcx.write_ty(id, sty);
2707 &Some(_) | &None => {}
2715 tcx.sess.span_err(expr.span,
2716 "only the managed heap and exchange heap are \
2717 currently supported")
2721 ast::ExprLit(lit) => {
2722 let typ = check_lit(fcx, lit);
2723 fcx.write_ty(id, typ);
2725 ast::ExprBinary(op, lhs, rhs) => {
2726 check_binop(fcx, expr, op, lhs, rhs, SimpleBinop);
2728 let lhs_ty = fcx.expr_ty(lhs);
2729 let rhs_ty = fcx.expr_ty(rhs);
2730 if ty::type_is_error(lhs_ty) ||
2731 ty::type_is_error(rhs_ty) {
2732 fcx.write_error(id);
2734 else if ty::type_is_bot(lhs_ty) ||
2735 (ty::type_is_bot(rhs_ty) && !ast_util::lazy_binop(op)) {
2739 ast::ExprAssignOp(op, lhs, rhs) => {
2740 check_binop(fcx, expr, op, lhs, rhs, BinopAssignment);
2742 let lhs_t = fcx.expr_ty(lhs);
2743 let result_t = fcx.expr_ty(expr);
2744 demand::suptype(fcx, expr.span, result_t, lhs_t);
2746 let tcx = fcx.tcx();
2747 if !ty::expr_is_lval(tcx, lhs) {
2748 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2751 // Overwrite result of check_binop...this preserves existing behavior
2752 // but seems quite dubious with regard to user-defined methods
2753 // and so forth. - Niko
2754 if !ty::type_is_error(result_t)
2755 && !ty::type_is_bot(result_t) {
2756 fcx.write_nil(expr.id);
2759 ast::ExprUnary(unop, oprnd) => {
2760 let exp_inner = unpack_expected(fcx, expected, |sty| {
2762 ast::UnBox | ast::UnUniq => match *sty {
2763 ty::ty_box(ty) | ty::ty_uniq(ty) => Some(ty),
2766 ast::UnNot | ast::UnNeg => expected,
2767 ast::UnDeref => None
2770 let lvalue_pref = match unop {
2771 ast::UnDeref => lvalue_pref,
2774 check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, exp_inner, lvalue_pref);
2775 let mut oprnd_t = fcx.expr_ty(oprnd);
2776 if !ty::type_is_error(oprnd_t) && !ty::type_is_bot(oprnd_t) {
2779 oprnd_t = ty::mk_box(tcx, oprnd_t)
2782 oprnd_t = ty::mk_uniq(tcx, oprnd_t);
2785 oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
2786 oprnd_t = match ty::deref(oprnd_t, true) {
2788 None => match try_overloaded_deref(fcx, expr.span,
2789 Some(MethodCall::expr(expr.id)),
2790 Some(&*oprnd), oprnd_t, lvalue_pref) {
2793 let is_newtype = match ty::get(oprnd_t).sty {
2794 ty::ty_struct(did, ref substs) => {
2795 let fields = ty::struct_fields(fcx.tcx(), did, substs);
2797 && fields.get(0).ident ==
2798 token::special_idents::unnamed_field
2803 // This is an obsolete struct deref
2804 tcx.sess.span_err(expr.span,
2805 "single-field tuple-structs can \
2806 no longer be dereferenced");
2808 fcx.type_error_message(expr.span, |actual| {
2809 format!("type `{}` cannot be dereferenced", actual)
2818 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2820 if !(ty::type_is_integral(oprnd_t) ||
2821 ty::get(oprnd_t).sty == ty::ty_bool) {
2822 oprnd_t = check_user_unop(fcx, "!", "not",
2823 tcx.lang_items.not_trait(),
2824 expr, oprnd, oprnd_t);
2828 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2830 if !(ty::type_is_integral(oprnd_t) ||
2831 ty::type_is_fp(oprnd_t)) {
2832 oprnd_t = check_user_unop(fcx, "-", "neg",
2833 tcx.lang_items.neg_trait(),
2834 expr, oprnd, oprnd_t);
2839 fcx.write_ty(id, oprnd_t);
2841 ast::ExprAddrOf(mutbl, oprnd) => {
2842 let hint = unpack_expected(
2844 |sty| match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty),
2846 let lvalue_pref = match mutbl {
2847 ast::MutMutable => PreferMutLvalue,
2848 ast::MutImmutable => NoPreference
2850 check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, hint, lvalue_pref);
2852 // Note: at this point, we cannot say what the best lifetime
2853 // is to use for resulting pointer. We want to use the
2854 // shortest lifetime possible so as to avoid spurious borrowck
2855 // errors. Moreover, the longest lifetime will depend on the
2856 // precise details of the value whose address is being taken
2857 // (and how long it is valid), which we don't know yet until type
2858 // inference is complete.
2860 // Therefore, here we simply generate a region variable. The
2861 // region inferencer will then select the ultimate value.
2862 // Finally, borrowck is charged with guaranteeing that the
2863 // value whose address was taken can actually be made to live
2864 // as long as it needs to live.
2865 let region = fcx.infcx().next_region_var(
2866 infer::AddrOfRegion(expr.span));
2868 let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
2869 let oprnd_t = if ty::type_is_error(tm.ty) {
2871 } else if ty::type_is_bot(tm.ty) {
2875 ty::mk_rptr(tcx, region, tm)
2877 fcx.write_ty(id, oprnd_t);
2879 ast::ExprPath(ref pth) => {
2880 let defn = lookup_def(fcx, pth.span, id);
2882 check_type_parameter_positions_in_path(fcx, pth, defn);
2883 let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2884 instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
2886 ast::ExprInlineAsm(ref ia) => {
2887 for &(_, input) in ia.inputs.iter() {
2888 check_expr(fcx, input);
2890 for &(_, out) in ia.outputs.iter() {
2891 check_expr(fcx, out);
2895 ast::ExprMac(_) => tcx.sess.bug("unexpanded macro"),
2896 ast::ExprBreak(_) => { fcx.write_bot(id); }
2897 ast::ExprAgain(_) => { fcx.write_bot(id); }
2898 ast::ExprRet(expr_opt) => {
2899 let ret_ty = fcx.ret_ty;
2901 None => match fcx.mk_eqty(false, infer::Misc(expr.span),
2902 ret_ty, ty::mk_nil()) {
2903 Ok(_) => { /* fall through */ }
2907 "`return;` in function returning non-nil");
2911 check_expr_has_type(fcx, e, ret_ty);
2916 ast::ExprParen(a) => {
2917 check_expr_with_opt_hint_and_lvalue_pref(fcx, a, expected, lvalue_pref);
2918 fcx.write_ty(id, fcx.expr_ty(a));
2920 ast::ExprAssign(lhs, rhs) => {
2921 check_expr_with_lvalue_pref(fcx, lhs, PreferMutLvalue);
2923 let tcx = fcx.tcx();
2924 if !ty::expr_is_lval(tcx, lhs) {
2925 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2928 let lhs_ty = fcx.expr_ty(lhs);
2929 check_expr_has_type(fcx, rhs, lhs_ty);
2930 let rhs_ty = fcx.expr_ty(rhs);
2932 if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
2933 fcx.write_error(id);
2934 } else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
2940 ast::ExprIf(cond, then_blk, opt_else_expr) => {
2941 check_then_else(fcx, cond, then_blk, opt_else_expr,
2942 id, expr.span, expected);
2944 ast::ExprWhile(cond, body) => {
2945 check_expr_has_type(fcx, cond, ty::mk_bool());
2946 check_block_no_value(fcx, body);
2947 let cond_ty = fcx.expr_ty(cond);
2948 let body_ty = fcx.node_ty(body.id);
2949 if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) {
2950 fcx.write_error(id);
2952 else if ty::type_is_bot(cond_ty) {
2959 ast::ExprForLoop(..) =>
2960 fail!("non-desugared expr_for_loop"),
2961 ast::ExprLoop(body, _) => {
2962 check_block_no_value(fcx, (body));
2963 if !may_break(tcx, expr.id, body) {
2970 ast::ExprMatch(discrim, ref arms) => {
2971 _match::check_match(fcx, expr, discrim, arms.as_slice());
2973 ast::ExprFnBlock(decl, body) => {
2974 let region = astconv::opt_ast_region_to_region(fcx,
2980 ty::RegionTraitStore(region, ast::MutMutable),
2986 ast::ExprProc(decl, body) => {
2995 ast::ExprBlock(b) => {
2996 check_block_with_expected(fcx, b, expected);
2997 fcx.write_ty(id, fcx.node_ty(b.id));
2999 ast::ExprCall(f, ref args) => {
3000 check_call(fcx, expr, f, args.as_slice());
3001 let f_ty = fcx.expr_ty(f);
3002 let (args_bot, args_err) = args.iter().fold((false, false),
3003 |(rest_bot, rest_err), a| {
3004 // is this not working?
3005 let a_ty = fcx.expr_ty(*a);
3006 (rest_bot || ty::type_is_bot(a_ty),
3007 rest_err || ty::type_is_error(a_ty))});
3008 if ty::type_is_error(f_ty) || args_err {
3009 fcx.write_error(id);
3011 else if ty::type_is_bot(f_ty) || args_bot {
3015 ast::ExprMethodCall(ident, ref tps, ref args) => {
3016 check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice());
3017 let mut arg_tys = args.iter().map(|a| fcx.expr_ty(*a));
3018 let (args_bot, args_err) = arg_tys.fold((false, false),
3019 |(rest_bot, rest_err), a| {
3020 (rest_bot || ty::type_is_bot(a),
3021 rest_err || ty::type_is_error(a))});
3023 fcx.write_error(id);
3024 } else if args_bot {
3028 ast::ExprCast(e, t) => {
3030 let t_1 = fcx.to_ty(t);
3031 let t_e = fcx.expr_ty(e);
3033 debug!("t_1={}", fcx.infcx().ty_to_str(t_1));
3034 debug!("t_e={}", fcx.infcx().ty_to_str(t_e));
3036 if ty::type_is_error(t_e) {
3037 fcx.write_error(id);
3039 else if ty::type_is_bot(t_e) {
3043 match ty::get(t_1).sty {
3044 // This will be looked up later on
3045 ty::ty_trait(..) => (),
3048 if ty::type_is_nil(t_e) {
3049 fcx.type_error_message(expr.span, |actual| {
3050 format!("cast from nil: `{}` as `{}`", actual,
3051 fcx.infcx().ty_to_str(t_1))
3053 } else if ty::type_is_nil(t_1) {
3054 fcx.type_error_message(expr.span, |actual| {
3055 format!("cast to nil: `{}` as `{}`", actual,
3056 fcx.infcx().ty_to_str(t_1))
3060 let t1 = structurally_resolved_type(fcx, e.span, t_1);
3061 let te = structurally_resolved_type(fcx, e.span, t_e);
3062 let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
3063 let t_1_is_char = type_is_char(fcx, expr.span, t_1);
3064 let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1);
3066 // casts to scalars other than `char` and `bare fn` are trivial
3067 let t_1_is_trivial = t_1_is_scalar &&
3068 !t_1_is_char && !t_1_is_bare_fn;
3070 if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial {
3071 // casts from C-like enums are allowed
3072 } else if t_1_is_char {
3073 let te = fcx.infcx().resolve_type_vars_if_possible(te);
3074 if ty::get(te).sty != ty::ty_uint(ast::TyU8) {
3075 fcx.type_error_message(expr.span, |actual| {
3076 format!("only `u8` can be cast as `char`, not `{}`", actual)
3079 } else if ty::get(t1).sty == ty::ty_bool {
3080 fcx.tcx().sess.span_err(expr.span,
3081 "cannot cast as `bool`, compare with zero instead");
3082 } else if type_is_region_ptr(fcx, expr.span, t_e) &&
3083 type_is_unsafe_ptr(fcx, expr.span, t_1) {
3085 fn is_vec(t: ty::t) -> bool {
3086 match ty::get(t).sty {
3087 ty::ty_vec(..) => true,
3088 ty::ty_ptr(ty::mt{ty: t, ..}) | ty::ty_rptr(_, ty::mt{ty: t, ..}) |
3089 ty::ty_box(t) | ty::ty_uniq(t) => match ty::get(t).sty {
3090 ty::ty_vec(_, None) => true,
3096 fn types_compatible(fcx: &FnCtxt, sp: Span,
3097 t1: ty::t, t2: ty::t) -> bool {
3101 let el = ty::sequence_element_type(fcx.tcx(),
3103 infer::mk_eqty(fcx.infcx(), false,
3104 infer::Misc(sp), el, t2).is_ok()
3108 // Due to the limitations of LLVM global constants,
3109 // region pointers end up pointing at copies of
3110 // vector elements instead of the original values.
3111 // To allow unsafe pointers to work correctly, we
3112 // need to special-case obtaining an unsafe pointer
3113 // from a region pointer to a vector.
3115 /* this cast is only allowed from &[T] to *T or
3117 match (&ty::get(te).sty, &ty::get(t_1).sty) {
3118 (&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
3119 if types_compatible(fcx, e.span,
3120 mt1.ty, mt2.ty) => {
3121 /* this case is allowed */
3124 demand::coerce(fcx, e.span, t_1, e);
3127 } else if !(type_is_scalar(fcx,expr.span,t_e)
3128 && t_1_is_trivial) {
3130 If more type combinations should be supported than are
3131 supported here, then file an enhancement issue and
3132 record the issue number in this comment.
3134 fcx.type_error_message(expr.span, |actual| {
3135 format!("non-scalar cast: `{}` as `{}`", actual,
3136 fcx.infcx().ty_to_str(t_1))
3141 fcx.write_ty(id, t_1);
3144 ast::ExprVec(ref args) => {
3145 let t: ty::t = fcx.infcx().next_ty_var();
3146 for e in args.iter() {
3147 check_expr_has_type(fcx, *e, t);
3149 let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable},
3151 fcx.write_ty(id, typ);
3153 ast::ExprRepeat(element, count_expr) => {
3154 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
3155 let count = ty::eval_repeat_count(fcx, count_expr);
3156 let t: ty::t = fcx.infcx().next_ty_var();
3157 check_expr_has_type(fcx, element, t);
3158 let element_ty = fcx.expr_ty(element);
3159 if ty::type_is_error(element_ty) {
3160 fcx.write_error(id);
3162 else if ty::type_is_bot(element_ty) {
3166 let t = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable},
3168 fcx.write_ty(id, t);
3171 ast::ExprTup(ref elts) => {
3172 let flds = unpack_expected(fcx, expected, |sty| {
3174 ty::ty_tup(ref flds) => Some((*flds).clone()),
3178 let mut bot_field = false;
3179 let mut err_field = false;
3181 let elt_ts = elts.iter().enumerate().map(|(i, e)| {
3182 let opt_hint = match flds {
3183 Some(ref fs) if i < fs.len() => Some(*fs.get(i)),
3186 check_expr_with_opt_hint(fcx, *e, opt_hint);
3187 let t = fcx.expr_ty(*e);
3188 err_field = err_field || ty::type_is_error(t);
3189 bot_field = bot_field || ty::type_is_bot(t);
3194 } else if err_field {
3195 fcx.write_error(id);
3197 let typ = ty::mk_tup(tcx, elt_ts);
3198 fcx.write_ty(id, typ);
3201 ast::ExprStruct(ref path, ref fields, base_expr) => {
3202 // Resolve the path.
3203 match tcx.def_map.borrow().find(&id) {
3204 Some(&ast::DefStruct(type_def_id)) => {
3205 check_struct_constructor(fcx, id, expr.span, type_def_id,
3206 fields.as_slice(), base_expr);
3208 Some(&ast::DefVariant(enum_id, variant_id, _)) => {
3209 check_struct_enum_variant(fcx, id, expr.span, enum_id,
3210 variant_id, fields.as_slice());
3213 tcx.sess.span_bug(path.span,
3214 "structure constructor does not name a structure type");
3218 ast::ExprField(base, field, ref tys) => {
3219 check_field(fcx, expr, lvalue_pref, base, field.name, tys.as_slice());
3221 ast::ExprIndex(base, idx) => {
3222 check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
3223 check_expr(fcx, idx);
3224 let raw_base_t = fcx.expr_ty(base);
3225 let idx_t = fcx.expr_ty(idx);
3226 if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
3227 fcx.write_ty(id, raw_base_t);
3228 } else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
3229 fcx.write_ty(id, idx_t);
3231 let (base_t, autoderefs, field_ty) =
3232 autoderef(fcx, expr.span, raw_base_t, Some(base.id),
3233 lvalue_pref, |base_t, _| ty::index(base_t));
3236 check_expr_has_type(fcx, idx, ty::mk_uint());
3237 fcx.write_ty(id, mt.ty);
3238 fcx.write_autoderef_adjustment(base.id, autoderefs);
3241 let resolved = structurally_resolved_type(fcx,
3244 let ret_ty = lookup_op_method(fcx,
3247 token::intern("index"),
3248 tcx.lang_items.index_trait(),
3252 fcx.type_error_message(expr.span,
3254 format!("cannot index a value \
3261 fcx.write_ty(id, ret_ty);
3268 debug!("type of expr({}) {} is...", expr.id,
3269 syntax::print::pprust::expr_to_str(expr));
3270 debug!("... {}, expected is {}",
3271 ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
3273 Some(t) => ppaux::ty_to_str(tcx, t),
3274 _ => "empty".to_owned()
3280 pub fn require_uint(fcx: &FnCtxt, sp: Span, t: ty::t) {
3281 if !type_is_uint(fcx, sp, t) {
3282 fcx.type_error_message(sp, |actual| {
3283 format!("mismatched types: expected `uint` type but found `{}`",
3289 pub fn require_integral(fcx: &FnCtxt, sp: Span, t: ty::t) {
3290 if !type_is_integral(fcx, sp, t) {
3291 fcx.type_error_message(sp, |actual| {
3292 format!("mismatched types: expected integral type but found `{}`",
3298 pub fn check_decl_initializer(fcx: &FnCtxt,
3302 let local_ty = fcx.local_ty(init.span, nid);
3303 check_expr_coercable_to_type(fcx, init, local_ty)
3306 pub fn check_decl_local(fcx: &FnCtxt, local: &ast::Local) {
3307 let tcx = fcx.ccx.tcx;
3309 let t = fcx.local_ty(local.span, local.id);
3310 fcx.write_ty(local.id, t);
3314 check_decl_initializer(fcx, local.id, init);
3315 let init_ty = fcx.expr_ty(init);
3316 if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
3317 fcx.write_ty(local.id, init_ty);
3323 let pcx = pat_ctxt {
3325 map: pat_id_map(&tcx.def_map, local.pat),
3327 _match::check_pat(&pcx, local.pat, t);
3328 let pat_ty = fcx.node_ty(local.pat.id);
3329 if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
3330 fcx.write_ty(local.id, pat_ty);
3334 pub fn check_stmt(fcx: &FnCtxt, stmt: &ast::Stmt) {
3336 let mut saw_bot = false;
3337 let mut saw_err = false;
3339 ast::StmtDecl(decl, id) => {
3342 ast::DeclLocal(ref l) => {
3343 check_decl_local(fcx, *l);
3344 let l_t = fcx.node_ty(l.id);
3345 saw_bot = saw_bot || ty::type_is_bot(l_t);
3346 saw_err = saw_err || ty::type_is_error(l_t);
3348 ast::DeclItem(_) => {/* ignore for now */ }
3351 ast::StmtExpr(expr, id) => {
3353 // Check with expected type of ()
3354 check_expr_has_type(fcx, expr, ty::mk_nil());
3355 let expr_ty = fcx.expr_ty(expr);
3356 saw_bot = saw_bot || ty::type_is_bot(expr_ty);
3357 saw_err = saw_err || ty::type_is_error(expr_ty);
3359 ast::StmtSemi(expr, id) => {
3361 check_expr(fcx, expr);
3362 let expr_ty = fcx.expr_ty(expr);
3363 saw_bot |= ty::type_is_bot(expr_ty);
3364 saw_err |= ty::type_is_error(expr_ty);
3366 ast::StmtMac(..) => fcx.ccx.tcx.sess.bug("unexpanded macro")
3369 fcx.write_bot(node_id);
3372 fcx.write_error(node_id);
3375 fcx.write_nil(node_id)
3379 pub fn check_block_no_value(fcx: &FnCtxt, blk: &ast::Block) {
3380 check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
3381 let blkty = fcx.node_ty(blk.id);
3382 if ty::type_is_error(blkty) {
3383 fcx.write_error(blk.id);
3385 else if ty::type_is_bot(blkty) {
3386 fcx.write_bot(blk.id);
3389 let nilty = ty::mk_nil();
3390 demand::suptype(fcx, blk.span, nilty, blkty);
3394 pub fn check_block_with_expected(fcx: &FnCtxt,
3396 expected: Option<ty::t>) {
3398 let mut fcx_ps = fcx.ps.borrow_mut();
3399 let fn_style_state = fcx_ps.recurse(blk);
3400 replace(&mut *fcx_ps, fn_style_state)
3403 fcx.with_region_lb(blk.id, || {
3404 let mut warned = false;
3405 let mut last_was_bot = false;
3406 let mut any_bot = false;
3407 let mut any_err = false;
3408 for s in blk.stmts.iter() {
3409 check_stmt(fcx, *s);
3410 let s_id = ast_util::stmt_id(*s);
3411 let s_ty = fcx.node_ty(s_id);
3412 if last_was_bot && !warned && match s.node {
3413 ast::StmtDecl(decl, _) => {
3415 ast::DeclLocal(_) => true,
3419 ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true,
3422 fcx.ccx.tcx.sess.add_lint(UnreachableCode, s_id, s.span,
3423 "unreachable statement".to_owned());
3426 if ty::type_is_bot(s_ty) {
3427 last_was_bot = true;
3429 any_bot = any_bot || ty::type_is_bot(s_ty);
3430 any_err = any_err || ty::type_is_error(s_ty);
3433 None => if any_err {
3434 fcx.write_error(blk.id);
3437 fcx.write_bot(blk.id);
3440 fcx.write_nil(blk.id);
3443 if any_bot && !warned {
3444 fcx.ccx.tcx.sess.add_lint(UnreachableCode, e.id, e.span,
3445 "unreachable expression".to_owned());
3447 check_expr_with_opt_hint(fcx, e, expected);
3448 let ety = fcx.expr_ty(e);
3449 fcx.write_ty(blk.id, ety);
3451 fcx.write_error(blk.id);
3454 fcx.write_bot(blk.id);
3460 *fcx.ps.borrow_mut() = prev;
3463 pub fn check_const(ccx: &CrateCtxt,
3467 let inh = blank_inherited_fields(ccx);
3468 let rty = ty::node_id_to_type(ccx.tcx, id);
3469 let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
3470 let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty;
3471 check_const_with_ty(&fcx, sp, e, declty);
3474 pub fn check_const_with_ty(fcx: &FnCtxt,
3479 let cty = fcx.expr_ty(e);
3480 demand::suptype(fcx, e.span, declty, cty);
3481 regionck::regionck_expr(fcx, e);
3482 writeback::resolve_type_vars_in_expr(fcx, e);
3485 /// Checks whether a type can be represented in memory. In particular, it
3486 /// identifies types that contain themselves without indirection through a
3487 /// pointer, which would mean their size is unbounded. This is different from
3488 /// the question of whether a type can be instantiated. See the definition of
3489 /// `check_instantiable`.
3490 pub fn check_representable(tcx: &ty::ctxt,
3492 item_id: ast::NodeId,
3493 designation: &str) -> bool {
3494 let rty = ty::node_id_to_type(tcx, item_id);
3496 // Check that it is possible to represent this type. This call identifies
3497 // (1) types that contain themselves and (2) types that contain a different
3498 // recursive type. It is only necessary to throw an error on those that
3499 // contain themselves. For case 2, there must be an inner type that will be
3500 // caught by case 1.
3501 match ty::is_type_representable(tcx, sp, rty) {
3502 ty::SelfRecursive => {
3504 sp, format!("illegal recursive {} type; \
3505 wrap the inner value in a box to make it representable",
3509 ty::Representable | ty::ContainsRecursive => (),
3514 /// Checks whether a type can be created without an instance of itself.
3515 /// This is similar but different from the question of whether a type
3516 /// can be represented. For example, the following type:
3518 /// enum foo { None, Some(foo) }
3520 /// is instantiable but is not representable. Similarly, the type
3522 /// enum foo { Some(@foo) }
3524 /// is representable, but not instantiable.
3525 pub fn check_instantiable(tcx: &ty::ctxt,
3527 item_id: ast::NodeId)
3529 let item_ty = ty::node_id_to_type(tcx, item_id);
3530 if !ty::is_instantiable(tcx, item_ty) {
3531 tcx.sess.span_err(sp, format!("this type cannot be instantiated \
3532 without an instance of itself; \
3533 consider using `Option<{}>`",
3534 ppaux::ty_to_str(tcx, item_ty)));
3541 pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
3542 let t = ty::node_id_to_type(tcx, id);
3543 if ty::type_needs_subst(t) {
3544 tcx.sess.span_err(sp, "SIMD vector cannot be generic");
3547 match ty::get(t).sty {
3548 ty::ty_struct(did, ref substs) => {
3549 let fields = ty::lookup_struct_fields(tcx, did);
3550 if fields.is_empty() {
3551 tcx.sess.span_err(sp, "SIMD vector cannot be empty");
3554 let e = ty::lookup_field_type(tcx, did, fields.get(0).id, substs);
3555 if !fields.iter().all(
3556 |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
3557 tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
3560 if !ty::type_is_machine(e) {
3561 tcx.sess.span_err(sp, "SIMD vector element type should be \
3570 pub fn check_enum_variants_sized(ccx: &CrateCtxt,
3571 vs: &[ast::P<ast::Variant>]) {
3572 for &v in vs.iter() {
3574 ast::TupleVariantKind(ref args) if args.len() > 0 => {
3575 let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id);
3576 let arg_tys: Vec<ty::t> = ty::ty_fn_args(ctor_ty).iter().map(|a| *a).collect();
3577 let len = arg_tys.len();
3581 for (i, t) in arg_tys.slice_to(len - 1).iter().enumerate() {
3582 // Allow the last field in an enum to be unsized.
3583 // We want to do this so that we can support smart pointers.
3584 // A struct value with an unsized final field is itself
3585 // unsized and we must track this in the type system.
3586 if !ty::type_is_sized(ccx.tcx, *t) {
3587 ccx.tcx.sess.span_err(args.get(i).ty.span,
3588 format!("type `{}` is dynamically sized. \
3589 dynamically sized types may only \
3590 appear as the final type in a variant",
3591 ppaux::ty_to_str(ccx.tcx, *t)));
3595 ast::StructVariantKind(struct_def) => check_fields_sized(ccx.tcx, struct_def),
3601 pub fn check_enum_variants(ccx: &CrateCtxt,
3603 vs: &[ast::P<ast::Variant>],
3606 fn disr_in_range(ccx: &CrateCtxt,
3608 disr: ty::Disr) -> bool {
3609 fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
3611 ast::TyU8 => disr as u8 as Disr == disr,
3612 ast::TyU16 => disr as u16 as Disr == disr,
3613 ast::TyU32 => disr as u32 as Disr == disr,
3614 ast::TyU64 => disr as u64 as Disr == disr,
3615 ast::TyU => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
3618 fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
3620 ast::TyI8 => disr as i8 as Disr == disr,
3621 ast::TyI16 => disr as i16 as Disr == disr,
3622 ast::TyI32 => disr as i32 as Disr == disr,
3623 ast::TyI64 => disr as i64 as Disr == disr,
3624 ast::TyI => int_in_range(ccx, ccx.tcx.sess.targ_cfg.int_type, disr)
3628 attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
3629 attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
3633 fn do_check(ccx: &CrateCtxt,
3634 vs: &[ast::P<ast::Variant>],
3636 hint: attr::ReprAttr)
3637 -> Vec<Rc<ty::VariantInfo>> {
3639 let rty = ty::node_id_to_type(ccx.tcx, id);
3640 let mut variants: Vec<Rc<ty::VariantInfo>> = Vec::new();
3641 let mut disr_vals: Vec<ty::Disr> = Vec::new();
3642 let mut prev_disr_val: Option<ty::Disr> = None;
3644 for &v in vs.iter() {
3646 // If the discriminant value is specified explicitly in the enum check whether the
3647 // initialization expression is valid, otherwise use the last value plus one.
3648 let mut current_disr_val = match prev_disr_val {
3649 Some(prev_disr_val) => prev_disr_val + 1,
3650 None => ty::INITIAL_DISCRIMINANT_VALUE
3653 match v.node.disr_expr {
3655 debug!("disr expr, checking {}", pprust::expr_to_str(e));
3657 let inh = blank_inherited_fields(ccx);
3658 let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
3659 let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
3660 check_const_with_ty(&fcx, e.span, e, declty);
3661 // check_expr (from check_const pass) doesn't guarantee
3662 // that the expression is in an form that eval_const_expr can
3663 // handle, so we may still get an internal compiler error
3665 match const_eval::eval_const_expr_partial(ccx.tcx, e) {
3666 Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
3667 Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
3669 ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
3672 ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", *err));
3679 // Check for duplicate discriminant values
3680 if disr_vals.contains(¤t_disr_val) {
3681 ccx.tcx.sess.span_err(v.span, "discriminant value already exists");
3683 // Check for unrepresentable discriminant values
3685 attr::ReprAny | attr::ReprExtern => (),
3686 attr::ReprInt(sp, ity) => {
3687 if !disr_in_range(ccx, ity, current_disr_val) {
3688 ccx.tcx.sess.span_err(v.span,
3689 "discriminant value outside specified type");
3690 ccx.tcx.sess.span_note(sp, "discriminant type specified here");
3694 disr_vals.push(current_disr_val);
3696 let variant_info = Rc::new(VariantInfo::from_ast_variant(ccx.tcx, v,
3698 prev_disr_val = Some(current_disr_val);
3700 variants.push(variant_info);
3706 let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id });
3707 if hint != attr::ReprAny && vs.len() <= 1 {
3708 let msg = if vs.len() == 1 {
3709 "unsupported representation for univariant enum"
3711 "unsupported representation for zero-variant enum"
3713 ccx.tcx.sess.span_err(sp, msg)
3716 let variants = do_check(ccx, vs, id, hint);
3718 // cache so that ty::enum_variants won't repeat this work
3719 ccx.tcx.enum_var_cache.borrow_mut().insert(local_def(id), Rc::new(variants));
3721 check_representable(ccx.tcx, sp, id, "enum");
3723 // Check that it is possible to instantiate this enum:
3725 // This *sounds* like the same that as representable, but it's
3726 // not. See def'n of `check_instantiable()` for details.
3727 check_instantiable(ccx.tcx, sp, id);
3730 pub fn lookup_def(fcx: &FnCtxt, sp: Span, id: ast::NodeId) -> ast::Def {
3731 lookup_def_ccx(fcx.ccx, sp, id)
3734 // Returns the type parameter count and the type for the given definition.
3735 pub fn ty_param_bounds_and_ty_for_def(fcx: &FnCtxt,
3738 -> ty_param_bounds_and_ty {
3740 ast::DefArg(nid, _) | ast::DefLocal(nid, _) |
3741 ast::DefBinding(nid, _) => {
3742 let typ = fcx.local_ty(sp, nid);
3743 return no_params(typ);
3745 ast::DefFn(id, _) | ast::DefStaticMethod(id, _, _) |
3746 ast::DefStatic(id, _) | ast::DefVariant(_, id, _) |
3747 ast::DefStruct(id) => {
3748 return ty::lookup_item_type(fcx.ccx.tcx, id);
3750 ast::DefUpvar(_, inner, _, _) => {
3751 return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
3756 ast::DefTyParam(..)=> {
3757 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type");
3759 ast::DefMod(..) | ast::DefForeignMod(..) => {
3760 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module");
3762 ast::DefUse(..) => {
3763 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use");
3765 ast::DefRegion(..) => {
3766 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region");
3768 ast::DefTyParamBinder(..) => {
3769 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter");
3771 ast::DefLabel(..) => {
3772 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label");
3774 ast::DefSelfTy(..) => {
3775 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty");
3777 ast::DefMethod(..) => {
3778 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method");
3783 // Instantiates the given path, which must refer to an item with the given
3784 // number of type parameters and type.
3785 pub fn instantiate_path(fcx: &FnCtxt,
3787 tpt: ty_param_bounds_and_ty,
3790 node_id: ast::NodeId) {
3791 debug!(">>> instantiate_path");
3793 let ty_param_count = tpt.generics.type_param_defs().len();
3794 let ty_param_req = tpt.generics.type_param_defs().iter()
3795 .take_while(|x| x.default.is_none())
3797 let mut ty_substs_len = 0;
3798 for segment in pth.segments.iter() {
3799 ty_substs_len += segment.types.len()
3802 debug!("tpt={} ty_param_count={:?} ty_substs_len={:?}",
3803 tpt.repr(fcx.tcx()),
3807 // determine the region parameters, using the value given by the user
3808 // (if any) and otherwise using a fresh region variable
3809 let num_expected_regions = tpt.generics.region_param_defs().len();
3810 let num_supplied_regions = pth.segments.last().unwrap().lifetimes.len();
3811 let regions = if num_expected_regions == num_supplied_regions {
3812 OwnedSlice::from_vec(pth.segments.last().unwrap().lifetimes.iter().map(
3813 |l| ast_region_to_region(fcx.tcx(), l)).collect())
3815 if num_supplied_regions != 0 {
3816 fcx.ccx.tcx.sess.span_err(
3818 format!("expected {nexpected, plural, =1{# lifetime parameter} \
3819 other{# lifetime parameters}}, \
3820 found {nsupplied, plural, =1{# lifetime parameter} \
3821 other{# lifetime parameters}}",
3822 nexpected = num_expected_regions,
3823 nsupplied = num_supplied_regions));
3826 fcx.infcx().region_vars_for_defs(span, tpt.generics.region_param_defs.as_slice())
3828 let regions = ty::NonerasedRegions(regions);
3830 // Special case: If there is a self parameter, omit it from the list of
3833 // Here we calculate the "user type parameter count", which is the number
3834 // of type parameters actually manifest in the AST. This will differ from
3835 // the internal type parameter count when there are self types involved.
3836 let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def {
3837 ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
3838 let generics = generics_of_static_method_container(fcx.ccx.tcx,
3840 (ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs().len()))
3842 _ => (ty_param_count, ty_param_req, None),
3845 // determine values for type parameters, using the values given by
3846 // the user (if any) and otherwise using fresh type variables
3847 let (tps, regions) = if ty_substs_len == 0 {
3848 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3849 } else if ty_param_count == 0 {
3850 fcx.ccx.tcx.sess.span_err
3851 (span, "this item does not take type parameters");
3852 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3853 } else if ty_substs_len > user_ty_param_count {
3854 let expected = if user_ty_param_req < user_ty_param_count {
3859 fcx.ccx.tcx.sess.span_err
3861 format!("too many type parameters provided: {} {}, found {}",
3862 expected, user_ty_param_count, ty_substs_len));
3863 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3864 } else if ty_substs_len < user_ty_param_req {
3865 let expected = if user_ty_param_req < user_ty_param_count {
3870 fcx.ccx.tcx.sess.span_err
3872 format!("not enough type parameters provided: {} {}, found {}",
3873 expected, user_ty_param_req, ty_substs_len));
3874 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3876 if ty_substs_len > user_ty_param_req
3877 && !fcx.tcx().sess.features.default_type_params.get() {
3878 fcx.tcx().sess.span_err(pth.span, "default type parameters are \
3879 experimental and possibly buggy");
3880 fcx.tcx().sess.span_note(pth.span, "add #![feature(default_type_params)] \
3881 to the crate attributes to enable");
3884 // Build up the list of type parameters, inserting the self parameter
3885 // at the appropriate position.
3886 let mut tps = Vec::new();
3887 let mut pushed = false;
3888 for (i, ty) in pth.segments.iter()
3889 .flat_map(|segment| segment.types.iter())
3890 .map(|&ast_type| fcx.to_ty(ast_type))
3892 match self_parameter_index {
3893 Some(index) if index == i => {
3894 tps.push(*fcx.infcx().next_ty_vars(1).get(0));
3902 let mut substs = substs {
3908 let defaults = tpt.generics.type_param_defs().iter()
3909 .enumerate().filter_map(|(i, x)| {
3910 match self_parameter_index {
3911 Some(index) if index == i => None,
3912 _ => Some(x.default)
3915 for (i, default) in defaults.skip(ty_substs_len).enumerate() {
3916 match self_parameter_index {
3917 Some(index) if index == i + ty_substs_len => {
3918 substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0));
3925 let ty = default.subst_spanned(fcx.tcx(), &substs, Some(span));
3926 substs.tps.push(ty);
3929 fcx.tcx().sess.span_bug(span,
3930 "missing default for a not explicitely provided type param")
3935 // If the self parameter goes at the end, insert it there.
3936 if !pushed && self_parameter_index.is_some() {
3937 substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0))
3940 assert_eq!(substs.tps.len(), ty_param_count)
3942 let substs {tps, regions, ..} = substs;
3946 fcx.write_ty_substs(node_id, tpt.ty, substs {
3955 // Resolves `typ` by a single level if `typ` is a type variable. If no
3956 // resolution is possible, then an error is reported.
3957 pub fn structurally_resolved_type(fcx: &FnCtxt, sp: Span, tp: ty::t) -> ty::t {
3958 match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
3959 Ok(t_s) if !ty::type_is_ty_var(t_s) => t_s,
3961 fcx.type_error_message(sp, |_actual| {
3962 "the type of this value must be known in this context".to_owned()
3964 demand::suptype(fcx, sp, ty::mk_err(), tp);
3970 // Returns the one-level-deep structure of the given type.
3971 pub fn structure_of<'a>(fcx: &FnCtxt, sp: Span, typ: ty::t)
3973 &ty::get(structurally_resolved_type(fcx, sp, typ)).sty
3976 pub fn type_is_integral(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3977 let typ_s = structurally_resolved_type(fcx, sp, typ);
3978 return ty::type_is_integral(typ_s);
3981 pub fn type_is_uint(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3982 let typ_s = structurally_resolved_type(fcx, sp, typ);
3983 return ty::type_is_uint(typ_s);
3986 pub fn type_is_scalar(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3987 let typ_s = structurally_resolved_type(fcx, sp, typ);
3988 return ty::type_is_scalar(typ_s);
3991 pub fn type_is_char(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3992 let typ_s = structurally_resolved_type(fcx, sp, typ);
3993 return ty::type_is_char(typ_s);
3996 pub fn type_is_bare_fn(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3997 let typ_s = structurally_resolved_type(fcx, sp, typ);
3998 return ty::type_is_bare_fn(typ_s);
4001 pub fn type_is_unsafe_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4002 let typ_s = structurally_resolved_type(fcx, sp, typ);
4003 return ty::type_is_unsafe_ptr(typ_s);
4006 pub fn type_is_region_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4007 let typ_s = structurally_resolved_type(fcx, sp, typ);
4008 return ty::type_is_region_ptr(typ_s);
4011 pub fn type_is_c_like_enum(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4012 let typ_s = structurally_resolved_type(fcx, sp, typ);
4013 return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
4016 pub fn ast_expr_vstore_to_vstore(fcx: &FnCtxt,
4021 ast::ExprVstoreUniq => ty::VstoreUniq,
4022 ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => {
4024 ast::ExprLit(..) => {
4025 // string literals and *empty slices* live in static memory
4026 ty::VstoreSlice(ty::ReStatic)
4028 ast::ExprVec(ref elements) if elements.len() == 0 => {
4029 // string literals and *empty slices* live in static memory
4030 ty::VstoreSlice(ty::ReStatic)
4032 ast::ExprRepeat(..) |
4033 ast::ExprVec(..) => {
4034 // vector literals are temporaries on the stack
4035 match fcx.tcx().region_maps.temporary_scope(e.id) {
4037 ty::VstoreSlice(ty::ReScope(scope))
4040 // this slice occurs in a static somewhere
4041 ty::VstoreSlice(ty::ReStatic)
4046 fcx.ccx.tcx.sess.span_bug(
4047 e.span, format!("vstore with unexpected contents"))
4054 // Returns true if b contains a break that can exit from b
4055 pub fn may_break(cx: &ty::ctxt, id: ast::NodeId, b: ast::P<ast::Block>) -> bool {
4056 // First: is there an unlabeled break immediately
4058 (loop_query(b, |e| {
4060 ast::ExprBreak(_) => true,
4064 // Second: is there a labeled break with label
4065 // <id> nested anywhere inside the loop?
4066 (block_query(b, |e| {
4068 ast::ExprBreak(Some(_)) => {
4069 match cx.def_map.borrow().find(&e.id) {
4070 Some(&ast::DefLabel(loop_id)) if id == loop_id => true,
4078 pub fn check_bounds_are_used(ccx: &CrateCtxt,
4080 tps: &OwnedSlice<ast::TyParam>,
4082 debug!("check_bounds_are_used(n_tps={}, ty={})",
4083 tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
4085 // make a vector of booleans initially false, set to true when used
4086 if tps.len() == 0u { return; }
4087 let mut tps_used = Vec::from_elem(tps.len(), false);
4089 ty::walk_ty(ty, |t| {
4090 match ty::get(t).sty {
4091 ty::ty_param(param_ty {idx, ..}) => {
4092 debug!("Found use of ty param \\#{}", idx);
4093 *tps_used.get_mut(idx) = true;
4099 for (i, b) in tps_used.iter().enumerate() {
4101 ccx.tcx.sess.span_err(
4102 span, format!("type parameter `{}` is unused",
4103 token::get_ident(tps.get(i).ident)));
4108 pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
4109 fn param(ccx: &CrateCtxt, n: uint) -> ty::t {
4110 ty::mk_param(ccx.tcx, n, local_def(0))
4114 let name = token::get_ident(it.ident);
4115 let (n_tps, inputs, output) = if name.get().starts_with("atomic_") {
4116 let split : Vec<&str> = name.get().split('_').collect();
4117 assert!(split.len() >= 2, "Atomic intrinsic not correct format");
4119 //We only care about the operation here
4120 match *split.get(1) {
4121 "cxchg" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)),
4125 "load" => (1, vec!(ty::mk_imm_ptr(tcx, param(ccx, 0))),
4127 "store" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)),
4130 "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
4131 "min" | "umax" | "umin" => {
4132 (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)),
4136 (0, Vec::new(), ty::mk_nil())
4139 tcx.sess.span_err(it.span,
4140 format!("unrecognized atomic operation function: `{}`",
4148 "abort" => (0, Vec::new(), ty::mk_bot()),
4149 "breakpoint" => (0, Vec::new(), ty::mk_nil()),
4151 "pref_align_of" | "min_align_of" => (1u, Vec::new(), ty::mk_uint()),
4152 "init" => (1u, Vec::new(), param(ccx, 0u)),
4153 "uninit" => (1u, Vec::new(), param(ccx, 0u)),
4154 "forget" => (1u, vec!( param(ccx, 0) ), ty::mk_nil()),
4155 "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)),
4156 "move_val_init" => {
4159 ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), param(ccx, 0)),
4164 "needs_drop" => (1u, Vec::new(), ty::mk_bool()),
4165 "owns_managed" => (1u, Vec::new(), ty::mk_bool()),
4168 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4170 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4172 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4174 mutbl: ast::MutImmutable
4176 (1u, Vec::new(), td_ptr)
4179 let langid = ccx.tcx.lang_items.require(TypeIdLangItem);
4181 Ok(did) => (1u, Vec::new(), ty::mk_struct(ccx.tcx, did, substs {
4184 regions: ty::NonerasedRegions(OwnedSlice::empty())
4186 Err(msg) => { tcx.sess.span_fatal(it.span, msg); }
4190 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4192 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4194 let region = ty::ReLateBound(it.id, ty::BrAnon(0));
4195 let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
4196 Ok((_, vot)) => vot,
4197 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4200 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4202 mutbl: ast::MutImmutable
4204 (0, vec!( td_ptr, visitor_object_ty ), ty::mk_nil())
4209 ty::mk_ptr(tcx, ty::mt {
4211 mutbl: ast::MutImmutable
4215 ty::mk_ptr(tcx, ty::mt {
4217 mutbl: ast::MutImmutable
4220 "copy_memory" | "copy_nonoverlapping_memory" |
4221 "volatile_copy_memory" | "volatile_copy_nonoverlapping_memory" => {
4224 ty::mk_ptr(tcx, ty::mt {
4226 mutbl: ast::MutMutable
4228 ty::mk_ptr(tcx, ty::mt {
4230 mutbl: ast::MutImmutable
4236 "set_memory" | "volatile_set_memory" => {
4239 ty::mk_ptr(tcx, ty::mt {
4241 mutbl: ast::MutMutable
4248 "sqrtf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4249 "sqrtf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4252 vec!( ty::mk_f32(), ty::mk_i32() ),
4257 vec!( ty::mk_f64(), ty::mk_i32() ),
4260 "sinf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4261 "sinf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4262 "cosf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4263 "cosf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4266 vec!( ty::mk_f32(), ty::mk_f32() ),
4271 vec!( ty::mk_f64(), ty::mk_f64() ),
4274 "expf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4275 "expf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4276 "exp2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4277 "exp2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4278 "logf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4279 "logf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4280 "log10f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4281 "log10f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4282 "log2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4283 "log2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4286 vec!( ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ),
4291 vec!( ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ),
4294 "fabsf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4295 "fabsf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4296 "copysignf32" => (0, vec!( ty::mk_f32(), ty::mk_f32() ), ty::mk_f32()),
4297 "copysignf64" => (0, vec!( ty::mk_f64(), ty::mk_f64() ), ty::mk_f64()),
4298 "floorf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4299 "floorf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4300 "ceilf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4301 "ceilf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4302 "truncf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4303 "truncf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4304 "rintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4305 "rintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4306 "nearbyintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4307 "nearbyintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4308 "roundf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4309 "roundf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4310 "ctpop8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()),
4311 "ctpop16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4312 "ctpop32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4313 "ctpop64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4314 "ctlz8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()),
4315 "ctlz16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4316 "ctlz32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4317 "ctlz64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4318 "cttz8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()),
4319 "cttz16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4320 "cttz32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4321 "cttz64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4322 "bswap16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4323 "bswap32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4324 "bswap64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4327 (1, vec!( ty::mk_imm_ptr(tcx, param(ccx, 0)) ), param(ccx, 0)),
4329 (1, vec!( ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ), ty::mk_nil()),
4331 "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
4332 (0, vec!(ty::mk_i8(), ty::mk_i8()),
4333 ty::mk_tup(tcx, vec!(ty::mk_i8(), ty::mk_bool()))),
4335 "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
4336 (0, vec!(ty::mk_i16(), ty::mk_i16()),
4337 ty::mk_tup(tcx, vec!(ty::mk_i16(), ty::mk_bool()))),
4339 "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
4340 (0, vec!(ty::mk_i32(), ty::mk_i32()),
4341 ty::mk_tup(tcx, vec!(ty::mk_i32(), ty::mk_bool()))),
4343 "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
4344 (0, vec!(ty::mk_i64(), ty::mk_i64()),
4345 ty::mk_tup(tcx, vec!(ty::mk_i64(), ty::mk_bool()))),
4347 "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
4348 (0, vec!(ty::mk_u8(), ty::mk_u8()),
4349 ty::mk_tup(tcx, vec!(ty::mk_u8(), ty::mk_bool()))),
4351 "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
4352 (0, vec!(ty::mk_u16(), ty::mk_u16()),
4353 ty::mk_tup(tcx, vec!(ty::mk_u16(), ty::mk_bool()))),
4355 "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
4356 (0, vec!(ty::mk_u32(), ty::mk_u32()),
4357 ty::mk_tup(tcx, vec!(ty::mk_u32(), ty::mk_bool()))),
4359 "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" =>
4360 (0, vec!(ty::mk_u64(), ty::mk_u64()),
4361 ty::mk_tup(tcx, vec!(ty::mk_u64(), ty::mk_bool()))),
4364 tcx.sess.span_err(it.span,
4365 format!("unrecognized intrinsic function: `{}`",
4371 let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
4372 fn_style: ast::UnsafeFn,
4373 abi: abi::RustIntrinsic,
4374 sig: FnSig {binder_id: it.id,
4379 let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
4380 let i_n_tps = i_ty.generics.type_param_defs().len();
4381 if i_n_tps != n_tps {
4382 tcx.sess.span_err(it.span, format!("intrinsic has wrong number \
4383 of type parameters: found {}, \
4384 expected {}", i_n_tps, n_tps));
4387 tcx, None, false, it.span, i_ty.ty, fty,
4388 || format!("intrinsic has wrong type: \
4390 ppaux::ty_to_str(ccx.tcx, fty)));