1 // Copyright 2012-2013 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::pat_util::pat_id_map;
83 use middle::lint::unreachable_code;
84 use middle::ty::{FnSig, VariantInfo};
85 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
86 use middle::ty::{substs, param_ty, ExprTyProvider};
88 use middle::typeck::astconv::AstConv;
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::{AutoderefReceiver};
93 use middle::typeck::check::method::{AutoderefReceiverFlag};
94 use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
95 use middle::typeck::check::method::{CheckTraitsOnly, DontAutoderefReceiver};
96 use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
97 use middle::typeck::check::regionmanip::relate_free_regions;
98 use middle::typeck::check::vtable::{LocationInfo, VtableContext};
99 use middle::typeck::CrateCtxt;
100 use middle::typeck::infer::{resolve_type, force_tvar};
101 use middle::typeck::infer;
102 use middle::typeck::rscope::bound_self_region;
103 use middle::typeck::rscope::{RegionError};
104 use middle::typeck::rscope::region_scope;
105 use middle::typeck::{isr_alist, lookup_def_ccx};
106 use middle::typeck::no_params;
107 use middle::typeck::{require_same_types, method_map, vtable_map};
108 use util::common::{block_query, indenter, loop_query};
109 use util::ppaux::{bound_region_ptr_to_str};
113 use std::cast::transmute;
114 use std::hashmap::HashMap;
116 use std::util::replace;
118 use extra::list::Nil;
119 use syntax::abi::AbiSet;
120 use syntax::ast::{provided, required};
123 use syntax::ast_util::local_def;
124 use syntax::ast_util;
125 use syntax::codemap::span;
127 use syntax::opt_vec::OptVec;
129 use syntax::parse::token;
130 use syntax::parse::token::special_idents;
131 use syntax::print::pprust;
132 use syntax::oldvisit;
143 pub struct SelfInfo {
145 self_id: ast::NodeId,
149 /// Fields that are part of a `FnCtxt` which are inherited by
150 /// closures defined within the function. For example:
156 /// Here, the function `foo()` and the closure passed to
157 /// `bar()` will each have their own `FnCtxt`, but they will
158 /// share the inherited fields.
159 pub struct inherited {
160 infcx: @mut infer::InferCtxt,
161 locals: @mut HashMap<ast::NodeId, ty::t>,
164 node_types: @mut HashMap<ast::NodeId, ty::t>,
165 node_type_substs: @mut HashMap<ast::NodeId, ty::substs>,
166 adjustments: @mut HashMap<ast::NodeId, @ty::AutoAdjustment>,
167 method_map: method_map,
168 vtable_map: vtable_map,
176 // A normal closure or fn item.
181 pub struct PurityState {
188 pub fn function(purity: ast::purity, def: ast::NodeId) -> PurityState {
189 PurityState { def: def, purity: purity, from_fn: true }
192 pub fn recurse(&mut self, blk: &ast::Block) -> PurityState {
194 // If this unsafe, then if the outer function was already marked as
195 // unsafe we shouldn't attribute the unsafe'ness to the block. This
196 // way the block can be warned about instead of ignoring this
197 // extraneous block (functions are never warned about).
198 ast::unsafe_fn if self.from_fn => *self,
201 let (purity, def) = match blk.rules {
202 ast::UnsafeBlock => (ast::unsafe_fn, blk.id),
203 ast::DefaultBlock => (purity, self.def),
205 PurityState{ def: def,
213 /// Whether `check_binop` allows overloaded operators to be invoked.
215 enum AllowOverloadedOperatorsFlag {
216 AllowOverloadedOperators,
217 DontAllowOverloadedOperators,
222 // Number of errors that had been reported when we started
223 // checking this function. On exit, if we find that *more* errors
224 // have been reported, we will skip regionck and other work that
225 // expects the types within the function to be consistent.
226 err_count_on_creation: uint,
231 // Sometimes we generate region pointers where the precise region
232 // to use is not known. For example, an expression like `&x.f`
233 // where `x` is of type `@T`: in this case, we will be rooting
234 // `x` onto the stack frame, and we could choose to root it until
235 // the end of (almost) any enclosing block or expression. We
236 // want to pick the narrowest block that encompasses all uses.
238 // What we do in such cases is to generate a region variable with
239 // `region_lb` as a lower bound. The regionck pass then adds
240 // other constriants based on how the variable is used and region
241 // inference selects the ultimate value. Finally, borrowck is
242 // charged with guaranteeing that the value whose address was taken
243 // can actually be made to live as long as it needs to live.
244 region_lb: ast::NodeId,
246 // Says whether we're inside a for loop, in a do block
247 // or neither. Helps with error messages involving the
248 // function return type.
251 in_scope_regions: isr_alist,
258 pub fn blank_inherited(ccx: @mut CrateCtxt) -> @inherited {
260 infcx: infer::new_infer_ctxt(ccx.tcx),
261 locals: @mut HashMap::new(),
262 node_types: @mut HashMap::new(),
263 node_type_substs: @mut HashMap::new(),
264 adjustments: @mut HashMap::new(),
265 method_map: @mut HashMap::new(),
266 vtable_map: @mut HashMap::new(),
270 // Used by check_const and check_enum_variants
271 pub fn blank_fn_ctxt(ccx: @mut CrateCtxt,
273 region_bnd: ast::NodeId)
275 // It's kind of a kludge to manufacture a fake function context
276 // and statement context, but we might as well do write the code only once
278 err_count_on_creation: ccx.tcx.sess.err_count(),
280 ps: PurityState::function(ast::impure_fn, 0),
281 region_lb: region_bnd,
282 in_scope_regions: @Nil,
284 inh: blank_inherited(ccx),
289 impl ExprTyProvider for FnCtxt {
290 pub fn expr_ty(&self, ex: &ast::expr) -> ty::t {
294 pub fn ty_ctxt(&self) -> ty::ctxt {
299 pub fn check_item_types(ccx: @mut CrateCtxt, crate: &ast::Crate) {
300 let visit = oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor {
301 visit_item: |a| check_item(ccx, a),
302 .. *oldvisit::default_simple_visitor()
304 oldvisit::visit_crate(crate, ((), visit));
307 pub fn check_bare_fn(ccx: @mut CrateCtxt,
311 self_info: Option<SelfInfo>) {
312 let fty = ty::node_id_to_type(ccx.tcx, id);
313 match ty::get(fty).sty {
314 ty::ty_bare_fn(ref fn_ty) => {
316 check_fn(ccx, self_info, fn_ty.purity,
317 &fn_ty.sig, decl, id, body, Vanilla,
318 @Nil, blank_inherited(ccx));;
320 vtable::resolve_in_block(fcx, body);
321 regionck::regionck_fn(fcx, body);
322 writeback::resolve_type_vars_in_fn(fcx, decl, body, self_info);
324 _ => ccx.tcx.sess.impossible_case(body.span,
325 "check_bare_fn: function type expected")
329 pub fn check_fn(ccx: @mut CrateCtxt,
330 opt_self_info: Option<SelfInfo>,
337 inherited_isr: isr_alist,
338 inherited: @inherited) -> @mut FnCtxt
342 * Helper used by check_bare_fn and check_expr_fn. Does the
343 * grungy work of checking a function body and returns the
344 * function context used for that purpose, since in the case of a
345 * fn item there is still a bit more to do.
348 * - inherited_isr: regions in scope from the enclosing fn (if any)
349 * - inherited: other fields inherited from the enclosing fn (if any)
353 let err_count_on_creation = tcx.sess.err_count();
355 // ______________________________________________________________________
356 // First, we have to replace any bound regions in the fn and self
357 // types with free ones. The free region references will be bound
358 // the node_id of the body block.
359 let (isr, opt_self_info, fn_sig) = {
360 let opt_self_ty = opt_self_info.map(|i| i.self_ty);
361 let (isr, opt_self_ty, fn_sig) =
362 replace_bound_regions_in_fn_sig(
363 tcx, inherited_isr, opt_self_ty, fn_sig,
364 |br| ty::re_free(ty::FreeRegion {scope_id: body.id,
368 |si| SelfInfo {self_ty: opt_self_ty.unwrap(), ..*si});
369 (isr, opt_self_info, fn_sig)
372 relate_free_regions(tcx, opt_self_info.map(|s| s.self_ty), &fn_sig);
374 let arg_tys = fn_sig.inputs.map(|a| *a);
375 let ret_ty = fn_sig.output;
377 debug!("check_fn(arg_tys=%?, ret_ty=%?, opt_self_ty=%?)",
378 arg_tys.map(|&a| ppaux::ty_to_str(tcx, a)),
379 ppaux::ty_to_str(tcx, ret_ty),
380 opt_self_info.map(|si| ppaux::ty_to_str(tcx, si.self_ty)));
382 // ______________________________________________________________________
383 // Create the function context. This is either derived from scratch or,
384 // in the case of function expressions, based on the outer context.
385 let fcx: @mut FnCtxt = {
387 err_count_on_creation: err_count_on_creation,
389 ps: PurityState::function(purity, id),
391 in_scope_regions: isr,
398 gather_locals(fcx, decl, body, arg_tys, opt_self_info);
399 check_block_with_expected(fcx, body, Some(ret_ty));
401 // We unify the tail expr's type with the
402 // function result type, if there is a tail expr.
405 let tail_expr_ty = fcx.expr_ty(tail_expr);
406 // Special case: we print a special error if there appears
407 // to be do-block/for-loop confusion
408 demand::suptype_with_fn(fcx, tail_expr.span, false,
409 fcx.ret_ty, tail_expr_ty,
411 fcx.report_mismatched_return_types(sp, e, a, s) });
416 for self_info in opt_self_info.iter() {
417 fcx.write_ty(self_info.self_id, self_info.self_ty);
419 for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
420 fcx.write_ty(input.id, *arg);
425 fn gather_locals(fcx: @mut FnCtxt,
429 opt_self_info: Option<SelfInfo>) {
430 let tcx = fcx.ccx.tcx;
432 let assign: @fn(ast::NodeId, Option<ty::t>) = |nid, ty_opt| {
435 // infer the variable's type
436 let var_id = fcx.infcx().next_ty_var_id();
437 let var_ty = ty::mk_var(fcx.tcx(), var_id);
438 fcx.inh.locals.insert(nid, var_ty);
441 // take type that the user specified
442 fcx.inh.locals.insert(nid, typ);
447 // Add the self parameter
448 for self_info in opt_self_info.iter() {
449 assign(self_info.self_id, Some(self_info.self_ty));
450 debug!("self is assigned to %s",
451 fcx.infcx().ty_to_str(
452 fcx.inh.locals.get_copy(&self_info.self_id)));
455 // Add formal parameters.
456 for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
457 // Create type variables for each argument.
458 do pat_util::pat_bindings(tcx.def_map, input.pat)
459 |_bm, pat_id, _sp, _path| {
460 assign(pat_id, None);
463 // Check the pattern.
466 map: pat_id_map(tcx.def_map, input.pat),
468 _match::check_pat(&pcx, input.pat, *arg_ty);
471 // Add explicitly-declared locals.
472 let visit_local: @fn(@ast::Local, ((), oldvisit::vt<()>)) =
474 let o_ty = match local.ty.node {
475 ast::ty_infer => None,
476 _ => Some(fcx.to_ty(&local.ty))
478 assign(local.id, o_ty);
479 debug!("Local variable %s is assigned type %s",
480 fcx.pat_to_str(local.pat),
481 fcx.infcx().ty_to_str(
482 fcx.inh.locals.get_copy(&local.id)));
483 oldvisit::visit_local(local, (e, v));
486 // Add pattern bindings.
487 let visit_pat: @fn(@ast::pat, ((), oldvisit::vt<()>)) = |p, (e, v)| {
489 ast::pat_ident(_, ref path, _)
490 if pat_util::pat_is_binding(fcx.ccx.tcx.def_map, p) => {
492 debug!("Pattern binding %s is assigned to %s",
493 tcx.sess.str_of(path.idents[0]),
494 fcx.infcx().ty_to_str(
495 fcx.inh.locals.get_copy(&p.id)));
499 oldvisit::visit_pat(p, (e, v));
503 @fn(&ast::Block, ((), oldvisit::vt<()>)) = |b, (e, v)| {
504 // non-obvious: the `blk` variable maps to region lb, so
505 // we have to keep this up-to-date. This
506 // is... unfortunate. It'd be nice to not need this.
507 do fcx.with_region_lb(b.id) {
508 oldvisit::visit_block(b, (e, v));
512 // Don't descend into fns and items
513 fn visit_fn(_fk: &oldvisit::fn_kind,
514 _decl: &ast::fn_decl,
518 (_t,_v): ((), oldvisit::vt<()>)) {
520 fn visit_item(_i: @ast::item, (_e,_v): ((), oldvisit::vt<()>)) { }
522 let visit = oldvisit::mk_vt(
523 @oldvisit::Visitor {visit_local: visit_local,
524 visit_pat: visit_pat,
526 visit_item: visit_item,
527 visit_block: visit_block,
528 ..*oldvisit::default_visitor()});
530 (visit.visit_block)(body, ((), visit));
534 pub fn check_method(ccx: @mut CrateCtxt,
535 method: @ast::method)
537 let method_def_id = local_def(method.id);
538 let method_ty = ty::method(ccx.tcx, method_def_id);
539 let opt_self_info = method_ty.transformed_self_ty.map(|&ty| {
540 SelfInfo {self_ty: ty,
541 self_id: method.self_id,
542 span: method.explicit_self.span}
554 pub fn check_no_duplicate_fields(tcx: ty::ctxt,
555 fields: ~[(ast::ident, span)]) {
556 let mut field_names = HashMap::new();
558 for p in fields.iter() {
560 let orig_sp = field_names.find(&id).map_consume(|x| *x);
563 tcx.sess.span_err(sp, fmt!("Duplicate field name %s in record type declaration",
564 tcx.sess.str_of(id)));
565 tcx.sess.span_note(orig_sp, "First declaration of this field occurred here");
569 field_names.insert(id, sp);
575 pub fn check_struct(ccx: @mut CrateCtxt, id: ast::NodeId, span: span) {
578 // Check that the class is instantiable
579 check_instantiable(tcx, span, id);
581 if ty::lookup_simd(tcx, local_def(id)) {
582 check_simd(tcx, span, id);
586 pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
587 debug!("check_item(it.id=%d, it.ident=%s)",
589 ty::item_path_str(ccx.tcx, local_def(it.id)));
590 let _indenter = indenter();
593 ast::item_static(_, _, e) => check_const(ccx, it.span, e, it.id),
594 ast::item_enum(ref enum_definition, _) => {
595 check_enum_variants(ccx,
597 enum_definition.variants,
600 ast::item_fn(ref decl, _, _, _, ref body) => {
601 check_bare_fn(ccx, decl, body, it.id, None);
603 ast::item_impl(_, _, _, ref ms) => {
604 let rp = ccx.tcx.region_paramd_items.find(&it.id).map_consume(|x| *x);
605 debug!("item_impl %s with id %d rp %?",
606 ccx.tcx.sess.str_of(it.ident), it.id, rp);
608 check_method(ccx, *m);
610 vtable::resolve_impl(ccx, it);
612 ast::item_trait(_, _, ref trait_methods) => {
613 for trait_method in (*trait_methods).iter() {
614 match *trait_method {
616 // Nothing to do, since required methods don't have
620 check_method(ccx, m);
625 ast::item_struct(*) => {
626 check_struct(ccx, it.id, it.span);
628 ast::item_ty(ref t, ref generics) => {
629 let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id);
630 check_bounds_are_used(ccx, t.span, &generics.ty_params, tpt_ty);
632 ast::item_foreign_mod(ref m) => {
633 if m.abis.is_intrinsic() {
634 for item in m.items.iter() {
635 check_intrinsic_type(ccx, *item);
638 for item in m.items.iter() {
639 let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id));
640 if tpt.generics.has_type_params() {
641 ccx.tcx.sess.span_err(
643 fmt!("foreign items may not have type parameters"));
648 _ => {/* nothing to do */ }
652 impl AstConv for FnCtxt {
653 fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
655 fn get_item_ty(&self, id: ast::def_id) -> ty::ty_param_bounds_and_ty {
656 ty::lookup_item_type(self.tcx(), id)
659 fn get_trait_def(&self, id: ast::def_id) -> @ty::TraitDef {
660 ty::lookup_trait_def(self.tcx(), id)
663 fn ty_infer(&self, _span: span) -> ty::t {
664 self.infcx().next_ty_var()
669 pub fn infcx(&self) -> @mut infer::InferCtxt {
672 pub fn err_count_since_creation(&self) -> uint {
673 self.ccx.tcx.sess.err_count() - self.err_count_on_creation
675 pub fn search_in_scope_regions(&self,
677 br: ty::bound_region)
678 -> Result<ty::Region, RegionError> {
679 let in_scope_regions = self.in_scope_regions;
680 match in_scope_regions.find(br) {
681 Some(r) => result::Ok(r),
683 let blk_br = ty::br_named(special_idents::blk);
685 result::Ok(self.block_region())
687 result::Err(RegionError {
689 fmt!("named region `%s` not in scope here",
690 bound_region_ptr_to_str(self.tcx(), br))
693 self.infcx().next_region_var(
694 infer::BoundRegionError(span))
703 impl region_scope for FnCtxt {
704 fn anon_region(&self, span: span) -> Result<ty::Region, RegionError> {
705 result::Ok(self.infcx().next_region_var(infer::MiscVariable(span)))
707 fn self_region(&self, span: span) -> Result<ty::Region, RegionError> {
708 self.search_in_scope_regions(span, ty::br_self)
710 fn named_region(&self,
712 id: ast::ident) -> Result<ty::Region, RegionError> {
713 self.search_in_scope_regions(span, ty::br_named(id))
718 pub fn tag(&self) -> ~str {
720 fmt!("%x", transmute(self))
724 pub fn local_ty(&self, span: span, nid: ast::NodeId) -> ty::t {
725 match self.inh.locals.find(&nid) {
728 self.tcx().sess.span_bug(
730 fmt!("No type for local variable %?", nid));
735 pub fn block_region(&self) -> ty::Region {
736 ty::re_scope(self.region_lb)
740 pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
741 debug!("write_ty(%d, %s) in fcx %s",
742 node_id, ppaux::ty_to_str(self.tcx(), ty), self.tag());
743 self.inh.node_types.insert(node_id, ty);
746 pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::substs) {
747 if !ty::substs_is_noop(&substs) {
748 debug!("write_substs(%d, %s) in fcx %s",
750 ty::substs_to_str(self.tcx(), &substs),
752 self.inh.node_type_substs.insert(node_id, substs);
756 pub fn write_ty_substs(&self,
757 node_id: ast::NodeId,
759 substs: ty::substs) {
760 let ty = ty::subst(self.tcx(), &substs, ty);
761 self.write_ty(node_id, ty);
762 self.write_substs(node_id, substs);
765 pub fn write_autoderef_adjustment(&self,
766 node_id: ast::NodeId,
768 if derefs == 0 { return; }
769 self.write_adjustment(
771 @ty::AutoDerefRef(ty::AutoDerefRef {
777 pub fn write_adjustment(&self,
778 node_id: ast::NodeId,
779 adj: @ty::AutoAdjustment) {
780 debug!("write_adjustment(node_id=%?, adj=%?)", node_id, adj);
781 self.inh.adjustments.insert(node_id, adj);
784 pub fn write_nil(&self, node_id: ast::NodeId) {
785 self.write_ty(node_id, ty::mk_nil());
787 pub fn write_bot(&self, node_id: ast::NodeId) {
788 self.write_ty(node_id, ty::mk_bot());
790 pub fn write_error(@mut self, node_id: ast::NodeId) {
791 self.write_ty(node_id, ty::mk_err());
794 pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
795 ast_ty_to_ty(self, self, ast_t)
798 pub fn pat_to_str(&self, pat: @ast::pat) -> ~str {
802 pub fn expr_ty(&self, ex: &ast::expr) -> ty::t {
803 match self.inh.node_types.find(&ex.id) {
806 self.tcx().sess.bug(fmt!("no type for expr in fcx %s",
812 pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
813 match self.inh.node_types.find(&id) {
817 fmt!("no type for node %d: %s in fcx %s",
818 id, ast_map::node_id_to_str(
819 self.tcx().items, id,
820 token::get_ident_interner()),
826 pub fn node_ty_substs(&self, id: ast::NodeId) -> ty::substs {
827 match self.inh.node_type_substs.find(&id) {
828 Some(ts) => (*ts).clone(),
831 fmt!("no type substs for node %d: %s in fcx %s",
832 id, ast_map::node_id_to_str(
833 self.tcx().items, id,
834 token::get_ident_interner()),
840 pub fn opt_node_ty_substs(&self,
842 f: &fn(&ty::substs) -> bool)
844 match self.inh.node_type_substs.find(&id) {
850 pub fn mk_subty(&self,
852 origin: infer::TypeOrigin,
855 -> Result<(), ty::type_err> {
856 infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
859 pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t)
860 -> Result<(), ty::type_err> {
861 infer::can_mk_subty(self.infcx(), sub, sup)
864 pub fn mk_assignty(&self,
868 -> Result<(), ty::type_err> {
869 match infer::mk_coercety(self.infcx(),
871 infer::ExprAssignable(expr),
874 Ok(None) => result::Ok(()),
875 Err(ref e) => result::Err((*e)),
876 Ok(Some(adjustment)) => {
877 self.write_adjustment(expr.id, adjustment);
883 pub fn can_mk_assignty(&self, sub: ty::t, sup: ty::t)
884 -> Result<(), ty::type_err> {
885 infer::can_mk_coercety(self.infcx(), sub, sup)
888 pub fn mk_eqty(&self,
890 origin: infer::TypeOrigin,
893 -> Result<(), ty::type_err> {
894 infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
897 pub fn mk_subr(&self,
899 origin: infer::SubregionOrigin,
902 infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
905 pub fn with_region_lb<R>(@mut self, lb: ast::NodeId, f: &fn() -> R)
907 let old_region_lb = self.region_lb;
910 self.region_lb = old_region_lb;
914 pub fn region_var_if_parameterized(&self,
915 rp: Option<ty::region_variance>,
917 -> OptVec<ty::Region> {
919 None => opt_vec::Empty,
922 self.infcx().next_region_var(
923 infer::BoundRegionInTypeOrImpl(span)))
928 pub fn type_error_message(&self,
930 mk_msg: &fn(~str) -> ~str,
932 err: Option<&ty::type_err>) {
933 self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
936 pub fn report_mismatched_return_types(&self,
940 err: &ty::type_err) {
942 if ty::type_is_error(e) || ty::type_is_error(a) {
946 DoBlock if ty::type_is_bool(e) && ty::type_is_nil(a) =>
947 // If we expected bool and got ()...
948 self.tcx().sess.span_err(sp, fmt!("Do-block body must \
949 return %s, but returns () here. Perhaps you meant \
950 to write a `for`-loop?",
951 ppaux::ty_to_str(self.tcx(), e))),
952 _ => self.infcx().report_mismatched_types(sp, e, a, err)
956 pub fn report_mismatched_types(&self,
960 err: &ty::type_err) {
961 self.infcx().report_mismatched_types(sp, e, a, err)
965 pub fn do_autoderef(fcx: @mut FnCtxt, sp: span, t: ty::t) -> (ty::t, uint) {
968 * Autoderefs the type `t` as many times as possible, returning
969 * a new type and a counter for how many times the type was
970 * deref'd. If the counter is non-zero, the receiver is responsible
971 * for inserting an AutoAdjustment record into `tcx.adjustments`
972 * so that trans/borrowck/etc know about this autoderef. */
975 let mut enum_dids = ~[];
976 let mut autoderefs = 0;
978 let sty = structure_of(fcx, sp, t1);
980 // Some extra checks to detect weird cycles and so forth:
982 ty::ty_box(inner) | ty::ty_uniq(inner) |
983 ty::ty_rptr(_, inner) => {
984 match ty::get(t1).sty {
985 ty::ty_infer(ty::TyVar(v1)) => {
986 ty::occurs_check(fcx.ccx.tcx, sp, v1,
987 ty::mk_box(fcx.ccx.tcx, inner));
992 ty::ty_enum(ref did, _) => {
993 // Watch out for a type like `enum t = @t`. Such a
994 // type would otherwise infinitely auto-deref. Only
995 // autoderef loops during typeck (basically, this one
996 // and the loops in typeck::check::method) need to be
997 // concerned with this, as an error will be reported
998 // on the enum definition as well because the enum is
1000 if enum_dids.contains(did) {
1001 return (t1, autoderefs);
1003 enum_dids.push(*did);
1008 // Otherwise, deref if type is derefable:
1009 match ty::deref_sty(fcx.ccx.tcx, sty, false) {
1011 return (t1, autoderefs);
1021 // AST fragment checking
1022 pub fn check_lit(fcx: @mut FnCtxt, lit: @ast::lit) -> ty::t {
1023 let tcx = fcx.ccx.tcx;
1026 ast::lit_str(*) => ty::mk_estr(tcx, ty::vstore_slice(ty::re_static)),
1027 ast::lit_int(_, t) => ty::mk_mach_int(t),
1028 ast::lit_uint(_, t) => ty::mk_mach_uint(t),
1029 ast::lit_int_unsuffixed(_) => {
1030 // An unsuffixed integer literal could have any integral type,
1031 // so we create an integral type variable for it.
1032 ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
1034 ast::lit_float(_, t) => ty::mk_mach_float(t),
1035 ast::lit_float_unsuffixed(_) => {
1036 // An unsuffixed floating point literal could have any floating point
1037 // type, so we create a floating point type variable for it.
1038 ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())
1040 ast::lit_nil => ty::mk_nil(),
1041 ast::lit_bool(_) => ty::mk_bool()
1045 pub fn valid_range_bounds(ccx: @mut CrateCtxt,
1049 match const_eval::compare_lit_exprs(ccx.tcx, from, to) {
1050 Some(val) => Some(val <= 0),
1055 pub fn check_expr_has_type(
1056 fcx: @mut FnCtxt, expr: @ast::expr,
1058 do check_expr_with_unifier(fcx, expr, Some(expected)) {
1059 demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
1063 pub fn check_expr_coercable_to_type(
1064 fcx: @mut FnCtxt, expr: @ast::expr,
1066 do check_expr_with_unifier(fcx, expr, Some(expected)) {
1067 demand::coerce(fcx, expr.span, expected, expr)
1071 pub fn check_expr_with_hint(
1072 fcx: @mut FnCtxt, expr: @ast::expr,
1074 check_expr_with_unifier(fcx, expr, Some(expected), || ())
1077 pub fn check_expr_with_opt_hint(
1078 fcx: @mut FnCtxt, expr: @ast::expr,
1079 expected: Option<ty::t>) {
1080 check_expr_with_unifier(fcx, expr, expected, || ())
1083 pub fn check_expr(fcx: @mut FnCtxt, expr: @ast::expr) {
1084 check_expr_with_unifier(fcx, expr, None, || ())
1087 // determine the `self` type, using fresh variables for all variables
1088 // declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
1089 // would return ($0, $1) where $0 and $1 are freshly instantiated type
1091 pub fn impl_self_ty(vcx: &VtableContext,
1092 location_info: &LocationInfo, // (potential) receiver for
1095 -> ty_param_substs_and_ty {
1096 let tcx = vcx.tcx();
1098 let (n_tps, region_param, raw_ty) = {
1099 let ity = ty::lookup_item_type(tcx, did);
1100 (ity.generics.type_param_defs.len(), ity.generics.region_param, ity.ty)
1103 let regions = ty::NonerasedRegions(if region_param.is_some() {
1104 opt_vec::with(vcx.infcx.next_region_var(
1105 infer::BoundRegionInTypeOrImpl(location_info.span)))
1109 let tps = vcx.infcx.next_ty_vars(n_tps);
1111 let substs = substs {regions: regions, self_ty: None, tps: tps};
1112 let substd_ty = ty::subst(tcx, &substs, raw_ty);
1114 ty_param_substs_and_ty { substs: substs, ty: substd_ty }
1117 // Only for fields! Returns <none> for methods>
1118 // Indifferent to privacy flags
1119 pub fn lookup_field_ty(tcx: ty::ctxt,
1120 class_id: ast::def_id,
1121 items: &[ty::field_ty],
1122 fieldname: ast::ident,
1123 substs: &ty::substs) -> Option<ty::t> {
1125 let o_field = items.iter().find_(|f| f.ident == fieldname);
1126 do o_field.map() |f| {
1127 ty::lookup_field_type(tcx, class_id, f.id, substs)
1131 // Controls whether the arguments are automatically referenced. This is useful
1132 // for overloaded binary and unary operators.
1133 pub enum DerefArgs {
1138 pub fn break_here() {
1139 debug!("break here!");
1143 /// If an expression has any sub-expressions that result in a type error,
1144 /// inspecting that expression's type with `ty::type_is_error` will return
1145 /// true. Likewise, if an expression is known to diverge, inspecting its
1146 /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
1147 /// strict, _|_ can appear in the type of an expression that does not,
1148 /// itself, diverge: for example, fn() -> _|_.)
1149 /// Note that inspecting a type's structure *directly* may expose the fact
1150 /// that there are actually multiple representations for both `ty_err` and
1151 /// `ty_bot`, so avoid that when err and bot need to be handled differently.
1152 pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
1154 expected: Option<ty::t>,
1156 debug!(">> typechecking");
1158 fn check_method_argument_types(
1161 method_fn_ty: ty::t,
1162 callee_expr: @ast::expr,
1163 args: &[@ast::expr],
1164 sugar: ast::CallSugar,
1165 deref_args: DerefArgs) -> ty::t
1167 if ty::type_is_error(method_fn_ty) {
1168 let err_inputs = err_args(args.len());
1169 check_argument_types(fcx, sp, err_inputs, callee_expr,
1170 args, sugar, deref_args);
1173 match ty::get(method_fn_ty).sty {
1174 ty::ty_bare_fn(ref fty) => {
1175 check_argument_types(fcx, sp, fty.sig.inputs, callee_expr,
1176 args, sugar, deref_args);
1180 fcx.tcx().sess.span_bug(
1182 fmt!("Method without bare fn type"));
1188 fn check_argument_types(
1191 fn_inputs: &[ty::t],
1192 callee_expr: @ast::expr,
1193 args: &[@ast::expr],
1194 sugar: ast::CallSugar,
1195 deref_args: DerefArgs)
1199 * Generic function that factors out common logic from
1200 * function calls, method calls and overloaded operators.
1203 let tcx = fcx.ccx.tcx;
1205 // Grab the argument types, supplying fresh type variables
1206 // if the wrong number of arguments were supplied
1207 let supplied_arg_count = args.len();
1208 let expected_arg_count = fn_inputs.len();
1209 let formal_tys = if expected_arg_count == supplied_arg_count {
1210 fn_inputs.map(|a| *a)
1212 let suffix = match sugar {
1214 ast::DoSugar => " (including the closure passed by \
1216 ast::ForSugar => " (including the closure passed by \
1219 let msg = fmt!("this function takes %u parameter%s but \
1220 %u parameter%s supplied%s",
1222 if expected_arg_count == 1 {""}
1225 if supplied_arg_count == 1 {" was"}
1229 tcx.sess.span_err(sp, msg);
1231 vec::from_elem(supplied_arg_count, ty::mk_err())
1234 debug!("check_argument_types: formal_tys=%?",
1235 formal_tys.map(|t| fcx.infcx().ty_to_str(*t)));
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 let xs = [false, true];
1244 for check_blocks in xs.iter() {
1245 let check_blocks = *check_blocks;
1246 debug!("check_blocks=%b", check_blocks);
1248 // More awful hacks: before we check the blocks, try to do
1249 // an "opportunistic" vtable resolution of any trait
1250 // bounds on the call.
1252 vtable::early_resolve_expr(callee_expr, fcx, true);
1255 for (i, arg) in args.iter().enumerate() {
1256 let is_block = match arg.node {
1257 ast::expr_fn_block(*) |
1258 ast::expr_do_body(*) => true,
1262 if is_block == check_blocks {
1263 debug!("checking the argument");
1264 let mut formal_ty = formal_tys[i];
1268 match ty::get(formal_ty).sty {
1269 ty::ty_rptr(_, mt) => formal_ty = mt.ty,
1272 fcx.ccx.tcx.sess.span_bug(arg.span, "no ref");
1279 check_expr_coercable_to_type(
1280 fcx, *arg, formal_ty);
1287 fn err_args(len: uint) -> ~[ty::t] {
1288 vec::from_fn(len, |_| ty::mk_err())
1291 // A generic function for checking assignment expressions
1292 fn check_assignment(fcx: @mut FnCtxt,
1296 check_expr(fcx, lhs);
1297 let lhs_type = fcx.expr_ty(lhs);
1298 check_expr_has_type(fcx, rhs, lhs_type);
1299 fcx.write_ty(id, ty::mk_nil());
1300 // The callee checks for bot / err, we don't need to
1303 fn write_call(fcx: @mut FnCtxt,
1304 call_expr: @ast::expr,
1306 sugar: ast::CallSugar) {
1307 let ret_ty = match sugar {
1309 match ty::get(output).sty {
1311 _ => fcx.type_error_message(call_expr.span, |actual| {
1312 fmt!("expected `for` closure to return `bool`, \
1313 but found `%s`", actual) },
1320 fcx.write_ty(call_expr.id, ret_ty);
1323 // A generic function for doing all of the checking for call expressions
1324 fn check_call(fcx: @mut FnCtxt,
1325 callee_id: ast::NodeId,
1326 call_expr: @ast::expr,
1328 args: &[@ast::expr],
1329 sugar: ast::CallSugar) {
1330 // Index expressions need to be handled separately, to inform them
1331 // that they appear in call position.
1334 // Store the type of `f` as the type of the callee
1335 let fn_ty = fcx.expr_ty(f);
1337 // FIXME(#6273) should write callee type AFTER regions have
1338 // been subst'd. However, it is awkward to deal with this
1339 // now. Best thing would I think be to just have a separate
1340 // "callee table" that contains the FnSig and not a general
1342 fcx.write_ty(callee_id, fn_ty);
1344 // Extract the function signature from `in_fty`.
1345 let fn_sty = structure_of(fcx, f.span, fn_ty);
1347 // This is the "default" function signature, used in case of error.
1348 // In that case, we check each argument against "error" in order to
1349 // set up all the node type bindings.
1350 let error_fn_sig = FnSig {
1351 bound_lifetime_names: opt_vec::Empty,
1352 inputs: err_args(args.len()),
1353 output: ty::mk_err()
1356 let fn_sig = match *fn_sty {
1357 ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) |
1358 ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => sig,
1360 fcx.type_error_message(call_expr.span, |actual| {
1361 fmt!("expected function but \
1362 found `%s`", actual) }, fn_ty, None);
1367 // Replace any bound regions that appear in the function
1368 // signature with region variables
1369 let (_, _, fn_sig) =
1370 replace_bound_regions_in_fn_sig(fcx.tcx(),
1376 infer::BoundRegionInFnCall(call_expr.span, br)));
1378 // Call the generic checker.
1379 check_argument_types(fcx, call_expr.span, fn_sig.inputs, f,
1380 args, sugar, DontDerefArgs);
1382 write_call(fcx, call_expr, fn_sig.output, sugar);
1385 // Checks a method call.
1386 fn check_method_call(fcx: @mut FnCtxt,
1387 callee_id: ast::NodeId,
1390 method_name: ast::ident,
1391 args: &[@ast::expr],
1393 sugar: ast::CallSugar) {
1394 check_expr(fcx, rcvr);
1396 // no need to check for bot/err -- callee does that
1397 let expr_t = structurally_resolved_type(fcx,
1401 let tps = tps.map(|ast_ty| fcx.to_ty(ast_ty));
1402 match method::lookup(fcx,
1410 CheckTraitsAndInherentMethods,
1411 AutoderefReceiver) {
1412 Some(ref entry) => {
1413 let method_map = fcx.inh.method_map;
1414 method_map.insert(expr.id, (*entry));
1417 debug!("(checking method call) failing expr is %d", expr.id);
1419 fcx.type_error_message(expr.span,
1421 fmt!("type `%s` does not implement any method in scope \
1424 fcx.ccx.tcx.sess.str_of(method_name))
1429 // Add error type for the result
1430 fcx.write_error(expr.id);
1431 fcx.write_error(callee_id);
1435 // Call the generic checker.
1436 let fn_ty = fcx.node_ty(callee_id);
1437 let ret_ty = check_method_argument_types(fcx, expr.span,
1438 fn_ty, expr, args, sugar,
1441 write_call(fcx, expr, ret_ty, sugar);
1444 // A generic function for checking the then and else in an if
1446 fn check_then_else(fcx: @mut FnCtxt,
1447 cond_expr: @ast::expr,
1448 then_blk: &ast::Block,
1449 opt_else_expr: Option<@ast::expr>,
1452 expected: Option<ty::t>) {
1453 check_expr_has_type(fcx, cond_expr, ty::mk_bool());
1455 let branches_ty = match opt_else_expr {
1456 Some(else_expr) => {
1457 check_block_with_expected(fcx, then_blk, expected);
1458 let then_ty = fcx.node_ty(then_blk.id);
1459 check_expr_with_opt_hint(fcx, else_expr, expected);
1460 let else_ty = fcx.expr_ty(else_expr);
1461 infer::common_supertype(fcx.infcx(),
1462 infer::IfExpression(sp),
1468 check_block_no_value(fcx, then_blk);
1473 let cond_ty = fcx.expr_ty(cond_expr);
1474 let if_ty = if ty::type_is_error(cond_ty) {
1476 } else if ty::type_is_bot(cond_ty) {
1482 fcx.write_ty(id, if_ty);
1485 fn lookup_op_method(fcx: @mut FnCtxt,
1486 callee_id: ast::NodeId,
1488 self_ex: @ast::expr,
1491 args: ~[@ast::expr],
1492 deref_args: DerefArgs,
1493 autoderef_receiver: AutoderefReceiverFlag,
1494 unbound_method: &fn(),
1495 _expected_result: Option<ty::t>
1498 match method::lookup(fcx, op_ex, self_ex,
1499 callee_id, opname, self_t, [],
1500 deref_args, CheckTraitsOnly, autoderef_receiver) {
1501 Some(ref origin) => {
1502 let method_ty = fcx.node_ty(callee_id);
1503 let method_map = fcx.inh.method_map;
1504 method_map.insert(op_ex.id, *origin);
1505 check_method_argument_types(fcx, op_ex.span,
1506 method_ty, op_ex, args,
1507 ast::NoSugar, deref_args)
1511 // Check the args anyway
1512 // so we get all the error messages
1513 let expected_ty = ty::mk_err();
1514 check_method_argument_types(fcx, op_ex.span,
1515 expected_ty, op_ex, args,
1516 ast::NoSugar, deref_args);
1522 // could be either a expr_binop or an expr_assign_binop
1523 fn check_binop(fcx: @mut FnCtxt,
1524 callee_id: ast::NodeId,
1529 // Used only in the error case
1530 expected_result: Option<ty::t>,
1531 allow_overloaded_operators: AllowOverloadedOperatorsFlag
1533 let tcx = fcx.ccx.tcx;
1535 check_expr(fcx, lhs);
1536 // Callee does bot / err checking
1537 let lhs_t = structurally_resolved_type(fcx, lhs.span,
1540 if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) {
1541 // Shift is a special case: rhs can be any integral type
1542 check_expr(fcx, rhs);
1543 let rhs_t = fcx.expr_ty(rhs);
1544 require_integral(fcx, rhs.span, rhs_t);
1545 fcx.write_ty(expr.id, lhs_t);
1549 if ty::is_binopable(tcx, lhs_t, op) {
1550 let tvar = fcx.infcx().next_ty_var();
1551 demand::suptype(fcx, expr.span, tvar, lhs_t);
1552 check_expr_has_type(fcx, rhs, tvar);
1554 let result_t = match op {
1555 ast::eq | ast::ne | ast::lt | ast::le | ast::ge |
1564 fcx.write_ty(expr.id, result_t);
1568 if op == ast::or || op == ast::and {
1569 // This is an error; one of the operands must have the wrong
1571 fcx.write_error(expr.id);
1572 fcx.write_error(rhs.id);
1573 fcx.type_error_message(expr.span, |actual| {
1574 fmt!("binary operation %s cannot be applied \
1576 ast_util::binop_to_str(op), actual)},
1581 // Check for overloaded operators if allowed.
1583 if allow_overloaded_operators == AllowOverloadedOperators {
1584 result_t = check_user_binop(fcx,
1593 fcx.type_error_message(expr.span,
1595 fmt!("binary operation %s cannot be \
1596 applied to type `%s`",
1597 ast_util::binop_to_str(op),
1602 result_t = ty::mk_err();
1605 fcx.write_ty(expr.id, result_t);
1606 if ty::type_is_error(result_t) {
1607 fcx.write_ty(rhs.id, result_t);
1611 fn check_user_binop(fcx: @mut FnCtxt,
1612 callee_id: ast::NodeId,
1614 lhs_expr: @ast::expr,
1615 lhs_resolved_t: ty::t,
1618 expected_result: Option<ty::t>) -> ty::t {
1619 let tcx = fcx.ccx.tcx;
1620 match ast_util::binop_to_method_name(op) {
1622 let if_op_unbound = || {
1623 fcx.type_error_message(ex.span, |actual| {
1624 fmt!("binary operation %s cannot be applied \
1626 ast_util::binop_to_str(op), actual)},
1627 lhs_resolved_t, None)
1629 return lookup_op_method(fcx, callee_id, ex, lhs_expr, lhs_resolved_t,
1630 fcx.tcx().sess.ident_of(*name),
1631 ~[rhs], DoDerefArgs, DontAutoderefReceiver, if_op_unbound,
1636 check_expr(fcx, rhs);
1638 // If the or operator is used it might be that the user forgot to
1639 // supply the do keyword. Let's be more helpful in that situation.
1641 match ty::get(lhs_resolved_t).sty {
1642 ty::ty_bare_fn(_) | ty::ty_closure(_) => {
1644 ex.span, "did you forget the `do` keyword for the call?");
1653 fn check_user_unop(fcx: @mut FnCtxt,
1654 callee_id: ast::NodeId,
1658 rhs_expr: @ast::expr,
1660 expected_t: Option<ty::t>)
1663 fcx, callee_id, ex, rhs_expr, rhs_t,
1664 fcx.tcx().sess.ident_of(mname), ~[],
1665 DoDerefArgs, DontAutoderefReceiver,
1667 fcx.type_error_message(ex.span, |actual| {
1668 fmt!("cannot apply unary operator `%s` to type `%s`",
1674 // Resolves `expected` by a single level if it is a variable and passes it
1675 // through the `unpack` function. It there is no expected type or
1676 // resolution is not possible (e.g., no constraints yet present), just
1678 fn unpack_expected<O>(fcx: @mut FnCtxt,
1679 expected: Option<ty::t>,
1680 unpack: &fn(&ty::sty) -> Option<O>)
1684 match resolve_type(fcx.infcx(), t, force_tvar) {
1685 Ok(t) => unpack(&ty::get(t).sty),
1693 fn check_expr_fn(fcx: @mut FnCtxt,
1695 ast_sigil_opt: Option<ast::Sigil>,
1696 decl: &ast::fn_decl,
1699 expected: Option<ty::t>) {
1700 let tcx = fcx.ccx.tcx;
1702 // Find the expected input/output types (if any). Careful to
1703 // avoid capture of bound regions in the expected type. See
1704 // def'n of br_cap_avoid() for a more lengthy explanation of
1705 // what's going on here.
1706 // Also try to pick up inferred purity and sigil, defaulting
1707 // to impure and block. Note that we only will use those for
1708 // block syntax lambdas; that is, lambdas without explicit
1710 let expected_sty = unpack_expected(fcx,
1712 |x| Some((*x).clone()));
1713 let error_happened = false;
1718 expected_bounds) = {
1719 match expected_sty {
1720 Some(ty::ty_closure(ref cenv)) => {
1723 replace_bound_regions_in_fn_sig(
1724 tcx, @Nil, None, &cenv.sig,
1725 |br| ty::re_bound(ty::br_cap_avoid(id, @br)));
1726 (Some(sig), cenv.purity, cenv.sigil,
1727 cenv.onceness, cenv.bounds)
1730 // Not an error! Means we're inferring the closure type
1731 (None, ast::impure_fn, ast::BorrowedSigil,
1732 ast::Many, ty::EmptyBuiltinBounds())
1737 // If the proto is specified, use that, otherwise select a
1738 // proto based on inference.
1739 let (sigil, purity) = match ast_sigil_opt {
1740 Some(p) => (p, ast::impure_fn),
1741 None => (expected_sigil, expected_purity)
1744 // construct the function type
1745 let fn_ty = astconv::ty_of_closure(fcx,
1758 let fty = if error_happened {
1760 bound_lifetime_names: opt_vec::Empty,
1761 inputs: fn_ty.sig.inputs.map(|_| ty::mk_err()),
1762 output: ty::mk_err()
1766 let fn_ty_copy = fn_ty.clone();
1767 fty_sig = fn_ty.sig.clone();
1768 ty::mk_closure(tcx, fn_ty_copy)
1771 debug!("check_expr_fn_with_unifier fty=%s",
1772 fcx.infcx().ty_to_str(fty));
1774 fcx.write_ty(expr.id, fty);
1776 let (inherited_purity, id) =
1777 ty::determine_inherited_purity((fcx.ps.purity, fcx.ps.def),
1781 check_fn(fcx.ccx, None, inherited_purity, &fty_sig,
1782 decl, id, body, fn_kind, fcx.in_scope_regions, fcx.inh);
1786 // Check field access expressions
1787 fn check_field(fcx: @mut FnCtxt,
1792 let tcx = fcx.ccx.tcx;
1793 let bot = check_expr(fcx, base);
1794 let expr_t = structurally_resolved_type(fcx, expr.span,
1796 let (base_t, derefs) = do_autoderef(fcx, expr.span, expr_t);
1798 match *structure_of(fcx, expr.span, base_t) {
1799 ty::ty_struct(base_id, ref substs) => {
1800 // This is just for fields -- the same code handles
1801 // methods in both classes and traits
1803 // (1) verify that the class id actually has a field called
1805 debug!("class named %s", ppaux::ty_to_str(tcx, base_t));
1806 let cls_items = ty::lookup_struct_fields(tcx, base_id);
1807 match lookup_field_ty(tcx, base_id, cls_items,
1808 field, &(*substs)) {
1810 // (2) look up what field's type is, and return it
1811 fcx.write_ty(expr.id, field_ty);
1812 fcx.write_autoderef_adjustment(base.id, derefs);
1821 let tps : ~[ty::t] = tys.iter().transform(|ty| fcx.to_ty(ty)).collect();
1822 match method::lookup(fcx,
1830 CheckTraitsAndInherentMethods,
1831 AutoderefReceiver) {
1833 fcx.type_error_message(
1836 fmt!("attempted to take value of method `%s` on type `%s` \
1837 (try writing an anonymous function)",
1838 tcx.sess.str_of(field), actual)
1844 fcx.type_error_message(
1847 fmt!("attempted access of field `%s` on type `%s`, \
1848 but no field with that name was found",
1849 tcx.sess.str_of(field), actual)
1855 fcx.write_error(expr.id);
1858 fn check_struct_or_variant_fields(fcx: @mut FnCtxt,
1860 class_id: ast::def_id,
1861 node_id: ast::NodeId,
1862 substitutions: ty::substs,
1863 field_types: &[ty::field_ty],
1864 ast_fields: &[ast::Field],
1865 check_completeness: bool) {
1866 let tcx = fcx.ccx.tcx;
1868 let mut class_field_map = HashMap::new();
1869 let mut fields_found = 0;
1870 for field in field_types.iter() {
1871 class_field_map.insert(field.ident, (field.id, false));
1874 let mut error_happened = false;
1876 // Typecheck each field.
1877 for field in ast_fields.iter() {
1878 let mut expected_field_type = ty::mk_err();
1880 let pair = class_field_map.find(&field.ident).
1881 map_consume(|x| *x);
1886 fmt!("structure has no field named `%s`",
1887 tcx.sess.str_of(field.ident)));
1888 error_happened = true;
1890 Some((_, true)) => {
1893 fmt!("field `%s` specified more than once",
1894 tcx.sess.str_of(field.ident)));
1895 error_happened = true;
1897 Some((field_id, false)) => {
1898 expected_field_type =
1899 ty::lookup_field_type(
1900 tcx, class_id, field_id, &substitutions);
1901 class_field_map.insert(
1902 field.ident, (field_id, true));
1906 // Make sure to give a type to the field even if there's
1907 // an error, so we can continue typechecking
1908 check_expr_coercable_to_type(
1911 expected_field_type);
1915 fcx.write_error(node_id);
1918 if check_completeness && !error_happened {
1919 // Make sure the programmer specified all the fields.
1920 assert!(fields_found <= field_types.len());
1921 if fields_found < field_types.len() {
1922 let mut missing_fields = ~[];
1923 for class_field in field_types.iter() {
1924 let name = class_field.ident;
1925 let (_, seen) = *class_field_map.get(&name);
1927 missing_fields.push(
1928 ~"`" + tcx.sess.str_of(name) + "`");
1932 tcx.sess.span_err(span,
1933 fmt!("missing field%s: %s",
1934 if missing_fields.len() == 1 {
1939 missing_fields.connect(", ")));
1943 if !error_happened {
1944 fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx,
1945 class_id, substitutions));
1949 fn check_struct_constructor(fcx: @mut FnCtxt,
1951 span: codemap::span,
1952 class_id: ast::def_id,
1953 fields: &[ast::Field],
1954 base_expr: Option<@ast::expr>) {
1955 let tcx = fcx.ccx.tcx;
1957 // Look up the number of type parameters and the raw type, and
1958 // determine whether the class is region-parameterized.
1959 let type_parameter_count;
1960 let region_parameterized;
1962 if class_id.crate == ast::LOCAL_CRATE {
1963 region_parameterized =
1964 tcx.region_paramd_items.find(&class_id.node).
1965 map_consume(|x| *x);
1966 match tcx.items.find(&class_id.node) {
1967 Some(&ast_map::node_item(@ast::item {
1968 node: ast::item_struct(_, ref generics),
1972 type_parameter_count = generics.ty_params.len();
1975 bound_self_region(region_parameterized);
1977 raw_type = ty::mk_struct(tcx, class_id, substs {
1978 regions: ty::NonerasedRegions(self_region),
1980 tps: ty::ty_params_to_tys(
1986 tcx.sess.span_bug(span,
1987 "resolve didn't map this to a class");
1991 let item_type = ty::lookup_item_type(tcx, class_id);
1992 type_parameter_count = item_type.generics.type_param_defs.len();
1993 region_parameterized = item_type.generics.region_param;
1994 raw_type = item_type.ty;
1997 // Generate the struct type.
1999 fcx.region_var_if_parameterized(region_parameterized, span);
2000 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2001 let substitutions = substs {
2002 regions: ty::NonerasedRegions(regions),
2004 tps: type_parameters
2007 let mut struct_type = ty::subst(tcx, &substitutions, raw_type);
2009 // Look up and check the fields.
2010 let class_fields = ty::lookup_struct_fields(tcx, class_id);
2011 check_struct_or_variant_fields(fcx,
2018 base_expr.is_none());
2019 if ty::type_is_error(fcx.node_ty(id)) {
2020 struct_type = ty::mk_err();
2023 // Check the base expression if necessary.
2026 Some(base_expr) => {
2027 check_expr_has_type(fcx, base_expr, struct_type);
2028 if ty::type_is_bot(fcx.node_ty(base_expr.id)) {
2029 struct_type = ty::mk_bot();
2034 // Write in the resulting type.
2035 fcx.write_ty(id, struct_type);
2038 fn check_struct_enum_variant(fcx: @mut FnCtxt,
2040 span: codemap::span,
2041 enum_id: ast::def_id,
2042 variant_id: ast::def_id,
2043 fields: &[ast::Field]) {
2044 let tcx = fcx.ccx.tcx;
2046 // Look up the number of type parameters and the raw type, and
2047 // determine whether the enum is region-parameterized.
2048 let type_parameter_count;
2049 let region_parameterized;
2051 if enum_id.crate == ast::LOCAL_CRATE {
2052 region_parameterized =
2053 tcx.region_paramd_items.find(&enum_id.node).map_consume(|x| *x);
2054 match tcx.items.find(&enum_id.node) {
2055 Some(&ast_map::node_item(@ast::item {
2056 node: ast::item_enum(_, ref generics),
2060 type_parameter_count = generics.ty_params.len();
2062 let regions = bound_self_region(region_parameterized);
2064 raw_type = ty::mk_enum(tcx, enum_id, substs {
2065 regions: ty::NonerasedRegions(regions),
2067 tps: ty::ty_params_to_tys(
2073 tcx.sess.span_bug(span,
2074 "resolve didn't map this to an enum");
2078 let item_type = ty::lookup_item_type(tcx, enum_id);
2079 type_parameter_count = item_type.generics.type_param_defs.len();
2080 region_parameterized = item_type.generics.region_param;
2081 raw_type = item_type.ty;
2084 // Generate the enum type.
2086 fcx.region_var_if_parameterized(region_parameterized, span);
2087 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2088 let substitutions = substs {
2089 regions: ty::NonerasedRegions(regions),
2091 tps: type_parameters
2094 let enum_type = ty::subst(tcx, &substitutions, raw_type);
2096 // Look up and check the enum variant fields.
2097 let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2098 check_struct_or_variant_fields(fcx,
2106 fcx.write_ty(id, enum_type);
2109 let tcx = fcx.ccx.tcx;
2112 ast::expr_vstore(ev, vst) => {
2113 let typ = match ev.node {
2114 ast::expr_lit(@codemap::spanned { node: ast::lit_str(_), _ }) => {
2115 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2116 ty::mk_estr(tcx, tt)
2118 ast::expr_vec(ref args, mutbl) => {
2119 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2121 let mut any_error = false;
2122 let mut any_bot = false;
2124 ast::expr_vstore_mut_box | ast::expr_vstore_mut_slice => {
2125 mutability = ast::m_mutbl
2127 _ => mutability = mutbl
2129 let t: ty::t = fcx.infcx().next_ty_var();
2130 for e in args.iter() {
2131 check_expr_has_type(fcx, *e, t);
2132 let arg_t = fcx.expr_ty(*e);
2133 if ty::type_is_error(arg_t) {
2136 else if ty::type_is_bot(arg_t) {
2147 ty::mk_evec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2150 ast::expr_repeat(element, count_expr, mutbl) => {
2151 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2152 let _ = ty::eval_repeat_count(fcx, count_expr);
2153 let tt = ast_expr_vstore_to_vstore(fcx, ev, vst);
2154 let mutability = match vst {
2155 ast::expr_vstore_mut_box | ast::expr_vstore_mut_slice => {
2160 let t: ty::t = fcx.infcx().next_ty_var();
2161 check_expr_has_type(fcx, element, t);
2162 let arg_t = fcx.expr_ty(element);
2163 if ty::type_is_error(arg_t) {
2165 } else if ty::type_is_bot(arg_t) {
2168 ty::mk_evec(tcx, ty::mt {ty: t, mutbl: mutability}, tt)
2172 tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence")
2174 fcx.write_ty(ev.id, typ);
2175 fcx.write_ty(id, typ);
2178 ast::expr_lit(lit) => {
2179 let typ = check_lit(fcx, lit);
2180 fcx.write_ty(id, typ);
2182 ast::expr_binary(callee_id, op, lhs, rhs) => {
2190 AllowOverloadedOperators);
2192 let lhs_ty = fcx.expr_ty(lhs);
2193 let rhs_ty = fcx.expr_ty(rhs);
2194 if ty::type_is_error(lhs_ty) ||
2195 ty::type_is_error(rhs_ty) {
2196 fcx.write_error(id);
2198 else if ty::type_is_bot(lhs_ty) ||
2199 (ty::type_is_bot(rhs_ty) && !ast_util::lazy_binop(op)) {
2203 ast::expr_assign_op(callee_id, op, lhs, rhs) => {
2211 DontAllowOverloadedOperators);
2213 let lhs_t = fcx.expr_ty(lhs);
2214 let result_t = fcx.expr_ty(expr);
2215 demand::suptype(fcx, expr.span, result_t, lhs_t);
2217 // Overwrite result of check_binop...this preserves existing behavior
2218 // but seems quite dubious with regard to user-defined methods
2219 // and so forth. - Niko
2220 if !ty::type_is_error(result_t)
2221 && !ty::type_is_bot(result_t) {
2222 fcx.write_nil(expr.id);
2225 ast::expr_unary(callee_id, unop, oprnd) => {
2226 let exp_inner = do unpack_expected(fcx, expected) |sty| {
2228 ast::box(_) | ast::uniq => match *sty {
2229 ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => Some(mt.ty),
2232 ast::not | ast::neg => expected,
2236 check_expr_with_opt_hint(fcx, oprnd, exp_inner);
2237 let mut oprnd_t = fcx.expr_ty(oprnd);
2238 if !ty::type_is_error(oprnd_t) &&
2239 !ty::type_is_bot(oprnd_t) {
2241 ast::box(mutbl) => {
2242 oprnd_t = ty::mk_box(tcx,
2243 ty::mt {ty: oprnd_t, mutbl: mutbl});
2246 oprnd_t = ty::mk_uniq(tcx,
2247 ty::mt {ty: oprnd_t,
2248 mutbl: ast::m_imm});
2251 let sty = structure_of(fcx, expr.span, oprnd_t);
2252 let operand_ty = ty::deref_sty(tcx, sty, true);
2262 "can only dereference enums with a single variant which \
2263 has a single argument");
2265 ty::ty_struct(*) => {
2268 "can only dereference structs with one anonymous field");
2271 fcx.type_error_message(expr.span,
2273 fmt!("type %s cannot be dereferenced", actual)
2281 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2283 if !(ty::type_is_integral(oprnd_t) ||
2284 ty::get(oprnd_t).sty == ty::ty_bool) {
2285 oprnd_t = check_user_unop(fcx, callee_id,
2286 "!", "not", expr, oprnd, oprnd_t,
2291 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2293 if !(ty::type_is_integral(oprnd_t) ||
2294 ty::type_is_fp(oprnd_t)) {
2295 oprnd_t = check_user_unop(fcx, callee_id,
2296 "-", "neg", expr, oprnd, oprnd_t, expected);
2301 fcx.write_ty(id, oprnd_t);
2303 ast::expr_addr_of(mutbl, oprnd) => {
2304 let hint = unpack_expected(
2306 |sty| match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty),
2308 check_expr_with_opt_hint(fcx, oprnd, hint);
2310 // Note: at this point, we cannot say what the best lifetime
2311 // is to use for resulting pointer. We want to use the
2312 // shortest lifetime possible so as to avoid spurious borrowck
2313 // errors. Moreover, the longest lifetime will depend on the
2314 // precise details of the value whose address is being taken
2315 // (and how long it is valid), which we don't know yet until type
2316 // inference is complete.
2318 // Therefore, here we simply generate a region variable. The
2319 // region inferencer will then select the ultimate value.
2320 // Finally, borrowck is charged with guaranteeing that the
2321 // value whose address was taken can actually be made to live
2322 // as long as it needs to live.
2323 let region = fcx.infcx().next_region_var(
2324 infer::AddrOfRegion(expr.span));
2326 let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
2327 let oprnd_t = if ty::type_is_error(tm.ty) {
2329 } else if ty::type_is_bot(tm.ty) {
2333 ty::mk_rptr(tcx, region, tm)
2335 fcx.write_ty(id, oprnd_t);
2337 ast::expr_path(ref pth) => {
2338 let defn = lookup_def(fcx, pth.span, id);
2340 let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2341 instantiate_path(fcx, pth, tpt, expr.span, expr.id);
2344 let definition = lookup_def(fcx, expr.span, id);
2345 let ty_param_bounds_and_ty =
2346 ty_param_bounds_and_ty_for_def(fcx, expr.span, definition);
2347 fcx.write_ty(id, ty_param_bounds_and_ty.ty);
2349 ast::expr_inline_asm(ref ia) => {
2350 for &(_, input) in ia.inputs.iter() {
2351 check_expr(fcx, input);
2353 for &(_, out) in ia.outputs.iter() {
2354 check_expr(fcx, out);
2358 ast::expr_mac(_) => tcx.sess.bug("unexpanded macro"),
2359 ast::expr_break(_) => { fcx.write_bot(id); }
2360 ast::expr_again(_) => { fcx.write_bot(id); }
2361 ast::expr_ret(expr_opt) => {
2362 let ret_ty = fcx.ret_ty;
2364 None => match fcx.mk_eqty(false, infer::Misc(expr.span),
2365 ret_ty, ty::mk_nil()) {
2366 result::Ok(_) => { /* fall through */ }
2370 "`return;` in function returning non-nil");
2374 check_expr_has_type(fcx, e, ret_ty);
2379 ast::expr_log(lv, e) => {
2380 check_expr_has_type(fcx, lv,
2381 ty::mk_mach_uint(ast::ty_u32));
2383 // Note: this does not always execute, so do not propagate bot:
2385 if ty::type_is_error(fcx.expr_ty(e)) {
2386 fcx.write_error(id);
2392 ast::expr_paren(a) => {
2393 check_expr_with_opt_hint(fcx, a, expected);
2394 fcx.write_ty(id, fcx.expr_ty(a));
2396 ast::expr_assign(lhs, rhs) => {
2397 check_assignment(fcx, lhs, rhs, id);
2398 let lhs_ty = fcx.expr_ty(lhs);
2399 let rhs_ty = fcx.expr_ty(rhs);
2400 if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
2401 fcx.write_error(id);
2403 else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
2410 ast::expr_if(cond, ref then_blk, opt_else_expr) => {
2411 check_then_else(fcx, cond, then_blk, opt_else_expr,
2412 id, expr.span, expected);
2414 ast::expr_while(cond, ref body) => {
2415 check_expr_has_type(fcx, cond, ty::mk_bool());
2416 check_block_no_value(fcx, body);
2417 let cond_ty = fcx.expr_ty(cond);
2418 let body_ty = fcx.node_ty(body.id);
2419 if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) {
2420 fcx.write_error(id);
2422 else if ty::type_is_bot(cond_ty) {
2429 ast::expr_for_loop(*) =>
2430 fail!("non-desugared expr_for_loop"),
2431 ast::expr_loop(ref body, _) => {
2432 check_block_no_value(fcx, (body));
2433 if !may_break(tcx, expr.id, body) {
2440 ast::expr_match(discrim, ref arms) => {
2441 _match::check_match(fcx, expr, discrim, *arms);
2443 ast::expr_fn_block(ref decl, ref body) => {
2444 check_expr_fn(fcx, expr, None,
2445 decl, body, Vanilla, expected);
2447 ast::expr_do_body(b) => {
2448 let expected_sty = unpack_expected(fcx,
2450 |x| Some((*x).clone()));
2451 let inner_ty = match expected_sty {
2452 Some(ty::ty_closure(_)) => expected.unwrap(),
2453 _ => match expected {
2454 Some(expected_t) => {
2455 fcx.type_error_message(expr.span, |actual| {
2456 fmt!("last argument in `do` call \
2457 has non-closure type: %s",
2459 }, expected_t, None);
2460 let err_ty = ty::mk_err();
2461 fcx.write_ty(id, err_ty);
2465 fcx.tcx().sess.impossible_case(
2467 "do body must have expected type")
2472 ast::expr_fn_block(ref decl, ref body) => {
2473 check_expr_fn(fcx, b, None,
2474 decl, body, DoBlock, Some(inner_ty));
2475 demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
2478 _ => fail!("expected fn ty")
2480 fcx.write_ty(expr.id, fcx.node_ty(b.id));
2482 ast::expr_block(ref b) => {
2483 check_block_with_expected(fcx, b, expected);
2484 fcx.write_ty(id, fcx.node_ty(b.id));
2486 ast::expr_call(f, ref args, sugar) => {
2487 check_call(fcx, expr.id, expr, f, *args, sugar);
2488 let f_ty = fcx.expr_ty(f);
2489 let (args_bot, args_err) = args.iter().fold((false, false),
2490 |(rest_bot, rest_err), a| {
2491 // is this not working?
2492 let a_ty = fcx.expr_ty(*a);
2493 (rest_bot || ty::type_is_bot(a_ty),
2494 rest_err || ty::type_is_error(a_ty))});
2495 if ty::type_is_error(f_ty) || args_err {
2496 fcx.write_error(id);
2498 else if ty::type_is_bot(f_ty) || args_bot {
2502 ast::expr_method_call(callee_id, rcvr, ident, ref tps, ref args, sugar) => {
2503 check_method_call(fcx, callee_id, expr, rcvr, ident, *args, *tps, sugar);
2504 let f_ty = fcx.expr_ty(rcvr);
2505 let arg_tys = args.map(|a| fcx.expr_ty(*a));
2506 let (args_bot, args_err) = arg_tys.iter().fold((false, false),
2507 |(rest_bot, rest_err), a| {
2508 (rest_bot || ty::type_is_bot(*a),
2509 rest_err || ty::type_is_error(*a))});
2510 if ty::type_is_error(f_ty) || args_err {
2511 fcx.write_error(id);
2513 else if ty::type_is_bot(f_ty) || args_bot {
2517 ast::expr_cast(e, ref t) => {
2519 let t_1 = fcx.to_ty(t);
2520 let t_e = fcx.expr_ty(e);
2522 debug!("t_1=%s", fcx.infcx().ty_to_str(t_1));
2523 debug!("t_e=%s", fcx.infcx().ty_to_str(t_e));
2525 if ty::type_is_error(t_e) {
2526 fcx.write_error(id);
2528 else if ty::type_is_bot(t_e) {
2532 match ty::get(t_1).sty {
2533 // This will be looked up later on
2534 ty::ty_trait(*) => (),
2537 if ty::type_is_nil(t_e) {
2538 fcx.type_error_message(expr.span, |actual| {
2539 fmt!("cast from nil: `%s` as `%s`", actual,
2540 fcx.infcx().ty_to_str(t_1))
2542 } else if ty::type_is_nil(t_1) {
2543 fcx.type_error_message(expr.span, |actual| {
2544 fmt!("cast to nil: `%s` as `%s`", actual,
2545 fcx.infcx().ty_to_str(t_1))
2549 let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
2550 if type_is_c_like_enum(fcx,expr.span,t_e)
2552 /* this case is allowed */
2553 } else if type_is_region_ptr(fcx, expr.span, t_e) &&
2554 type_is_unsafe_ptr(fcx, expr.span, t_1) {
2556 fn is_vec(t: ty::t) -> bool {
2557 match ty::get(t).sty {
2558 ty::ty_evec(_,_) => true,
2562 fn types_compatible(fcx: @mut FnCtxt, sp: span,
2563 t1: ty::t, t2: ty::t) -> bool {
2567 let el = ty::sequence_element_type(fcx.tcx(),
2569 infer::mk_eqty(fcx.infcx(), false,
2570 infer::Misc(sp), el, t2).is_ok()
2574 // Due to the limitations of LLVM global constants,
2575 // region pointers end up pointing at copies of
2576 // vector elements instead of the original values.
2577 // To allow unsafe pointers to work correctly, we
2578 // need to special-case obtaining an unsafe pointer
2579 // from a region pointer to a vector.
2581 /* this cast is only allowed from &[T] to *T or
2583 let te = structurally_resolved_type(fcx, e.span, t_e);
2584 match (&ty::get(te).sty, &ty::get(t_1).sty) {
2585 (&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
2586 if types_compatible(fcx, e.span,
2587 mt1.ty, mt2.ty) => {
2588 /* this case is allowed */
2591 demand::coerce(fcx, e.span, t_1, e);
2594 } else if !(type_is_scalar(fcx,expr.span,t_e)
2597 If more type combinations should be supported than are
2598 supported here, then file an enhancement issue and
2599 record the issue number in this comment.
2601 fcx.type_error_message(expr.span, |actual| {
2602 fmt!("non-scalar cast: `%s` as `%s`", actual,
2603 fcx.infcx().ty_to_str(t_1))
2608 fcx.write_ty(id, t_1);
2611 ast::expr_vec(ref args, mutbl) => {
2612 let t: ty::t = fcx.infcx().next_ty_var();
2613 for e in args.iter() {
2614 check_expr_has_type(fcx, *e, t);
2616 let typ = ty::mk_evec(tcx, ty::mt {ty: t, mutbl: mutbl},
2617 ty::vstore_fixed(args.len()));
2618 fcx.write_ty(id, typ);
2620 ast::expr_repeat(element, count_expr, mutbl) => {
2621 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2622 let count = ty::eval_repeat_count(fcx, count_expr);
2623 let t: ty::t = fcx.infcx().next_ty_var();
2624 check_expr_has_type(fcx, element, t);
2625 let element_ty = fcx.expr_ty(element);
2626 if ty::type_is_error(element_ty) {
2627 fcx.write_error(id);
2629 else if ty::type_is_bot(element_ty) {
2633 let t = ty::mk_evec(tcx, ty::mt {ty: t, mutbl: mutbl},
2634 ty::vstore_fixed(count));
2635 fcx.write_ty(id, t);
2638 ast::expr_tup(ref elts) => {
2639 let flds = unpack_expected(fcx, expected, |sty| {
2641 ty::ty_tup(ref flds) => Some((*flds).clone()),
2645 let mut bot_field = false;
2646 let mut err_field = false;
2648 let elt_ts = do elts.iter().enumerate().transform |(i, e)| {
2649 let opt_hint = match flds {
2650 Some(ref fs) if i < fs.len() => Some(fs[i]),
2653 check_expr_with_opt_hint(fcx, *e, opt_hint);
2654 let t = fcx.expr_ty(*e);
2655 err_field = err_field || ty::type_is_error(t);
2656 bot_field = bot_field || ty::type_is_bot(t);
2661 } else if err_field {
2662 fcx.write_error(id);
2664 let typ = ty::mk_tup(tcx, elt_ts);
2665 fcx.write_ty(id, typ);
2668 ast::expr_struct(ref path, ref fields, base_expr) => {
2669 // Resolve the path.
2670 match tcx.def_map.find(&id) {
2671 Some(&ast::def_struct(type_def_id)) => {
2672 check_struct_constructor(fcx, id, expr.span, type_def_id,
2673 *fields, base_expr);
2675 Some(&ast::def_variant(enum_id, variant_id)) => {
2676 check_struct_enum_variant(fcx, id, expr.span, enum_id,
2677 variant_id, *fields);
2680 tcx.sess.span_bug(path.span,
2681 "structure constructor does not name a structure type");
2685 ast::expr_field(base, field, ref tys) => {
2686 check_field(fcx, expr, base, field, *tys);
2688 ast::expr_index(callee_id, base, idx) => {
2689 check_expr(fcx, base);
2690 check_expr(fcx, idx);
2691 let raw_base_t = fcx.expr_ty(base);
2692 let idx_t = fcx.expr_ty(idx);
2693 if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
2694 fcx.write_ty(id, raw_base_t);
2695 } else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
2696 fcx.write_ty(id, idx_t);
2698 let (base_t, derefs) = do_autoderef(fcx, expr.span, raw_base_t);
2699 let base_sty = structure_of(fcx, expr.span, base_t);
2700 match ty::index_sty(base_sty) {
2702 require_integral(fcx, idx.span, idx_t);
2703 fcx.write_ty(id, mt.ty);
2704 fcx.write_autoderef_adjustment(base.id, derefs);
2707 let resolved = structurally_resolved_type(fcx,
2710 let index_ident = tcx.sess.ident_of("index");
2711 let error_message = || {
2712 fcx.type_error_message(expr.span,
2714 fmt!("cannot index a value \
2721 let ret_ty = lookup_op_method(fcx,
2732 fcx.write_ty(id, ret_ty);
2739 debug!("type of expr(%d) %s is...", expr.id,
2740 syntax::print::pprust::expr_to_str(expr, tcx.sess.intr()));
2741 debug!("... %s, expected is %s",
2742 ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
2744 Some(t) => ppaux::ty_to_str(tcx, t),
2751 pub fn require_integral(fcx: @mut FnCtxt, sp: span, t: ty::t) {
2752 if !type_is_integral(fcx, sp, t) {
2753 fcx.type_error_message(sp, |actual| {
2754 fmt!("mismatched types: expected integral type but found `%s`",
2760 pub fn check_decl_initializer(fcx: @mut FnCtxt,
2764 let local_ty = fcx.local_ty(init.span, nid);
2765 check_expr_coercable_to_type(fcx, init, local_ty)
2768 pub fn check_decl_local(fcx: @mut FnCtxt, local: @ast::Local) {
2769 let tcx = fcx.ccx.tcx;
2771 let t = fcx.local_ty(local.span, local.id);
2772 fcx.write_ty(local.id, t);
2776 check_decl_initializer(fcx, local.id, init);
2777 let init_ty = fcx.expr_ty(init);
2778 if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
2779 fcx.write_ty(local.id, init_ty);
2785 let pcx = pat_ctxt {
2787 map: pat_id_map(tcx.def_map, local.pat),
2789 _match::check_pat(&pcx, local.pat, t);
2790 let pat_ty = fcx.node_ty(local.pat.id);
2791 if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
2792 fcx.write_ty(local.id, pat_ty);
2796 pub fn check_stmt(fcx: @mut FnCtxt, stmt: @ast::stmt) {
2798 let mut saw_bot = false;
2799 let mut saw_err = false;
2801 ast::stmt_decl(decl, id) => {
2804 ast::decl_local(ref l) => {
2805 check_decl_local(fcx, *l);
2806 let l_t = fcx.node_ty(l.id);
2807 saw_bot = saw_bot || ty::type_is_bot(l_t);
2808 saw_err = saw_err || ty::type_is_error(l_t);
2810 ast::decl_item(_) => {/* ignore for now */ }
2813 ast::stmt_expr(expr, id) => {
2815 // Check with expected type of ()
2816 check_expr_has_type(fcx, expr, ty::mk_nil());
2817 let expr_ty = fcx.expr_ty(expr);
2818 saw_bot = saw_bot || ty::type_is_bot(expr_ty);
2819 saw_err = saw_err || ty::type_is_error(expr_ty);
2821 ast::stmt_semi(expr, id) => {
2823 check_expr(fcx, expr);
2824 let expr_ty = fcx.expr_ty(expr);
2825 saw_bot |= ty::type_is_bot(expr_ty);
2826 saw_err |= ty::type_is_error(expr_ty);
2828 ast::stmt_mac(*) => fcx.ccx.tcx.sess.bug("unexpanded macro")
2831 fcx.write_bot(node_id);
2834 fcx.write_error(node_id);
2837 fcx.write_nil(node_id)
2841 pub fn check_block_no_value(fcx: @mut FnCtxt, blk: &ast::Block) {
2842 check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
2843 let blkty = fcx.node_ty(blk.id);
2844 if ty::type_is_error(blkty) {
2845 fcx.write_error(blk.id);
2847 else if ty::type_is_bot(blkty) {
2848 fcx.write_bot(blk.id);
2851 let nilty = ty::mk_nil();
2852 demand::suptype(fcx, blk.span, nilty, blkty);
2856 pub fn check_block(fcx0: @mut FnCtxt, blk: &ast::Block) {
2857 check_block_with_expected(fcx0, blk, None)
2860 pub fn check_block_with_expected(fcx: @mut FnCtxt,
2862 expected: Option<ty::t>) {
2863 let purity_state = fcx.ps.recurse(blk);
2864 let prev = replace(&mut fcx.ps, purity_state);
2866 do fcx.with_region_lb(blk.id) {
2867 let mut warned = false;
2868 let mut last_was_bot = false;
2869 let mut any_bot = false;
2870 let mut any_err = false;
2871 for s in blk.stmts.iter() {
2872 check_stmt(fcx, *s);
2873 let s_id = ast_util::stmt_id(*s);
2874 let s_ty = fcx.node_ty(s_id);
2875 if last_was_bot && !warned && match s.node {
2876 ast::stmt_decl(@codemap::spanned { node: ast::decl_local(_),
2878 ast::stmt_expr(_, _) | ast::stmt_semi(_, _) => {
2883 fcx.ccx.tcx.sess.add_lint(unreachable_code, s_id, s.span,
2884 ~"unreachable statement");
2887 if ty::type_is_bot(s_ty) {
2888 last_was_bot = true;
2890 any_bot = any_bot || ty::type_is_bot(s_ty);
2891 any_err = any_err || ty::type_is_error(s_ty);
2894 None => if any_err {
2895 fcx.write_error(blk.id);
2898 fcx.write_bot(blk.id);
2901 fcx.write_nil(blk.id);
2904 if any_bot && !warned {
2905 fcx.ccx.tcx.sess.span_warn(e.span, "unreachable expression");
2907 check_expr_with_opt_hint(fcx, e, expected);
2908 let ety = fcx.expr_ty(e);
2909 fcx.write_ty(blk.id, ety);
2911 fcx.write_error(blk.id);
2914 fcx.write_bot(blk.id);
2923 pub fn check_const(ccx: @mut CrateCtxt,
2927 let rty = ty::node_id_to_type(ccx.tcx, id);
2928 let fcx = blank_fn_ctxt(ccx, rty, e.id);
2929 let declty = fcx.ccx.tcx.tcache.get(&local_def(id)).ty;
2930 check_const_with_ty(fcx, sp, e, declty);
2933 pub fn check_const_with_ty(fcx: @mut FnCtxt,
2938 let cty = fcx.expr_ty(e);
2939 demand::suptype(fcx, e.span, declty, cty);
2940 regionck::regionck_expr(fcx, e);
2941 writeback::resolve_type_vars_in_expr(fcx, e);
2944 /// Checks whether a type can be created without an instance of itself.
2945 /// This is similar but different from the question of whether a type
2946 /// can be represented. For example, the following type:
2948 /// enum foo { None, Some(foo) }
2950 /// is instantiable but is not representable. Similarly, the type
2952 /// enum foo { Some(@foo) }
2954 /// is representable, but not instantiable.
2955 pub fn check_instantiable(tcx: ty::ctxt,
2957 item_id: ast::NodeId) {
2958 let item_ty = ty::node_id_to_type(tcx, item_id);
2959 if !ty::is_instantiable(tcx, item_ty) {
2960 tcx.sess.span_err(sp, fmt!("this type cannot be instantiated \
2961 without an instance of itself; \
2962 consider using `Option<%s>`",
2963 ppaux::ty_to_str(tcx, item_ty)));
2967 pub fn check_simd(tcx: ty::ctxt, sp: span, id: ast::NodeId) {
2968 let t = ty::node_id_to_type(tcx, id);
2969 if ty::type_needs_subst(t) {
2970 tcx.sess.span_err(sp, "SIMD vector cannot be generic");
2973 match ty::get(t).sty {
2974 ty::ty_struct(did, ref substs) => {
2975 let fields = ty::lookup_struct_fields(tcx, did);
2976 if fields.is_empty() {
2977 tcx.sess.span_err(sp, "SIMD vector cannot be empty");
2980 let e = ty::lookup_field_type(tcx, did, fields[0].id, substs);
2981 if !fields.iter().all(
2982 |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
2983 tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
2986 if !ty::type_is_machine(e) {
2987 tcx.sess.span_err(sp, "SIMD vector element type should be \
2996 pub fn check_enum_variants(ccx: @mut CrateCtxt,
2998 vs: &[ast::variant],
3000 fn do_check(ccx: @mut CrateCtxt,
3001 vs: &[ast::variant],
3003 -> ~[@ty::VariantInfo] {
3005 let rty = ty::node_id_to_type(ccx.tcx, id);
3006 let mut variants: ~[@ty::VariantInfo] = ~[];
3007 let mut disr_vals: ~[uint] = ~[];
3008 let mut prev_disr_val: Option<uint> = None;
3010 for v in vs.iter() {
3012 // If the discriminant value is specified explicitly in the enum check whether the
3013 // initialization expression is valid, otherwise use the last value plus one.
3014 let mut current_disr_val = match prev_disr_val {
3015 Some(prev_disr_val) => prev_disr_val + 1,
3016 None => ty::INITIAL_DISCRIMINANT_VALUE
3019 match v.node.disr_expr {
3021 debug!("disr expr, checking %s", pprust::expr_to_str(e, ccx.tcx.sess.intr()));
3023 let fcx = blank_fn_ctxt(ccx, rty, e.id);
3024 let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
3025 check_const_with_ty(fcx, e.span, e, declty);
3026 // check_expr (from check_const pass) doesn't guarantee
3027 // that the expression is in an form that eval_const_expr can
3028 // handle, so we may still get an internal compiler error
3030 match const_eval::eval_const_expr_partial(&ccx.tcx, e) {
3031 Ok(const_eval::const_int(val)) => current_disr_val = val as uint,
3032 Ok(const_eval::const_uint(val)) => current_disr_val = val as uint,
3034 ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
3037 ccx.tcx.sess.span_err(e.span, fmt!("expected constant: %s", (*err)));
3044 // Check for duplicate discriminator values
3045 if disr_vals.contains(¤t_disr_val) {
3046 ccx.tcx.sess.span_err(v.span, "discriminator value already exists");
3048 disr_vals.push(current_disr_val);
3050 let variant_info = @VariantInfo::from_ast_variant(ccx.tcx, v, current_disr_val);
3051 prev_disr_val = Some(current_disr_val);
3053 variants.push(variant_info);
3059 let rty = ty::node_id_to_type(ccx.tcx, id);
3061 let variants = do_check(ccx, vs, id);
3063 // cache so that ty::enum_variants won't repeat this work
3064 ccx.tcx.enum_var_cache.insert(local_def(id), @variants);
3066 // Check that it is possible to represent this enum:
3067 let mut outer = true;
3068 let did = local_def(id);
3069 if ty::type_structurally_contains(ccx.tcx, rty, |sty| {
3071 ty::ty_enum(id, _) if id == did => {
3072 if outer { outer = false; false }
3078 ccx.tcx.sess.span_err(sp,
3079 "illegal recursive enum type; \
3080 wrap the inner value in a box to make it representable");
3083 // Check that it is possible to instantiate this enum:
3085 // This *sounds* like the same that as representable, but it's
3086 // not. See def'n of `check_instantiable()` for details.
3087 check_instantiable(ccx.tcx, sp, id);
3090 pub fn lookup_def(fcx: @mut FnCtxt, sp: span, id: ast::NodeId) -> ast::def {
3091 lookup_def_ccx(fcx.ccx, sp, id)
3094 // Returns the type parameter count and the type for the given definition.
3095 pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt,
3098 -> ty_param_bounds_and_ty {
3101 ast::def_arg(nid, _) | ast::def_local(nid, _) | ast::def_self(nid, _) |
3102 ast::def_binding(nid, _) => {
3103 let typ = fcx.local_ty(sp, nid);
3104 return no_params(typ);
3106 ast::def_fn(_, ast::extern_fn) => {
3107 // extern functions are just u8 pointers
3108 return ty_param_bounds_and_ty {
3109 generics: ty::Generics {
3110 type_param_defs: @~[],
3116 ty: ty::mk_mach_uint(ast::ty_u8),
3122 ast::def_fn(id, _) | ast::def_static_method(id, _, _) |
3123 ast::def_static(id, _) | ast::def_variant(_, id) |
3124 ast::def_struct(id) => {
3125 return ty::lookup_item_type(fcx.ccx.tcx, id);
3127 ast::def_upvar(_, inner, _, _) => {
3128 return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
3132 ast::def_prim_ty(_) |
3133 ast::def_ty_param(*)=> {
3134 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type");
3136 ast::def_mod(*) | ast::def_foreign_mod(*) => {
3137 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module");
3139 ast::def_use(*) => {
3140 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use");
3142 ast::def_region(*) => {
3143 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region");
3145 ast::def_typaram_binder(*) => {
3146 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter");
3148 ast::def_label(*) => {
3149 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label");
3151 ast::def_self_ty(*) => {
3152 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty");
3154 ast::def_method(*) => {
3155 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method");
3160 // Instantiates the given path, which must refer to an item with the given
3161 // number of type parameters and type.
3162 pub fn instantiate_path(fcx: @mut FnCtxt,
3164 tpt: ty_param_bounds_and_ty,
3166 node_id: ast::NodeId) {
3167 debug!(">>> instantiate_path");
3169 let ty_param_count = tpt.generics.type_param_defs.len();
3170 let ty_substs_len = pth.types.len();
3172 debug!("ty_param_count=%? ty_substs_len=%?",
3176 // determine the region bound, using the value given by the user
3177 // (if any) and otherwise using a fresh region variable
3178 let regions = match pth.rp {
3179 Some(_) => { // user supplied a lifetime parameter...
3180 match tpt.generics.region_param {
3181 None => { // ...but the type is not lifetime parameterized!
3182 fcx.ccx.tcx.sess.span_err
3183 (span, "this item is not region-parameterized");
3186 Some(_) => { // ...and the type is lifetime parameterized, ok.
3188 ast_region_to_region(fcx, fcx, span, &pth.rp))
3192 None => { // no lifetime parameter supplied, insert default
3193 fcx.region_var_if_parameterized(tpt.generics.region_param, span)
3197 // determine values for type parameters, using the values given by
3198 // the user (if any) and otherwise using fresh type variables
3199 let tps = if ty_substs_len == 0 {
3200 fcx.infcx().next_ty_vars(ty_param_count)
3201 } else if ty_param_count == 0 {
3202 fcx.ccx.tcx.sess.span_err
3203 (span, "this item does not take type parameters");
3204 fcx.infcx().next_ty_vars(ty_param_count)
3205 } else if ty_substs_len > ty_param_count {
3206 fcx.ccx.tcx.sess.span_err
3208 fmt!("too many type parameters provided: expected %u, found %u",
3209 ty_param_count, ty_substs_len));
3210 fcx.infcx().next_ty_vars(ty_param_count)
3211 } else if ty_substs_len < ty_param_count {
3212 fcx.ccx.tcx.sess.span_err
3214 fmt!("not enough type parameters provided: expected %u, found %u",
3215 ty_param_count, ty_substs_len));
3216 fcx.infcx().next_ty_vars(ty_param_count)
3218 pth.types.map(|aty| fcx.to_ty(aty))
3221 let substs = substs {regions: ty::NonerasedRegions(regions),
3224 fcx.write_ty_substs(node_id, tpt.ty, substs);
3229 // Resolves `typ` by a single level if `typ` is a type variable. If no
3230 // resolution is possible, then an error is reported.
3231 pub fn structurally_resolved_type(fcx: @mut FnCtxt, sp: span, tp: ty::t)
3233 match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
3234 Ok(t_s) if !ty::type_is_ty_var(t_s) => t_s,
3236 fcx.type_error_message(sp, |_actual| {
3237 ~"the type of this value must be known in this context"
3239 demand::suptype(fcx, sp, ty::mk_err(), tp);
3245 // Returns the one-level-deep structure of the given type.
3246 pub fn structure_of<'a>(fcx: @mut FnCtxt, sp: span, typ: ty::t)
3248 &ty::get(structurally_resolved_type(fcx, sp, typ)).sty
3251 pub fn type_is_integral(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
3252 let typ_s = structurally_resolved_type(fcx, sp, typ);
3253 return ty::type_is_integral(typ_s);
3256 pub fn type_is_scalar(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
3257 let typ_s = structurally_resolved_type(fcx, sp, typ);
3258 return ty::type_is_scalar(typ_s);
3261 pub fn type_is_unsafe_ptr(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
3262 let typ_s = structurally_resolved_type(fcx, sp, typ);
3263 return ty::type_is_unsafe_ptr(typ_s);
3266 pub fn type_is_region_ptr(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
3267 let typ_s = structurally_resolved_type(fcx, sp, typ);
3268 return ty::type_is_region_ptr(typ_s);
3271 pub fn type_is_c_like_enum(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
3272 let typ_s = structurally_resolved_type(fcx, sp, typ);
3273 return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
3276 pub fn ast_expr_vstore_to_vstore(fcx: @mut FnCtxt,
3278 v: ast::expr_vstore)
3281 ast::expr_vstore_uniq => ty::vstore_uniq,
3282 ast::expr_vstore_box | ast::expr_vstore_mut_box => ty::vstore_box,
3283 ast::expr_vstore_slice | ast::expr_vstore_mut_slice => {
3284 let r = fcx.infcx().next_region_var(infer::AddrOfSlice(e.span));
3290 // Returns true if b contains a break that can exit from b
3291 pub fn may_break(cx: ty::ctxt, id: ast::NodeId, b: &ast::Block) -> bool {
3292 // First: is there an unlabeled break immediately
3294 (loop_query(b, |e| {
3296 ast::expr_break(_) => true,
3300 // Second: is there a labeled break with label
3301 // <id> nested anywhere inside the loop?
3302 (block_query(b, |e| {
3304 ast::expr_break(Some(_)) =>
3305 match cx.def_map.find(&e.id) {
3306 Some(&ast::def_label(loop_id)) if id == loop_id => true,
3313 pub fn check_bounds_are_used(ccx: @mut CrateCtxt,
3315 tps: &OptVec<ast::TyParam>,
3317 debug!("check_bounds_are_used(n_tps=%u, ty=%s)",
3318 tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
3320 // make a vector of booleans initially false, set to true when used
3321 if tps.len() == 0u { return; }
3322 let mut tps_used = vec::from_elem(tps.len(), false);
3324 ty::walk_regions_and_ty(
3328 match ty::get(t).sty {
3329 ty::ty_param(param_ty {idx, _}) => {
3330 debug!("Found use of ty param #%u", idx);
3331 tps_used[idx] = true;
3338 for (i, b) in tps_used.iter().enumerate() {
3340 ccx.tcx.sess.span_err(
3341 span, fmt!("type parameter `%s` is unused",
3342 ccx.tcx.sess.str_of(tps.get(i).ident)));
3347 pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
3348 fn param(ccx: @mut CrateCtxt, n: uint) -> ty::t {
3349 ty::mk_param(ccx.tcx, n, local_def(0))
3353 let nm = ccx.tcx.sess.str_of(it.ident);
3354 let name = nm.as_slice();
3355 let (n_tps, inputs, output) = if name.starts_with("atomic_") {
3356 let split : ~[&str] = name.split_iter('_').collect();
3357 assert!(split.len() >= 2, "Atomic intrinsic not correct format");
3359 //We only care about the operation here
3361 "cxchg" => (0, ~[ty::mk_mut_rptr(tcx,
3362 ty::re_bound(ty::br_anon(0)),
3369 ty::mk_imm_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int())
3374 ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()),
3379 "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
3380 "min" | "umax" | "umin" => {
3381 (0, ~[ty::mk_mut_rptr(tcx,
3382 ty::re_bound(ty::br_anon(0)),
3383 ty::mk_int()), ty::mk_int() ], ty::mk_int())
3386 (0, ~[], ty::mk_nil())
3389 tcx.sess.span_err(it.span,
3390 fmt!("unrecognized atomic operation function: `%s`",
3399 "pref_align_of" | "min_align_of" => (1u, ~[], ty::mk_uint()),
3400 "init" => (1u, ~[], param(ccx, 0u)),
3401 "uninit" => (1u, ~[], param(ccx, 0u)),
3402 "forget" => (1u, ~[ param(ccx, 0) ], ty::mk_nil()),
3403 "transmute" => (2, ~[ param(ccx, 0) ], param(ccx, 1)),
3404 "move_val" | "move_val_init" => {
3407 ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), param(ccx, 0)),
3412 "needs_drop" => (1u, ~[], ty::mk_bool()),
3413 "contains_managed" => (1u, ~[], ty::mk_bool()),
3414 "atomic_xchg" | "atomic_xadd" | "atomic_xsub" |
3415 "atomic_xchg_acq" | "atomic_xadd_acq" | "atomic_xsub_acq" |
3416 "atomic_xchg_rel" | "atomic_xadd_rel" | "atomic_xsub_rel" => {
3419 ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)), ty::mk_int()),
3426 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
3428 Err(s) => { tcx.sess.span_fatal(it.span, s); }
3430 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
3437 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
3439 Err(s) => { tcx.sess.span_fatal(it.span, s); }
3441 let visitor_object_ty = match ty::visitor_object_ty(tcx) {
3442 Ok((_, vot)) => vot,
3443 Err(s) => { tcx.sess.span_fatal(it.span, s); }
3446 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
3450 (0, ~[ td_ptr, visitor_object_ty ], ty::mk_nil())
3452 "frame_address" => {
3453 let fty = ty::mk_closure(ccx.tcx, ty::ClosureTy {
3454 purity: ast::impure_fn,
3455 sigil: ast::BorrowedSigil,
3456 onceness: ast::Once,
3457 region: ty::re_bound(ty::br_anon(0)),
3458 bounds: ty::EmptyBuiltinBounds(),
3460 bound_lifetime_names: opt_vec::Empty,
3461 inputs: ~[ty::mk_imm_ptr(ccx.tcx, ty::mk_mach_uint(ast::ty_u8))],
3462 output: ty::mk_nil()
3465 (0u, ~[fty], ty::mk_nil())
3467 "morestack_addr" => {
3468 (0u, ~[], ty::mk_nil_ptr(ccx.tcx))
3473 ty::mk_ptr(tcx, ty::mt {
3479 ty::mk_ptr(tcx, ty::mt {
3484 "offset_inbounds" => {
3487 ty::mk_ptr(tcx, ty::mt {
3493 ty::mk_ptr(tcx, ty::mt {
3501 ty::mk_ptr(tcx, ty::mt {
3505 ty::mk_ptr(tcx, ty::mt {
3516 ty::mk_ptr(tcx, ty::mt {
3520 ty::mk_ptr(tcx, ty::mt {
3531 ty::mk_ptr(tcx, ty::mt {
3535 ty::mk_ptr(tcx, ty::mt {
3546 ty::mk_ptr(tcx, ty::mt {
3550 ty::mk_ptr(tcx, ty::mt {
3561 ty::mk_ptr(tcx, ty::mt {
3573 ty::mk_ptr(tcx, ty::mt {
3582 "sqrtf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3583 "sqrtf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3586 ~[ ty::mk_f32(), ty::mk_i32() ],
3591 ~[ ty::mk_f64(), ty::mk_i32() ],
3594 "sinf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3595 "sinf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3596 "cosf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3597 "cosf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3600 ~[ ty::mk_f32(), ty::mk_f32() ],
3605 ~[ ty::mk_f64(), ty::mk_f64() ],
3608 "expf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3609 "expf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3610 "exp2f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3611 "exp2f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3612 "logf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3613 "logf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3614 "log10f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3615 "log10f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3616 "log2f32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3617 "log2f64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3620 ~[ ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ],
3625 ~[ ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ],
3628 "fabsf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3629 "fabsf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3630 "floorf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3631 "floorf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3632 "ceilf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3633 "ceilf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3634 "truncf32" => (0, ~[ ty::mk_f32() ], ty::mk_f32()),
3635 "truncf64" => (0, ~[ ty::mk_f64() ], ty::mk_f64()),
3636 "ctpop8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()),
3637 "ctpop16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
3638 "ctpop32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
3639 "ctpop64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
3640 "ctlz8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()),
3641 "ctlz16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
3642 "ctlz32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
3643 "ctlz64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
3644 "cttz8" => (0, ~[ ty::mk_i8() ], ty::mk_i8()),
3645 "cttz16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
3646 "cttz32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
3647 "cttz64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
3648 "bswap16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
3649 "bswap32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
3650 "bswap64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
3652 tcx.sess.span_err(it.span,
3653 fmt!("unrecognized intrinsic function: `%s`",
3659 let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
3660 purity: ast::unsafe_fn,
3661 abis: AbiSet::Intrinsic(),
3662 sig: FnSig {bound_lifetime_names: opt_vec::Empty,
3666 let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
3667 let i_n_tps = i_ty.generics.type_param_defs.len();
3668 if i_n_tps != n_tps {
3669 tcx.sess.span_err(it.span, fmt!("intrinsic has wrong number \
3670 of type parameters: found %u, \
3671 expected %u", i_n_tps, n_tps));
3674 tcx, None, false, it.span, i_ty.ty, fty,
3675 || fmt!("intrinsic has wrong type: \
3677 ppaux::ty_to_str(ccx.tcx, fty)));