1 // Copyright 2012 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
81 use middle::const_eval;
82 use middle::pat_util::pat_id_map;
84 use middle::ty::{TyVid, Vid, FnSig, VariantInfo_, field};
85 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
86 use middle::ty::{re_bound, br_cap_avoid, substs, arg, param_ty};
88 use middle::typeck::astconv::{AstConv, ast_path_to_ty};
89 use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
90 use middle::typeck::astconv;
91 use middle::typeck::check::_match::pat_ctxt;
92 use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
93 use middle::typeck::check::method::{CheckTraitsOnly, TransformTypeNormally};
94 use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
95 use middle::typeck::check::vtable::{LocationInfo, VtableContext};
96 use middle::typeck::CrateCtxt;
97 use middle::typeck::infer::{resolve_type, force_tvar, mk_eqty};
98 use middle::typeck::infer;
99 use middle::typeck::rscope::{binding_rscope, bound_self_region};
100 use middle::typeck::rscope::{RegionError};
101 use middle::typeck::rscope::{in_binding_rscope, region_scope, type_rscope};
102 use middle::typeck::rscope;
103 use middle::typeck::{isr_alist, lookup_def_ccx, method_map_entry};
104 use middle::typeck::{method_origin, method_self, method_trait, no_params};
105 use middle::typeck::{require_same_types};
106 use util::common::{block_query, indenter, loop_query};
107 use util::ppaux::{bound_region_to_str, expr_repr, pat_repr};
113 use core::result::{Result, Ok, Err};
118 use std::oldmap::HashMap;
120 use syntax::ast::{provided, required, ty_i};
123 use syntax::ast_util::{Private, Public, is_local, local_def};
124 use syntax::ast_util;
125 use syntax::codemap::{span, spanned, respan};
127 use syntax::parse::token::special_idents;
128 use syntax::print::pprust;
130 use syntax::opt_vec::OptVec;
141 pub struct SelfInfo {
143 self_id: ast::node_id,
145 explicit_self: ast::self_ty
148 /// Fields that are part of a `FnCtxt` which are inherited by
149 /// closures defined within the function. For example:
155 /// Here, the function `foo()` and the closure passed to
156 /// `bar()` will each have their own `FnCtxt`, but they will
157 /// share the inherited fields.
158 pub struct inherited {
159 infcx: @mut infer::InferCtxt,
160 locals: HashMap<ast::node_id, ty::t>,
161 node_types: HashMap<ast::node_id, ty::t>,
162 node_type_substs: HashMap<ast::node_id, ty::substs>,
163 adjustments: HashMap<ast::node_id, @ty::AutoAdjustment>
167 // This is a for-closure. The ty::t is the return type of the
168 // enclosing function.
174 // A normal closure or fn item.
179 // var_bindings, locals and next_var_id are shared
180 // with any nested functions that capture the environment
181 // (and with any functions whose environment is being captured).
183 // Refers to whichever `self` is in scope, even this FnCtxt is
184 // for a nested closure that captures `self`
185 self_info: Option<SelfInfo>,
187 // Used by loop bodies that return from the outer function
188 indirect_ret_ty: Option<ty::t>,
191 // Sometimes we generate region pointers where the precise region
192 // to use is not known. For example, an expression like `&x.f`
193 // where `x` is of type `@T`: in this case, we will be rooting
194 // `x` onto the stack frame, and we could choose to root it until
195 // the end of (almost) any enclosing block or expression. We
196 // want to pick the narrowest block that encompasses all uses.
198 // What we do in such cases is to generate a region variable with
199 // `region_lb` as a lower bound. The regionck pass then adds
200 // other constriants based on how the variable is used and region
201 // inference selects the ultimate value. Finally, borrowck is
202 // charged with guaranteeing that the value whose address was taken
203 // can actually be made to live as long as it needs to live.
204 region_lb: ast::node_id,
206 // Says whether we're inside a for loop, in a do block
207 // or neither. Helps with error messages involving the
208 // function return type.
211 in_scope_regions: isr_alist,
218 pub fn blank_inherited(ccx: @mut CrateCtxt) -> @inherited {
220 infcx: infer::new_infer_ctxt(ccx.tcx),
222 node_types: oldmap::HashMap(),
223 node_type_substs: oldmap::HashMap(),
224 adjustments: oldmap::HashMap()
228 // Used by check_const and check_enum_variants
229 pub fn blank_fn_ctxt(ccx: @mut CrateCtxt,
231 region_bnd: ast::node_id)
233 // It's kind of a kludge to manufacture a fake function context
234 // and statement context, but we might as well do write the code only once
238 indirect_ret_ty: None,
239 purity: ast::pure_fn,
240 region_lb: region_bnd,
241 in_scope_regions: @Nil,
243 inh: blank_inherited(ccx),
248 pub fn check_item_types(ccx: @mut CrateCtxt, crate: @ast::crate) {
249 let visit = visit::mk_simple_visitor(@visit::SimpleVisitor {
250 visit_item: |a| check_item(ccx, a),
251 .. *visit::default_simple_visitor()
253 visit::visit_crate(*crate, (), visit);
256 pub fn check_bare_fn(ccx: @mut CrateCtxt,
260 self_info: Option<SelfInfo>) {
261 let fty = ty::node_id_to_type(ccx.tcx, id);
262 match ty::get(fty).sty {
263 ty::ty_bare_fn(ref fn_ty) => {
265 check_fn(ccx, self_info, fn_ty.purity,
266 &fn_ty.sig, decl, body, Vanilla,
267 @Nil, blank_inherited(ccx));;
269 vtable::resolve_in_block(fcx, body);
270 regionck::regionck_fn(fcx, body);
271 writeback::resolve_type_vars_in_fn(fcx, decl, body, self_info);
273 _ => ccx.tcx.sess.impossible_case(body.span,
274 "check_bare_fn: function type expected")
278 pub fn check_fn(ccx: @mut CrateCtxt,
279 +self_info: Option<SelfInfo>,
285 inherited_isr: isr_alist,
286 inherited: @inherited) -> @mut FnCtxt
290 * Helper used by check_bare_fn and check_expr_fn. Does the
291 * grungy work of checking a function body and returns the
292 * function context used for that purpose, since in the case of a
293 * fn item there is still a bit more to do.
296 * - inherited_isr: regions in scope from the enclosing fn (if any)
297 * - inherited: other fields inherited from the enclosing fn (if any)
302 // ______________________________________________________________________
303 // First, we have to replace any bound regions in the fn and self
304 // types with free ones. The free region references will be bound
305 // the node_id of the body block.
307 let (isr, self_info, fn_sig) = {
308 replace_bound_regions_in_fn_sig(tcx, inherited_isr, self_info, fn_sig,
309 |br| ty::re_free(body.node.id, br))
312 let arg_tys = fn_sig.inputs.map(|a| a.ty);
313 let ret_ty = fn_sig.output;
315 debug!("check_fn(arg_tys=%?, ret_ty=%?, self_info.self_ty=%?)",
316 arg_tys.map(|a| ppaux::ty_to_str(tcx, *a)),
317 ppaux::ty_to_str(tcx, ret_ty),
318 option::map(&self_info, |s| ppaux::ty_to_str(tcx, s.self_ty)));
320 // ______________________________________________________________________
321 // Create the function context. This is either derived from scratch or,
322 // in the case of function expressions, based on the outer context.
323 let fcx: @mut FnCtxt = {
324 // In a for-loop, you have an 'indirect return' because return
325 // does not return out of the directly enclosing fn
326 let indirect_ret_ty = match fn_kind {
327 ForLoop(t) => Some(t),
328 DoBlock | Vanilla => None
332 self_info: self_info,
334 indirect_ret_ty: indirect_ret_ty,
336 region_lb: body.node.id,
337 in_scope_regions: isr,
344 // Update the SelfInfo to contain an accurate self type (taking
345 // into account explicit self).
346 let self_info = do self_info.chain_ref |self_info| {
347 // If the self type is sty_static, we don't have a self ty.
348 if self_info.explicit_self.node == ast::sty_static {
351 let in_scope_regions = fcx.in_scope_regions;
352 let self_region = in_scope_regions.find(ty::br_self);
353 let ty = method::transform_self_type_for_method(
357 self_info.explicit_self.node,
358 TransformTypeNormally);
359 Some(SelfInfo { self_ty: ty,.. *self_info })
363 gather_locals(fcx, decl, body, arg_tys, self_info);
364 check_block(fcx, body);
366 // We unify the tail expr's type with the
367 // function result type, if there is a tail expr.
368 match body.node.expr {
370 let tail_expr_ty = fcx.expr_ty(tail_expr);
371 // Special case: we print a special error if there appears
372 // to be do-block/for-loop confusion
373 demand::suptype_with_fn(fcx, tail_expr.span, false,
374 fcx.ret_ty, tail_expr_ty,
376 fcx.report_mismatched_return_types(sp, e, a, s) });
381 for self_info.each |self_info| {
382 fcx.write_ty(self_info.self_id, self_info.self_ty);
384 for vec::each2(decl.inputs, arg_tys) |input, arg| {
385 fcx.write_ty(input.id, *arg);
390 fn gather_locals(fcx: @mut FnCtxt,
394 self_info: Option<SelfInfo>) {
395 let tcx = fcx.ccx.tcx;
397 let assign: @fn(ast::node_id, Option<ty::t>) = |nid, ty_opt| {
400 // infer the variable's type
401 let var_id = fcx.infcx().next_ty_var_id();
402 let var_ty = ty::mk_var(fcx.tcx(), var_id);
403 fcx.inh.locals.insert(nid, var_ty);
406 // take type that the user specified
407 fcx.inh.locals.insert(nid, typ);
412 // Add the self parameter
413 for self_info.each |self_info| {
414 assign(self_info.self_id, Some(self_info.self_ty));
415 debug!("self is assigned to %s",
416 fcx.infcx().ty_to_str(
417 fcx.inh.locals.get(&self_info.self_id)));
420 // Add formal parameters.
421 for vec::each2(arg_tys, decl.inputs) |arg_ty, input| {
422 // Create type variables for each argument.
423 do pat_util::pat_bindings(tcx.def_map, input.pat)
424 |_bm, pat_id, _sp, _path| {
425 assign(pat_id, None);
428 // Check the pattern.
429 let region = fcx.block_region();
432 map: pat_id_map(tcx.def_map, input.pat),
433 match_region: region,
434 block_region: region,
436 _match::check_pat(pcx, input.pat, *arg_ty);
439 // Add explicitly-declared locals.
440 let visit_local: @fn(@ast::local, &&e: (), visit::vt<()>) =
442 let o_ty = match local.node.ty.node {
443 ast::ty_infer => None,
444 _ => Some(fcx.to_ty(local.node.ty))
446 assign(local.node.id, o_ty);
447 debug!("Local variable %s is assigned type %s",
448 fcx.pat_to_str(local.node.pat),
449 fcx.infcx().ty_to_str(
450 fcx.inh.locals.get(&local.node.id)));
451 visit::visit_local(local, e, v);
454 // Add pattern bindings.
455 let visit_pat: @fn(@ast::pat, &&e: (), visit::vt<()>) = |p, e, v| {
457 ast::pat_ident(_, path, _)
458 if pat_util::pat_is_binding(fcx.ccx.tcx.def_map, p) => {
460 debug!("Pattern binding %s is assigned to %s",
461 *tcx.sess.str_of(path.idents[0]),
462 fcx.infcx().ty_to_str(
463 fcx.inh.locals.get(&p.id)));
467 visit::visit_pat(p, e, v);
470 let visit_block: @fn(&ast::blk, &&e: (), visit::vt<()>) = |b, e, v| {
471 // non-obvious: the `blk` variable maps to region lb, so
472 // we have to keep this up-to-date. This
473 // is... unfortunate. It'd be nice to not need this.
474 do fcx.with_region_lb(b.node.id) {
475 visit::visit_block(b, e, v);
479 // Don't descend into fns and items
480 fn visit_fn(_fk: &visit::fn_kind, _decl: &ast::fn_decl,
481 _body: &ast::blk, _sp: span,
482 _id: ast::node_id, &&_t: (), _v: visit::vt<()>) {
484 fn visit_item(_i: @ast::item, &&_e: (), _v: visit::vt<()>) { }
486 let visit = visit::mk_vt(
487 @visit::Visitor {visit_local: visit_local,
488 visit_pat: visit_pat,
490 visit_item: visit_item,
491 visit_block: visit_block,
492 ..*visit::default_visitor()});
494 (visit.visit_block)(body, (), visit);
498 pub fn check_method(ccx: @mut CrateCtxt,
499 method: @ast::method,
501 self_impl_def_id: ast::def_id) {
502 let self_info = SelfInfo {
504 self_id: method.self_id,
505 def_id: self_impl_def_id,
506 explicit_self: method.self_ty
517 pub fn check_no_duplicate_fields(tcx: ty::ctxt,
518 fields: ~[(ast::ident, span)]) {
519 let field_names = HashMap();
521 for fields.each |p| {
523 match field_names.find(&id) {
525 tcx.sess.span_err(sp, fmt!("Duplicate field \
526 name %s in record type declaration",
527 *tcx.sess.str_of(id)));
528 tcx.sess.span_note(orig_sp, ~"First declaration of \
529 this field occurred here");
533 field_names.insert(id, sp);
539 pub fn check_struct(ccx: @mut CrateCtxt,
540 struct_def: @ast::struct_def,
544 let self_ty = ty::node_id_to_type(tcx, id);
546 for struct_def.dtor.each |dtor| {
547 let class_t = SelfInfo {
549 self_id: dtor.node.self_id,
550 def_id: local_def(id),
551 explicit_self: spanned {
552 node: ast::sty_by_ref,
553 span: codemap::dummy_sp()
556 // typecheck the dtor
557 let dtor_dec = ast_util::dtor_dec();
567 // Check that the class is instantiable
568 check_instantiable(ccx.tcx, span, id);
571 pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
572 debug!("check_item(it.id=%d, it.ident=%s)",
574 ty::item_path_str(ccx.tcx, local_def(it.id)));
575 let _indenter = indenter();
577 match /*bad*/copy it.node {
578 ast::item_const(_, e) => check_const(ccx, it.span, e, it.id),
579 ast::item_enum(ref enum_definition, _) => {
580 check_enum_variants(ccx,
582 /*bad*/copy (*enum_definition).variants,
585 ast::item_fn(ref decl, _, _, ref body) => {
586 check_bare_fn(ccx, decl, body, it.id, None);
588 ast::item_impl(_, _, ty, ms) => {
589 let rp = ccx.tcx.region_paramd_items.find(&it.id);
590 debug!("item_impl %s with id %d rp %?",
591 *ccx.tcx.sess.str_of(it.ident), it.id, rp);
592 let self_ty = ccx.to_ty(&rscope::type_rscope(rp), ty);
594 check_method(ccx, *m, self_ty, local_def(it.id));
597 ast::item_trait(_, _, ref trait_methods) => {
598 for (*trait_methods).each |trait_method| {
599 match *trait_method {
601 // Nothing to do, since required methods don't have
605 check_method(ccx, m, ty::mk_self(ccx.tcx), local_def(it.id));
610 ast::item_struct(struct_def, _) => {
611 check_struct(ccx, struct_def, it.id, it.span);
613 ast::item_ty(t, ref generics) => {
614 let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id);
615 check_bounds_are_used(ccx, t.span, &generics.ty_params, tpt_ty);
617 ast::item_foreign_mod(m) => {
618 if syntax::attr::foreign_abi(it.attrs) ==
619 either::Right(ast::foreign_abi_rust_intrinsic) {
620 for m.items.each |item| {
621 check_intrinsic_type(ccx, *item);
624 for m.items.each |item| {
625 let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id));
626 if !tpt.bounds.is_empty() {
627 ccx.tcx.sess.span_err(
629 fmt!("foreign items may not have type parameters"));
634 _ => {/* nothing to do */ }
638 impl AstConv for FnCtxt {
639 fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
641 fn get_item_ty(&self, id: ast::def_id) -> ty::ty_param_bounds_and_ty {
642 ty::lookup_item_type(self.tcx(), id)
645 fn ty_infer(&self, _span: span) -> ty::t {
646 self.infcx().next_ty_var()
651 fn infcx(&self) -> @mut infer::InferCtxt { self.inh.infcx }
652 fn search_in_scope_regions(
655 br: ty::bound_region) -> Result<ty::Region, RegionError>
657 let in_scope_regions = self.in_scope_regions;
658 match in_scope_regions.find(br) {
659 Some(r) => result::Ok(r),
661 let blk_br = ty::br_named(special_idents::blk);
663 result::Ok(self.block_region())
665 result::Err(RegionError {
666 msg: fmt!("named region `%s` not in scope here",
667 bound_region_to_str(self.tcx(), br)),
668 replacement: self.infcx().next_region_var_nb(span)
676 impl region_scope for FnCtxt {
677 fn anon_region(&self, span: span) -> Result<ty::Region, RegionError> {
678 result::Ok(self.infcx().next_region_var_nb(span))
680 fn self_region(&self, span: span) -> Result<ty::Region, RegionError> {
681 self.search_in_scope_regions(span, ty::br_self)
683 fn named_region(&self,
685 id: ast::ident) -> Result<ty::Region, RegionError> {
686 self.search_in_scope_regions(span, ty::br_named(id))
691 fn tag(&self) -> ~str { fmt!("%x", ptr::addr_of(&(*self)) as uint) }
693 fn local_ty(&self, span: span, nid: ast::node_id) -> ty::t {
694 match self.inh.locals.find(&nid) {
697 self.tcx().sess.span_bug(
699 fmt!("No type for local variable %?", nid));
704 fn expr_to_str(&self, expr: @ast::expr) -> ~str {
705 fmt!("expr(%?:%s)", expr.id,
706 pprust::expr_to_str(expr, self.tcx().sess.intr()))
709 fn block_region(&self) -> ty::Region {
710 ty::re_scope(self.region_lb)
714 fn write_ty(&self, node_id: ast::node_id, ty: ty::t) {
715 debug!("write_ty(%d, %s) in fcx %s",
716 node_id, ppaux::ty_to_str(self.tcx(), ty), self.tag());
717 self.inh.node_types.insert(node_id, ty);
720 fn write_substs(&self, node_id: ast::node_id, +substs: ty::substs) {
721 if !ty::substs_is_noop(&substs) {
722 debug!("write_substs(%d, %s) in fcx %s",
724 ty::substs_to_str(self.tcx(), &substs),
726 self.inh.node_type_substs.insert(node_id, substs);
730 fn write_ty_substs(&self,
731 node_id: ast::node_id,
733 +substs: ty::substs) {
734 let ty = ty::subst(self.tcx(), &substs, ty);
735 self.write_ty(node_id, ty);
736 self.write_substs(node_id, substs);
739 fn write_autoderef_adjustment(&self,
740 node_id: ast::node_id,
742 if derefs == 0 { return; }
743 self.write_adjustment(
745 @ty::AutoDerefRef(ty::AutoDerefRef {
751 fn write_adjustment(&self,
752 node_id: ast::node_id,
753 adj: @ty::AutoAdjustment) {
754 debug!("write_adjustment(node_id=%?, adj=%?)", node_id, adj);
755 self.inh.adjustments.insert(node_id, adj);
758 fn write_nil(&self, node_id: ast::node_id) {
759 self.write_ty(node_id, ty::mk_nil(self.tcx()));
761 fn write_bot(&self, node_id: ast::node_id) {
762 self.write_ty(node_id, ty::mk_bot(self.tcx()));
765 fn to_ty(&self, ast_t: @ast::Ty) -> ty::t {
766 ast_ty_to_ty(self, self, ast_t)
769 fn expr_to_str(&self, expr: @ast::expr) -> ~str {
770 expr_repr(self.tcx(), expr)
773 fn pat_to_str(&self, pat: @ast::pat) -> ~str {
774 pat_repr(self.tcx(), pat)
777 fn expr_ty(&self, ex: @ast::expr) -> ty::t {
778 match self.inh.node_types.find(&ex.id) {
782 fmt!("no type for %s in fcx %s",
783 self.expr_to_str(ex), self.tag()));
787 fn node_ty(&self, id: ast::node_id) -> ty::t {
788 match self.inh.node_types.find(&id) {
792 fmt!("no type for node %d: %s in fcx %s",
793 id, ast_map::node_id_to_str(
794 self.tcx().items, id,
795 self.tcx().sess.parse_sess.interner),
800 fn node_ty_substs(&self, id: ast::node_id) -> ty::substs {
801 match self.inh.node_type_substs.find(&id) {
802 Some(ref ts) => (/*bad*/copy *ts),
805 fmt!("no type substs for node %d: %s in fcx %s",
806 id, ast_map::node_id_to_str(
807 self.tcx().items, id,
808 self.tcx().sess.parse_sess.interner),
813 fn opt_node_ty_substs(&self, id: ast::node_id) -> Option<ty::substs> {
814 self.inh.node_type_substs.find(&id)
823 -> Result<(), ty::type_err> {
824 infer::mk_subty(self.infcx(), a_is_expected, span, sub, sup)
827 fn can_mk_subty(&self,
830 -> Result<(), ty::type_err> {
831 infer::can_mk_subty(self.infcx(), sub, sup)
834 fn mk_assignty(&self, expr: @ast::expr, sub: ty::t, sup: ty::t)
835 -> Result<(), ty::type_err> {
836 match infer::mk_coercety(self.infcx(), false, expr.span, sub, sup) {
837 Ok(None) => result::Ok(()),
838 Err(ref e) => result::Err((*e)),
839 Ok(Some(adjustment)) => {
840 self.write_adjustment(expr.id, adjustment);
846 fn can_mk_assignty(&self,
849 -> Result<(), ty::type_err> {
850 infer::can_mk_coercety(self.infcx(), sub, sup)
858 -> Result<(), ty::type_err> {
859 infer::mk_eqty(self.infcx(), a_is_expected, span, sub, sup)
867 -> Result<(), ty::type_err> {
868 infer::mk_subr(self.infcx(), a_is_expected, span, sub, sup)
871 fn require_unsafe(&self, sp: span, op: ~str) {
873 ast::unsafe_fn => {/*ok*/}
875 self.ccx.tcx.sess.span_err(
877 fmt!("%s requires unsafe function or block", op));
882 fn with_region_lb<R>(@mut self, lb: ast::node_id, f: &fn() -> R) -> R {
883 let old_region_lb = self.region_lb;
886 self.region_lb = old_region_lb;
890 fn region_var_if_parameterized(&self,
891 rp: Option<ty::region_variance>,
893 lower_bound: ty::Region)
894 -> Option<ty::Region> {
896 |_rp| self.infcx().next_region_var_with_lb(span, lower_bound))
899 fn type_error_message(&self,
901 mk_msg: &fn(~str) -> ~str,
903 err: Option<&ty::type_err>) {
904 self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
907 fn report_mismatched_return_types(&self,
911 err: &ty::type_err) {
913 ForLoop(_) if !ty::type_is_bool(e) && !ty::type_is_nil(a) =>
914 self.tcx().sess.span_err(sp, fmt!("A for-loop body must \
915 return (), but it returns %s here. \
916 Perhaps you meant to write a `do`-block?",
917 ppaux::ty_to_str(self.tcx(), a))),
918 DoBlock if ty::type_is_bool(e) && ty::type_is_nil(a) =>
919 // If we expected bool and got ()...
920 self.tcx().sess.span_err(sp, fmt!("Do-block body must \
921 return %s, but returns () here. Perhaps you meant \
922 to write a `for`-loop?",
923 ppaux::ty_to_str(self.tcx(), e))),
924 _ => self.infcx().report_mismatched_types(sp, e, a, err)
928 fn report_mismatched_types(&self,
932 err: &ty::type_err) {
933 self.infcx().report_mismatched_types(sp, e, a, err)
937 pub fn do_autoderef(fcx: @mut FnCtxt, sp: span, t: ty::t) -> (ty::t, uint) {
940 * Autoderefs the type `t` as many times as possible, returning
941 * a new type and a counter for how many times the type was
942 * deref'd. If the counter is non-zero, the receiver is responsible
943 * for inserting an AutoAdjustment record into `tcx.adjustments`
944 * so that trans/borrowck/etc know about this autoderef. */
947 let mut enum_dids = ~[];
948 let mut autoderefs = 0;
950 let sty = structure_of(fcx, sp, t1);
952 // Some extra checks to detect weird cycles and so forth:
954 ty::ty_box(inner) | ty::ty_uniq(inner) |
955 ty::ty_rptr(_, inner) => {
956 match ty::get(t1).sty {
957 ty::ty_infer(ty::TyVar(v1)) => {
958 ty::occurs_check(fcx.ccx.tcx, sp, v1,
959 ty::mk_box(fcx.ccx.tcx, inner));
964 ty::ty_enum(ref did, _) => {
965 // Watch out for a type like `enum t = @t`. Such a
966 // type would otherwise infinitely auto-deref. Only
967 // autoderef loops during typeck (basically, this one
968 // and the loops in typeck::check::method) need to be
969 // concerned with this, as an error will be reported
970 // on the enum definition as well because the enum is
972 if vec::contains(enum_dids, did) {
973 return (t1, autoderefs);
975 enum_dids.push(*did);
980 // Otherwise, deref if type is derefable:
981 match ty::deref_sty(fcx.ccx.tcx, &sty, false) {
983 return (t1, autoderefs);
993 // AST fragment checking
994 pub fn check_lit(fcx: @mut FnCtxt, lit: @ast::lit) -> ty::t {
995 let tcx = fcx.ccx.tcx;
998 ast::lit_str(*) => ty::mk_estr(tcx, ty::vstore_slice(ty::re_static)),
999 ast::lit_int(_, t) => ty::mk_mach_int(tcx, t),
1000 ast::lit_uint(_, t) => ty::mk_mach_uint(tcx, t),
1001 ast::lit_int_unsuffixed(_) => {
1002 // An unsuffixed integer literal could have any integral type,
1003 // so we create an integral type variable for it.
1004 ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
1006 ast::lit_float(_, t) => ty::mk_mach_float(tcx, t),
1007 ast::lit_float_unsuffixed(_) => {
1008 // An unsuffixed floating point literal could have any floating point
1009 // type, so we create a floating point type variable for it.
1010 ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())
1012 ast::lit_nil => ty::mk_nil(tcx),
1013 ast::lit_bool(_) => ty::mk_bool(tcx)
1017 pub fn valid_range_bounds(ccx: @mut CrateCtxt,
1021 const_eval::compare_lit_exprs(ccx.tcx, from, to) <= 0
1024 pub fn check_expr_has_type(
1025 fcx: @mut FnCtxt, expr: @ast::expr,
1026 expected: ty::t) -> bool {
1027 do check_expr_with_unifier(fcx, expr, Some(expected)) {
1028 demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
1032 pub fn check_expr_coercable_to_type(
1033 fcx: @mut FnCtxt, expr: @ast::expr,
1034 expected: ty::t) -> bool {
1035 do check_expr_with_unifier(fcx, expr, Some(expected)) {
1036 demand::coerce(fcx, expr.span, expected, expr)
1040 pub fn check_expr_with_hint(
1041 fcx: @mut FnCtxt, expr: @ast::expr,
1042 expected: ty::t) -> bool {
1043 check_expr_with_unifier(fcx, expr, Some(expected), || ())
1046 pub fn check_expr_with_opt_hint(
1047 fcx: @mut FnCtxt, expr: @ast::expr,
1048 expected: Option<ty::t>) -> bool {
1049 check_expr_with_unifier(fcx, expr, expected, || ())
1052 pub fn check_expr(fcx: @mut FnCtxt, expr: @ast::expr) -> bool {
1053 check_expr_with_unifier(fcx, expr, None, || ())
1056 // determine the `self` type, using fresh variables for all variables
1057 // declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
1058 // would return ($0, $1) where $0 and $1 are freshly instantiated type
1060 pub fn impl_self_ty(vcx: &VtableContext,
1061 location_info: &LocationInfo, // (potential) receiver for
1064 -> ty_param_substs_and_ty {
1065 let tcx = vcx.tcx();
1067 let (n_tps, region_param, raw_ty) = if did.crate == ast::local_crate {
1068 let region_param = tcx.region_paramd_items.find(&did.node);
1069 match tcx.items.find(&did.node) {
1070 Some(ast_map::node_item(@ast::item {
1071 node: ast::item_impl(ref ts, _, st, _),
1074 (ts.ty_params.len(),
1076 vcx.ccx.to_ty(&rscope::type_rscope(region_param), st))
1078 Some(ast_map::node_item(@ast::item {
1079 node: ast::item_struct(_, ref ts),
1083 /* If the impl is a class, the self ty is just the class ty
1084 (doing a no-op subst for the ty params; in the next step,
1085 we substitute in fresh vars for them)
1087 (ts.ty_params.len(),
1089 ty::mk_struct(tcx, local_def(class_id),
1091 self_r: rscope::bound_self_region(region_param),
1093 tps: ty::ty_params_to_tys(tcx, ts)
1096 _ => { tcx.sess.bug(~"impl_self_ty: unbound item or item that \
1097 doesn't have a self_ty"); }
1100 let ity = ty::lookup_item_type(tcx, did);
1101 (vec::len(*ity.bounds), ity.region_param, ity.ty)
1104 let self_r = if region_param.is_some() {
1105 Some(vcx.infcx.next_region_var(location_info.span,
1110 let tps = vcx.infcx.next_ty_vars(n_tps);
1112 let substs = substs { self_r: self_r, self_ty: None, tps: tps };
1113 let substd_ty = ty::subst(tcx, &substs, raw_ty);
1115 ty_param_substs_and_ty { substs: substs, ty: substd_ty }
1118 // Only for fields! Returns <none> for methods>
1119 // Indifferent to privacy flags
1120 pub fn lookup_field_ty(tcx: ty::ctxt,
1121 class_id: ast::def_id,
1122 items: &[ty::field_ty],
1123 fieldname: ast::ident,
1124 substs: &ty::substs) -> Option<ty::t> {
1126 let o_field = vec::find(items, |f| f.ident == fieldname);
1127 do o_field.map() |f| {
1128 ty::lookup_field_type(tcx, class_id, f.id, substs)
1132 // Controls whether the arguments are automatically referenced. This is useful
1133 // for overloaded binary and unary operators.
1134 pub enum DerefArgs {
1139 pub fn break_here() {
1140 debug!("break here!");
1143 pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
1145 expected: Option<ty::t>,
1146 unifier: &fn()) -> bool {
1147 debug!(">> typechecking %s", fcx.expr_to_str(expr));
1149 // A generic function to factor out common logic from call and
1150 // overloaded operations
1151 fn check_call_inner(
1154 call_expr_id: ast::node_id,
1156 callee_expr: @ast::expr,
1157 args: ~[@ast::expr],
1158 sugar: ast::CallSugar,
1159 deref_args: DerefArgs) -> (ty::t, bool)
1161 let tcx = fcx.ccx.tcx;
1162 let mut bot = false;
1164 // Replace all region parameters in the arguments and return
1165 // type with fresh region variables.
1167 debug!("check_call_inner: before universal quant., in_fty=%s",
1168 fcx.infcx().ty_to_str(in_fty));
1172 // This is subtle: we expect `fty` to be a function type, which
1173 // normally introduce a level of binding. In this case, we want to
1174 // process the types bound by the function but not by any nested
1175 // functions. Therefore, we match one level of structure.
1176 let ret_ty = match structure_of(fcx, sp, in_fty) {
1177 ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) |
1178 ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => {
1180 replace_bound_regions_in_fn_sig(
1181 tcx, @Nil, None, sig,
1182 |_br| fcx.infcx().next_region_var(
1185 let supplied_arg_count = args.len();
1187 bot |= ty::type_is_bot(sig.output);
1189 // Grab the argument types, supplying fresh type variables
1190 // if the wrong number of arguments were supplied
1191 let expected_arg_count = sig.inputs.len();
1192 formal_tys = if expected_arg_count == supplied_arg_count {
1193 sig.inputs.map(|a| a.ty)
1195 let suffix = match sugar {
1197 ast::DoSugar => " (including the closure passed by \
1199 ast::ForSugar => " (including the closure passed by \
1202 let msg = fmt!("this function takes %u parameter%s but \
1203 %u parameter%s supplied%s",
1205 if expected_arg_count == 1 {""}
1208 if supplied_arg_count == 1 {" was"}
1212 tcx.sess.span_err(sp, msg);
1214 vec::from_fn(supplied_arg_count, |_| ty::mk_err(tcx))
1221 fcx.type_error_message(sp, |actual| {
1222 fmt!("expected function or foreign function but \
1223 found `%s`", actual) }, in_fty, None);
1225 // check each arg against "error", in order to set up
1226 // all the node type bindings
1227 formal_tys = args.map(|_x| ty::mk_err(tcx));
1232 debug!("check_call_inner: after universal quant., \
1233 formal_tys=%? ret_ty=%s",
1234 formal_tys.map(|t| fcx.infcx().ty_to_str(*t)),
1235 fcx.infcx().ty_to_str(ret_ty));
1237 // Check the arguments.
1238 // We do this in a pretty awful way: first we typecheck any arguments
1239 // that are not anonymous functions, then we typecheck the anonymous
1240 // functions. This is so that we have more information about the types
1241 // of arguments when we typecheck the functions. This isn't really the
1242 // right way to do this.
1243 for [false, true].each |check_blocks| {
1244 let check_blocks = *check_blocks;
1245 debug!("check_blocks=%b", check_blocks);
1247 // More awful hacks: before we check the blocks, try to do
1248 // an "opportunistic" vtable resolution of any trait
1249 // bounds on the call.
1251 vtable::early_resolve_expr(callee_expr, fcx, true);
1254 for args.eachi |i, arg| {
1255 let is_block = match arg.node {
1256 ast::expr_fn_block(*) | ast::expr_loop_body(*) |
1257 ast::expr_do_body(*) => true,
1261 if is_block == check_blocks {
1262 debug!("checking the argument");
1263 let mut formal_ty = formal_tys[i];
1267 match ty::get(formal_ty).sty {
1268 ty::ty_rptr(_, mt) => formal_ty = mt.ty,
1270 fcx.ccx.tcx.sess.span_bug(arg.span,
1278 // mismatch error happens in here
1279 bot |= check_expr_coercable_to_type(
1280 fcx, *arg, formal_ty);
1289 // A generic function for checking assignment expressions
1290 fn check_assignment(fcx: @mut FnCtxt,
1295 let mut bot = check_expr(fcx, lhs);
1296 let lhs_type = fcx.expr_ty(lhs);
1297 bot |= check_expr_has_type(fcx, rhs, lhs_type);
1298 fcx.write_ty(id, ty::mk_nil(fcx.ccx.tcx));
1302 // A generic function for doing all of the checking for call or
1303 // method expressions
1304 fn check_call_or_method(fcx: @mut FnCtxt,
1306 call_expr_id: ast::node_id,
1309 +args: ~[@ast::expr],
1311 sugar: ast::CallSugar) -> bool
1315 // Call the generic checker.
1316 let (ret_ty, b) = check_call_inner(fcx, sp, call_expr_id,
1317 fn_ty, expr, args, sugar,
1321 // Pull the return type out of the type of the function.
1322 fcx.write_ty(call_expr_id, ret_ty);
1326 // A generic function for doing all of the checking for call expressions
1327 fn check_call(fcx: @mut FnCtxt,
1329 call_expr_id: ast::node_id,
1331 +args: ~[@ast::expr],
1332 sugar: ast::CallSugar)
1334 // Index expressions need to be handled separately, to inform them
1335 // that they appear in call position.
1336 let mut bot = match /*bad*/copy f.node {
1337 ast::expr_field(base, field, tys) => {
1338 check_field(fcx, f, true, base, field, tys)
1340 _ => check_expr(fcx, f)
1343 check_call_or_method(fcx,
1353 // Checks a method call.
1354 fn check_method_call(fcx: @mut FnCtxt,
1357 method_name: ast::ident,
1358 +args: ~[@ast::expr],
1360 sugar: ast::CallSugar)
1362 let bot = check_expr(fcx, rcvr);
1363 let expr_t = structurally_resolved_type(fcx,
1367 let tps = tps.map(|ast_ty| fcx.to_ty(*ast_ty));
1368 match method::lookup(fcx,
1376 CheckTraitsAndInherentMethods) {
1377 Some(ref entry) => {
1378 let method_map = fcx.ccx.method_map;
1379 method_map.insert(expr.id, (*entry));
1382 fcx.type_error_message(expr.span,
1384 fmt!("type `%s` does not implement any method in scope \
1387 *fcx.ccx.tcx.sess.str_of(method_name))
1392 // Add error type for the result
1393 fcx.write_ty(expr.id, ty::mk_err(fcx.ccx.tcx));
1394 fcx.write_ty(expr.callee_id, ty::mk_err(fcx.ccx.tcx));
1398 check_call_or_method(fcx,
1401 fcx.node_ty(expr.callee_id),
1408 // A generic function for checking for or for-each loops
1409 fn check_for(fcx: @mut FnCtxt,
1413 node_id: ast::node_id)
1415 let local_ty = fcx.local_ty(local.span, local.node.id);
1416 demand::suptype(fcx, local.span, local_ty, element_ty);
1417 let bot = check_decl_local(fcx, local);
1418 check_block_no_value(fcx, body);
1419 fcx.write_nil(node_id);
1423 // A generic function for checking the then and else in an if
1425 fn check_then_else(fcx: @mut FnCtxt,
1427 elsopt: Option<@ast::expr>,
1431 let (if_t, if_bot) =
1434 let if_t = fcx.infcx().next_ty_var();
1435 let thn_bot = check_block(fcx, thn);
1436 let thn_t = fcx.node_ty(thn.node.id);
1437 demand::suptype(fcx, thn.span, if_t, thn_t);
1438 let els_bot = check_expr_has_type(fcx, els, if_t);
1439 (if_t, thn_bot & els_bot)
1442 check_block_no_value(fcx, thn);
1443 (ty::mk_nil(fcx.ccx.tcx), false)
1446 fcx.write_ty(id, if_t);
1450 fn lookup_op_method(fcx: @mut FnCtxt,
1452 self_ex: @ast::expr,
1455 +args: ~[@ast::expr],
1456 +deref_args: DerefArgs)
1457 -> Option<(ty::t, bool)> {
1458 match method::lookup(fcx,
1467 Some(ref origin) => {
1468 let method_ty = fcx.node_ty(op_ex.callee_id);
1469 let method_map = fcx.ccx.method_map;
1470 method_map.insert(op_ex.id, *origin);
1471 Some(check_call_inner(fcx,
1484 // could be either a expr_binop or an expr_assign_binop
1485 fn check_binop(fcx: @mut FnCtxt,
1491 let tcx = fcx.ccx.tcx;
1493 let lhs_bot = check_expr(fcx, lhs);
1494 let lhs_t = fcx.expr_ty(lhs);
1495 let lhs_t = structurally_resolved_type(fcx, lhs.span, lhs_t);
1497 if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) {
1498 // Shift is a special case: rhs can be any integral type
1499 let rhs_bot = check_expr(fcx, rhs);
1500 let rhs_t = fcx.expr_ty(rhs);
1501 require_integral(fcx, rhs.span, rhs_t);
1502 fcx.write_ty(expr.id, lhs_t);
1503 return lhs_bot | rhs_bot;
1506 if ty::is_binopable(tcx, lhs_t, op) {
1507 let tvar = fcx.infcx().next_ty_var();
1508 demand::suptype(fcx, expr.span, tvar, lhs_t);
1509 let rhs_bot = check_expr_has_type(fcx, rhs, tvar);
1511 let result_t = match op {
1512 ast::eq | ast::ne | ast::lt | ast::le | ast::ge |
1521 fcx.write_ty(expr.id, result_t);
1523 if !ast_util::lazy_binop(op) { lhs_bot | rhs_bot }
1528 // A hack, but this prevents multiple errors for the same code
1529 // (since check_user_binop calls structurally_resolve_type)
1530 let (result, rhs_bot) =
1531 match ty::deref(fcx.tcx(), lhs_t, false).map(
1532 |tt| structurally_resolved_type(fcx,
1533 expr.span, tt.ty)) {
1534 Some(t) if ty::get(t).sty == ty::ty_err => (t, false),
1535 _ => check_user_binop(fcx, expr, lhs, lhs_t, op, rhs)
1537 fcx.write_ty(expr.id, result);
1538 return lhs_bot | rhs_bot;
1541 fn check_user_binop(fcx: @mut FnCtxt,
1543 lhs_expr: @ast::expr,
1544 lhs_resolved_t: ty::t,
1548 let tcx = fcx.ccx.tcx;
1549 match ast_util::binop_to_method_name(op) {
1551 match lookup_op_method(fcx, ex, lhs_expr, lhs_resolved_t,
1552 fcx.tcx().sess.ident_of(copy *name),
1553 ~[rhs], DoDerefArgs) {
1554 Some(pair) => return pair,
1560 check_expr(fcx, rhs);
1561 fcx.type_error_message(ex.span,
1563 fmt!("binary operation %s cannot be applied to type `%s`",
1564 ast_util::binop_to_str(op), actual)
1566 lhs_resolved_t, None);
1568 // If the or operator is used it might be that the user forgot to
1569 // supply the do keyword. Let's be more helpful in that situation.
1571 match ty::get(lhs_resolved_t).sty {
1572 ty::ty_bare_fn(_) | ty::ty_closure(_) => {
1574 ex.span, ~"did you forget the `do` keyword \
1581 (lhs_resolved_t, false)
1584 fn check_user_unop(fcx: @mut FnCtxt,
1588 rhs_expr: @ast::expr,
1591 match lookup_op_method(
1592 fcx, ex, rhs_expr, rhs_t,
1593 fcx.tcx().sess.ident_of(/*bad*/ copy mname), ~[],
1596 Some((ret_ty, _)) => ret_ty,
1598 fcx.type_error_message(ex.span, |actual| {
1599 fmt!("cannot apply unary operator `%s` to type `%s`",
1607 // Resolves `expected` by a single level if it is a variable and passes it
1608 // through the `unpack` function. It there is no expected type or
1609 // resolution is not possible (e.g., no constraints yet present), just
1611 fn unpack_expected<O:Copy>(fcx: @mut FnCtxt,
1612 expected: Option<ty::t>,
1613 unpack: &fn(&ty::sty) -> Option<O>)
1617 match resolve_type(fcx.infcx(), t, force_tvar) {
1618 Ok(t) => unpack(&ty::get(t).sty),
1626 fn check_expr_fn(fcx: @mut FnCtxt,
1628 ast_sigil_opt: Option<ast::Sigil>,
1629 decl: &ast::fn_decl,
1632 expected: Option<ty::t>) {
1633 let tcx = fcx.ccx.tcx;
1635 // Find the expected input/output types (if any). Careful to
1636 // avoid capture of bound regions in the expected type. See
1637 // def'n of br_cap_avoid() for a more lengthy explanation of
1638 // what's going on here.
1639 // Also try to pick up inferred purity and sigil, defaulting
1640 // to impure and block. Note that we only will use those for
1641 // block syntax lambdas; that is, lambdas without explicit
1643 let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
1647 expected_onceness) = {
1648 match expected_sty {
1649 Some(ty::ty_closure(ref cenv)) => {
1652 replace_bound_regions_in_fn_sig(
1653 tcx, @Nil, None, &cenv.sig,
1654 |br| ty::re_bound(ty::br_cap_avoid(id, @br)));
1655 (Some(sig), cenv.purity, cenv.sigil, cenv.onceness)
1658 (None, ast::impure_fn, ast::BorrowedSigil, ast::Many)
1663 // If the proto is specified, use that, otherwise select a
1664 // proto based on inference.
1665 let (sigil, purity) = match ast_sigil_opt {
1666 Some(p) => (p, ast::impure_fn),
1667 None => (expected_sigil, expected_purity)
1670 // construct the function type
1671 let mut fn_ty = astconv::ty_of_closure(
1673 sigil, purity, expected_onceness,
1674 None, decl, expected_tys, expr.span);
1676 let fty = ty::mk_closure(tcx, copy fn_ty);
1678 debug!("check_expr_fn_with_unifier %s fty=%s",
1679 fcx.expr_to_str(expr),
1680 fcx.infcx().ty_to_str(fty));
1682 fcx.write_ty(expr.id, fty);
1684 let inherited_purity =
1685 ty::determine_inherited_purity(fcx.purity, purity,
1688 // We inherit the same self info as the enclosing scope,
1689 // since the function we're checking might capture `self`
1690 check_fn(fcx.ccx, fcx.self_info, inherited_purity,
1691 &fn_ty.sig, decl, body, fn_kind,
1692 fcx.in_scope_regions, fcx.inh);
1696 // Check field access expressions
1697 fn check_field(fcx: @mut FnCtxt,
1704 let tcx = fcx.ccx.tcx;
1705 let bot = check_expr(fcx, base);
1706 let expr_t = structurally_resolved_type(fcx, expr.span,
1708 let (base_t, derefs) = do_autoderef(fcx, expr.span, expr_t);
1709 let n_tys = tys.len();
1711 match structure_of(fcx, expr.span, base_t) {
1712 ty::ty_struct(base_id, ref substs) => {
1713 // This is just for fields -- the same code handles
1714 // methods in both classes and traits
1716 // (1) verify that the class id actually has a field called
1718 debug!("class named %s", ppaux::ty_to_str(tcx, base_t));
1719 let cls_items = ty::lookup_struct_fields(tcx, base_id);
1720 match lookup_field_ty(tcx, base_id, cls_items,
1721 field, &(*substs)) {
1723 // (2) look up what field's type is, and return it
1724 fcx.write_ty(expr.id, field_ty);
1725 fcx.write_autoderef_adjustment(base.id, derefs);
1734 let tps = vec::map(tys, |ty| fcx.to_ty(*ty));
1736 match method::lookup(fcx,
1744 CheckTraitsAndInherentMethods) {
1745 Some(ref entry) => {
1746 let method_map = fcx.ccx.method_map;
1747 method_map.insert(expr.id, (*entry));
1749 // If we have resolved to a method but this is not in
1750 // a callee position, error
1754 ~"attempted to take value of method \
1755 (try writing an anonymous function)");
1756 // Add error type for the result
1757 fcx.write_ty(expr.id, ty::mk_err(tcx));
1761 fcx.type_error_message(expr.span,
1763 fmt!("attempted access of field `%s` on type `%s`, but \
1764 no field or method with that name was found",
1765 *tcx.sess.str_of(field), actual)
1768 // Add error type for the result
1769 fcx.write_ty(expr.id, ty::mk_err(tcx));
1776 fn check_struct_or_variant_fields(fcx: @mut FnCtxt,
1778 class_id: ast::def_id,
1779 substitutions: &ty::substs,
1780 field_types: ~[ty::field_ty],
1781 ast_fields: ~[ast::field],
1782 check_completeness: bool)
1784 let tcx = fcx.ccx.tcx;
1785 let mut bot = false;
1787 debug!("%? %?", ast_fields.len(), field_types.len());
1789 let class_field_map = HashMap();
1790 let mut fields_found = 0;
1791 for field_types.each |field| {
1792 // XXX: Check visibility here.
1793 class_field_map.insert(field.ident, (field.id, false));
1796 // Typecheck each field.
1797 for ast_fields.each |field| {
1798 match class_field_map.find(&field.node.ident) {
1802 fmt!("structure has no field named `%s`",
1803 *tcx.sess.str_of(field.node.ident)));
1805 Some((_, true)) => {
1808 fmt!("field `%s` specified more than once",
1809 *tcx.sess.str_of(field.node.ident)));
1811 Some((field_id, false)) => {
1812 let expected_field_type =
1813 ty::lookup_field_type(
1814 tcx, class_id, field_id, substitutions);
1816 check_expr_coercable_to_type(
1819 expected_field_type);
1820 class_field_map.insert(
1821 field.node.ident, (field_id, true));
1827 if check_completeness {
1828 // Make sure the programmer specified all the fields.
1829 fail_unless!(fields_found <= field_types.len());
1830 if fields_found < field_types.len() {
1831 let mut missing_fields = ~[];
1832 for field_types.each |class_field| {
1833 let name = class_field.ident;
1834 let (_, seen) = class_field_map.get(&name);
1836 missing_fields.push(
1837 ~"`" + *tcx.sess.str_of(name) + ~"`");
1841 tcx.sess.span_err(span,
1842 fmt!("missing field%s: %s",
1843 if missing_fields.len() == 1 {
1848 str::connect(missing_fields, ~", ")));
1855 fn check_struct_constructor(fcx: @mut FnCtxt,
1857 span: codemap::span,
1858 class_id: ast::def_id,
1859 fields: ~[ast::field],
1860 base_expr: Option<@ast::expr>)
1862 let mut bot = false;
1863 let tcx = fcx.ccx.tcx;
1865 // Look up the number of type parameters and the raw type, and
1866 // determine whether the class is region-parameterized.
1867 let type_parameter_count, region_parameterized, raw_type;
1868 if class_id.crate == ast::local_crate {
1869 region_parameterized =
1870 tcx.region_paramd_items.find(&class_id.node);
1871 match tcx.items.find(&class_id.node) {
1872 Some(ast_map::node_item(@ast::item {
1873 node: ast::item_struct(_, ref generics),
1877 type_parameter_count = generics.ty_params.len();
1880 bound_self_region(region_parameterized);
1882 raw_type = ty::mk_struct(tcx, class_id, substs {
1883 self_r: self_region,
1885 tps: ty::ty_params_to_tys(
1891 tcx.sess.span_bug(span,
1892 ~"resolve didn't map this to a class");
1896 let item_type = ty::lookup_item_type(tcx, class_id);
1897 type_parameter_count = (*item_type.bounds).len();
1898 region_parameterized = item_type.region_param;
1899 raw_type = item_type.ty;
1902 // Generate the struct type.
1904 fcx.region_var_if_parameterized(region_parameterized,
1907 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
1908 let substitutions = substs {
1909 self_r: self_region,
1911 tps: type_parameters
1914 let struct_type = ty::subst(tcx, &substitutions, raw_type);
1916 // Look up and check the fields.
1917 let class_fields = ty::lookup_struct_fields(tcx, class_id);
1918 bot = check_struct_or_variant_fields(fcx,
1924 base_expr.is_none()) || bot;
1926 // Check the base expression if necessary.
1929 Some(base_expr) => {
1930 bot = check_expr_has_type(fcx, base_expr, struct_type) || bot
1934 // Write in the resulting type.
1935 fcx.write_ty(id, struct_type);
1939 fn check_struct_enum_variant(fcx: @mut FnCtxt,
1941 span: codemap::span,
1942 enum_id: ast::def_id,
1943 variant_id: ast::def_id,
1944 fields: ~[ast::field])
1946 let mut bot = false;
1947 let tcx = fcx.ccx.tcx;
1949 // Look up the number of type parameters and the raw type, and
1950 // determine whether the enum is region-parameterized.
1951 let type_parameter_count, region_parameterized, raw_type;
1952 if enum_id.crate == ast::local_crate {
1953 region_parameterized =
1954 tcx.region_paramd_items.find(&enum_id.node);
1955 match tcx.items.find(&enum_id.node) {
1956 Some(ast_map::node_item(@ast::item {
1957 node: ast::item_enum(_, ref generics),
1961 type_parameter_count = generics.ty_params.len();
1964 bound_self_region(region_parameterized);
1966 raw_type = ty::mk_enum(tcx, enum_id, substs {
1967 self_r: self_region,
1969 tps: ty::ty_params_to_tys(
1975 tcx.sess.span_bug(span,
1976 ~"resolve didn't map this to an enum");
1980 let item_type = ty::lookup_item_type(tcx, enum_id);
1981 type_parameter_count = (*item_type.bounds).len();
1982 region_parameterized = item_type.region_param;
1983 raw_type = item_type.ty;
1986 // Generate the enum type.
1988 fcx.region_var_if_parameterized(region_parameterized,
1991 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
1992 let substitutions = substs {
1993 self_r: self_region,
1995 tps: type_parameters
1998 let enum_type = ty::subst(tcx, &substitutions, raw_type);
2000 // Look up and check the enum variant fields.
2001 let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2002 bot = check_struct_or_variant_fields(fcx,
2010 // Write in the resulting type.
2011 fcx.write_ty(id, enum_type);
2015 fn check_loop_body(fcx: @mut FnCtxt,
2017 expected: Option<ty::t>,
2018 loop_body: @ast::expr) {
2019 // a loop body is the special argument to a `for` loop. We know that
2020 // there will be an expected type in this context because it can only
2021 // appear in the context of a call, so we get the expected type of the
2022 // parameter. The catch here is that we need to validate two things:
2023 // 1. a closure that returns a bool is expected
2024 // 2. the closure that was given returns unit
2025 let tcx = fcx.tcx();
2026 let mut err_happened = false;
2027 let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
2028 let inner_ty = match expected_sty {
2029 Some(ty::ty_closure(ref fty)) => {
2030 match fcx.mk_subty(false, expr.span,
2031 fty.sig.output, ty::mk_bool(tcx)) {
2033 ty::mk_closure(tcx, ty::ClosureTy {
2034 sig: FnSig {output: ty::mk_nil(tcx),
2040 fcx.type_error_message(
2043 let did_you_mean = {
2044 if ty::type_is_nil(fty.sig.output) {
2045 "\nDid you mean to use \
2046 `do` instead of `for`?"
2051 fmt!("A `for` loop iterator should expect a \
2052 closure that returns `bool`. This \
2053 iterator expects a closure that \
2055 actual, did_you_mean)
2059 err_happened = true;
2061 // Kind of a hack: create a function type with
2062 // the result replaced with ty_err, to
2063 // suppress derived errors.
2064 let t = ty::replace_closure_return_type(
2065 tcx, ty::mk_closure(tcx, copy *fty),
2067 fcx.write_ty(expr.id, ty::mk_err(tcx));
2074 Some(expected_t) => {
2075 fcx.type_error_message(
2078 fmt!("last argument in `for` call \
2079 has non-closure type: %s",
2083 let err_ty = ty::mk_err(tcx);
2084 fcx.write_ty(expr.id, err_ty);
2085 err_happened = true;
2088 None => fcx.tcx().sess.impossible_case(
2090 ~"loop body must have an expected type")
2095 match loop_body.node {
2096 ast::expr_fn_block(ref decl, ref body) => {
2097 // If an error occurred, we pretend this isn't a for
2098 // loop, so as to assign types to all nodes while also
2099 // propagating ty_err throughout so as to suppress
2100 // derived errors. If we passed in ForLoop in the
2101 // error case, we'd potentially emit a spurious error
2102 // message because of the indirect_ret_ty.
2103 let fn_kind = if err_happened {
2106 let indirect_ret_ty =
2107 fcx.indirect_ret_ty.get_or_default(fcx.ret_ty);
2108 ForLoop(indirect_ret_ty)
2110 check_expr_fn(fcx, loop_body, None,
2111 decl, body, fn_kind, Some(inner_ty));
2112 demand::suptype(fcx, loop_body.span,
2113 inner_ty, fcx.expr_ty(loop_body));
2117 "check_loop_body expected expr_fn_block, not %?", n))
2121 let block_ty = structurally_resolved_type(
2122 fcx, expr.span, fcx.node_ty(loop_body.id));
2124 fcx.write_ty(expr.id, ty::mk_err(fcx.tcx()));
2127 ty::replace_closure_return_type(
2128 tcx, block_ty, ty::mk_bool(tcx));
2129 fcx.write_ty(expr.id, loop_body_ty);
2133 let tcx = fcx.ccx.tcx;
2135 let mut bot = false;
2136 match /*bad*/copy expr.node {
2137 ast::expr_vstore(ev, vst) => {
2138 let typ = match /*bad*/copy ev.node {
2139 ast::expr_lit(@codemap::spanned { node: ast::lit_str(s), _ }) => {
2140 let tt = ast_expr_vstore_to_vstore(fcx, ev, str::len(*s), vst);
2141 ty::mk_estr(tcx, tt)
2143 ast::expr_vec(args, mutbl) => {
2144 let tt = ast_expr_vstore_to_vstore(fcx, ev, args.len(), vst);
2147 ast::expr_vstore_mut_box | ast::expr_vstore_mut_slice => {
2148 mutability = ast::m_mutbl
2150 _ => mutability = mutbl
2152 let t: ty::t = fcx.infcx().next_ty_var();
2153 for args.each |e| { bot |= check_expr_has_type(fcx, *e, t); }
2154 ty::mk_evec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2156 ast::expr_repeat(element, count_expr, mutbl) => {
2157 let count = ty::eval_repeat_count(tcx, count_expr);
2158 fcx.write_ty(count_expr.id, ty::mk_uint(tcx));
2159 let tt = ast_expr_vstore_to_vstore(fcx, ev, count, vst);
2160 let t: ty::t = fcx.infcx().next_ty_var();
2161 bot |= check_expr_has_type(fcx, element, t);
2162 ty::mk_evec(tcx, ty::mt {ty: t, mutbl: mutbl}, tt)
2165 tcx.sess.span_bug(expr.span, ~"vstore modifier on non-sequence")
2167 fcx.write_ty(ev.id, typ);
2168 fcx.write_ty(id, typ);
2171 ast::expr_lit(lit) => {
2172 let typ = check_lit(fcx, lit);
2173 fcx.write_ty(id, typ);
2175 ast::expr_binary(op, lhs, rhs) => {
2176 bot |= check_binop(fcx, expr, op, lhs, rhs);
2178 ast::expr_assign_op(op, lhs, rhs) => {
2179 bot |= check_binop(fcx, expr, op, lhs, rhs);
2180 let lhs_t = fcx.expr_ty(lhs);
2181 let result_t = fcx.expr_ty(expr);
2182 demand::suptype(fcx, expr.span, result_t, lhs_t);
2184 // Overwrite result of check_binop...this preserves existing behavior
2185 // but seems quite dubious with regard to user-defined methods
2186 // and so forth. - Niko
2187 fcx.write_nil(expr.id);
2189 ast::expr_unary(unop, oprnd) => {
2190 let exp_inner = do unpack_expected(fcx, expected) |sty| {
2192 ast::box(_) | ast::uniq(_) => match *sty {
2193 ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => Some(mt.ty),
2196 ast::not | ast::neg => expected,
2200 bot = check_expr_with_opt_hint(fcx, oprnd, exp_inner);
2201 let mut oprnd_t = fcx.expr_ty(oprnd);
2203 ast::box(mutbl) => {
2204 oprnd_t = ty::mk_box(tcx, ty::mt {ty: oprnd_t, mutbl: mutbl});
2206 ast::uniq(mutbl) => {
2207 oprnd_t = ty::mk_uniq(tcx, ty::mt {ty: oprnd_t, mutbl: mutbl});
2210 let sty = structure_of(fcx, expr.span, oprnd_t);
2213 // deref'ing an unsafe pointer requires that we be in an unsafe
2218 ~"dereference of unsafe pointer");
2223 let operand_ty = ty::deref_sty(tcx, &sty, true);
2234 ~"can only dereference enums \
2235 with a single variant which has a \
2238 ty::ty_struct(*) => {
2241 ~"can only dereference structs with one anonymous \
2245 fcx.type_error_message(expr.span, |actual| {
2246 fmt!("type %s cannot be dereferenced", actual)
2254 oprnd_t = structurally_resolved_type(fcx, oprnd.span, oprnd_t);
2255 if !(ty::type_is_integral(oprnd_t) ||
2256 ty::get(oprnd_t).sty == ty::ty_bool) {
2257 oprnd_t = check_user_unop(fcx, ~"!", ~"not", expr,
2262 oprnd_t = structurally_resolved_type(fcx, oprnd.span, oprnd_t);
2263 if !(ty::type_is_integral(oprnd_t) ||
2264 ty::type_is_fp(oprnd_t)) {
2265 oprnd_t = check_user_unop(fcx, ~"-", ~"neg", expr,
2270 fcx.write_ty(id, oprnd_t);
2272 ast::expr_addr_of(mutbl, oprnd) => {
2273 let hint = unpack_expected(
2275 |sty| match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty),
2277 bot = check_expr_with_opt_hint(fcx, oprnd, hint);
2279 // Note: at this point, we cannot say what the best lifetime
2280 // is to use for resulting pointer. We want to use the
2281 // shortest lifetime possible so as to avoid spurious borrowck
2282 // errors. Moreover, the longest lifetime will depend on the
2283 // precise details of the value whose address is being taken
2284 // (and how long it is valid), which we don't know yet until type
2285 // inference is complete.
2287 // Therefore, here we simply generate a region variable with
2288 // the current expression as a lower bound. The region
2289 // inferencer will then select the ultimate value. Finally,
2290 // borrowck is charged with guaranteeing that the value whose
2291 // address was taken can actually be made to live as long as
2292 // it needs to live.
2293 let region = fcx.infcx().next_region_var(expr.span, expr.id);
2295 let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
2296 let oprnd_t = ty::mk_rptr(tcx, region, tm);
2297 fcx.write_ty(id, oprnd_t);
2299 ast::expr_path(pth) => {
2300 let defn = lookup_def(fcx, pth.span, id);
2302 let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2303 let region_lb = ty::re_scope(expr.id);
2304 instantiate_path(fcx, pth, tpt, expr.span, expr.id, region_lb);
2306 ast::expr_inline_asm(*) => {
2307 fcx.require_unsafe(expr.span, ~"use of inline assembly");
2310 ast::expr_mac(_) => tcx.sess.bug(~"unexpanded macro"),
2311 ast::expr_break(_) => { fcx.write_bot(id); bot = true; }
2312 ast::expr_again(_) => { fcx.write_bot(id); bot = true; }
2313 ast::expr_ret(expr_opt) => {
2315 let ret_ty = match fcx.indirect_ret_ty {
2316 Some(t) => t, None => fcx.ret_ty
2319 None => match fcx.mk_eqty(false, expr.span,
2320 ret_ty, ty::mk_nil(tcx)) {
2321 result::Ok(_) => { /* fall through */ }
2325 ~"`return;` in function returning non-nil");
2329 check_expr_has_type(fcx, e, ret_ty);
2334 ast::expr_log(_, lv, e) => {
2335 bot = check_expr_has_type(fcx, lv,
2336 ty::mk_mach_uint(tcx, ast::ty_u32));
2338 // Note: this does not always execute, so do not propagate bot:
2342 ast::expr_copy(a) => {
2343 bot = check_expr_with_opt_hint(fcx, a, expected);
2344 fcx.write_ty(id, fcx.expr_ty(a));
2346 ast::expr_paren(a) => {
2347 bot = check_expr_with_opt_hint(fcx, a, expected);
2348 fcx.write_ty(id, fcx.expr_ty(a));
2350 ast::expr_assign(lhs, rhs) => {
2351 bot = check_assignment(fcx, lhs, rhs, id);
2353 ast::expr_swap(lhs, rhs) => {
2354 bot = check_assignment(fcx, lhs, rhs, id);
2356 ast::expr_if(cond, ref thn, elsopt) => {
2357 bot = check_expr_has_type(fcx, cond, ty::mk_bool(tcx));
2358 bot |= check_then_else(fcx, thn, elsopt, id, expr.span);
2360 ast::expr_while(cond, ref body) => {
2361 bot = check_expr_has_type(fcx, cond, ty::mk_bool(tcx));
2362 check_block_no_value(fcx, body);
2363 fcx.write_ty(id, ty::mk_nil(tcx));
2365 ast::expr_loop(ref body, _) => {
2366 check_block_no_value(fcx, body);
2367 fcx.write_ty(id, ty::mk_nil(tcx));
2368 bot = !may_break(tcx, expr.id, body);
2370 ast::expr_match(discrim, ref arms) => {
2371 bot = _match::check_match(fcx, expr, discrim, (/*bad*/copy *arms));
2373 ast::expr_fn_block(ref decl, ref body) => {
2374 check_expr_fn(fcx, expr, None,
2375 decl, body, Vanilla, expected);
2377 ast::expr_loop_body(loop_body) => {
2378 check_loop_body(fcx, expr, expected, loop_body);
2380 ast::expr_do_body(b) => {
2381 let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
2382 let inner_ty = match expected_sty {
2383 Some(ty::ty_closure(_)) => expected.get(),
2384 _ => match expected {
2385 Some(expected_t) => {
2386 fcx.type_error_message(expr.span, |actual| {
2387 fmt!("last argument in `do` call \
2388 has non-closure type: %s",
2390 }, expected_t, None);
2391 let err_ty = ty::mk_err(tcx);
2392 fcx.write_ty(id, err_ty);
2396 fcx.tcx().sess.impossible_case(
2398 ~"do body must have expected type")
2403 ast::expr_fn_block(ref decl, ref body) => {
2404 check_expr_fn(fcx, b, None,
2405 decl, body, DoBlock, Some(inner_ty));
2406 demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
2409 _ => fail!(~"expected fn ty")
2411 fcx.write_ty(expr.id, fcx.node_ty(b.id));
2413 ast::expr_block(ref b) => {
2414 // If this is an unchecked block, turn off purity-checking
2415 bot = check_block_with_expected(fcx, b, expected);
2418 Some(expr) => fcx.expr_ty(expr),
2419 None => ty::mk_nil(tcx)
2421 fcx.write_ty(id, typ);
2423 ast::expr_call(f, args, sugar) => {
2424 bot = check_call(fcx, expr.span, expr.id, f, args, sugar);
2426 ast::expr_method_call(rcvr, ident, tps, args, sugar) => {
2427 bot = check_method_call(fcx, expr, rcvr, ident, args, tps, sugar);
2429 ast::expr_cast(e, t) => {
2430 bot = check_expr(fcx, e);
2431 let t_1 = fcx.to_ty(t);
2432 let t_e = fcx.expr_ty(e);
2434 debug!("t_1=%s", fcx.infcx().ty_to_str(t_1));
2435 debug!("t_e=%s", fcx.infcx().ty_to_str(t_e));
2437 match ty::get(t_1).sty {
2438 // This will be looked up later on
2439 ty::ty_trait(*) => (),
2442 if ty::type_is_nil(t_e) {
2443 fcx.type_error_message(expr.span, |actual| {
2444 fmt!("cast from nil: `%s` as `%s`", actual,
2445 fcx.infcx().ty_to_str(t_1))
2447 } else if ty::type_is_nil(t_1) {
2448 fcx.type_error_message(expr.span, |actual| {
2449 fmt!("cast to nil: `%s` as `%s`", actual,
2450 fcx.infcx().ty_to_str(t_1))
2454 let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
2455 if type_is_c_like_enum(fcx,expr.span,t_e) && t_1_is_scalar {
2456 /* this case is allowed */
2457 } else if type_is_region_ptr(fcx, expr.span, t_e) &&
2458 type_is_unsafe_ptr(fcx, expr.span, t_1) {
2460 fn is_vec(t: ty::t) -> bool {
2461 match ty::get(t).sty {
2462 ty::ty_evec(_,_) => true,
2466 fn types_compatible(fcx: @mut FnCtxt, sp: span, t1: ty::t,
2467 t2: ty::t) -> bool {
2471 let el = ty::sequence_element_type(fcx.tcx(), t1);
2472 infer::mk_eqty(fcx.infcx(), false, sp, el, t2).is_ok()
2476 // Due to the limitations of LLVM global constants,
2477 // region pointers end up pointing at copies of
2478 // vector elements instead of the original values.
2479 // To allow unsafe pointers to work correctly, we
2480 // need to special-case obtaining an unsafe pointer
2481 // from a region pointer to a vector.
2483 /* this cast is only allowed from &[T] to *T or
2485 let te = structurally_resolved_type(fcx, e.span, t_e);
2486 match (&ty::get(te).sty, &ty::get(t_1).sty) {
2487 (&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
2488 if types_compatible(fcx, e.span, mt1.ty, mt2.ty) => {
2489 /* this case is allowed */
2492 demand::coerce(fcx, e.span, t_1, e);
2495 } else if !(type_is_scalar(fcx,expr.span,t_e) && t_1_is_scalar) {
2497 If more type combinations should be supported than are
2498 supported here, then file an enhancement issue and record the
2499 issue number in this comment.
2501 fcx.type_error_message(expr.span, |actual| {
2502 fmt!("non-scalar cast: `%s` as `%s`", actual,
2503 fcx.infcx().ty_to_str(t_1))
2508 fcx.write_ty(id, t_1);
2510 ast::expr_vec(args, mutbl) => {
2511 let t: ty::t = fcx.infcx().next_ty_var();
2512 for args.each |e| { bot |= check_expr_has_type(fcx, *e, t); }
2513 let typ = ty::mk_evec(tcx, ty::mt {ty: t, mutbl: mutbl},
2514 ty::vstore_fixed(args.len()));
2515 fcx.write_ty(id, typ);
2517 ast::expr_repeat(element, count_expr, mutbl) => {
2518 let count = ty::eval_repeat_count(tcx, count_expr);
2519 fcx.write_ty(count_expr.id, ty::mk_uint(tcx));
2520 let t: ty::t = fcx.infcx().next_ty_var();
2521 bot |= check_expr_has_type(fcx, element, t);
2522 let t = ty::mk_evec(tcx, ty::mt {ty: t, mutbl: mutbl},
2523 ty::vstore_fixed(count));
2524 fcx.write_ty(id, t);
2526 ast::expr_tup(elts) => {
2527 let flds = unpack_expected(fcx, expected, |sty| {
2528 match *sty { ty::ty_tup(ref flds) => Some(copy *flds), _ => None }
2530 let elt_ts = do elts.mapi |i, e| {
2531 check_expr_with_opt_hint(fcx, *e, flds.map(|fs| fs[i]));
2534 let typ = ty::mk_tup(tcx, elt_ts);
2535 fcx.write_ty(id, typ);
2537 ast::expr_struct(path, ref fields, base_expr) => {
2538 // Resolve the path.
2539 match tcx.def_map.find(&id) {
2540 Some(ast::def_struct(type_def_id)) => {
2541 check_struct_constructor(fcx, id, expr.span, type_def_id,
2542 (/*bad*/copy *fields), base_expr);
2544 Some(ast::def_variant(enum_id, variant_id)) => {
2545 check_struct_enum_variant(fcx, id, expr.span, enum_id,
2546 variant_id, (/*bad*/copy *fields));
2549 tcx.sess.span_bug(path.span, ~"structure constructor does \
2550 not name a structure type");
2554 ast::expr_field(base, field, tys) => {
2555 bot = check_field(fcx, expr, false, base, field, tys);
2557 ast::expr_index(base, idx) => {
2558 bot |= check_expr(fcx, base);
2559 let raw_base_t = fcx.expr_ty(base);
2560 let (base_t, derefs) = do_autoderef(fcx, expr.span, raw_base_t);
2561 bot |= check_expr(fcx, idx);
2562 let idx_t = fcx.expr_ty(idx);
2563 let base_sty = structure_of(fcx, expr.span, base_t);
2564 match ty::index_sty(tcx, &base_sty) {
2566 require_integral(fcx, idx.span, idx_t);
2567 fcx.write_ty(id, mt.ty);
2568 fcx.write_autoderef_adjustment(base.id, derefs);
2571 let resolved = structurally_resolved_type(fcx, expr.span,
2573 match lookup_op_method(fcx, expr, base, resolved,
2574 tcx.sess.ident_of(~"index"),
2575 ~[idx], DontDerefArgs) {
2576 Some((ret_ty, _)) => fcx.write_ty(id, ret_ty),
2578 fcx.type_error_message(expr.span, |actual|
2579 fmt!("cannot index a value of type `%s`",
2580 actual), base_t, None);
2581 fcx.write_ty(id, ty::mk_err(tcx));
2589 if bot { fcx.write_bot(expr.id); }
2591 debug!("type of expr %s is...",
2592 syntax::print::pprust::expr_to_str(expr, tcx.sess.intr()));
2593 debug!("... %s, expected is %s",
2594 ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
2596 Some(t) => ppaux::ty_to_str(tcx, t),
2602 debug!("<< bot=%b", bot);
2606 pub fn require_integral(fcx: @mut FnCtxt, sp: span, t: ty::t) {
2607 if !type_is_integral(fcx, sp, t) {
2608 fcx.type_error_message(sp, |actual| {
2609 fmt!("mismatched types: expected integral type but found `%s`",
2615 pub fn check_decl_initializer(fcx: @mut FnCtxt,
2619 let local_ty = fcx.local_ty(init.span, nid);
2620 return check_expr_coercable_to_type(fcx, init, local_ty);
2623 pub fn check_decl_local(fcx: @mut FnCtxt, local: @ast::local) -> bool {
2624 let mut bot = false;
2625 let tcx = fcx.ccx.tcx;
2627 let t = fcx.local_ty(local.span, local.node.id);
2628 fcx.write_ty(local.node.id, t);
2630 match local.node.init {
2632 bot = check_decl_initializer(fcx, local.node.id, init);
2638 ty::re_scope(tcx.region_map.get(&local.node.id));
2639 let pcx = pat_ctxt {
2641 map: pat_id_map(tcx.def_map, local.node.pat),
2642 match_region: region,
2643 block_region: region,
2645 _match::check_pat(pcx, local.node.pat, t);
2649 pub fn check_stmt(fcx: @mut FnCtxt, stmt: @ast::stmt) -> bool {
2651 let mut bot = false;
2653 ast::stmt_decl(decl, id) => {
2655 match /*bad*/copy decl.node {
2656 ast::decl_local(ls) => for ls.each |l| {
2657 bot |= check_decl_local(fcx, *l);
2659 ast::decl_item(_) => {/* ignore for now */ }
2662 ast::stmt_expr(expr, id) => {
2664 bot = check_expr_has_type(fcx, expr, ty::mk_nil(fcx.ccx.tcx));
2666 ast::stmt_semi(expr, id) => {
2668 bot = check_expr(fcx, expr);
2670 ast::stmt_mac(*) => fcx.ccx.tcx.sess.bug(~"unexpanded macro")
2672 fcx.write_nil(node_id);
2676 pub fn check_block_no_value(fcx: @mut FnCtxt, blk: &ast::blk) -> bool {
2677 let bot = check_block(fcx, blk);
2679 let blkty = fcx.node_ty(blk.node.id);
2680 let nilty = ty::mk_nil(fcx.ccx.tcx);
2681 demand::suptype(fcx, blk.span, nilty, blkty);
2686 pub fn check_block(fcx0: @mut FnCtxt, blk: &ast::blk) -> bool {
2687 check_block_with_expected(fcx0, blk, None)
2690 pub fn check_block_with_expected(fcx0: @mut FnCtxt,
2692 expected: Option<ty::t>)
2694 let fcx = match blk.node.rules {
2695 ast::unsafe_blk => @mut FnCtxt {purity: ast::unsafe_fn,.. copy *fcx0},
2696 ast::default_blk => fcx0
2698 do fcx.with_region_lb(blk.node.id) {
2699 let mut bot = false;
2700 let mut warned = false;
2701 for blk.node.stmts.each |s| {
2702 if bot && !warned &&
2704 ast::stmt_decl(@codemap::spanned { node: ast::decl_local(_),
2706 ast::stmt_expr(_, _) | ast::stmt_semi(_, _) => {
2711 fcx.ccx.tcx.sess.span_warn(s.span, ~"unreachable statement");
2714 bot |= check_stmt(fcx, *s);
2716 match blk.node.expr {
2717 None => fcx.write_nil(blk.node.id),
2720 fcx.ccx.tcx.sess.span_warn(e.span, ~"unreachable expression");
2722 bot |= check_expr_with_opt_hint(fcx, e, expected);
2723 let ety = fcx.expr_ty(e);
2724 fcx.write_ty(blk.node.id, ety);
2728 fcx.write_bot(blk.node.id);
2734 pub fn check_const(ccx: @mut CrateCtxt,
2738 let rty = ty::node_id_to_type(ccx.tcx, id);
2739 let fcx = blank_fn_ctxt(ccx, rty, e.id);
2740 let declty = fcx.ccx.tcx.tcache.get(&local_def(id)).ty;
2741 check_const_with_ty(fcx, sp, e, declty);
2744 pub fn check_const_with_ty(fcx: @mut FnCtxt,
2749 let cty = fcx.expr_ty(e);
2750 demand::suptype(fcx, e.span, declty, cty);
2751 regionck::regionck_expr(fcx, e);
2752 writeback::resolve_type_vars_in_expr(fcx, e);
2755 /// Checks whether a type can be created without an instance of itself.
2756 /// This is similar but different from the question of whether a type
2757 /// can be represented. For example, the following type:
2759 /// enum foo { None, Some(foo) }
2761 /// is instantiable but is not representable. Similarly, the type
2763 /// enum foo { Some(@foo) }
2765 /// is representable, but not instantiable.
2766 pub fn check_instantiable(tcx: ty::ctxt,
2768 item_id: ast::node_id) {
2769 let item_ty = ty::node_id_to_type(tcx, item_id);
2770 if !ty::is_instantiable(tcx, item_ty) {
2771 tcx.sess.span_err(sp, fmt!("this type cannot be instantiated \
2772 without an instance of itself; \
2773 consider using `Option<%s>`",
2774 ppaux::ty_to_str(tcx, item_ty)));
2778 pub fn check_enum_variants(ccx: @mut CrateCtxt,
2780 +vs: ~[ast::variant],
2782 fn do_check(ccx: @mut CrateCtxt,
2784 vs: ~[ast::variant],
2786 disr_vals: &mut ~[int],
2788 variants: &mut ~[ty::VariantInfo]) {
2789 let rty = ty::node_id_to_type(ccx.tcx, id);
2791 for v.node.disr_expr.each |e_ref| {
2793 debug!("disr expr, checking %s",
2794 pprust::expr_to_str(e, ccx.tcx.sess.intr()));
2795 let declty = ty::mk_int(ccx.tcx);
2796 let fcx = blank_fn_ctxt(ccx, rty, e.id);
2797 check_const_with_ty(fcx, e.span, e, declty);
2798 // check_expr (from check_const pass) doesn't guarantee
2799 // that the expression is in an form that eval_const_expr can
2800 // handle, so we may still get an internal compiler error
2802 match const_eval::eval_const_expr_partial(ccx.tcx, e) {
2803 Ok(const_eval::const_int(val)) => {
2804 *disr_val = val as int;
2807 ccx.tcx.sess.span_err(e.span, ~"expected signed integer \
2811 ccx.tcx.sess.span_err(e.span,
2812 fmt!("expected constant: %s", (*err)));
2817 if vec::contains(*disr_vals, &*disr_val) {
2818 ccx.tcx.sess.span_err(v.span,
2819 ~"discriminator value already exists");
2821 disr_vals.push(*disr_val);
2822 let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id);
2825 let this_disr_val = *disr_val;
2829 ast::tuple_variant_kind(ref args) if args.len() > 0u => {
2830 arg_tys = Some(ty::ty_fn_args(ctor_ty).map(|a| a.ty));
2832 ast::tuple_variant_kind(_) => {
2833 arg_tys = Some(~[]);
2835 ast::struct_variant_kind(_) => {
2836 arg_tys = Some(ty::lookup_struct_fields(
2837 ccx.tcx, local_def(v.node.id)).map(|cf|
2838 ty::node_id_to_type(ccx.tcx, cf.id.node)));
2840 ast::enum_variant_kind(_) => {
2856 @VariantInfo_{args: arg_tys, ctor_ty: ctor_ty,
2857 name: v.node.name, id: local_def(v.node.id),
2858 disr_val: this_disr_val, vis: v.node.vis});
2864 let rty = ty::node_id_to_type(ccx.tcx, id);
2865 let mut disr_vals: ~[int] = ~[];
2866 let mut disr_val = 0;
2867 let mut variants = ~[];
2869 do_check(ccx, sp, vs, id, &mut disr_vals, &mut disr_val, &mut variants);
2871 // cache so that ty::enum_variants won't repeat this work
2872 ccx.tcx.enum_var_cache.insert(local_def(id), @variants);
2874 // Check that it is possible to represent this enum:
2875 let mut outer = true, did = local_def(id);
2876 if ty::type_structurally_contains(ccx.tcx, rty, |sty| {
2878 ty::ty_enum(id, _) if id == did => {
2879 if outer { outer = false; false }
2885 ccx.tcx.sess.span_err(sp, ~"illegal recursive enum type; \
2886 wrap the inner value in a box to \
2887 make it representable");
2890 // Check that it is possible to instantiate this enum:
2892 // This *sounds* like the same that as representable, but it's
2893 // not. See def'n of `check_instantiable()` for details.
2894 check_instantiable(ccx.tcx, sp, id);
2897 pub fn lookup_def(fcx: @mut FnCtxt, sp: span, id: ast::node_id) -> ast::def {
2898 lookup_def_ccx(fcx.ccx, sp, id)
2901 // Returns the type parameter count and the type for the given definition.
2902 pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt,
2905 -> ty_param_bounds_and_ty {
2908 ast::def_arg(nid, _, _) | ast::def_local(nid, _) |
2909 ast::def_self(nid, _) | ast::def_binding(nid, _) => {
2910 let typ = fcx.local_ty(sp, nid);
2911 return no_params(typ);
2913 ast::def_fn(_, ast::extern_fn) => {
2914 // extern functions are just u8 pointers
2915 return ty_param_bounds_and_ty {
2921 ty: ty::mk_mach_uint(fcx.ccx.tcx, ast::ty_u8),
2927 ast::def_fn(id, ast::unsafe_fn) |
2928 ast::def_static_method(id, _, ast::unsafe_fn) => {
2929 // Unsafe functions can only be touched in an unsafe context
2930 fcx.require_unsafe(sp, ~"access to unsafe function");
2931 return ty::lookup_item_type(fcx.ccx.tcx, id);
2934 ast::def_fn(id, _) | ast::def_static_method(id, _, _) |
2935 ast::def_const(id) | ast::def_variant(_, id) |
2936 ast::def_struct(id) => {
2937 return ty::lookup_item_type(fcx.ccx.tcx, id);
2939 ast::def_upvar(_, inner, _, _) => {
2940 return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
2942 ast::def_ty(_) | ast::def_prim_ty(_) | ast::def_ty_param(*)=> {
2943 fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found type");
2945 ast::def_mod(*) | ast::def_foreign_mod(*) => {
2946 fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found module");
2948 ast::def_use(*) => {
2949 fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found use");
2951 ast::def_region(*) => {
2952 fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found region");
2954 ast::def_typaram_binder(*) => {
2955 fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found type \
2958 ast::def_label(*) => {
2959 fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found label");
2961 ast::def_self_ty(*) => {
2962 fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found self ty");
2967 // Instantiates the given path, which must refer to an item with the given
2968 // number of type parameters and type.
2969 pub fn instantiate_path(fcx: @mut FnCtxt,
2971 tpt: ty_param_bounds_and_ty,
2973 node_id: ast::node_id,
2974 region_lb: ty::Region) {
2975 debug!(">>> instantiate_path");
2977 let ty_param_count = vec::len(*tpt.bounds);
2978 let ty_substs_len = vec::len(pth.types);
2980 // determine the region bound, using the value given by the user
2981 // (if any) and otherwise using a fresh region variable
2982 let self_r = match pth.rp {
2983 Some(_) => { // user supplied a lifetime parameter...
2984 match tpt.region_param {
2985 None => { // ...but the type is not lifetime parameterized!
2986 fcx.ccx.tcx.sess.span_err
2987 (span, ~"this item is not region-parameterized");
2990 Some(_) => { // ...and the type is lifetime parameterized, ok.
2991 Some(ast_region_to_region(fcx, fcx, span, pth.rp))
2995 None => { // no lifetime parameter supplied, insert default
2996 fcx.region_var_if_parameterized(
2997 tpt.region_param, span, region_lb)
3001 // determine values for type parameters, using the values given by
3002 // the user (if any) and otherwise using fresh type variables
3003 let tps = if ty_substs_len == 0 {
3004 fcx.infcx().next_ty_vars(ty_param_count)
3005 } else if ty_param_count == 0 {
3006 fcx.ccx.tcx.sess.span_err
3007 (span, ~"this item does not take type parameters");
3008 fcx.infcx().next_ty_vars(ty_param_count)
3009 } else if ty_substs_len > ty_param_count {
3010 fcx.ccx.tcx.sess.span_err
3011 (span, ~"too many type parameters provided for this item");
3012 fcx.infcx().next_ty_vars(ty_param_count)
3013 } else if ty_substs_len < ty_param_count {
3014 fcx.ccx.tcx.sess.span_err
3015 (span, ~"not enough type parameters provided for this item");
3016 fcx.infcx().next_ty_vars(ty_param_count)
3018 pth.types.map(|aty| fcx.to_ty(*aty))
3021 let substs = substs { self_r: self_r, self_ty: None, tps: tps };
3022 fcx.write_ty_substs(node_id, tpt.ty, substs);
3027 // Resolves `typ` by a single level if `typ` is a type variable. If no
3028 // resolution is possible, then an error is reported.
3029 pub fn structurally_resolved_type(fcx: @mut FnCtxt, sp: span, tp: ty::t)
3031 match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
3032 Ok(t_s) if !ty::type_is_ty_var(t_s) => return t_s,
3034 fcx.type_error_message(sp, |_actual| {
3035 ~"the type of this value must be known in this context"
3037 return ty::mk_err(fcx.tcx());
3042 // Returns the one-level-deep structure of the given type.
3043 pub fn structure_of(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> ty::sty {
3044 /*bad*/copy ty::get(structurally_resolved_type(fcx, sp, typ)).sty
3047 pub fn type_is_integral(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
3048 let typ_s = structurally_resolved_type(fcx, sp, typ);
3049 return ty::type_is_integral(typ_s);
3052 pub fn type_is_scalar(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
3053 let typ_s = structurally_resolved_type(fcx, sp, typ);
3054 return ty::type_is_scalar(typ_s);
3057 pub fn type_is_unsafe_ptr(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
3058 let typ_s = structurally_resolved_type(fcx, sp, typ);
3059 return ty::type_is_unsafe_ptr(typ_s);
3062 pub fn type_is_region_ptr(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
3063 let typ_s = structurally_resolved_type(fcx, sp, typ);
3064 return ty::type_is_region_ptr(typ_s);
3067 pub fn type_is_c_like_enum(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
3068 let typ_s = structurally_resolved_type(fcx, sp, typ);
3069 return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
3072 pub fn ast_expr_vstore_to_vstore(fcx: @mut FnCtxt,
3075 v: ast::expr_vstore)
3078 ast::expr_vstore_fixed(None) => ty::vstore_fixed(n),
3079 ast::expr_vstore_fixed(Some(u)) => {
3081 let s = fmt!("fixed-size sequence mismatch: %u vs. %u",u, n);
3082 fcx.ccx.tcx.sess.span_err(e.span,s);
3086 ast::expr_vstore_uniq => ty::vstore_uniq,
3087 ast::expr_vstore_box | ast::expr_vstore_mut_box => ty::vstore_box,
3088 ast::expr_vstore_slice | ast::expr_vstore_mut_slice => {
3089 let r = fcx.infcx().next_region_var(e.span, e.id);
3095 // Returns true if b contains a break that can exit from b
3096 pub fn may_break(cx: ty::ctxt, id: ast::node_id, b: &ast::blk) -> bool {
3097 // First: is there an unlabeled break immediately
3099 (loop_query(b, |e| {
3101 ast::expr_break(_) => true,
3105 // Second: is there a labeled break with label
3106 // <id> nested anywhere inside the loop?
3107 (block_query(b, |e| {
3109 ast::expr_break(Some(_)) =>
3110 match cx.def_map.find(&e.id) {
3111 Some(ast::def_label(loop_id)) if id == loop_id => true,
3118 pub fn check_bounds_are_used(ccx: @mut CrateCtxt,
3120 tps: &OptVec<ast::TyParam>,
3122 debug!("check_bounds_are_used(n_tps=%u, ty=%s)",
3123 tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
3125 // make a vector of booleans initially false, set to true when used
3126 if tps.len() == 0u { return; }
3127 let mut tps_used = vec::from_elem(tps.len(), false);
3129 ty::walk_regions_and_ty(
3133 match ty::get(t).sty {
3134 ty::ty_param(param_ty {idx, _}) => {
3135 debug!("Found use of ty param #%u", idx);
3136 tps_used[idx] = true;
3143 for tps_used.eachi |i, b| {
3145 ccx.tcx.sess.span_err(
3146 span, fmt!("type parameter `%s` is unused",
3147 *ccx.tcx.sess.str_of(tps.get(i).ident)));
3152 pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
3153 fn param(ccx: @mut CrateCtxt, n: uint) -> ty::t {
3154 ty::mk_param(ccx.tcx, n, local_def(0))
3156 fn arg(m: ast::rmode, ty: ty::t) -> ty::arg {
3157 arg {mode: ast::expl(m), ty: ty}
3160 let (n_tps, inputs, output) = match *ccx.tcx.sess.str_of(it.ident) {
3162 ~"pref_align_of" | ~"min_align_of" => (1u, ~[], ty::mk_uint(ccx.tcx)),
3163 ~"init" => (1u, ~[], param(ccx, 0u)),
3164 ~"forget" => (1u, ~[arg(ast::by_copy, param(ccx, 0u))],
3166 ~"reinterpret_cast" => (2u, ~[arg(ast::by_ref, param(ccx, 0u))],
3168 ~"addr_of" => (1u, ~[arg(ast::by_ref, param(ccx, 0u))],
3169 ty::mk_imm_ptr(tcx, param(ccx, 0u))),
3170 ~"move_val" | ~"move_val_init" => {
3171 (1u, ~[arg(ast::by_copy,
3172 ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)),
3174 arg(ast::by_copy, param(ccx, 0u))],
3177 ~"needs_drop" => (1u, ~[], ty::mk_bool(tcx)),
3179 ~"atomic_cxchg" | ~"atomic_cxchg_acq"| ~"atomic_cxchg_rel" => {
3180 (0u, ~[arg(ast::by_copy,
3181 ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)),
3183 arg(ast::by_copy, ty::mk_int(tcx)),
3184 arg(ast::by_copy, ty::mk_int(tcx))],
3187 ~"atomic_xchg" | ~"atomic_xadd" | ~"atomic_xsub" |
3188 ~"atomic_xchg_acq" | ~"atomic_xadd_acq" | ~"atomic_xsub_acq" |
3189 ~"atomic_xchg_rel" | ~"atomic_xadd_rel" | ~"atomic_xsub_rel" => {
3190 (0u, ~[arg(ast::by_copy,
3191 ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)),
3193 arg(ast::by_copy, ty::mk_int(tcx))],
3198 // FIXME (#3730): return *intrinsic::tydesc, not *()
3199 (1u, ~[], ty::mk_nil_ptr(tcx))
3201 ~"visit_tydesc" => {
3202 let tydesc_name = special_idents::tydesc;
3203 let ty_visitor_name = tcx.sess.ident_of(~"TyVisitor");
3204 fail_unless!(tcx.intrinsic_defs.contains_key(&tydesc_name));
3205 fail_unless!(ccx.tcx.intrinsic_defs.contains_key(&ty_visitor_name));
3206 let (_, tydesc_ty) = tcx.intrinsic_defs.get(&tydesc_name);
3207 let (_, visitor_trait) = tcx.intrinsic_defs.get(&ty_visitor_name);
3208 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {ty: tydesc_ty,
3209 mutbl: ast::m_imm});
3210 (0u, ~[arg(ast::by_val, td_ptr),
3211 arg(ast::by_ref, visitor_trait)], ty::mk_nil(tcx))
3213 ~"frame_address" => {
3214 let fty = ty::mk_closure(ccx.tcx, ty::ClosureTy {
3215 purity: ast::impure_fn,
3216 sigil: ast::BorrowedSigil,
3217 onceness: ast::Once,
3218 region: ty::re_bound(ty::br_anon(0)),
3220 inputs: ~[arg {mode: ast::expl(ast::by_val),
3223 ty::mk_mach_uint(ccx.tcx, ast::ty_u8))}],
3224 output: ty::mk_nil(ccx.tcx)
3227 (0u, ~[arg(ast::by_ref, fty)], ty::mk_nil(tcx))
3229 ~"morestack_addr" => {
3230 (0u, ~[], ty::mk_nil_ptr(tcx))
3233 (0, ~[arg(ast::by_copy,
3235 ty::mt { ty: ty::mk_u8(tcx), mutbl: ast::m_mutbl })),
3238 ty::mt { ty: ty::mk_u8(tcx), mutbl: ast::m_imm })),
3244 (0, ~[arg(ast::by_copy,
3246 ty::mt { ty: ty::mk_u8(tcx), mutbl: ast::m_mutbl })),
3249 ty::mt { ty: ty::mk_u8(tcx), mutbl: ast::m_imm })),
3255 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))],
3259 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
3263 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx)),
3264 arg(ast::by_copy, ty::mk_i32(tcx))],
3268 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx)),
3269 arg(ast::by_copy, ty::mk_i32(tcx))],
3273 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))],
3277 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
3281 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))],
3285 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
3289 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx)),
3290 arg(ast::by_copy, ty::mk_f32(tcx))],
3294 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx)),
3295 arg(ast::by_copy, ty::mk_f64(tcx))],
3299 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))],
3303 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
3307 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))],
3311 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
3315 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))],
3319 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
3323 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))],
3327 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
3331 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))],
3335 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
3339 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx)),
3340 arg(ast::by_copy, ty::mk_f32(tcx)),
3341 arg(ast::by_copy, ty::mk_f32(tcx))],
3345 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx)),
3346 arg(ast::by_copy, ty::mk_f64(tcx)),
3347 arg(ast::by_copy, ty::mk_f64(tcx))],
3351 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))],
3355 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
3359 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))],
3363 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
3367 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))],
3371 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
3375 (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))],
3379 (0u, ~[arg(ast::by_copy, ty::mk_f64(tcx))],
3383 (0u, ~[arg(ast::by_copy, ty::mk_i8(tcx))],
3387 (0u, ~[arg(ast::by_copy, ty::mk_i16(tcx))],
3391 (0u, ~[arg(ast::by_copy, ty::mk_i32(tcx))],
3395 (0u, ~[arg(ast::by_copy, ty::mk_i64(tcx))],
3399 (0u, ~[arg(ast::by_copy, ty::mk_i8(tcx))],
3403 (0u, ~[arg(ast::by_copy, ty::mk_i16(tcx))],
3407 (0u, ~[arg(ast::by_copy, ty::mk_i32(tcx))],
3411 (0u, ~[arg(ast::by_copy, ty::mk_i64(tcx))],
3415 (0u, ~[arg(ast::by_copy, ty::mk_i8(tcx))],
3419 (0u, ~[arg(ast::by_copy, ty::mk_i16(tcx))],
3423 (0u, ~[arg(ast::by_copy, ty::mk_i32(tcx))],
3427 (0u, ~[arg(ast::by_copy, ty::mk_i64(tcx))],
3431 (0u, ~[arg(ast::by_copy, ty::mk_i16(tcx))],
3435 (0u, ~[arg(ast::by_copy, ty::mk_i32(tcx))],
3439 (0u, ~[arg(ast::by_copy, ty::mk_i64(tcx))],
3443 tcx.sess.span_err(it.span, ~"unrecognized intrinsic function: `" +
3448 let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
3449 purity: ast::unsafe_fn,
3451 sig: FnSig {inputs: inputs,
3454 let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
3455 let i_n_tps = (*i_ty.bounds).len();
3456 if i_n_tps != n_tps {
3457 tcx.sess.span_err(it.span, fmt!("intrinsic has wrong number \
3458 of type parameters: found %u, \
3459 expected %u", i_n_tps, n_tps));
3462 tcx, None, false, it.span, i_ty.ty, fty,
3463 || fmt!("intrinsic has wrong type: \
3465 ppaux::ty_to_str(ccx.tcx, fty)));