1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
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.
10
11 /*
12
13 # check.rs
14
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
18 unknown.
19
20 By far the most complex case is checking the body of a function. This
21 can be broken down into several distinct phases:
22
23 - gather: creates type variables to represent the type of each local
24 variable and pattern binding.
25
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.
31
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.
36
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
41 flexibility.
42
43 - vtable: find and records the impls to use for each trait bound that
44 appears on a type parameter.
45
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.
50
51 ## Intermediate types
52
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`.
60
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.
64
65 The types of top-level items, which never contain unbound type
66 variables, are stored directly into the `tcx` tables.
67
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
75 type parameter).
76
77 */
78
79
80 use middle::const_eval;
81 use middle::lang_items::{ExchangeHeapLangItem, GcLangItem};
82 use middle::lang_items::{ManagedHeapLangItem};
83 use middle::lint::UnreachableCode;
84 use middle::pat_util::pat_id_map;
85 use middle::pat_util;
86 use middle::subst::Subst;
87 use middle::ty::{FnSig, VariantInfo};
88 use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
89 use middle::ty::{substs, param_ty, Disr, ExprTyProvider};
90 use middle::ty;
91 use middle::ty_fold::TypeFolder;
92 use middle::typeck::astconv::AstConv;
93 use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
94 use middle::typeck::astconv;
95 use middle::typeck::check::_match::pat_ctxt;
96 use middle::typeck::check::method::{AutoderefReceiver};
97 use middle::typeck::check::method::{AutoderefReceiverFlag};
98 use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
99 use middle::typeck::check::method::{DontAutoderefReceiver};
100 use middle::typeck::check::method::{IgnoreStaticMethods, ReportStaticMethods};
101 use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
102 use middle::typeck::check::regionmanip::relate_free_regions;
103 use middle::typeck::check::vtable::VtableContext;
104 use middle::typeck::CrateCtxt;
105 use middle::typeck::infer::{resolve_type, force_tvar};
106 use middle::typeck::infer;
107 use middle::typeck::rscope::RegionScope;
108 use middle::typeck::{lookup_def_ccx};
109 use middle::typeck::no_params;
110 use middle::typeck::{require_same_types, vtable_map};
111 use middle::typeck::{MethodCall, MethodMap};
112 use middle::lang_items::TypeIdLangItem;
113 use util::common::{block_query, indenter, loop_query};
114 use util::ppaux;
115 use util::ppaux::{UserString, Repr};
116 use util::nodemap::{FnvHashMap, NodeMap};
117
118 use std::cell::{Cell, RefCell};
119 use collections::HashMap;
120 use std::mem::replace;
121 use std::rc::Rc;
122 use std::vec::Vec;
123 use syntax::abi;
124 use syntax::ast::{Provided, Required};
125 use syntax::ast;
126 use syntax::ast_map;
127 use syntax::ast_util::local_def;
128 use syntax::ast_util;
129 use syntax::attr;
130 use syntax::codemap::Span;
131 use syntax::codemap;
132 use syntax::owned_slice::OwnedSlice;
133 use syntax::parse::token;
134 use syntax::print::pprust;
135 use syntax::visit;
136 use syntax::visit::Visitor;
137 use syntax;
138
139 pub mod _match;
140 pub mod vtable;
141 pub mod writeback;
142 pub mod regionmanip;
143 pub mod regionck;
144 pub mod demand;
145 pub mod method;
146
147 /// Fields that are part of a `FnCtxt` which are inherited by
148 /// closures defined within the function. For example:
149 ///
150 /// fn foo() {
151 /// bar(proc() { ... })
152 /// }
153 ///
154 /// Here, the function `foo()` and the closure passed to
155 /// `bar()` will each have their own `FnCtxt`, but they will
156 /// share the inherited fields.
157 pub struct Inherited<'a> {
158 infcx: infer::InferCtxt<'a>,
159 locals: RefCell<NodeMap<ty::t>>,
160 param_env: ty::ParameterEnvironment,
161
162 // Temporary tables:
163 node_types: RefCell<NodeMap<ty::t>>,
164 node_type_substs: RefCell<NodeMap<ty::substs>>,
165 adjustments: RefCell<NodeMap<ty::AutoAdjustment>>,
166 method_map: MethodMap,
167 vtable_map: vtable_map,
168 upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
169 }
170
171 #[deriving(Clone)]
172 pub enum FnKind {
173 // A do-closure.
174 DoBlock,
175
176 // A normal closure or fn item.
177 Vanilla
178 }
179
180 #[deriving(Clone)]
181 pub struct FnStyleState {
182 pub def: ast::NodeId,
183 pub fn_style: ast::FnStyle,
184 from_fn: bool
185 }
186
187 impl FnStyleState {
188 pub fn function(fn_style: ast::FnStyle, def: ast::NodeId) -> FnStyleState {
189 FnStyleState { def: def, fn_style: fn_style, from_fn: true }
190 }
191
192 pub fn recurse(&mut self, blk: &ast::Block) -> FnStyleState {
193 match self.fn_style {
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::UnsafeFn if self.from_fn => *self,
199
200 fn_style => {
201 let (fn_style, def) = match blk.rules {
202 ast::UnsafeBlock(..) => (ast::UnsafeFn, blk.id),
203 ast::DefaultBlock => (fn_style, self.def),
204 };
205 FnStyleState{ def: def,
206 fn_style: fn_style,
207 from_fn: false }
208 }
209 }
210 }
211 }
212
213 /// Whether `check_binop` is part of an assignment or not.
214 /// Used to know wether we allow user overloads and to print
215 /// better messages on error.
216 #[deriving(Eq)]
217 enum IsBinopAssignment{
218 SimpleBinop,
219 BinopAssignment,
220 }
221
222 #[deriving(Clone)]
223 pub struct FnCtxt<'a> {
224 // This flag is set to true if, during the writeback phase, we encounter
225 // a type error in this function.
226 writeback_errors: Cell<bool>,
227
228 // Number of errors that had been reported when we started
229 // checking this function. On exit, if we find that *more* errors
230 // have been reported, we will skip regionck and other work that
231 // expects the types within the function to be consistent.
232 err_count_on_creation: uint,
233
234 ret_ty: ty::t,
235 ps: RefCell<FnStyleState>,
236
237 // Sometimes we generate region pointers where the precise region
238 // to use is not known. For example, an expression like `&x.f`
239 // where `x` is of type `@T`: in this case, we will be rooting
240 // `x` onto the stack frame, and we could choose to root it until
241 // the end of (almost) any enclosing block or expression. We
242 // want to pick the narrowest block that encompasses all uses.
243 //
244 // What we do in such cases is to generate a region variable with
245 // `region_lb` as a lower bound. The regionck pass then adds
246 // other constraints based on how the variable is used and region
247 // inference selects the ultimate value. Finally, borrowck is
248 // charged with guaranteeing that the value whose address was taken
249 // can actually be made to live as long as it needs to live.
250 region_lb: Cell<ast::NodeId>,
251
252 // Says whether we're inside a for loop, in a do block
253 // or neither. Helps with error messages involving the
254 // function return type.
255 fn_kind: FnKind,
256
257 inh: &'a Inherited<'a>,
258
259 ccx: &'a CrateCtxt<'a>,
260 }
261
262 impl<'a> Inherited<'a> {
263 fn new(tcx: &'a ty::ctxt,
264 param_env: ty::ParameterEnvironment)
265 -> Inherited<'a> {
266 Inherited {
267 infcx: infer::new_infer_ctxt(tcx),
268 locals: RefCell::new(NodeMap::new()),
269 param_env: param_env,
270 node_types: RefCell::new(NodeMap::new()),
271 node_type_substs: RefCell::new(NodeMap::new()),
272 adjustments: RefCell::new(NodeMap::new()),
273 method_map: RefCell::new(FnvHashMap::new()),
274 vtable_map: RefCell::new(FnvHashMap::new()),
275 upvar_borrow_map: RefCell::new(HashMap::new()),
276 }
277 }
278 }
279
280 // Used by check_const and check_enum_variants
281 fn blank_fn_ctxt<'a>(ccx: &'a CrateCtxt<'a>,
282 inh: &'a Inherited<'a>,
283 rty: ty::t,
284 region_bnd: ast::NodeId)
285 -> FnCtxt<'a> {
286 FnCtxt {
287 writeback_errors: Cell::new(false),
288 err_count_on_creation: ccx.tcx.sess.err_count(),
289 ret_ty: rty,
290 ps: RefCell::new(FnStyleState::function(ast::NormalFn, 0)),
291 region_lb: Cell::new(region_bnd),
292 fn_kind: Vanilla,
293 inh: inh,
294 ccx: ccx
295 }
296 }
297
298 fn blank_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> {
299 // It's kind of a kludge to manufacture a fake function context
300 // and statement context, but we might as well do write the code only once
301 let param_env = ty::ParameterEnvironment { free_substs: substs::empty(),
302 self_param_bound: None,
303 type_param_bounds: Vec::new() };
304 Inherited::new(ccx.tcx, param_env)
305 }
306
307 impl<'a> ExprTyProvider for FnCtxt<'a> {
308 fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
309 self.expr_ty(ex)
310 }
311
312 fn ty_ctxt<'a>(&'a self) -> &'a ty::ctxt {
313 self.ccx.tcx
314 }
315 }
316
317 struct CheckItemTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
318
319 impl<'a> Visitor<()> for CheckItemTypesVisitor<'a> {
320 fn visit_item(&mut self, i: &ast::Item, _: ()) {
321 check_item(self.ccx, i);
322 visit::walk_item(self, i, ());
323 }
324 }
325
326 struct CheckItemSizedTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
327
328 impl<'a> Visitor<()> for CheckItemSizedTypesVisitor<'a> {
329 fn visit_item(&mut self, i: &ast::Item, _: ()) {
330 check_item_sized(self.ccx, i);
331 visit::walk_item(self, i, ());
332 }
333 }
334
335 pub fn check_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
336 let mut visit = CheckItemTypesVisitor { ccx: ccx };
337 visit::walk_crate(&mut visit, krate, ());
338
339 ccx.tcx.sess.abort_if_errors();
340
341 let mut visit = CheckItemSizedTypesVisitor { ccx: ccx };
342 visit::walk_crate(&mut visit, krate, ());
343 }
344
345 fn check_bare_fn(ccx: &CrateCtxt,
346 decl: &ast::FnDecl,
347 body: &ast::Block,
348 id: ast::NodeId,
349 fty: ty::t,
350 param_env: ty::ParameterEnvironment) {
351 // Compute the fty from point of view of inside fn
352 // (replace any type-scheme with a type)
353 let fty = fty.subst(ccx.tcx, ¶m_env.free_substs);
354
355 match ty::get(fty).sty {
356 ty::ty_bare_fn(ref fn_ty) => {
357 let inh = Inherited::new(ccx.tcx, param_env);
358 let fcx = check_fn(ccx, fn_ty.fn_style, &fn_ty.sig,
359 decl, id, body, Vanilla, &inh);
360
361 vtable::resolve_in_block(&fcx, body);
362 regionck::regionck_fn(&fcx, body);
363 writeback::resolve_type_vars_in_fn(&fcx, decl, body);
364 }
365 _ => ccx.tcx.sess.impossible_case(body.span,
366 "check_bare_fn: function type expected")
367 }
368 }
369
370 struct GatherLocalsVisitor<'a> {
371 fcx: &'a FnCtxt<'a>
372 }
373
374 impl<'a> GatherLocalsVisitor<'a> {
375 fn assign(&mut self, nid: ast::NodeId, ty_opt: Option<ty::t>) {
376 match ty_opt {
377 None => {
378 // infer the variable's type
379 let var_id = self.fcx.infcx().next_ty_var_id();
380 let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
381 self.fcx.inh.locals.borrow_mut().insert(nid, var_ty);
382 }
383 Some(typ) => {
384 // take type that the user specified
385 self.fcx.inh.locals.borrow_mut().insert(nid, typ);
386 }
387 }
388 }
389 }
390
391 impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
392 // Add explicitly-declared locals.
393 fn visit_local(&mut self, local: &ast::Local, _: ()) {
394 let o_ty = match local.ty.node {
395 ast::TyInfer => None,
396 _ => Some(self.fcx.to_ty(local.ty))
397 };
398 self.assign(local.id, o_ty);
399 debug!("Local variable {} is assigned type {}",
400 self.fcx.pat_to_str(local.pat),
401 self.fcx.infcx().ty_to_str(
402 self.fcx.inh.locals.borrow().get_copy(&local.id)));
403 visit::walk_local(self, local, ());
404 }
405
406 // Add pattern bindings.
407 fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
408 match p.node {
409 ast::PatIdent(_, ref path, _)
410 if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) => {
411 self.assign(p.id, None);
412 debug!("Pattern binding {} is assigned to {}",
413 token::get_ident(path.segments.get(0).identifier),
414 self.fcx.infcx().ty_to_str(
415 self.fcx.inh.locals.borrow().get_copy(&p.id)));
416 }
417 _ => {}
418 }
419 visit::walk_pat(self, p, ());
420
421 }
422
423 fn visit_block(&mut self, b: &ast::Block, _: ()) {
424 // non-obvious: the `blk` variable maps to region lb, so
425 // we have to keep this up-to-date. This
426 // is... unfortunate. It'd be nice to not need this.
427 self.fcx.with_region_lb(b.id, || visit::walk_block(self, b, ()));
428 }
429
430 // Don't descend into fns and items
431 fn visit_fn(&mut self, _: &visit::FnKind, _: &ast::FnDecl,
432 _: &ast::Block, _: Span, _: ast::NodeId, _: ()) { }
433 fn visit_item(&mut self, _: &ast::Item, _: ()) { }
434
435 }
436
437 fn check_fn<'a>(ccx: &'a CrateCtxt<'a>,
438 fn_style: ast::FnStyle,
439 fn_sig: &ty::FnSig,
440 decl: &ast::FnDecl,
441 id: ast::NodeId,
442 body: &ast::Block,
443 fn_kind: FnKind,
444 inherited: &'a Inherited<'a>) -> FnCtxt<'a>
445 {
446 /*!
447 * Helper used by check_bare_fn and check_expr_fn. Does the
448 * grungy work of checking a function body and returns the
449 * function context used for that purpose, since in the case of a
450 * fn item there is still a bit more to do.
451 *
452 * - ...
453 * - inherited: other fields inherited from the enclosing fn (if any)
454 */
455
456 let tcx = ccx.tcx;
457 let err_count_on_creation = tcx.sess.err_count();
458
459 // First, we have to replace any bound regions in the fn type with free ones.
460 // The free region references will be bound the node_id of the body block.
461 let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(tcx, fn_sig, |br| {
462 ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
463 });
464
465 relate_free_regions(tcx, &fn_sig);
466
467 let arg_tys = fn_sig.inputs.as_slice();
468 let ret_ty = fn_sig.output;
469
470 debug!("check_fn(arg_tys={:?}, ret_ty={:?})",
471 arg_tys.iter().map(|&a| ppaux::ty_to_str(tcx, a)).collect::<Vec<~str>>(),
472 ppaux::ty_to_str(tcx, ret_ty));
473
474 // Create the function context. This is either derived from scratch or,
475 // in the case of function expressions, based on the outer context.
476 let fcx = FnCtxt {
477 writeback_errors: Cell::new(false),
478 err_count_on_creation: err_count_on_creation,
479 ret_ty: ret_ty,
480 ps: RefCell::new(FnStyleState::function(fn_style, id)),
481 region_lb: Cell::new(body.id),
482 fn_kind: fn_kind,
483 inh: inherited,
484 ccx: ccx
485 };
486
487 {
488
489 let mut visit = GatherLocalsVisitor { fcx: &fcx, };
490 // Add formal parameters.
491 for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
492 // Create type variables for each argument.
493 pat_util::pat_bindings(&tcx.def_map,
494 input.pat,
495 |_bm, pat_id, _sp, _path| {
496 visit.assign(pat_id, None);
497 });
498
499 // Check the pattern.
500 let pcx = pat_ctxt {
501 fcx: &fcx,
502 map: pat_id_map(&tcx.def_map, input.pat),
503 };
504 _match::check_pat(&pcx, input.pat, *arg_ty);
505 }
506
507 visit.visit_block(body, ());
508 }
509
510 check_block_with_expected(&fcx, body, Some(ret_ty));
511
512 // We unify the tail expr's type with the
513 // function result type, if there is a tail expr.
514 match body.expr {
515 Some(tail_expr) => {
516 // Special case: we print a special error if there appears
517 // to be do-block/for-loop confusion
518 demand::suptype_with_fn(&fcx, tail_expr.span, false,
519 fcx.ret_ty, fcx.expr_ty(tail_expr),
520 |sp, e, a, s| {
521 fcx.report_mismatched_return_types(sp, e, a, s);
522 });
523 }
524 None => {}
525 }
526
527 for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
528 fcx.write_ty(input.id, *arg);
529 }
530
531 fcx
532 }
533
534 fn span_for_field(tcx: &ty::ctxt, field: &ty::field_ty, struct_id: ast::DefId) -> Span {
535 assert!(field.id.krate == ast::LOCAL_CRATE);
536 let item = match tcx.map.find(struct_id.node) {
537 Some(ast_map::NodeItem(item)) => item,
538 None => fail!("node not in ast map: {}", struct_id.node),
539 _ => fail!("expected item, found {}", tcx.map.node_to_str(struct_id.node))
540 };
541
542 match item.node {
543 ast::ItemStruct(struct_def, _) => {
544 match struct_def.fields.iter().find(|f| match f.node.kind {
545 ast::NamedField(ident, _) => ident.name == field.name,
546 _ => false,
547 }) {
548 Some(f) => f.span,
549 None => tcx.sess.bug(format!("Could not find field {}",
550 token::get_name(field.name))),
551 }
552 },
553 _ => tcx.sess.bug("Field found outside of a struct?"),
554 }
555 }
556
557 // Check struct fields are uniquely named wrt parents.
558 fn check_for_field_shadowing(tcx: &ty::ctxt,
559 id: ast::DefId) {
560 let struct_fields = tcx.struct_fields.borrow();
561 let fields = struct_fields.get(&id);
562
563 let superstructs = tcx.superstructs.borrow();
564 let super_struct = superstructs.get(&id);
565 match *super_struct {
566 Some(parent_id) => {
567 let super_fields = ty::lookup_struct_fields(tcx, parent_id);
568 for f in fields.iter() {
569 match super_fields.iter().find(|sf| f.name == sf.name) {
570 Some(prev_field) => {
571 tcx.sess.span_err(span_for_field(tcx, f, id),
572 format!("field `{}` hides field declared in super-struct",
573 token::get_name(f.name)));
574 tcx.sess.span_note(span_for_field(tcx, prev_field, parent_id),
575 "previously declared here");
576 },
577 None => {}
578 }
579 }
580 },
581 None => {}
582 }
583 }
584
585 fn check_fields_sized(tcx: &ty::ctxt,
586 struct_def: &ast::StructDef) {
587 let len = struct_def.fields.len();
588 if len == 0 {
589 return;
590 }
591 for f in struct_def.fields.slice_to(len - 1).iter() {
592 let t = ty::node_id_to_type(tcx, f.node.id);
593 if !ty::type_is_sized(tcx, t) {
594 match f.node.kind {
595 ast::NamedField(ident, _) => {
596 tcx.sess.span_err(f.span, format!("type `{}` is dynamically sized. \
597 dynamically sized types may only \
598 appear as the type of the final \
599 field in a struct",
600 token::get_ident(ident)));
601 }
602 ast::UnnamedField(_) => {
603 tcx.sess.span_err(f.span, "dynamically sized type in field");
604 }
605 }
606 }
607 }
608 }
609
610 pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
611 let tcx = ccx.tcx;
612
613 check_representable(tcx, span, id, "struct");
614 check_instantiable(tcx, span, id);
615
616 // Check there are no overlapping fields in super-structs
617 check_for_field_shadowing(tcx, local_def(id));
618
619 if ty::lookup_simd(tcx, local_def(id)) {
620 check_simd(tcx, span, id);
621 }
622 }
623
624 pub fn check_item_sized(ccx: &CrateCtxt, it: &ast::Item) {
625 debug!("check_item(it.id={}, it.ident={})",
626 it.id,
627 ty::item_path_str(ccx.tcx, local_def(it.id)));
628 let _indenter = indenter();
629
630 match it.node {
631 ast::ItemEnum(ref enum_definition, _) => {
632 check_enum_variants_sized(ccx,
633 enum_definition.variants.as_slice());
634 }
635 ast::ItemStruct(..) => {
636 check_fields_sized(ccx.tcx, ccx.tcx.map.expect_struct(it.id));
637 }
638 _ => {}
639 }
640 }
641
642 pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
643 debug!("check_item(it.id={}, it.ident={})",
644 it.id,
645 ty::item_path_str(ccx.tcx, local_def(it.id)));
646 let _indenter = indenter();
647
648 match it.node {
649 ast::ItemStatic(_, _, e) => check_const(ccx, it.span, e, it.id),
650 ast::ItemEnum(ref enum_definition, _) => {
651 check_enum_variants(ccx,
652 it.span,
653 enum_definition.variants.as_slice(),
654 it.id);
655 }
656 ast::ItemFn(decl, _, _, _, body) => {
657 let fn_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
658
659 let param_env = ty::construct_parameter_environment(
660 ccx.tcx,
661 None,
662 fn_tpt.generics.type_param_defs(),
663 [],
664 [],
665 fn_tpt.generics.region_param_defs.as_slice(),
666 body.id);
667
668 check_bare_fn(ccx, decl, body, it.id, fn_tpt.ty, param_env);
669 }
670 ast::ItemImpl(_, ref opt_trait_ref, _, ref ms) => {
671 debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
672
673 let impl_tpt = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
674 for m in ms.iter() {
675 check_method_body(ccx, &impl_tpt.generics, None, *m);
676 }
677
678 match *opt_trait_ref {
679 Some(ref ast_trait_ref) => {
680 let impl_trait_ref =
681 ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id);
682 check_impl_methods_against_trait(ccx,
683 it.span,
684 &impl_tpt.generics,
685 ast_trait_ref,
686 &*impl_trait_ref,
687 ms.as_slice());
688 vtable::resolve_impl(ccx.tcx, it, &impl_tpt.generics, &*impl_trait_ref);
689 }
690 None => { }
691 }
692
693 }
694 ast::ItemTrait(_, _, _, ref trait_methods) => {
695 let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
696 for trait_method in (*trait_methods).iter() {
697 match *trait_method {
698 Required(..) => {
699 // Nothing to do, since required methods don't have
700 // bodies to check.
701 }
702 Provided(m) => {
703 check_method_body(ccx, &trait_def.generics,
704 Some(trait_def.trait_ref.clone()), m);
705 }
706 }
707 }
708 }
709 ast::ItemStruct(..) => {
710 check_struct(ccx, it.id, it.span);
711 }
712 ast::ItemTy(ref t, ref generics) => {
713 let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id);
714 check_bounds_are_used(ccx, t.span, &generics.ty_params, tpt_ty);
715 }
716 ast::ItemForeignMod(ref m) => {
717 if m.abi == abi::RustIntrinsic {
718 for item in m.items.iter() {
719 check_intrinsic_type(ccx, *item);
720 }
721 } else {
722 for item in m.items.iter() {
723 let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id));
724 if tpt.generics.has_type_params() {
725 ccx.tcx.sess.span_err(item.span, "foreign items may not have type parameters");
726 }
727
728 match item.node {
729 ast::ForeignItemFn(ref fn_decl, _) => {
730 if fn_decl.variadic && m.abi != abi::C {
731 ccx.tcx.sess.span_err(
732 item.span, "variadic function must have C calling convention");
733 }
734 }
735 _ => {}
736 }
737 }
738 }
739 }
740 _ => {/* nothing to do */ }
741 }
742 }
743
744 fn check_method_body(ccx: &CrateCtxt,
745 item_generics: &ty::Generics,
746 self_bound: Option<Rc<ty::TraitRef>>,
747 method: &ast::Method) {
748 /*!
749 * Type checks a method body.
750 *
751 * # Parameters
752 * - `item_generics`: generics defined on the impl/trait that contains
753 * the method
754 * - `self_bound`: bound for the `Self` type parameter, if any
755 * - `method`: the method definition
756 */
757
758 debug!("check_method_body(item_generics={}, \
759 self_bound={}, \
760 method.id={})",
761 item_generics.repr(ccx.tcx),
762 self_bound.repr(ccx.tcx),
763 method.id);
764 let method_def_id = local_def(method.id);
765 let method_ty = ty::method(ccx.tcx, method_def_id);
766 let method_generics = &method_ty.generics;
767
768 let param_env =
769 ty::construct_parameter_environment(
770 ccx.tcx,
771 self_bound,
772 item_generics.type_param_defs(),
773 method_generics.type_param_defs(),
774 item_generics.region_param_defs(),
775 method_generics.region_param_defs(),
776 method.body.id);
777
778 let fty = ty::node_id_to_type(ccx.tcx, method.id);
779
780 check_bare_fn(ccx, method.decl, method.body, method.id, fty, param_env);
781 }
782
783 fn check_impl_methods_against_trait(ccx: &CrateCtxt,
784 impl_span: Span,
785 impl_generics: &ty::Generics,
786 ast_trait_ref: &ast::TraitRef,
787 impl_trait_ref: &ty::TraitRef,
788 impl_methods: &[@ast::Method]) {
789 // Locate trait methods
790 let tcx = ccx.tcx;
791 let trait_methods = ty::trait_methods(tcx, impl_trait_ref.def_id);
792
793 // Check existing impl methods to see if they are both present in trait
794 // and compatible with trait signature
795 for impl_method in impl_methods.iter() {
796 let impl_method_def_id = local_def(impl_method.id);
797 let impl_method_ty = ty::method(ccx.tcx, impl_method_def_id);
798
799 // If this is an impl of a trait method, find the corresponding
800 // method definition in the trait.
801 let opt_trait_method_ty =
802 trait_methods.iter().
803 find(|tm| tm.ident.name == impl_method_ty.ident.name);
804 match opt_trait_method_ty {
805 Some(trait_method_ty) => {
806 compare_impl_method(ccx.tcx,
807 impl_generics,
808 &*impl_method_ty,
809 impl_method.span,
810 impl_method.body.id,
811 &**trait_method_ty,
812 &impl_trait_ref.substs);
813 }
814 None => {
815 tcx.sess.span_err(
816 impl_method.span,
817 format!("method `{}` is not a member of trait `{}`",
818 token::get_ident(impl_method_ty.ident),
819 pprust::path_to_str(&ast_trait_ref.path)));
820 }
821 }
822 }
823
824 // Check for missing methods from trait
825 let provided_methods = ty::provided_trait_methods(tcx,
826 impl_trait_ref.def_id);
827 let mut missing_methods = Vec::new();
828 for trait_method in trait_methods.iter() {
829 let is_implemented =
830 impl_methods.iter().any(
831 |m| m.ident.name == trait_method.ident.name);
832 let is_provided =
833 provided_methods.iter().any(
834 |m| m.ident.name == trait_method.ident.name);
835 if !is_implemented && !is_provided {
836 missing_methods.push(
837 format!("`{}`", token::get_ident(trait_method.ident)));
838 }
839 }
840
841 if !missing_methods.is_empty() {
842 tcx.sess.span_err(
843 impl_span,
844 format!("not all trait methods implemented, missing: {}",
845 missing_methods.connect(", ")));
846 }
847 }
848
849 /**
850 * Checks that a method from an impl/class conforms to the signature of
851 * the same method as declared in the trait.
852 *
853 * # Parameters
854 *
855 * - impl_generics: the generics declared on the impl itself (not the method!)
856 * - impl_m: type of the method we are checking
857 * - impl_m_span: span to use for reporting errors
858 * - impl_m_body_id: id of the method body
859 * - trait_m: the method in the trait
860 * - trait_substs: the substitutions used on the type of the trait
861 */
862 fn compare_impl_method(tcx: &ty::ctxt,
863 impl_generics: &ty::Generics,
864 impl_m: &ty::Method,
865 impl_m_span: Span,
866 impl_m_body_id: ast::NodeId,
867 trait_m: &ty::Method,
868 trait_substs: &ty::substs) {
869 debug!("compare_impl_method()");
870 let infcx = infer::new_infer_ctxt(tcx);
871
872 let impl_tps = impl_generics.type_param_defs().len();
873
874 // Try to give more informative error messages about self typing
875 // mismatches. Note that any mismatch will also be detected
876 // below, where we construct a canonical function type that
877 // includes the self parameter as a normal parameter. It's just
878 // that the error messages you get out of this code are a bit more
879 // inscrutable, particularly for cases where one method has no
880 // self.
881 match (&trait_m.explicit_self, &impl_m.explicit_self) {
882 (&ast::SelfStatic, &ast::SelfStatic) => {}
883 (&ast::SelfStatic, _) => {
884 tcx.sess.span_err(
885 impl_m_span,
886 format!("method `{}` has a `{}` declaration in the impl, \
887 but not in the trait",
888 token::get_ident(trait_m.ident),
889 pprust::explicit_self_to_str(impl_m.explicit_self)));
890 return;
891 }
892 (_, &ast::SelfStatic) => {
893 tcx.sess.span_err(
894 impl_m_span,
895 format!("method `{}` has a `{}` declaration in the trait, \
896 but not in the impl",
897 token::get_ident(trait_m.ident),
898 pprust::explicit_self_to_str(trait_m.explicit_self)));
899 return;
900 }
901 _ => {
902 // Let the type checker catch other errors below
903 }
904 }
905
906 let num_impl_m_type_params = impl_m.generics.type_param_defs().len();
907 let num_trait_m_type_params = trait_m.generics.type_param_defs().len();
908 if num_impl_m_type_params != num_trait_m_type_params {
909 tcx.sess.span_err(
910 impl_m_span,
911 format!("method `{method}` has {nimpl, plural, =1{# type parameter} \
912 other{# type parameters}}, \
913 but its trait declaration has {ntrait, plural, =1{# type parameter} \
914 other{# type parameters}}",
915 method = token::get_ident(trait_m.ident),
916 nimpl = num_impl_m_type_params,
917 ntrait = num_trait_m_type_params));
918 return;
919 }
920
921 if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() {
922 tcx.sess.span_err(
923 impl_m_span,
924 format!("method `{method}` has {nimpl, plural, =1{# parameter} \
925 other{# parameters}} \
926 but the declaration in trait `{trait}` has {ntrait}",
927 method = token::get_ident(trait_m.ident),
928 nimpl = impl_m.fty.sig.inputs.len(),
929 trait = ty::item_path_str(tcx, trait_m.def_id),
930 ntrait = trait_m.fty.sig.inputs.len()));
931 return;
932 }
933
934 let it = trait_m.generics.type_param_defs().iter()
935 .zip(impl_m.generics.type_param_defs().iter());
936
937 for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
938 // Check that the impl does not require any builtin-bounds
939 // that the trait does not guarantee:
940 let extra_bounds =
941 impl_param_def.bounds.builtin_bounds -
942 trait_param_def.bounds.builtin_bounds;
943 if !extra_bounds.is_empty() {
944 tcx.sess.span_err(
945 impl_m_span,
946 format!("in method `{}`, \
947 type parameter {} requires `{}`, \
948 which is not required by \
949 the corresponding type parameter \
950 in the trait declaration",
951 token::get_ident(trait_m.ident),
952 i,
953 extra_bounds.user_string(tcx)));
954 return;
955 }
956
957 // FIXME(#2687)---we should be checking that the bounds of the
958 // trait imply the bounds of the subtype, but it appears we
959 // are...not checking this.
960 if impl_param_def.bounds.trait_bounds.len() !=
961 trait_param_def.bounds.trait_bounds.len()
962 {
963 tcx.sess.span_err(
964 impl_m_span,
965 format!("in method `{method}`, \
966 type parameter {typaram} has \
967 {nimpl, plural, =1{# trait bound} other{# trait bounds}}, \
968 but the corresponding type parameter in \
969 the trait declaration has \
970 {ntrait, plural, =1{# trait bound} other{# trait bounds}}",
971 method = token::get_ident(trait_m.ident),
972 typaram = i,
973 nimpl = impl_param_def.bounds.trait_bounds.len(),
974 ntrait = trait_param_def.bounds.trait_bounds.len()));
975 return;
976 }
977 }
978
979 // Create a substitution that maps the type parameters on the impl
980 // to themselves and which replace any references to bound regions
981 // in the self type with free regions. So, for example, if the
982 // impl type is "&'a str", then this would replace the self
983 // type with a free region `self`.
984 let dummy_impl_tps: Vec<ty::t> =
985 impl_generics.type_param_defs().iter().enumerate().
986 map(|(i,t)| ty::mk_param(tcx, i, t.def_id)).
987 collect();
988 let dummy_method_tps: Vec<ty::t> =
989 impl_m.generics.type_param_defs().iter().enumerate().
990 map(|(i,t)| ty::mk_param(tcx, i + impl_tps, t.def_id)).
991 collect();
992 let dummy_impl_regions: OwnedSlice<ty::Region> =
993 impl_generics.region_param_defs().iter().
994 map(|l| ty::ReFree(ty::FreeRegion {
995 scope_id: impl_m_body_id,
996 bound_region: ty::BrNamed(l.def_id, l.name)})).
997 collect();
998 let dummy_substs = ty::substs {
999 tps: dummy_impl_tps.append(dummy_method_tps.as_slice()),
1000 regions: ty::NonerasedRegions(dummy_impl_regions),
1001 self_ty: None };
1002
1003 // Create a bare fn type for trait/impl
1004 // It'd be nice to refactor so as to provide the bare fn types instead.
1005 let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
1006 let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
1007
1008 // Perform substitutions so that the trait/impl methods are expressed
1009 // in terms of the same set of type/region parameters:
1010 // - replace trait type parameters with those from `trait_substs`,
1011 // except with any reference to bound self replaced with `dummy_self_r`
1012 // - replace method parameters on the trait with fresh, dummy parameters
1013 // that correspond to the parameters we will find on the impl
1014 // - replace self region with a fresh, dummy region
1015 let impl_fty = {
1016 debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
1017 impl_fty.subst(tcx, &dummy_substs)
1018 };
1019 debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
1020 let trait_fty = {
1021 let substs { regions: trait_regions,
1022 tps: trait_tps,
1023 self_ty: self_ty } = trait_substs.subst(tcx, &dummy_substs);
1024 let substs = substs {
1025 regions: trait_regions,
1026 tps: trait_tps.append(dummy_method_tps.as_slice()),
1027 self_ty: self_ty,
1028 };
1029 debug!("trait_fty (pre-subst): {} substs={}",
1030 trait_fty.repr(tcx), substs.repr(tcx));
1031 trait_fty.subst(tcx, &substs)
1032 };
1033 debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx));
1034
1035 match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span),
1036 impl_fty, trait_fty) {
1037 Ok(()) => {}
1038 Err(ref terr) => {
1039 tcx.sess.span_err(
1040 impl_m_span,
1041 format!("method `{}` has an incompatible type for trait: {}",
1042 token::get_ident(trait_m.ident),
1043 ty::type_err_to_str(tcx, terr)));
1044 ty::note_and_explain_type_err(tcx, terr);
1045 }
1046 }
1047 }
1048
1049 impl<'a> AstConv for FnCtxt<'a> {
1050 fn tcx<'a>(&'a self) -> &'a ty::ctxt { self.ccx.tcx }
1051
1052 fn get_item_ty(&self, id: ast::DefId) -> ty::ty_param_bounds_and_ty {
1053 ty::lookup_item_type(self.tcx(), id)
1054 }
1055
1056 fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef> {
1057 ty::lookup_trait_def(self.tcx(), id)
1058 }
1059
1060 fn ty_infer(&self, _span: Span) -> ty::t {
1061 self.infcx().next_ty_var()
1062 }
1063 }
1064
1065 impl<'a> FnCtxt<'a> {
1066 pub fn infcx<'b>(&'b self) -> &'b infer::InferCtxt<'a> {
1067 &self.inh.infcx
1068 }
1069
1070 pub fn err_count_since_creation(&self) -> uint {
1071 self.ccx.tcx.sess.err_count() - self.err_count_on_creation
1072 }
1073
1074 pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
1075 VtableContext {
1076 infcx: self.infcx(),
1077 param_env: &self.inh.param_env
1078 }
1079 }
1080 }
1081
1082 impl<'a> RegionScope for infer::InferCtxt<'a> {
1083 fn anon_regions(&self, span: Span, count: uint)
1084 -> Result<Vec<ty::Region> , ()> {
1085 Ok(Vec::from_fn(count, |_| {
1086 self.next_region_var(infer::MiscVariable(span))
1087 }))
1088 }
1089 }
1090
1091 impl<'a> FnCtxt<'a> {
1092 pub fn tag(&self) -> ~str {
1093 format!("{}", self as *FnCtxt)
1094 }
1095
1096 pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t {
1097 match self.inh.locals.borrow().find(&nid) {
1098 Some(&t) => t,
1099 None => {
1100 self.tcx().sess.span_bug(
1101 span,
1102 format!("no type for local variable {:?}", nid));
1103 }
1104 }
1105 }
1106
1107 #[inline]
1108 pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
1109 debug!("write_ty({}, {}) in fcx {}",
1110 node_id, ppaux::ty_to_str(self.tcx(), ty), self.tag());
1111 self.inh.node_types.borrow_mut().insert(node_id, ty);
1112 }
1113
1114 pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::substs) {
1115 if !ty::substs_is_noop(&substs) {
1116 debug!("write_substs({}, {}) in fcx {}",
1117 node_id,
1118 ty::substs_to_str(self.tcx(), &substs),
1119 self.tag());
1120
1121 self.inh.node_type_substs.borrow_mut().insert(node_id, substs);
1122 }
1123 }
1124
1125 pub fn write_ty_substs(&self,
1126 node_id: ast::NodeId,
1127 ty: ty::t,
1128 substs: ty::substs) {
1129 let ty = ty::subst(self.tcx(), &substs, ty);
1130 self.write_ty(node_id, ty);
1131 self.write_substs(node_id, substs);
1132 }
1133
1134 pub fn write_autoderef_adjustment(&self,
1135 node_id: ast::NodeId,
1136 derefs: uint) {
1137 if derefs == 0 { return; }
1138 self.write_adjustment(
1139 node_id,
1140 ty::AutoDerefRef(ty::AutoDerefRef {
1141 autoderefs: derefs,
1142 autoref: None })
1143 );
1144 }
1145
1146 pub fn write_adjustment(&self,
1147 node_id: ast::NodeId,
1148 adj: ty::AutoAdjustment) {
1149 debug!("write_adjustment(node_id={:?}, adj={:?})", node_id, adj);
1150 self.inh.adjustments.borrow_mut().insert(node_id, adj);
1151 }
1152
1153 pub fn write_nil(&self, node_id: ast::NodeId) {
1154 self.write_ty(node_id, ty::mk_nil());
1155 }
1156 pub fn write_bot(&self, node_id: ast::NodeId) {
1157 self.write_ty(node_id, ty::mk_bot());
1158 }
1159 pub fn write_error(&self, node_id: ast::NodeId) {
1160 self.write_ty(node_id, ty::mk_err());
1161 }
1162
1163 pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
1164 ast_ty_to_ty(self, self.infcx(), ast_t)
1165 }
1166
1167 pub fn pat_to_str(&self, pat: &ast::Pat) -> ~str {
1168 pat.repr(self.tcx())
1169 }
1170
1171 pub fn expr_ty(&self, ex: &ast::Expr) -> ty::t {
1172 match self.inh.node_types.borrow().find(&ex.id) {
1173 Some(&t) => t,
1174 None => {
1175 self.tcx().sess.bug(format!("no type for expr in fcx {}",
1176 self.tag()));
1177 }
1178 }
1179 }
1180
1181 pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
1182 match self.inh.node_types.borrow().find(&id) {
1183 Some(&t) => t,
1184 None => {
1185 self.tcx().sess.bug(
1186 format!("no type for node {}: {} in fcx {}",
1187 id, self.tcx().map.node_to_str(id),
1188 self.tag()));
1189 }
1190 }
1191 }
1192
1193 pub fn method_ty_substs(&self, id: ast::NodeId) -> ty::substs {
1194 match self.inh.method_map.borrow().find(&MethodCall::expr(id)) {
1195 Some(method) => method.substs.clone(),
1196 None => {
1197 self.tcx().sess.bug(
1198 format!("no method entry for node {}: {} in fcx {}",
1199 id, self.tcx().map.node_to_str(id),
1200 self.tag()));
1201 }
1202 }
1203 }
1204
1205 pub fn opt_node_ty_substs(&self,
1206 id: ast::NodeId,
1207 f: |&ty::substs|) {
1208 match self.inh.node_type_substs.borrow().find(&id) {
1209 Some(s) => { f(s) }
1210 None => { }
1211 }
1212 }
1213
1214 pub fn mk_subty(&self,
1215 a_is_expected: bool,
1216 origin: infer::TypeOrigin,
1217 sub: ty::t,
1218 sup: ty::t)
1219 -> Result<(), ty::type_err> {
1220 infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
1221 }
1222
1223 pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t)
1224 -> Result<(), ty::type_err> {
1225 infer::can_mk_subty(self.infcx(), sub, sup)
1226 }
1227
1228 pub fn mk_assignty(&self,
1229 expr: &ast::Expr,
1230 sub: ty::t,
1231 sup: ty::t)
1232 -> Result<(), ty::type_err> {
1233 match infer::mk_coercety(self.infcx(),
1234 false,
1235 infer::ExprAssignable(expr.span),
1236 sub,
1237 sup) {
1238 Ok(None) => Ok(()),
1239 Err(ref e) => Err((*e)),
1240 Ok(Some(adjustment)) => {
1241 self.write_adjustment(expr.id, adjustment);
1242 Ok(())
1243 }
1244 }
1245 }
1246
1247 pub fn mk_eqty(&self,
1248 a_is_expected: bool,
1249 origin: infer::TypeOrigin,
1250 sub: ty::t,
1251 sup: ty::t)
1252 -> Result<(), ty::type_err> {
1253 infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
1254 }
1255
1256 pub fn mk_subr(&self,
1257 a_is_expected: bool,
1258 origin: infer::SubregionOrigin,
1259 sub: ty::Region,
1260 sup: ty::Region) {
1261 infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
1262 }
1263
1264 pub fn with_region_lb<R>(&self, lb: ast::NodeId, f: || -> R) -> R {
1265 let old_region_lb = self.region_lb.get();
1266 self.region_lb.set(lb);
1267 let v = f();
1268 self.region_lb.set(old_region_lb);
1269 v
1270 }
1271
1272 pub fn type_error_message(&self,
1273 sp: Span,
1274 mk_msg: |~str| -> ~str,
1275 actual_ty: ty::t,
1276 err: Option<&ty::type_err>) {
1277 self.infcx().type_error_message(sp, mk_msg, actual_ty, err);
1278 }
1279
1280 pub fn report_mismatched_return_types(&self,
1281 sp: Span,
1282 e: ty::t,
1283 a: ty::t,
1284 err: &ty::type_err) {
1285 // Derived error
1286 if ty::type_is_error(e) || ty::type_is_error(a) {
1287 return;
1288 }
1289 self.infcx().report_mismatched_types(sp, e, a, err)
1290 }
1291
1292 pub fn report_mismatched_types(&self,
1293 sp: Span,
1294 e: ty::t,
1295 a: ty::t,
1296 err: &ty::type_err) {
1297 self.infcx().report_mismatched_types(sp, e, a, err)
1298 }
1299 }
1300
1301 pub enum LvaluePreference {
1302 PreferMutLvalue,
1303 NoPreference
1304 }
1305
1306 pub fn autoderef<T>(fcx: &FnCtxt, sp: Span, base_ty: ty::t,
1307 expr_id: Option<ast::NodeId>,
1308 mut lvalue_pref: LvaluePreference,
1309 should_stop: |ty::t, uint| -> Option<T>)
1310 -> (ty::t, uint, Option<T>) {
1311 /*!
1312 * Executes an autoderef loop for the type `t`. At each step, invokes
1313 * `should_stop` to decide whether to terminate the loop. Returns
1314 * the final type and number of derefs that it performed.
1315 *
1316 * Note: this method does not modify the adjustments table. The caller is
1317 * responsible for inserting an AutoAdjustment record into the `fcx`
1318 * using one of the suitable methods.
1319 */
1320
1321 let mut t = base_ty;
1322 for autoderefs in range(0, fcx.tcx().sess.recursion_limit.get()) {
1323 let resolved_t = structurally_resolved_type(fcx, sp, t);
1324
1325 match should_stop(resolved_t, autoderefs) {
1326 Some(x) => return (resolved_t, autoderefs, Some(x)),
1327 None => {}
1328 }
1329
1330 // Otherwise, deref if type is derefable:
1331 let mt = match ty::deref(resolved_t, false) {
1332 Some(mt) => Some(mt),
1333 None => {
1334 let method_call =
1335 expr_id.map(|id| MethodCall::autoderef(id, autoderefs as u32));
1336 try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
1337 }
1338 };
1339 match mt {
1340 Some(mt) => {
1341 t = mt.ty;
1342 if mt.mutbl == ast::MutImmutable {
1343 lvalue_pref = NoPreference;
1344 }
1345 }
1346 None => return (resolved_t, autoderefs, None)
1347 }
1348 }
1349
1350 // We've reached the recursion limit, error gracefully.
1351 fcx.tcx().sess.span_err(sp,
1352 format!("reached the recursion limit while auto-dereferencing {}",
1353 base_ty.repr(fcx.tcx())));
1354 (ty::mk_err(), 0, None)
1355 }
1356
1357 fn try_overloaded_deref(fcx: &FnCtxt,
1358 span: Span,
1359 method_call: Option<MethodCall>,
1360 base_expr: Option<&ast::Expr>,
1361 base_ty: ty::t,
1362 lvalue_pref: LvaluePreference)
1363 -> Option<ty::mt> {
1364 // Try DerefMut first, if preferred.
1365 let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
1366 (PreferMutLvalue, Some(trait_did)) => {
1367 method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
1368 token::intern("deref_mut"), trait_did,
1369 base_ty, [], DontAutoderefReceiver, IgnoreStaticMethods)
1370 }
1371 _ => None
1372 };
1373
1374 // Otherwise, fall back to Deref.
1375 let method = match (method, fcx.tcx().lang_items.deref_trait()) {
1376 (None, Some(trait_did)) => {
1377 method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
1378 token::intern("deref"), trait_did,
1379 base_ty, [], DontAutoderefReceiver, IgnoreStaticMethods)
1380 }
1381 (method, _) => method
1382 };
1383
1384 match method {
1385 Some(method) => {
1386 let ref_ty = ty::ty_fn_ret(method.ty);
1387 match method_call {
1388 Some(method_call) => {
1389 fcx.inh.method_map.borrow_mut().insert(method_call, method);
1390 }
1391 None => {}
1392 }
1393 ty::deref(ref_ty, true)
1394 }
1395 None => None
1396 }
1397 }
1398
1399 // AST fragment checking
1400 pub fn check_lit(fcx: &FnCtxt, lit: &ast::Lit) -> ty::t {
1401 let tcx = fcx.ccx.tcx;
1402
1403 match lit.node {
1404 ast::LitStr(..) => ty::mk_str_slice(tcx, ty::ReStatic, ast::MutImmutable),
1405 ast::LitBinary(..) => {
1406 ty::mk_slice(tcx, ty::ReStatic, ty::mt{ ty: ty::mk_u8(), mutbl: ast::MutImmutable })
1407 }
1408 ast::LitChar(_) => ty::mk_char(),
1409 ast::LitInt(_, t) => ty::mk_mach_int(t),
1410 ast::LitUint(_, t) => ty::mk_mach_uint(t),
1411 ast::LitIntUnsuffixed(_) => {
1412 // An unsuffixed integer literal could have any integral type,
1413 // so we create an integral type variable for it.
1414 ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())
1415 }
1416 ast::LitFloat(_, t) => ty::mk_mach_float(t),
1417 ast::LitFloatUnsuffixed(_) => {
1418 // An unsuffixed floating point literal could have any floating point
1419 // type, so we create a floating point type variable for it.
1420 ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())
1421 }
1422 ast::LitNil => ty::mk_nil(),
1423 ast::LitBool(_) => ty::mk_bool()
1424 }
1425 }
1426
1427 pub fn valid_range_bounds(ccx: &CrateCtxt,
1428 from: &ast::Expr,
1429 to: &ast::Expr)
1430 -> Option<bool> {
1431 match const_eval::compare_lit_exprs(ccx.tcx, from, to) {
1432 Some(val) => Some(val <= 0),
1433 None => None
1434 }
1435 }
1436
1437 pub fn check_expr_has_type(
1438 fcx: &FnCtxt, expr: &ast::Expr,
1439 expected: ty::t) {
1440 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1441 demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
1442 });
1443 }
1444
1445 fn check_expr_coercable_to_type(fcx: &FnCtxt, expr: &ast::Expr, expected: ty::t) {
1446 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
1447 demand::coerce(fcx, expr.span, expected, expr)
1448 });
1449 }
1450
1451 fn check_expr_with_hint(fcx: &FnCtxt, expr: &ast::Expr, expected: ty::t) {
1452 check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || ())
1453 }
1454
1455 fn check_expr_with_opt_hint(fcx: &FnCtxt, expr: &ast::Expr,
1456 expected: Option<ty::t>) {
1457 check_expr_with_unifier(fcx, expr, expected, NoPreference, || ())
1458 }
1459
1460 fn check_expr_with_opt_hint_and_lvalue_pref(fcx: &FnCtxt,
1461 expr: &ast::Expr,
1462 expected: Option<ty::t>,
1463 lvalue_pref: LvaluePreference) {
1464 check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ())
1465 }
1466
1467 fn check_expr(fcx: &FnCtxt, expr: &ast::Expr) {
1468 check_expr_with_unifier(fcx, expr, None, NoPreference, || ())
1469 }
1470
1471 fn check_expr_with_lvalue_pref(fcx: &FnCtxt, expr: &ast::Expr,
1472 lvalue_pref: LvaluePreference) {
1473 check_expr_with_unifier(fcx, expr, None, lvalue_pref, || ())
1474 }
1475
1476
1477 // determine the `self` type, using fresh variables for all variables
1478 // declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
1479 // would return ($0, $1) where $0 and $1 are freshly instantiated type
1480 // variables.
1481 pub fn impl_self_ty(vcx: &VtableContext,
1482 span: Span, // (potential) receiver for this impl
1483 did: ast::DefId)
1484 -> ty_param_substs_and_ty {
1485 let tcx = vcx.tcx();
1486
1487 let ity = ty::lookup_item_type(tcx, did);
1488 let (n_tps, rps, raw_ty) =
1489 (ity.generics.type_param_defs().len(),
1490 ity.generics.region_param_defs(),
1491 ity.ty);
1492
1493 let rps = vcx.infcx.region_vars_for_defs(span, rps);
1494 let tps = vcx.infcx.next_ty_vars(n_tps);
1495
1496 let substs = substs {
1497 regions: ty::NonerasedRegions(rps),
1498 self_ty: None,
1499 tps: tps,
1500 };
1501 let substd_ty = ty::subst(tcx, &substs, raw_ty);
1502
1503 ty_param_substs_and_ty { substs: substs, ty: substd_ty }
1504 }
1505
1506 // Only for fields! Returns <none> for methods>
1507 // Indifferent to privacy flags
1508 pub fn lookup_field_ty(tcx: &ty::ctxt,
1509 class_id: ast::DefId,
1510 items: &[ty::field_ty],
1511 fieldname: ast::Name,
1512 substs: &ty::substs) -> Option<ty::t> {
1513
1514 let o_field = items.iter().find(|f| f.name == fieldname);
1515 o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
1516 }
1517
1518 // Controls whether the arguments are automatically referenced. This is useful
1519 // for overloaded binary and unary operators.
1520 pub enum DerefArgs {
1521 DontDerefArgs,
1522 DoDerefArgs
1523 }
1524
1525 // Given the provenance of a static method, returns the generics of the static
1526 // method's container.
1527 fn generics_of_static_method_container(type_context: &ty::ctxt,
1528 provenance: ast::MethodProvenance)
1529 -> ty::Generics {
1530 match provenance {
1531 ast::FromTrait(trait_def_id) => {
1532 ty::lookup_trait_def(type_context, trait_def_id).generics.clone()
1533 }
1534 ast::FromImpl(impl_def_id) => {
1535 ty::lookup_item_type(type_context, impl_def_id).generics.clone()
1536 }
1537 }
1538 }
1539
1540 // Verifies that type parameters supplied in paths are in the right
1541 // locations.
1542 fn check_type_parameter_positions_in_path(function_context: &FnCtxt,
1543 path: &ast::Path,
1544 def: ast::Def) {
1545 // We only care about checking the case in which the path has two or
1546 // more segments.
1547 if path.segments.len() < 2 {
1548 return
1549 }
1550
1551 // Verify that no lifetimes or type parameters are present anywhere
1552 // except the final two elements of the path.
1553 for i in range(0, path.segments.len() - 2) {
1554 for lifetime in path.segments.get(i).lifetimes.iter() {
1555 function_context.tcx()
1556 .sess
1557 .span_err(lifetime.span,
1558 "lifetime parameters may not \
1559 appear here");
1560 break;
1561 }
1562
1563 for typ in path.segments.get(i).types.iter() {
1564 function_context.tcx()
1565 .sess
1566 .span_err(typ.span,
1567 "type parameters may not appear here");
1568 break;
1569 }
1570 }
1571
1572 // If there are no parameters at all, there is nothing more to do; the
1573 // rest of typechecking will (attempt to) infer everything.
1574 if path.segments
1575 .iter()
1576 .all(|s| s.lifetimes.is_empty() && s.types.is_empty()) {
1577 return
1578 }
1579
1580 match def {
1581 // If this is a static method of a trait or implementation, then
1582 // ensure that the segment of the path which names the trait or
1583 // implementation (the penultimate segment) is annotated with the
1584 // right number of type parameters.
1585 ast::DefStaticMethod(_, provenance, _) => {
1586 let generics =
1587 generics_of_static_method_container(function_context.ccx.tcx,
1588 provenance);
1589 let name = match provenance {
1590 ast::FromTrait(_) => "trait",
1591 ast::FromImpl(_) => "impl",
1592 };
1593
1594 let trait_segment = &path.segments.get(path.segments.len() - 2);
1595
1596 // Make sure lifetime parameterization agrees with the trait or
1597 // implementation type.
1598 let trait_region_parameter_count = generics.region_param_defs().len();
1599 let supplied_region_parameter_count = trait_segment.lifetimes.len();
1600 if trait_region_parameter_count != supplied_region_parameter_count
1601 && supplied_region_parameter_count != 0 {
1602 function_context.tcx()
1603 .sess
1604 .span_err(path.span,
1605 format!("expected {nexpected, plural, =1{# lifetime parameter} \
1606 other{# lifetime parameters}}, \
1607 found {nsupplied, plural, =1{# lifetime parameter} \
1608 other{# lifetime parameters}}",
1609 nexpected = trait_region_parameter_count,
1610 nsupplied = supplied_region_parameter_count));
1611 }
1612
1613 // Make sure the number of type parameters supplied on the trait
1614 // or implementation segment equals the number of type parameters
1615 // on the trait or implementation definition.
1616 let formal_ty_param_count = generics.type_param_defs().len();
1617 let required_ty_param_count = generics.type_param_defs().iter()
1618 .take_while(|x| x.default.is_none())
1619 .len();
1620 let supplied_ty_param_count = trait_segment.types.len();
1621 if supplied_ty_param_count < required_ty_param_count {
1622 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1623 format!("the {trait_or_impl} referenced by this path needs at least \
1624 {nexpected, plural, =1{# type parameter} \
1625 other{# type parameters}}, \
1626 but {nsupplied, plural, =1{# type parameter} \
1627 other{# type parameters}} were supplied",
1628 trait_or_impl = name,
1629 nexpected = required_ty_param_count,
1630 nsupplied = supplied_ty_param_count)
1631 } else {
1632 format!("the {trait_or_impl} referenced by this path needs \
1633 {nexpected, plural, =1{# type parameter} \
1634 other{# type parameters}}, \
1635 but {nsupplied, plural, =1{# type parameter} \
1636 other{# type parameters}} were supplied",
1637 trait_or_impl = name,
1638 nexpected = required_ty_param_count,
1639 nsupplied = supplied_ty_param_count)
1640 };
1641 function_context.tcx().sess.span_err(path.span, msg)
1642 } else if supplied_ty_param_count > formal_ty_param_count {
1643 let msg = if required_ty_param_count < generics.type_param_defs().len() {
1644 format!("the {trait_or_impl} referenced by this path needs at most \
1645 {nexpected, plural, =1{# type parameter} \
1646 other{# type parameters}}, \
1647 but {nsupplied, plural, =1{# type parameter} \
1648 other{# type parameters}} were supplied",
1649 trait_or_impl = name,
1650 nexpected = formal_ty_param_count,
1651 nsupplied = supplied_ty_param_count)
1652 } else {
1653 format!("the {trait_or_impl} referenced by this path needs \
1654 {nexpected, plural, =1{# type parameter} \
1655 other{# type parameters}}, \
1656 but {nsupplied, plural, =1{# type parameter} \
1657 other{# type parameters}} were supplied",
1658 trait_or_impl = name,
1659 nexpected = formal_ty_param_count,
1660 nsupplied = supplied_ty_param_count)
1661 };
1662 function_context.tcx().sess.span_err(path.span, msg)
1663 }
1664 }
1665 _ => {
1666 // Verify that no lifetimes or type parameters are present on
1667 // the penultimate segment of the path.
1668 let segment = &path.segments.get(path.segments.len() - 2);
1669 for lifetime in segment.lifetimes.iter() {
1670 function_context.tcx()
1671 .sess
1672 .span_err(lifetime.span,
1673 "lifetime parameters may not
1674 appear here");
1675 break;
1676 }
1677 for typ in segment.types.iter() {
1678 function_context.tcx()
1679 .sess
1680 .span_err(typ.span,
1681 "type parameters may not appear \
1682 here");
1683 break;
1684 }
1685 }
1686 }
1687 }
1688
1689 /// Invariant:
1690 /// If an expression has any sub-expressions that result in a type error,
1691 /// inspecting that expression's type with `ty::type_is_error` will return
1692 /// true. Likewise, if an expression is known to diverge, inspecting its
1693 /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
1694 /// strict, _|_ can appear in the type of an expression that does not,
1695 /// itself, diverge: for example, fn() -> _|_.)
1696 /// Note that inspecting a type's structure *directly* may expose the fact
1697 /// that there are actually multiple representations for both `ty_err` and
1698 /// `ty_bot`, so avoid that when err and bot need to be handled differently.
1699 fn check_expr_with_unifier(fcx: &FnCtxt,
1700 expr: &ast::Expr,
1701 expected: Option<ty::t>,
1702 lvalue_pref: LvaluePreference,
1703 unifier: ||) {
1704 debug!(">> typechecking");
1705
1706 fn check_method_argument_types(
1707 fcx: &FnCtxt,
1708 sp: Span,
1709 method_fn_ty: ty::t,
1710 callee_expr: &ast::Expr,
1711 args: &[@ast::Expr],
1712 deref_args: DerefArgs) -> ty::t {
1713 // HACK(eddyb) ignore provided self (it has special typeck rules).
1714 let args = args.slice_from(1);
1715 if ty::type_is_error(method_fn_ty) {
1716 let err_inputs = err_args(args.len());
1717 check_argument_types(fcx, sp, err_inputs.as_slice(), callee_expr,
1718 args, deref_args, false);
1719 method_fn_ty
1720 } else {
1721 match ty::get(method_fn_ty).sty {
1722 ty::ty_bare_fn(ref fty) => {
1723 // HACK(eddyb) ignore self in the definition (see above).
1724 check_argument_types(fcx, sp, fty.sig.inputs.slice_from(1),
1725 callee_expr, args, deref_args,
1726 fty.sig.variadic);
1727 fty.sig.output
1728 }
1729 _ => {
1730 fcx.tcx().sess.span_bug(
1731 callee_expr.span,
1732 format!("method without bare fn type"));
1733 }
1734 }
1735 }
1736 }
1737
1738 fn check_argument_types(fcx: &FnCtxt,
1739 sp: Span,
1740 fn_inputs: &[ty::t],
1741 callee_expr: &ast::Expr,
1742 args: &[@ast::Expr],
1743 deref_args: DerefArgs,
1744 variadic: bool) {
1745 /*!
1746 *
1747 * Generic function that factors out common logic from
1748 * function calls, method calls and overloaded operators.
1749 */
1750
1751 let tcx = fcx.ccx.tcx;
1752
1753 // Grab the argument types, supplying fresh type variables
1754 // if the wrong number of arguments were supplied
1755 let supplied_arg_count = args.len();
1756 let expected_arg_count = fn_inputs.len();
1757 let formal_tys = if expected_arg_count == supplied_arg_count {
1758 fn_inputs.iter().map(|a| *a).collect()
1759 } else if variadic {
1760 if supplied_arg_count >= expected_arg_count {
1761 fn_inputs.iter().map(|a| *a).collect()
1762 } else {
1763 let msg = format!(
1764 "this function takes at least {nexpected, plural, =1{# parameter} \
1765 other{# parameters}} \
1766 but {nsupplied, plural, =1{# parameter was} \
1767 other{# parameters were}} supplied",
1768 nexpected = expected_arg_count,
1769 nsupplied = supplied_arg_count);
1770
1771 tcx.sess.span_err(sp, msg);
1772
1773 err_args(supplied_arg_count)
1774 }
1775 } else {
1776 let msg = format!(
1777 "this function takes {nexpected, plural, =1{# parameter} \
1778 other{# parameters}} \
1779 but {nsupplied, plural, =1{# parameter was} \
1780 other{# parameters were}} supplied",
1781 nexpected = expected_arg_count,
1782 nsupplied = supplied_arg_count);
1783
1784 tcx.sess.span_err(sp, msg);
1785
1786 err_args(supplied_arg_count)
1787 };
1788
1789 debug!("check_argument_types: formal_tys={:?}",
1790 formal_tys.iter().map(|t| fcx.infcx().ty_to_str(*t)).collect::<Vec<~str>>());
1791
1792 // Check the arguments.
1793 // We do this in a pretty awful way: first we typecheck any arguments
1794 // that are not anonymous functions, then we typecheck the anonymous
1795 // functions. This is so that we have more information about the types
1796 // of arguments when we typecheck the functions. This isn't really the
1797 // right way to do this.
1798 let xs = [false, true];
1799 for check_blocks in xs.iter() {
1800 let check_blocks = *check_blocks;
1801 debug!("check_blocks={}", check_blocks);
1802
1803 // More awful hacks: before we check the blocks, try to do
1804 // an "opportunistic" vtable resolution of any trait
1805 // bounds on the call.
1806 if check_blocks {
1807 vtable::early_resolve_expr(callee_expr, fcx, true);
1808 }
1809
1810 // For variadic functions, we don't have a declared type for all of
1811 // the arguments hence we only do our usual type checking with
1812 // the arguments who's types we do know.
1813 let t = if variadic {
1814 expected_arg_count
1815 } else {
1816 supplied_arg_count
1817 };
1818 for (i, arg) in args.iter().take(t).enumerate() {
1819 let is_block = match arg.node {
1820 ast::ExprFnBlock(..) |
1821 ast::ExprProc(..) => true,
1822 _ => false
1823 };
1824
1825 if is_block == check_blocks {
1826 debug!("checking the argument");
1827 let mut formal_ty = *formal_tys.get(i);
1828
1829 match deref_args {
1830 DoDerefArgs => {
1831 match ty::get(formal_ty).sty {
1832 ty::ty_rptr(_, mt) => formal_ty = mt.ty,
1833 ty::ty_err => (),
1834 _ => {
1835 // So we hit this case when one implements the
1836 // operator traits but leaves an argument as
1837 // just T instead of &T. We'll catch it in the
1838 // mismatch impl/trait method phase no need to
1839 // ICE here.
1840 // See: #11450
1841 formal_ty = ty::mk_err();
1842 }
1843 }
1844 }
1845 DontDerefArgs => {}
1846 }
1847
1848 check_expr_coercable_to_type(fcx, *arg, formal_ty);
1849
1850 }
1851 }
1852 }
1853
1854 // We also need to make sure we at least write the ty of the other
1855 // arguments which we skipped above.
1856 if variadic {
1857 for arg in args.iter().skip(expected_arg_count) {
1858 check_expr(fcx, *arg);
1859
1860 // There are a few types which get autopromoted when passed via varargs
1861 // in C but we just error out instead and require explicit casts.
1862 let arg_ty = structurally_resolved_type(fcx, arg.span, fcx.expr_ty(*arg));
1863 match ty::get(arg_ty).sty {
1864 ty::ty_float(ast::TyF32) => {
1865 fcx.type_error_message(arg.span,
1866 |t| format!("can't pass an {} to variadic function, \
1867 cast to c_double", t), arg_ty, None);
1868 }
1869 ty::ty_int(ast::TyI8) | ty::ty_int(ast::TyI16) | ty::ty_bool => {
1870 fcx.type_error_message(arg.span,
1871 |t| format!("can't pass {} to variadic function, cast to c_int",
1872 t), arg_ty, None);
1873 }
1874 ty::ty_uint(ast::TyU8) | ty::ty_uint(ast::TyU16) => {
1875 fcx.type_error_message(arg.span,
1876 |t| format!("can't pass {} to variadic function, cast to c_uint",
1877 t), arg_ty, None);
1878 }
1879 _ => {}
1880 }
1881 }
1882 }
1883 }
1884
1885 fn err_args(len: uint) -> Vec<ty::t> {
1886 Vec::from_fn(len, |_| ty::mk_err())
1887 }
1888
1889 fn write_call(fcx: &FnCtxt, call_expr: &ast::Expr, output: ty::t) {
1890 fcx.write_ty(call_expr.id, output);
1891 }
1892
1893 // A generic function for doing all of the checking for call expressions
1894 fn check_call(fcx: &FnCtxt,
1895 call_expr: &ast::Expr,
1896 f: &ast::Expr,
1897 args: &[@ast::Expr]) {
1898 // Index expressions need to be handled separately, to inform them
1899 // that they appear in call position.
1900 check_expr(fcx, f);
1901
1902 // Store the type of `f` as the type of the callee
1903 let fn_ty = fcx.expr_ty(f);
1904
1905 // Extract the function signature from `in_fty`.
1906 let fn_sty = structure_of(fcx, f.span, fn_ty);
1907
1908 // This is the "default" function signature, used in case of error.
1909 // In that case, we check each argument against "error" in order to
1910 // set up all the node type bindings.
1911 let error_fn_sig = FnSig {
1912 binder_id: ast::CRATE_NODE_ID,
1913 inputs: err_args(args.len()),
1914 output: ty::mk_err(),
1915 variadic: false
1916 };
1917
1918 let fn_sig = match *fn_sty {
1919 ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, ..}) |
1920 ty::ty_closure(box ty::ClosureTy {sig: ref sig, ..}) => sig,
1921 _ => {
1922 fcx.type_error_message(call_expr.span, |actual| {
1923 format!("expected function but \
1924 found `{}`", actual) }, fn_ty, None);
1925 &error_fn_sig
1926 }
1927 };
1928
1929 // Replace any bound regions that appear in the function
1930 // signature with region variables
1931 let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
1932 fcx.infcx().next_region_var(infer::LateBoundRegion(call_expr.span, br))
1933 });
1934
1935 // Call the generic checker.
1936 check_argument_types(fcx, call_expr.span, fn_sig.inputs.as_slice(), f,
1937 args, DontDerefArgs, fn_sig.variadic);
1938
1939 write_call(fcx, call_expr, fn_sig.output);
1940 }
1941
1942 // Checks a method call.
1943 fn check_method_call(fcx: &FnCtxt,
1944 expr: &ast::Expr,
1945 method_name: ast::SpannedIdent,
1946 args: &[@ast::Expr],
1947 tps: &[ast::P<ast::Ty>]) {
1948 let rcvr = args[0];
1949 // We can't know if we need &mut self before we look up the method,
1950 // so treat the receiver as mutable just in case - only explicit
1951 // overloaded dereferences care about the distinction.
1952 check_expr_with_lvalue_pref(fcx, rcvr, PreferMutLvalue);
1953
1954 // no need to check for bot/err -- callee does that
1955 let expr_t = structurally_resolved_type(fcx,
1956 expr.span,
1957 fcx.expr_ty(rcvr));
1958
1959 let tps = tps.iter().map(|&ast_ty| fcx.to_ty(ast_ty)).collect::<Vec<_>>();
1960 let fn_ty = match method::lookup(fcx, expr, rcvr,
1961 method_name.node.name,
1962 expr_t, tps.as_slice(),
1963 DontDerefArgs,
1964 CheckTraitsAndInherentMethods,
1965 AutoderefReceiver, IgnoreStaticMethods) {
1966 Some(method) => {
1967 let method_ty = method.ty;
1968 let method_call = MethodCall::expr(expr.id);
1969 fcx.inh.method_map.borrow_mut().insert(method_call, method);
1970 method_ty
1971 }
1972 None => {
1973 debug!("(checking method call) failing expr is {}", expr.id);
1974
1975 fcx.type_error_message(method_name.span,
1976 |actual| {
1977 format!("type `{}` does not implement any method in scope named `{}`",
1978 actual, token::get_ident(method_name.node))
1979 },
1980 expr_t,
1981 None);
1982
1983 // Add error type for the result
1984 fcx.write_error(expr.id);
1985
1986 // Check for potential static matches (missing self parameters)
1987 method::lookup(fcx, expr, rcvr,
1988 method_name.node.name,
1989 expr_t, tps.as_slice(),
1990 DontDerefArgs,
1991 CheckTraitsAndInherentMethods,
1992 DontAutoderefReceiver, ReportStaticMethods);
1993
1994 ty::mk_err()
1995 }
1996 };
1997
1998 // Call the generic checker.
1999 let ret_ty = check_method_argument_types(fcx, method_name.span,
2000 fn_ty, expr, args,
2001 DontDerefArgs);
2002
2003 write_call(fcx, expr, ret_ty);
2004 }
2005
2006 // A generic function for checking the then and else in an if
2007 // or if-check
2008 fn check_then_else(fcx: &FnCtxt,
2009 cond_expr: &ast::Expr,
2010 then_blk: &ast::Block,
2011 opt_else_expr: Option<@ast::Expr>,
2012 id: ast::NodeId,
2013 sp: Span,
2014 expected: Option<ty::t>) {
2015 check_expr_has_type(fcx, cond_expr, ty::mk_bool());
2016
2017 let branches_ty = match opt_else_expr {
2018 Some(else_expr) => {
2019 check_block_with_expected(fcx, then_blk, expected);
2020 let then_ty = fcx.node_ty(then_blk.id);
2021 check_expr_with_opt_hint(fcx, else_expr, expected);
2022 let else_ty = fcx.expr_ty(else_expr);
2023 infer::common_supertype(fcx.infcx(),
2024 infer::IfExpression(sp),
2025 true,
2026 then_ty,
2027 else_ty)
2028 }
2029 None => {
2030 check_block_no_value(fcx, then_blk);
2031 ty::mk_nil()
2032 }
2033 };
2034
2035 let cond_ty = fcx.expr_ty(cond_expr);
2036 let if_ty = if ty::type_is_error(cond_ty) {
2037 ty::mk_err()
2038 } else if ty::type_is_bot(cond_ty) {
2039 ty::mk_bot()
2040 } else {
2041 branches_ty
2042 };
2043
2044 fcx.write_ty(id, if_ty);
2045 }
2046
2047 fn lookup_op_method(fcx: &FnCtxt,
2048 op_ex: &ast::Expr,
2049 self_t: ty::t,
2050 opname: ast::Name,
2051 trait_did: Option<ast::DefId>,
2052 args: &[@ast::Expr],
2053 autoderef_receiver: AutoderefReceiverFlag,
2054 unbound_method: ||) -> ty::t {
2055 let method = match trait_did {
2056 Some(trait_did) => {
2057 method::lookup_in_trait(fcx, op_ex.span, Some(&*args[0]), opname,
2058 trait_did, self_t, [], autoderef_receiver,
2059 IgnoreStaticMethods)
2060 }
2061 None => None
2062 };
2063 match method {
2064 Some(method) => {
2065 let method_ty = method.ty;
2066 // HACK(eddyb) Fully qualified path to work around a resolve bug.
2067 let method_call = ::middle::typeck::MethodCall::expr(op_ex.id);
2068 fcx.inh.method_map.borrow_mut().insert(method_call, method);
2069 check_method_argument_types(fcx, op_ex.span,
2070 method_ty, op_ex,
2071 args, DoDerefArgs)
2072 }
2073 None => {
2074 unbound_method();
2075 // Check the args anyway
2076 // so we get all the error messages
2077 let expected_ty = ty::mk_err();
2078 check_method_argument_types(fcx, op_ex.span,
2079 expected_ty, op_ex,
2080 args, DoDerefArgs);
2081 ty::mk_err()
2082 }
2083 }
2084 }
2085
2086 // could be either an expr_binop or an expr_assign_binop
2087 fn check_binop(fcx: &FnCtxt,
2088 expr: &ast::Expr,
2089 op: ast::BinOp,
2090 lhs: @ast::Expr,
2091 rhs: @ast::Expr,
2092 is_binop_assignment: IsBinopAssignment) {
2093 let tcx = fcx.ccx.tcx;
2094
2095 let lvalue_pref = match is_binop_assignment {
2096 BinopAssignment => PreferMutLvalue,
2097 SimpleBinop => NoPreference
2098 };
2099 check_expr_with_lvalue_pref(fcx, lhs, lvalue_pref);
2100
2101 // Callee does bot / err checking
2102 let lhs_t = structurally_resolved_type(fcx, lhs.span,
2103 fcx.expr_ty(lhs));
2104
2105 if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) {
2106 // Shift is a special case: rhs can be any integral type
2107 check_expr(fcx, rhs);
2108 let rhs_t = fcx.expr_ty(rhs);
2109 require_integral(fcx, rhs.span, rhs_t);
2110 fcx.write_ty(expr.id, lhs_t);
2111 return;
2112 }
2113
2114 if ty::is_binopable(tcx, lhs_t, op) {
2115 let tvar = fcx.infcx().next_ty_var();
2116 demand::suptype(fcx, expr.span, tvar, lhs_t);
2117 check_expr_has_type(fcx, rhs, tvar);
2118
2119 let result_t = match op {
2120 ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGe |
2121 ast::BiGt => {
2122 if ty::type_is_simd(tcx, lhs_t) {
2123 if ty::type_is_fp(ty::simd_type(tcx, lhs_t)) {
2124 fcx.type_error_message(expr.span,
2125 |actual| {
2126 format!("binary comparison operation `{}` not supported \
2127 for floating point SIMD vector `{}`",
2128 ast_util::binop_to_str(op), actual)
2129 },
2130 lhs_t,
2131 None
2132 );
2133 ty::mk_err()
2134 } else {
2135 lhs_t
2136 }
2137 } else {
2138 ty::mk_bool()
2139 }
2140 },
2141 _ => lhs_t,
2142 };
2143
2144 fcx.write_ty(expr.id, result_t);
2145 return;
2146 }
2147
2148 if op == ast::BiOr || op == ast::BiAnd {
2149 // This is an error; one of the operands must have the wrong
2150 // type
2151 fcx.write_error(expr.id);
2152 fcx.write_error(rhs.id);
2153 fcx.type_error_message(expr.span, |actual| {
2154 format!("binary operation `{}` cannot be applied \
2155 to type `{}`",
2156 ast_util::binop_to_str(op), actual)},
2157 lhs_t, None)
2158
2159 }
2160
2161 // Check for overloaded operators if not an assignment.
2162 let result_t = if is_binop_assignment == SimpleBinop {
2163 check_user_binop(fcx, expr, lhs, lhs_t, op, rhs)
2164 } else {
2165 fcx.type_error_message(expr.span,
2166 |actual| {
2167 format!("binary assignment operation \
2168 `{}=` cannot be applied to type `{}`",
2169 ast_util::binop_to_str(op),
2170 actual)
2171 },
2172 lhs_t,
2173 None);
2174 check_expr(fcx, rhs);
2175 ty::mk_err()
2176 };
2177
2178 fcx.write_ty(expr.id, result_t);
2179 if ty::type_is_error(result_t) {
2180 fcx.write_ty(rhs.id, result_t);
2181 }
2182 }
2183
2184 fn check_user_binop(fcx: &FnCtxt,
2185 ex: &ast::Expr,
2186 lhs_expr: @ast::Expr,
2187 lhs_resolved_t: ty::t,
2188 op: ast::BinOp,
2189 rhs: @ast::Expr) -> ty::t {
2190 let tcx = fcx.ccx.tcx;
2191 let lang = &tcx.lang_items;
2192 let (name, trait_did) = match op {
2193 ast::BiAdd => ("add", lang.add_trait()),
2194 ast::BiSub => ("sub", lang.sub_trait()),
2195 ast::BiMul => ("mul", lang.mul_trait()),
2196 ast::BiDiv => ("div", lang.div_trait()),
2197 ast::BiRem => ("rem", lang.rem_trait()),
2198 ast::BiBitXor => ("bitxor", lang.bitxor_trait()),
2199 ast::BiBitAnd => ("bitand", lang.bitand_trait()),
2200 ast::BiBitOr => ("bitor", lang.bitor_trait()),
2201 ast::BiShl => ("shl", lang.shl_trait()),
2202 ast::BiShr => ("shr", lang.shr_trait()),
2203 ast::BiLt => ("lt", lang.ord_trait()),
2204 ast::BiLe => ("le", lang.ord_trait()),
2205 ast::BiGe => ("ge", lang.ord_trait()),
2206 ast::BiGt => ("gt", lang.ord_trait()),
2207 ast::BiEq => ("eq", lang.eq_trait()),
2208 ast::BiNe => ("ne", lang.eq_trait()),
2209 ast::BiAnd | ast::BiOr => {
2210 check_expr(fcx, rhs);
2211 return ty::mk_err();
2212 }
2213 };
2214 lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
2215 trait_did, [lhs_expr, rhs], DontAutoderefReceiver, || {
2216 fcx.type_error_message(ex.span, |actual| {
2217 format!("binary operation `{}` cannot be applied to type `{}`",
2218 ast_util::binop_to_str(op), actual)
2219 }, lhs_resolved_t, None)
2220 })
2221 }
2222
2223 fn check_user_unop(fcx: &FnCtxt,
2224 op_str: &str,
2225 mname: &str,
2226 trait_did: Option<ast::DefId>,
2227 ex: &ast::Expr,
2228 rhs_expr: @ast::Expr,
2229 rhs_t: ty::t) -> ty::t {
2230 lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
2231 trait_did, [rhs_expr], DontAutoderefReceiver, || {
2232 fcx.type_error_message(ex.span, |actual| {
2233 format!("cannot apply unary operator `{}` to type `{}`", op_str, actual)
2234 }, rhs_t, None);
2235 })
2236 }
2237
2238 // Resolves `expected` by a single level if it is a variable and passes it
2239 // through the `unpack` function. It there is no expected type or
2240 // resolution is not possible (e.g., no constraints yet present), just
2241 // returns `none`.
2242 fn unpack_expected<O>(
2243 fcx: &FnCtxt,
2244 expected: Option<ty::t>,
2245 unpack: |&ty::sty| -> Option<O>)
2246 -> Option<O> {
2247 match expected {
2248 Some(t) => {
2249 match resolve_type(fcx.infcx(), t, force_tvar) {
2250 Ok(t) => unpack(&ty::get(t).sty),
2251 _ => None
2252 }
2253 }
2254 _ => None
2255 }
2256 }
2257
2258 fn check_expr_fn(fcx: &FnCtxt,
2259 expr: &ast::Expr,
2260 store: ty::TraitStore,
2261 decl: &ast::FnDecl,
2262 body: ast::P<ast::Block>,
2263 fn_kind: FnKind,
2264 expected: Option<ty::t>) {
2265 let tcx = fcx.ccx.tcx;
2266
2267 // Find the expected input/output types (if any). Substitute
2268 // fresh bound regions for any bound regions we find in the
2269 // expected types so as to avoid capture.
2270 let expected_sty = unpack_expected(fcx,
2271 expected,
2272 |x| Some((*x).clone()));
2273 let (expected_sig,
2274 expected_onceness,
2275 expected_bounds) = {
2276 match expected_sty {
2277 Some(ty::ty_closure(ref cenv)) => {
2278 let (_, sig) =
2279 replace_late_bound_regions_in_fn_sig(
2280 tcx, &cenv.sig,
2281 |_| fcx.inh.infcx.fresh_bound_region(expr.id));
2282 let onceness = match (&store, &cenv.store) {
2283 // As the closure type and onceness go, only three
2284 // combinations are legit:
2285 // once closure
2286 // many closure
2287 // once proc
2288 // If the actual and expected closure type disagree with
2289 // each other, set expected onceness to be always Once or
2290 // Many according to the actual type. Otherwise, it will
2291 // yield either an illegal "many proc" or a less known
2292 // "once closure" in the error message.
2293 (&ty::UniqTraitStore, &ty::UniqTraitStore) |
2294 (&ty::RegionTraitStore(..), &ty::RegionTraitStore(..)) =>
2295 cenv.onceness,
2296 (&ty::UniqTraitStore, _) => ast::Once,
2297 (&ty::RegionTraitStore(..), _) => ast::Many,
2298 };
2299 (Some(sig), onceness, cenv.bounds)
2300 }
2301 _ => {
2302 // Not an error! Means we're inferring the closure type
2303 let mut bounds = ty::EmptyBuiltinBounds();
2304 let onceness = match expr.node {
2305 ast::ExprProc(..) => {
2306 bounds.add(ty::BoundSend);
2307 ast::Once
2308 }
2309 _ => ast::Many
2310 };
2311 (None, onceness, bounds)
2312 }
2313 }
2314 };
2315
2316 // construct the function type
2317 let fn_ty = astconv::ty_of_closure(fcx,
2318 expr.id,
2319 ast::NormalFn,
2320 expected_onceness,
2321 expected_bounds,
2322 store,
2323 decl,
2324 expected_sig);
2325 let fty_sig = fn_ty.sig.clone();
2326 let fty = ty::mk_closure(tcx, fn_ty);
2327 debug!("check_expr_fn fty={}", fcx.infcx().ty_to_str(fty));
2328
2329 fcx.write_ty(expr.id, fty);
2330
2331 // If the closure is a stack closure and hasn't had some non-standard
2332 // style inferred for it, then check it under its parent's style.
2333 // Otherwise, use its own
2334 let (inherited_style, id) = match store {
2335 ty::RegionTraitStore(..) => (fcx.ps.borrow().fn_style,
2336 fcx.ps.borrow().def),
2337 ty::UniqTraitStore => (ast::NormalFn, expr.id)
2338 };
2339
2340 check_fn(fcx.ccx, inherited_style, &fty_sig,
2341 decl, id, body, fn_kind, fcx.inh);
2342 }
2343
2344
2345 // Check field access expressions
2346 fn check_field(fcx: &FnCtxt,
2347 expr: &ast::Expr,
2348 lvalue_pref: LvaluePreference,
2349 base: &ast::Expr,
2350 field: ast::Name,
2351 tys: &[ast::P<ast::Ty>]) {
2352 let tcx = fcx.ccx.tcx;
2353 check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
2354 let expr_t = structurally_resolved_type(fcx, expr.span,
2355 fcx.expr_ty(base));
2356 // FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
2357 let (_, autoderefs, field_ty) =
2358 autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
2359 match ty::get(base_t).sty {
2360 ty::ty_struct(base_id, ref substs) => {
2361 debug!("struct named {}", ppaux::ty_to_str(tcx, base_t));
2362 let fields = ty::lookup_struct_fields(tcx, base_id);
2363 lookup_field_ty(tcx, base_id, fields.as_slice(), field, &(*substs))
2364 }
2365 _ => None
2366 }
2367 });
2368 match field_ty {
2369 Some(field_ty) => {
2370 fcx.write_ty(expr.id, field_ty);
2371 fcx.write_autoderef_adjustment(base.id, autoderefs);
2372 return;
2373 }
2374 None => {}
2375 }
2376
2377 let tps: Vec<ty::t> = tys.iter().map(|&ty| fcx.to_ty(ty)).collect();
2378 match method::lookup(fcx,
2379 expr,
2380 base,
2381 field,
2382 expr_t,
2383 tps.as_slice(),
2384 DontDerefArgs,
2385 CheckTraitsAndInherentMethods,
2386 AutoderefReceiver,
2387 IgnoreStaticMethods) {
2388 Some(_) => {
2389 fcx.type_error_message(
2390 expr.span,
2391 |actual| {
2392 format!("attempted to take value of method `{}` on type `{}`",
2393 token::get_name(field), actual)
2394 },
2395 expr_t, None);
2396
2397 tcx.sess.span_note(expr.span,
2398 "maybe a missing `()` to call it? If not, try an anonymous function.");
2399 }
2400
2401 None => {
2402 fcx.type_error_message(
2403 expr.span,
2404 |actual| {
2405 format!("attempted access of field `{}` on type `{}`, \
2406 but no field with that name was found",
2407 token::get_name(field), actual)
2408 },
2409 expr_t, None);
2410 }
2411 }
2412
2413 fcx.write_error(expr.id);
2414 }
2415
2416 fn check_struct_or_variant_fields(fcx: &FnCtxt,
2417 struct_ty: ty::t,
2418 span: Span,
2419 class_id: ast::DefId,
2420 node_id: ast::NodeId,
2421 substitutions: ty::substs,
2422 field_types: &[ty::field_ty],
2423 ast_fields: &[ast::Field],
2424 check_completeness: bool) {
2425 let tcx = fcx.ccx.tcx;
2426
2427 let mut class_field_map = HashMap::new();
2428 let mut fields_found = 0;
2429 for field in field_types.iter() {
2430 class_field_map.insert(field.name, (field.id, false));
2431 }
2432
2433 let mut error_happened = false;
2434
2435 // Typecheck each field.
2436 for field in ast_fields.iter() {
2437 let mut expected_field_type = ty::mk_err();
2438
2439 let pair = class_field_map.find(&field.ident.node.name).map(|x| *x);
2440 match pair {
2441 None => {
2442 fcx.type_error_message(
2443 field.ident.span,
2444 |actual| {
2445 format!("structure `{}` has no field named `{}`",
2446 actual, token::get_ident(field.ident.node))
2447 }, struct_ty, None);
2448 error_happened = true;
2449 }
2450 Some((_, true)) => {
2451 tcx.sess.span_err(
2452 field.ident.span,
2453 format!("field `{}` specified more than once",
2454 token::get_ident(field.ident.node)));
2455 error_happened = true;
2456 }
2457 Some((field_id, false)) => {
2458 expected_field_type =
2459 ty::lookup_field_type(
2460 tcx, class_id, field_id, &substitutions);
2461 class_field_map.insert(
2462 field.ident.node.name, (field_id, true));
2463 fields_found += 1;
2464 }
2465 }
2466 // Make sure to give a type to the field even if there's
2467 // an error, so we can continue typechecking
2468 check_expr_coercable_to_type(
2469 fcx,
2470 field.expr,
2471 expected_field_type);
2472 }
2473
2474 if error_happened {
2475 fcx.write_error(node_id);
2476 }
2477
2478 if check_completeness && !error_happened {
2479 // Make sure the programmer specified all the fields.
2480 assert!(fields_found <= field_types.len());
2481 if fields_found < field_types.len() {
2482 let mut missing_fields = Vec::new();
2483 for class_field in field_types.iter() {
2484 let name = class_field.name;
2485 let (_, seen) = *class_field_map.get(&name);
2486 if !seen {
2487 missing_fields.push("`".to_owned() + token::get_name(name).get() + "`");
2488 }
2489 }
2490
2491 tcx.sess.span_err(span,
2492 format!("missing {nfields, plural, =1{field} other{fields}}: {fields}",
2493 nfields = missing_fields.len(),
2494 fields = missing_fields.connect(", ")));
2495 }
2496 }
2497
2498 if !error_happened {
2499 fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx,
2500 class_id, substitutions));
2501 }
2502 }
2503
2504 fn check_struct_constructor(fcx: &FnCtxt,
2505 id: ast::NodeId,
2506 span: codemap::Span,
2507 class_id: ast::DefId,
2508 fields: &[ast::Field],
2509 base_expr: Option<@ast::Expr>) {
2510 let tcx = fcx.ccx.tcx;
2511
2512 // Look up the number of type parameters and the raw type, and
2513 // determine whether the class is region-parameterized.
2514 let item_type = ty::lookup_item_type(tcx, class_id);
2515 let type_parameter_count = item_type.generics.type_param_defs().len();
2516 let region_param_defs = item_type.generics.region_param_defs();
2517 let raw_type = item_type.ty;
2518
2519 // Generate the struct type.
2520 let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs);
2521 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2522 let substitutions = substs {
2523 regions: ty::NonerasedRegions(regions),
2524 self_ty: None,
2525 tps: type_parameters
2526 };
2527
2528 let mut struct_type = ty::subst(tcx, &substitutions, raw_type);
2529
2530 // Look up and check the fields.
2531 let class_fields = ty::lookup_struct_fields(tcx, class_id);
2532 check_struct_or_variant_fields(fcx,
2533 struct_type,
2534 span,
2535 class_id,
2536 id,
2537 substitutions,
2538 class_fields.as_slice(),
2539 fields,
2540 base_expr.is_none());
2541 if ty::type_is_error(fcx.node_ty(id)) {
2542 struct_type = ty::mk_err();
2543 }
2544
2545 // Check the base expression if necessary.
2546 match base_expr {
2547 None => {}
2548 Some(base_expr) => {
2549 check_expr_has_type(fcx, base_expr, struct_type);
2550 if ty::type_is_bot(fcx.node_ty(base_expr.id)) {
2551 struct_type = ty::mk_bot();
2552 }
2553 }
2554 }
2555
2556 // Write in the resulting type.
2557 fcx.write_ty(id, struct_type);
2558 }
2559
2560 fn check_struct_enum_variant(fcx: &FnCtxt,
2561 id: ast::NodeId,
2562 span: codemap::Span,
2563 enum_id: ast::DefId,
2564 variant_id: ast::DefId,
2565 fields: &[ast::Field]) {
2566 let tcx = fcx.ccx.tcx;
2567
2568 // Look up the number of type parameters and the raw type, and
2569 // determine whether the enum is region-parameterized.
2570 let item_type = ty::lookup_item_type(tcx, enum_id);
2571 let type_parameter_count = item_type.generics.type_param_defs().len();
2572 let region_param_defs = item_type.generics.region_param_defs();
2573 let raw_type = item_type.ty;
2574
2575 // Generate the enum type.
2576 let regions = fcx.infcx().region_vars_for_defs(span, region_param_defs);
2577 let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count);
2578 let substitutions = substs {
2579 regions: ty::NonerasedRegions(regions),
2580 self_ty: None,
2581 tps: type_parameters
2582 };
2583
2584 let enum_type = ty::subst(tcx, &substitutions, raw_type);
2585
2586 // Look up and check the enum variant fields.
2587 let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2588 check_struct_or_variant_fields(fcx,
2589 enum_type,
2590 span,
2591 variant_id,
2592 id,
2593 substitutions,
2594 variant_fields.as_slice(),
2595 fields,
2596 true);
2597 fcx.write_ty(id, enum_type);
2598 }
2599
2600 let tcx = fcx.ccx.tcx;
2601 let id = expr.id;
2602 match expr.node {
2603 ast::ExprVstore(ev, vst) => {
2604 let typ = match ev.node {
2605 ast::ExprVec(ref args) => {
2606 let mutability = match vst {
2607 ast::ExprVstoreMutSlice => ast::MutMutable,
2608 _ => ast::MutImmutable,
2609 };
2610 let mut any_error = false;
2611 let mut any_bot = false;
2612 let t: ty::t = fcx.infcx().next_ty_var();
2613 for e in args.iter() {
2614 check_expr_has_type(fcx, *e, t);
2615 let arg_t = fcx.expr_ty(*e);
2616 if ty::type_is_error(arg_t) {
2617 any_error = true;
2618 }
2619 else if ty::type_is_bot(arg_t) {
2620 any_bot = true;
2621 }
2622 }
2623 if any_error {
2624 ty::mk_err()
2625 } else if any_bot {
2626 ty::mk_bot()
2627 } else {
2628 ast_expr_vstore_to_ty(fcx, ev, vst, ||
2629 ty::mt{ ty: ty::mk_vec(tcx,
2630 ty::mt {ty: t, mutbl: mutability},
2631 None),
2632 mutbl: mutability })
2633 }
2634 }
2635 ast::ExprRepeat(element, count_expr) => {
2636 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
2637 let _ = ty::eval_repeat_count(fcx, count_expr);
2638 let mutability = match vst {
2639 ast::ExprVstoreMutSlice => ast::MutMutable,
2640 _ => ast::MutImmutable,
2641 };
2642 let t = fcx.infcx().next_ty_var();
2643 check_expr_has_type(fcx, element, t);
2644 let arg_t = fcx.expr_ty(element);
2645 if ty::type_is_error(arg_t) {
2646 ty::mk_err()
2647 } else if ty::type_is_bot(arg_t) {
2648 ty::mk_bot()
2649 } else {
2650 ast_expr_vstore_to_ty(fcx, ev, vst, ||
2651 ty::mt{ ty: ty::mk_vec(tcx,
2652 ty::mt {ty: t, mutbl: mutability},
2653 None),
2654 mutbl: mutability})
2655 }
2656 }
2657 ast::ExprLit(_) => {
2658 let error = if vst == ast::ExprVstoreSlice {
2659 "`&\"string\"` has been removed; use `\"string\"` instead"
2660 } else {
2661 "`~\"string\"` has been removed; use `\"string\".to_owned()` instead"
2662 };
2663 tcx.sess.span_err(expr.span, error);
2664 ty::mk_err()
2665 }
2666 _ => tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence"),
2667 };
2668 fcx.write_ty(ev.id, typ);
2669 fcx.write_ty(id, typ);
2670 }
2671
2672 ast::ExprBox(place, subexpr) => {
2673 check_expr(fcx, place);
2674 check_expr(fcx, subexpr);
2675
2676 let mut checked = false;
2677 match place.node {
2678 ast::ExprPath(ref path) => {
2679 // FIXME(pcwalton): For now we hardcode the two permissible
2680 // places: the exchange heap and the managed heap.
2681 let definition = lookup_def(fcx, path.span, place.id);
2682 let def_id = ast_util::def_id_of_def(definition);
2683 match tcx.lang_items
2684 .items
2685 .get(ExchangeHeapLangItem as uint) {
2686 &Some(item_def_id) if def_id == item_def_id => {
2687 fcx.write_ty(id, ty::mk_uniq(tcx,
2688 fcx.expr_ty(subexpr)));
2689 checked = true
2690 }
2691 &Some(_) | &None => {}
2692 }
2693 if !checked {
2694 match tcx.lang_items
2695 .items
2696 .get(ManagedHeapLangItem as uint) {
2697 &Some(item_def_id) if def_id == item_def_id => {
2698 // Assign the magic `Gc<T>` struct.
2699 let gc_struct_id =
2700 match tcx.lang_items
2701 .require(GcLangItem) {
2702 Ok(id) => id,
2703 Err(msg) => {
2704 tcx.sess.span_err(expr.span, msg);
2705 ast::DefId {
2706 krate: ast::CRATE_NODE_ID,
2707 node: ast::DUMMY_NODE_ID,
2708 }
2709 }
2710 };
2711 let regions =
2712 ty::NonerasedRegions(OwnedSlice::empty());
2713 let sty = ty::mk_struct(tcx,
2714 gc_struct_id,
2715 substs {
2716 self_ty: None,
2717 tps: vec!(
2718 fcx.expr_ty(
2719 subexpr)
2720 ),
2721 regions: regions,
2722 });
2723 fcx.write_ty(id, sty);
2724 checked = true
2725 }
2726 &Some(_) | &None => {}
2727 }
2728 }
2729 }
2730 _ => {}
2731 }
2732
2733 if !checked {
2734 tcx.sess.span_err(expr.span,
2735 "only the managed heap and exchange heap are \
2736 currently supported")
2737 }
2738 }
2739
2740 ast::ExprLit(lit) => {
2741 let typ = check_lit(fcx, lit);
2742 fcx.write_ty(id, typ);
2743 }
2744 ast::ExprBinary(op, lhs, rhs) => {
2745 check_binop(fcx, expr, op, lhs, rhs, SimpleBinop);
2746
2747 let lhs_ty = fcx.expr_ty(lhs);
2748 let rhs_ty = fcx.expr_ty(rhs);
2749 if ty::type_is_error(lhs_ty) ||
2750 ty::type_is_error(rhs_ty) {
2751 fcx.write_error(id);
2752 }
2753 else if ty::type_is_bot(lhs_ty) ||
2754 (ty::type_is_bot(rhs_ty) && !ast_util::lazy_binop(op)) {
2755 fcx.write_bot(id);
2756 }
2757 }
2758 ast::ExprAssignOp(op, lhs, rhs) => {
2759 check_binop(fcx, expr, op, lhs, rhs, BinopAssignment);
2760
2761 let lhs_t = fcx.expr_ty(lhs);
2762 let result_t = fcx.expr_ty(expr);
2763 demand::suptype(fcx, expr.span, result_t, lhs_t);
2764
2765 let tcx = fcx.tcx();
2766 if !ty::expr_is_lval(tcx, lhs) {
2767 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2768 }
2769
2770 // Overwrite result of check_binop...this preserves existing behavior
2771 // but seems quite dubious with regard to user-defined methods
2772 // and so forth. - Niko
2773 if !ty::type_is_error(result_t)
2774 && !ty::type_is_bot(result_t) {
2775 fcx.write_nil(expr.id);
2776 }
2777 }
2778 ast::ExprUnary(unop, oprnd) => {
2779 let exp_inner = unpack_expected(fcx, expected, |sty| {
2780 match unop {
2781 ast::UnBox | ast::UnUniq => match *sty {
2782 ty::ty_box(ty) | ty::ty_uniq(ty) => Some(ty),
2783 _ => None
2784 },
2785 ast::UnNot | ast::UnNeg => expected,
2786 ast::UnDeref => None
2787 }
2788 });
2789 let lvalue_pref = match unop {
2790 ast::UnDeref => lvalue_pref,
2791 _ => NoPreference
2792 };
2793 check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, exp_inner, lvalue_pref);
2794 let mut oprnd_t = fcx.expr_ty(oprnd);
2795 if !ty::type_is_error(oprnd_t) && !ty::type_is_bot(oprnd_t) {
2796 match unop {
2797 ast::UnBox => {
2798 oprnd_t = ty::mk_box(tcx, oprnd_t)
2799 }
2800 ast::UnUniq => {
2801 oprnd_t = ty::mk_uniq(tcx, oprnd_t);
2802 }
2803 ast::UnDeref => {
2804 oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
2805 oprnd_t = match ty::deref(oprnd_t, true) {
2806 Some(mt) => mt.ty,
2807 None => match try_overloaded_deref(fcx, expr.span,
2808 Some(MethodCall::expr(expr.id)),
2809 Some(&*oprnd), oprnd_t, lvalue_pref) {
2810 Some(mt) => mt.ty,
2811 None => {
2812 let is_newtype = match ty::get(oprnd_t).sty {
2813 ty::ty_struct(did, ref substs) => {
2814 let fields = ty::struct_fields(fcx.tcx(), did, substs);
2815 fields.len() == 1
2816 && fields.get(0).ident ==
2817 token::special_idents::unnamed_field
2818 }
2819 _ => false
2820 };
2821 if is_newtype {
2822 // This is an obsolete struct deref
2823 tcx.sess.span_err(expr.span,
2824 "single-field tuple-structs can \
2825 no longer be dereferenced");
2826 } else {
2827 fcx.type_error_message(expr.span, |actual| {
2828 format!("type `{}` cannot be dereferenced", actual)
2829 }, oprnd_t, None);
2830 }
2831 ty::mk_err()
2832 }
2833 }
2834 };
2835 }
2836 ast::UnNot => {
2837 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2838 oprnd_t);
2839 if !(ty::type_is_integral(oprnd_t) ||
2840 ty::get(oprnd_t).sty == ty::ty_bool) {
2841 oprnd_t = check_user_unop(fcx, "!", "not",
2842 tcx.lang_items.not_trait(),
2843 expr, oprnd, oprnd_t);
2844 }
2845 }
2846 ast::UnNeg => {
2847 oprnd_t = structurally_resolved_type(fcx, oprnd.span,
2848 oprnd_t);
2849 if !(ty::type_is_integral(oprnd_t) ||
2850 ty::type_is_fp(oprnd_t)) {
2851 oprnd_t = check_user_unop(fcx, "-", "neg",
2852 tcx.lang_items.neg_trait(),
2853 expr, oprnd, oprnd_t);
2854 }
2855 }
2856 }
2857 }
2858 fcx.write_ty(id, oprnd_t);
2859 }
2860 ast::ExprAddrOf(mutbl, oprnd) => {
2861 let hint = unpack_expected(
2862 fcx, expected,
2863 |sty| match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty),
2864 _ => None });
2865 let lvalue_pref = match mutbl {
2866 ast::MutMutable => PreferMutLvalue,
2867 ast::MutImmutable => NoPreference
2868 };
2869 check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, hint, lvalue_pref);
2870
2871 // Note: at this point, we cannot say what the best lifetime
2872 // is to use for resulting pointer. We want to use the
2873 // shortest lifetime possible so as to avoid spurious borrowck
2874 // errors. Moreover, the longest lifetime will depend on the
2875 // precise details of the value whose address is being taken
2876 // (and how long it is valid), which we don't know yet until type
2877 // inference is complete.
2878 //
2879 // Therefore, here we simply generate a region variable. The
2880 // region inferencer will then select the ultimate value.
2881 // Finally, borrowck is charged with guaranteeing that the
2882 // value whose address was taken can actually be made to live
2883 // as long as it needs to live.
2884 let region = fcx.infcx().next_region_var(
2885 infer::AddrOfRegion(expr.span));
2886
2887 let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
2888 let oprnd_t = if ty::type_is_error(tm.ty) {
2889 ty::mk_err()
2890 } else if ty::type_is_bot(tm.ty) {
2891 ty::mk_bot()
2892 }
2893 else {
2894 ty::mk_rptr(tcx, region, tm)
2895 };
2896 fcx.write_ty(id, oprnd_t);
2897 }
2898 ast::ExprPath(ref pth) => {
2899 let defn = lookup_def(fcx, pth.span, id);
2900
2901 check_type_parameter_positions_in_path(fcx, pth, defn);
2902 let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2903 instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
2904 }
2905 ast::ExprInlineAsm(ref ia) => {
2906 for &(_, input) in ia.inputs.iter() {
2907 check_expr(fcx, input);
2908 }
2909 for &(_, out) in ia.outputs.iter() {
2910 check_expr(fcx, out);
2911 }
2912 fcx.write_nil(id);
2913 }
2914 ast::ExprMac(_) => tcx.sess.bug("unexpanded macro"),
2915 ast::ExprBreak(_) => { fcx.write_bot(id); }
2916 ast::ExprAgain(_) => { fcx.write_bot(id); }
2917 ast::ExprRet(expr_opt) => {
2918 let ret_ty = fcx.ret_ty;
2919 match expr_opt {
2920 None => match fcx.mk_eqty(false, infer::Misc(expr.span),
2921 ret_ty, ty::mk_nil()) {
2922 Ok(_) => { /* fall through */ }
2923 Err(_) => {
2924 tcx.sess.span_err(
2925 expr.span,
2926 "`return;` in function returning non-nil");
2927 }
2928 },
2929 Some(e) => {
2930 check_expr_has_type(fcx, e, ret_ty);
2931 }
2932 }
2933 fcx.write_bot(id);
2934 }
2935 ast::ExprParen(a) => {
2936 check_expr_with_opt_hint_and_lvalue_pref(fcx, a, expected, lvalue_pref);
2937 fcx.write_ty(id, fcx.expr_ty(a));
2938 }
2939 ast::ExprAssign(lhs, rhs) => {
2940 check_expr_with_lvalue_pref(fcx, lhs, PreferMutLvalue);
2941
2942 let tcx = fcx.tcx();
2943 if !ty::expr_is_lval(tcx, lhs) {
2944 tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
2945 }
2946
2947 let lhs_ty = fcx.expr_ty(lhs);
2948 check_expr_has_type(fcx, rhs, lhs_ty);
2949 let rhs_ty = fcx.expr_ty(rhs);
2950
2951 if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
2952 fcx.write_error(id);
2953 } else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
2954 fcx.write_bot(id);
2955 } else {
2956 fcx.write_nil(id);
2957 }
2958 }
2959 ast::ExprIf(cond, then_blk, opt_else_expr) => {
2960 check_then_else(fcx, cond, then_blk, opt_else_expr,
2961 id, expr.span, expected);
2962 }
2963 ast::ExprWhile(cond, body) => {
2964 check_expr_has_type(fcx, cond, ty::mk_bool());
2965 check_block_no_value(fcx, body);
2966 let cond_ty = fcx.expr_ty(cond);
2967 let body_ty = fcx.node_ty(body.id);
2968 if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) {
2969 fcx.write_error(id);
2970 }
2971 else if ty::type_is_bot(cond_ty) {
2972 fcx.write_bot(id);
2973 }
2974 else {
2975 fcx.write_nil(id);
2976 }
2977 }
2978 ast::ExprForLoop(..) =>
2979 fail!("non-desugared expr_for_loop"),
2980 ast::ExprLoop(body, _) => {
2981 check_block_no_value(fcx, (body));
2982 if !may_break(tcx, expr.id, body) {
2983 fcx.write_bot(id);
2984 }
2985 else {
2986 fcx.write_nil(id);
2987 }
2988 }
2989 ast::ExprMatch(discrim, ref arms) => {
2990 _match::check_match(fcx, expr, discrim, arms.as_slice());
2991 }
2992 ast::ExprFnBlock(decl, body) => {
2993 let region = astconv::opt_ast_region_to_region(fcx,
2994 fcx.infcx(),
2995 expr.span,
2996 &None);
2997 check_expr_fn(fcx,
2998 expr,
2999 ty::RegionTraitStore(region, ast::MutMutable),
3000 decl,
3001 body,
3002 Vanilla,
3003 expected);
3004 }
3005 ast::ExprProc(decl, body) => {
3006 check_expr_fn(fcx,
3007 expr,
3008 ty::UniqTraitStore,
3009 decl,
3010 body,
3011 Vanilla,
3012 expected);
3013 }
3014 ast::ExprBlock(b) => {
3015 check_block_with_expected(fcx, b, expected);
3016 fcx.write_ty(id, fcx.node_ty(b.id));
3017 }
3018 ast::ExprCall(f, ref args) => {
3019 check_call(fcx, expr, f, args.as_slice());
3020 let f_ty = fcx.expr_ty(f);
3021 let (args_bot, args_err) = args.iter().fold((false, false),
3022 |(rest_bot, rest_err), a| {
3023 // is this not working?
3024 let a_ty = fcx.expr_ty(*a);
3025 (rest_bot || ty::type_is_bot(a_ty),
3026 rest_err || ty::type_is_error(a_ty))});
3027 if ty::type_is_error(f_ty) || args_err {
3028 fcx.write_error(id);
3029 }
3030 else if ty::type_is_bot(f_ty) || args_bot {
3031 fcx.write_bot(id);
3032 }
3033 }
3034 ast::ExprMethodCall(ident, ref tps, ref args) => {
3035 check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice());
3036 let mut arg_tys = args.iter().map(|a| fcx.expr_ty(*a));
3037 let (args_bot, args_err) = arg_tys.fold((false, false),
3038 |(rest_bot, rest_err), a| {
3039 (rest_bot || ty::type_is_bot(a),
3040 rest_err || ty::type_is_error(a))});
3041 if args_err {
3042 fcx.write_error(id);
3043 } else if args_bot {
3044 fcx.write_bot(id);
3045 }
3046 }
3047 ast::ExprCast(e, t) => {
3048 check_expr(fcx, e);
3049 let t_1 = fcx.to_ty(t);
3050 let t_e = fcx.expr_ty(e);
3051
3052 debug!("t_1={}", fcx.infcx().ty_to_str(t_1));
3053 debug!("t_e={}", fcx.infcx().ty_to_str(t_e));
3054
3055 if ty::type_is_error(t_e) {
3056 fcx.write_error(id);
3057 }
3058 else if ty::type_is_bot(t_e) {
3059 fcx.write_bot(id);
3060 }
3061 else {
3062 match ty::get(t_1).sty {
3063 // This will be looked up later on
3064 ty::ty_trait(..) => (),
3065
3066 _ => {
3067 if ty::type_is_nil(t_e) {
3068 fcx.type_error_message(expr.span, |actual| {
3069 format!("cast from nil: `{}` as `{}`", actual,
3070 fcx.infcx().ty_to_str(t_1))
3071 }, t_e, None);
3072 } else if ty::type_is_nil(t_1) {
3073 fcx.type_error_message(expr.span, |actual| {
3074 format!("cast to nil: `{}` as `{}`", actual,
3075 fcx.infcx().ty_to_str(t_1))
3076 }, t_e, None);
3077 }
3078
3079 let t1 = structurally_resolved_type(fcx, e.span, t_1);
3080 let te = structurally_resolved_type(fcx, e.span, t_e);
3081 let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
3082 let t_1_is_char = type_is_char(fcx, expr.span, t_1);
3083 let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1);
3084
3085 // casts to scalars other than `char` and `bare fn` are trivial
3086 let t_1_is_trivial = t_1_is_scalar &&
3087 !t_1_is_char && !t_1_is_bare_fn;
3088
3089 if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial {
3090 // casts from C-like enums are allowed
3091 } else if t_1_is_char {
3092 let te = fcx.infcx().resolve_type_vars_if_possible(te);
3093 if ty::get(te).sty != ty::ty_uint(ast::TyU8) {
3094 fcx.type_error_message(expr.span, |actual| {
3095 format!("only `u8` can be cast as `char`, not `{}`", actual)
3096 }, t_e, None);
3097 }
3098 } else if ty::get(t1).sty == ty::ty_bool {
3099 fcx.tcx().sess.span_err(expr.span,
3100 "cannot cast as `bool`, compare with zero instead");
3101 } else if type_is_region_ptr(fcx, expr.span, t_e) &&
3102 type_is_unsafe_ptr(fcx, expr.span, t_1) {
3103
3104 fn is_vec(t: ty::t) -> bool {
3105 match ty::get(t).sty {
3106 ty::ty_vec(..) => true,
3107 ty::ty_ptr(ty::mt{ty: t, ..}) | ty::ty_rptr(_, ty::mt{ty: t, ..}) |
3108 ty::ty_box(t) | ty::ty_uniq(t) => match ty::get(t).sty {
3109 ty::ty_vec(_, None) => true,
3110 _ => false,
3111 },
3112 _ => false
3113 }
3114 }
3115 fn types_compatible(fcx: &FnCtxt, sp: Span,
3116 t1: ty::t, t2: ty::t) -> bool {
3117 if !is_vec(t1) {
3118 false
3119 } else {
3120 let el = ty::sequence_element_type(fcx.tcx(),
3121 t1);
3122 infer::mk_eqty(fcx.infcx(), false,
3123 infer::Misc(sp), el, t2).is_ok()
3124 }
3125 }
3126
3127 // Due to the limitations of LLVM global constants,
3128 // region pointers end up pointing at copies of
3129 // vector elements instead of the original values.
3130 // To allow unsafe pointers to work correctly, we
3131 // need to special-case obtaining an unsafe pointer
3132 // from a region pointer to a vector.
3133
3134 /* this cast is only allowed from &[T] to *T or
3135 &T to *T. */
3136 match (&ty::get(te).sty, &ty::get(t_1).sty) {
3137 (&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
3138 if types_compatible(fcx, e.span,
3139 mt1.ty, mt2.ty) => {
3140 /* this case is allowed */
3141 }
3142 _ => {
3143 demand::coerce(fcx, e.span, t_1, e);
3144 }
3145 }
3146 } else if !(type_is_scalar(fcx,expr.span,t_e)
3147 && t_1_is_trivial) {
3148 /*
3149 If more type combinations should be supported than are
3150 supported here, then file an enhancement issue and
3151 record the issue number in this comment.
3152 */
3153 fcx.type_error_message(expr.span, |actual| {
3154 format!("non-scalar cast: `{}` as `{}`", actual,
3155 fcx.infcx().ty_to_str(t_1))
3156 }, t_e, None);
3157 }
3158 }
3159 }
3160 fcx.write_ty(id, t_1);
3161 }
3162 }
3163 ast::ExprVec(ref args) => {
3164 let t: ty::t = fcx.infcx().next_ty_var();
3165 for e in args.iter() {
3166 check_expr_has_type(fcx, *e, t);
3167 }
3168 let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable},
3169 Some(args.len()));
3170 fcx.write_ty(id, typ);
3171 }
3172 ast::ExprRepeat(element, count_expr) => {
3173 check_expr_with_hint(fcx, count_expr, ty::mk_uint());
3174 let count = ty::eval_repeat_count(fcx, count_expr);
3175 let t: ty::t = fcx.infcx().next_ty_var();
3176 check_expr_has_type(fcx, element, t);
3177 let element_ty = fcx.expr_ty(element);
3178 if ty::type_is_error(element_ty) {
3179 fcx.write_error(id);
3180 }
3181 else if ty::type_is_bot(element_ty) {
3182 fcx.write_bot(id);
3183 }
3184 else {
3185 let t = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable},
3186 Some(count));
3187 fcx.write_ty(id, t);
3188 }
3189 }
3190 ast::ExprTup(ref elts) => {
3191 let flds = unpack_expected(fcx, expected, |sty| {
3192 match *sty {
3193 ty::ty_tup(ref flds) => Some((*flds).clone()),
3194 _ => None
3195 }
3196 });
3197 let mut bot_field = false;
3198 let mut err_field = false;
3199
3200 let elt_ts = elts.iter().enumerate().map(|(i, e)| {
3201 let opt_hint = match flds {
3202 Some(ref fs) if i < fs.len() => Some(*fs.get(i)),
3203 _ => None
3204 };
3205 check_expr_with_opt_hint(fcx, *e, opt_hint);
3206 let t = fcx.expr_ty(*e);
3207 err_field = err_field || ty::type_is_error(t);
3208 bot_field = bot_field || ty::type_is_bot(t);
3209 t
3210 }).collect();
3211 if bot_field {
3212 fcx.write_bot(id);
3213 } else if err_field {
3214 fcx.write_error(id);
3215 } else {
3216 let typ = ty::mk_tup(tcx, elt_ts);
3217 fcx.write_ty(id, typ);
3218 }
3219 }
3220 ast::ExprStruct(ref path, ref fields, base_expr) => {
3221 // Resolve the path.
3222 let def = tcx.def_map.borrow().find(&id).map(|i| *i);
3223 match def {
3224 Some(ast::DefStruct(type_def_id)) => {
3225 check_struct_constructor(fcx, id, expr.span, type_def_id,
3226 fields.as_slice(), base_expr);
3227 }
3228 Some(ast::DefVariant(enum_id, variant_id, _)) => {
3229 check_struct_enum_variant(fcx, id, expr.span, enum_id,
3230 variant_id, fields.as_slice());
3231 }
3232 _ => {
3233 tcx.sess.span_bug(path.span,
3234 "structure constructor does not name a structure type");
3235 }
3236 }
3237 }
3238 ast::ExprField(base, field, ref tys) => {
3239 check_field(fcx, expr, lvalue_pref, base, field.name, tys.as_slice());
3240 }
3241 ast::ExprIndex(base, idx) => {
3242 check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
3243 check_expr(fcx, idx);
3244 let raw_base_t = fcx.expr_ty(base);
3245 let idx_t = fcx.expr_ty(idx);
3246 if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
3247 fcx.write_ty(id, raw_base_t);
3248 } else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
3249 fcx.write_ty(id, idx_t);
3250 } else {
3251 let (base_t, autoderefs, field_ty) =
3252 autoderef(fcx, expr.span, raw_base_t, Some(base.id),
3253 lvalue_pref, |base_t, _| ty::index(base_t));
3254 match field_ty {
3255 Some(mt) => {
3256 check_expr_has_type(fcx, idx, ty::mk_uint());
3257 fcx.write_ty(id, mt.ty);
3258 fcx.write_autoderef_adjustment(base.id, autoderefs);
3259 }
3260 None => {
3261 let resolved = structurally_resolved_type(fcx,
3262 expr.span,
3263 raw_base_t);
3264 let ret_ty = lookup_op_method(fcx,
3265 expr,
3266 resolved,
3267 token::intern("index"),
3268 tcx.lang_items.index_trait(),
3269 [base, idx],
3270 AutoderefReceiver,
3271 || {
3272 fcx.type_error_message(expr.span,
3273 |actual| {
3274 format!("cannot index a value \
3275 of type `{}`",
3276 actual)
3277 },
3278 base_t,
3279 None);
3280 });
3281 fcx.write_ty(id, ret_ty);
3282 }
3283 }
3284 }
3285 }
3286 }
3287
3288 debug!("type of expr({}) {} is...", expr.id,
3289 syntax::print::pprust::expr_to_str(expr));
3290 debug!("... {}, expected is {}",
3291 ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
3292 match expected {
3293 Some(t) => ppaux::ty_to_str(tcx, t),
3294 _ => "empty".to_owned()
3295 });
3296
3297 unifier();
3298 }
3299
3300 pub fn require_uint(fcx: &FnCtxt, sp: Span, t: ty::t) {
3301 if !type_is_uint(fcx, sp, t) {
3302 fcx.type_error_message(sp, |actual| {
3303 format!("mismatched types: expected `uint` type but found `{}`",
3304 actual)
3305 }, t, None);
3306 }
3307 }
3308
3309 pub fn require_integral(fcx: &FnCtxt, sp: Span, t: ty::t) {
3310 if !type_is_integral(fcx, sp, t) {
3311 fcx.type_error_message(sp, |actual| {
3312 format!("mismatched types: expected integral type but found `{}`",
3313 actual)
3314 }, t, None);
3315 }
3316 }
3317
3318 pub fn check_decl_initializer(fcx: &FnCtxt,
3319 nid: ast::NodeId,
3320 init: &ast::Expr)
3321 {
3322 let local_ty = fcx.local_ty(init.span, nid);
3323 check_expr_coercable_to_type(fcx, init, local_ty)
3324 }
3325
3326 pub fn check_decl_local(fcx: &FnCtxt, local: &ast::Local) {
3327 let tcx = fcx.ccx.tcx;
3328
3329 let t = fcx.local_ty(local.span, local.id);
3330 fcx.write_ty(local.id, t);
3331
3332 match local.init {
3333 Some(init) => {
3334 check_decl_initializer(fcx, local.id, init);
3335 let init_ty = fcx.expr_ty(init);
3336 if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
3337 fcx.write_ty(local.id, init_ty);
3338 }
3339 }
3340 _ => {}
3341 }
3342
3343 let pcx = pat_ctxt {
3344 fcx: fcx,
3345 map: pat_id_map(&tcx.def_map, local.pat),
3346 };
3347 _match::check_pat(&pcx, local.pat, t);
3348 let pat_ty = fcx.node_ty(local.pat.id);
3349 if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
3350 fcx.write_ty(local.id, pat_ty);
3351 }
3352 }
3353
3354 pub fn check_stmt(fcx: &FnCtxt, stmt: &ast::Stmt) {
3355 let node_id;
3356 let mut saw_bot = false;
3357 let mut saw_err = false;
3358 match stmt.node {
3359 ast::StmtDecl(decl, id) => {
3360 node_id = id;
3361 match decl.node {
3362 ast::DeclLocal(ref l) => {
3363 check_decl_local(fcx, *l);
3364 let l_t = fcx.node_ty(l.id);
3365 saw_bot = saw_bot || ty::type_is_bot(l_t);
3366 saw_err = saw_err || ty::type_is_error(l_t);
3367 }
3368 ast::DeclItem(_) => {/* ignore for now */ }
3369 }
3370 }
3371 ast::StmtExpr(expr, id) => {
3372 node_id = id;
3373 // Check with expected type of ()
3374 check_expr_has_type(fcx, expr, ty::mk_nil());
3375 let expr_ty = fcx.expr_ty(expr);
3376 saw_bot = saw_bot || ty::type_is_bot(expr_ty);
3377 saw_err = saw_err || ty::type_is_error(expr_ty);
3378 }
3379 ast::StmtSemi(expr, id) => {
3380 node_id = id;
3381 check_expr(fcx, expr);
3382 let expr_ty = fcx.expr_ty(expr);
3383 saw_bot |= ty::type_is_bot(expr_ty);
3384 saw_err |= ty::type_is_error(expr_ty);
3385 }
3386 ast::StmtMac(..) => fcx.ccx.tcx.sess.bug("unexpanded macro")
3387 }
3388 if saw_bot {
3389 fcx.write_bot(node_id);
3390 }
3391 else if saw_err {
3392 fcx.write_error(node_id);
3393 }
3394 else {
3395 fcx.write_nil(node_id)
3396 }
3397 }
3398
3399 pub fn check_block_no_value(fcx: &FnCtxt, blk: &ast::Block) {
3400 check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
3401 let blkty = fcx.node_ty(blk.id);
3402 if ty::type_is_error(blkty) {
3403 fcx.write_error(blk.id);
3404 }
3405 else if ty::type_is_bot(blkty) {
3406 fcx.write_bot(blk.id);
3407 }
3408 else {
3409 let nilty = ty::mk_nil();
3410 demand::suptype(fcx, blk.span, nilty, blkty);
3411 }
3412 }
3413
3414 pub fn check_block_with_expected(fcx: &FnCtxt,
3415 blk: &ast::Block,
3416 expected: Option<ty::t>) {
3417 let prev = {
3418 let mut fcx_ps = fcx.ps.borrow_mut();
3419 let fn_style_state = fcx_ps.recurse(blk);
3420 replace(&mut *fcx_ps, fn_style_state)
3421 };
3422
3423 fcx.with_region_lb(blk.id, || {
3424 let mut warned = false;
3425 let mut last_was_bot = false;
3426 let mut any_bot = false;
3427 let mut any_err = false;
3428 for s in blk.stmts.iter() {
3429 check_stmt(fcx, *s);
3430 let s_id = ast_util::stmt_id(*s);
3431 let s_ty = fcx.node_ty(s_id);
3432 if last_was_bot && !warned && match s.node {
3433 ast::StmtDecl(decl, _) => {
3434 match decl.node {
3435 ast::DeclLocal(_) => true,
3436 _ => false,
3437 }
3438 }
3439 ast::StmtExpr(_, _) | ast::StmtSemi(_, _) => true,
3440 _ => false
3441 } {
3442 fcx.ccx.tcx.sess.add_lint(UnreachableCode, s_id, s.span,
3443 "unreachable statement".to_owned());
3444 warned = true;
3445 }
3446 if ty::type_is_bot(s_ty) {
3447 last_was_bot = true;
3448 }
3449 any_bot = any_bot || ty::type_is_bot(s_ty);
3450 any_err = any_err || ty::type_is_error(s_ty);
3451 }
3452 match blk.expr {
3453 None => if any_err {
3454 fcx.write_error(blk.id);
3455 }
3456 else if any_bot {
3457 fcx.write_bot(blk.id);
3458 }
3459 else {
3460 fcx.write_nil(blk.id);
3461 },
3462 Some(e) => {
3463 if any_bot && !warned {
3464 fcx.ccx.tcx.sess.add_lint(UnreachableCode, e.id, e.span,
3465 "unreachable expression".to_owned());
3466 }
3467 check_expr_with_opt_hint(fcx, e, expected);
3468 let ety = fcx.expr_ty(e);
3469 fcx.write_ty(blk.id, ety);
3470 if any_err {
3471 fcx.write_error(blk.id);
3472 }
3473 else if any_bot {
3474 fcx.write_bot(blk.id);
3475 }
3476 }
3477 };
3478 });
3479
3480 *fcx.ps.borrow_mut() = prev;
3481 }
3482
3483 pub fn check_const(ccx: &CrateCtxt,
3484 sp: Span,
3485 e: &ast::Expr,
3486 id: ast::NodeId) {
3487 let inh = blank_inherited_fields(ccx);
3488 let rty = ty::node_id_to_type(ccx.tcx, id);
3489 let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
3490 let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty;
3491 check_const_with_ty(&fcx, sp, e, declty);
3492 }
3493
3494 pub fn check_const_with_ty(fcx: &FnCtxt,
3495 _: Span,
3496 e: &ast::Expr,
3497 declty: ty::t) {
3498 check_expr(fcx, e);
3499 let cty = fcx.expr_ty(e);
3500 demand::suptype(fcx, e.span, declty, cty);
3501 regionck::regionck_expr(fcx, e);
3502 writeback::resolve_type_vars_in_expr(fcx, e);
3503 }
3504
3505 /// Checks whether a type can be represented in memory. In particular, it
3506 /// identifies types that contain themselves without indirection through a
3507 /// pointer, which would mean their size is unbounded. This is different from
3508 /// the question of whether a type can be instantiated. See the definition of
3509 /// `check_instantiable`.
3510 pub fn check_representable(tcx: &ty::ctxt,
3511 sp: Span,
3512 item_id: ast::NodeId,
3513 designation: &str) -> bool {
3514 let rty = ty::node_id_to_type(tcx, item_id);
3515
3516 // Check that it is possible to represent this type. This call identifies
3517 // (1) types that contain themselves and (2) types that contain a different
3518 // recursive type. It is only necessary to throw an error on those that
3519 // contain themselves. For case 2, there must be an inner type that will be
3520 // caught by case 1.
3521 match ty::is_type_representable(tcx, sp, rty) {
3522 ty::SelfRecursive => {
3523 tcx.sess.span_err(
3524 sp, format!("illegal recursive {} type; \
3525 wrap the inner value in a box to make it representable",
3526 designation));
3527 return false
3528 }
3529 ty::Representable | ty::ContainsRecursive => (),
3530 }
3531 return true
3532 }
3533
3534 /// Checks whether a type can be created without an instance of itself.
3535 /// This is similar but different from the question of whether a type
3536 /// can be represented. For example, the following type:
3537 ///
3538 /// enum foo { None, Some(foo) }
3539 ///
3540 /// is instantiable but is not representable. Similarly, the type
3541 ///
3542 /// enum foo { Some(@foo) }
3543 ///
3544 /// is representable, but not instantiable.
3545 pub fn check_instantiable(tcx: &ty::ctxt,
3546 sp: Span,
3547 item_id: ast::NodeId)
3548 -> bool {
3549 let item_ty = ty::node_id_to_type(tcx, item_id);
3550 if !ty::is_instantiable(tcx, item_ty) {
3551 tcx.sess.span_err(sp, format!("this type cannot be instantiated \
3552 without an instance of itself; \
3553 consider using `Option<{}>`",
3554 ppaux::ty_to_str(tcx, item_ty)));
3555 false
3556 } else {
3557 true
3558 }
3559 }
3560
3561 pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
3562 let t = ty::node_id_to_type(tcx, id);
3563 if ty::type_needs_subst(t) {
3564 tcx.sess.span_err(sp, "SIMD vector cannot be generic");
3565 return;
3566 }
3567 match ty::get(t).sty {
3568 ty::ty_struct(did, ref substs) => {
3569 let fields = ty::lookup_struct_fields(tcx, did);
3570 if fields.is_empty() {
3571 tcx.sess.span_err(sp, "SIMD vector cannot be empty");
3572 return;
3573 }
3574 let e = ty::lookup_field_type(tcx, did, fields.get(0).id, substs);
3575 if !fields.iter().all(
3576 |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) {
3577 tcx.sess.span_err(sp, "SIMD vector should be homogeneous");
3578 return;
3579 }
3580 if !ty::type_is_machine(e) {
3581 tcx.sess.span_err(sp, "SIMD vector element type should be \
3582 machine type");
3583 return;
3584 }
3585 }
3586 _ => ()
3587 }
3588 }
3589
3590 pub fn check_enum_variants_sized(ccx: &CrateCtxt,
3591 vs: &[ast::P<ast::Variant>]) {
3592 for &v in vs.iter() {
3593 match v.node.kind {
3594 ast::TupleVariantKind(ref args) if args.len() > 0 => {
3595 let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id);
3596 let arg_tys: Vec<ty::t> = ty::ty_fn_args(ctor_ty).iter().map(|a| *a).collect();
3597 let len = arg_tys.len();
3598 if len == 0 {
3599 return;
3600 }
3601 for (i, t) in arg_tys.slice_to(len - 1).iter().enumerate() {
3602 // Allow the last field in an enum to be unsized.
3603 // We want to do this so that we can support smart pointers.
3604 // A struct value with an unsized final field is itself
3605 // unsized and we must track this in the type system.
3606 if !ty::type_is_sized(ccx.tcx, *t) {
3607 ccx.tcx.sess.span_err(args.get(i).ty.span,
3608 format!("type `{}` is dynamically sized. \
3609 dynamically sized types may only \
3610 appear as the final type in a variant",
3611 ppaux::ty_to_str(ccx.tcx, *t)));
3612 }
3613 }
3614 },
3615 ast::StructVariantKind(struct_def) => check_fields_sized(ccx.tcx, struct_def),
3616 _ => {}
3617 }
3618 }
3619 }
3620
3621 pub fn check_enum_variants(ccx: &CrateCtxt,
3622 sp: Span,
3623 vs: &[ast::P<ast::Variant>],
3624 id: ast::NodeId) {
3625
3626 fn disr_in_range(ccx: &CrateCtxt,
3627 ty: attr::IntType,
3628 disr: ty::Disr) -> bool {
3629 fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
3630 match ty {
3631 ast::TyU8 => disr as u8 as Disr == disr,
3632 ast::TyU16 => disr as u16 as Disr == disr,
3633 ast::TyU32 => disr as u32 as Disr == disr,
3634 ast::TyU64 => disr as u64 as Disr == disr,
3635 ast::TyU => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
3636 }
3637 }
3638 fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
3639 match ty {
3640 ast::TyI8 => disr as i8 as Disr == disr,
3641 ast::TyI16 => disr as i16 as Disr == disr,
3642 ast::TyI32 => disr as i32 as Disr == disr,
3643 ast::TyI64 => disr as i64 as Disr == disr,
3644 ast::TyI => int_in_range(ccx, ccx.tcx.sess.targ_cfg.int_type, disr)
3645 }
3646 }
3647 match ty {
3648 attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
3649 attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
3650 }
3651 }
3652
3653 fn do_check(ccx: &CrateCtxt,
3654 vs: &[ast::P<ast::Variant>],
3655 id: ast::NodeId,
3656 hint: attr::ReprAttr)
3657 -> Vec<Rc<ty::VariantInfo>> {
3658
3659 let rty = ty::node_id_to_type(ccx.tcx, id);
3660 let mut variants: Vec<Rc<ty::VariantInfo>> = Vec::new();
3661 let mut disr_vals: Vec<ty::Disr> = Vec::new();
3662 let mut prev_disr_val: Option<ty::Disr> = None;
3663
3664 for &v in vs.iter() {
3665
3666 // If the discriminant value is specified explicitly in the enum check whether the
3667 // initialization expression is valid, otherwise use the last value plus one.
3668 let mut current_disr_val = match prev_disr_val {
3669 Some(prev_disr_val) => prev_disr_val + 1,
3670 None => ty::INITIAL_DISCRIMINANT_VALUE
3671 };
3672
3673 match v.node.disr_expr {
3674 Some(e) => {
3675 debug!("disr expr, checking {}", pprust::expr_to_str(e));
3676
3677 let inh = blank_inherited_fields(ccx);
3678 let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
3679 let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
3680 check_const_with_ty(&fcx, e.span, e, declty);
3681 // check_expr (from check_const pass) doesn't guarantee
3682 // that the expression is in a form that eval_const_expr can
3683 // handle, so we may still get an internal compiler error
3684
3685 match const_eval::eval_const_expr_partial(ccx.tcx, e) {
3686 Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
3687 Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
3688 Ok(_) => {
3689 ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
3690 }
3691 Err(ref err) => {
3692 ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", *err));
3693 }
3694 }
3695 },
3696 None => ()
3697 };
3698
3699 // Check for duplicate discriminant values
3700 if disr_vals.contains(¤t_disr_val) {
3701 ccx.tcx.sess.span_err(v.span, "discriminant value already exists");
3702 }
3703 // Check for unrepresentable discriminant values
3704 match hint {
3705 attr::ReprAny | attr::ReprExtern => (),
3706 attr::ReprInt(sp, ity) => {
3707 if !disr_in_range(ccx, ity, current_disr_val) {
3708 ccx.tcx.sess.span_err(v.span,
3709 "discriminant value outside specified type");
3710 ccx.tcx.sess.span_note(sp, "discriminant type specified here");
3711 }
3712 }
3713 }
3714 disr_vals.push(current_disr_val);
3715
3716 let variant_info = Rc::new(VariantInfo::from_ast_variant(ccx.tcx, v,
3717 current_disr_val));
3718 prev_disr_val = Some(current_disr_val);
3719
3720 variants.push(variant_info);
3721 }
3722
3723 return variants;
3724 }
3725
3726 let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id });
3727 if hint != attr::ReprAny && vs.len() <= 1 {
3728 let msg = if vs.len() == 1 {
3729 "unsupported representation for univariant enum"
3730 } else {
3731 "unsupported representation for zero-variant enum"
3732 };
3733 ccx.tcx.sess.span_err(sp, msg)
3734 }
3735
3736 let variants = do_check(ccx, vs, id, hint);
3737
3738 // cache so that ty::enum_variants won't repeat this work
3739 ccx.tcx.enum_var_cache.borrow_mut().insert(local_def(id), Rc::new(variants));
3740
3741 check_representable(ccx.tcx, sp, id, "enum");
3742
3743 // Check that it is possible to instantiate this enum:
3744 //
3745 // This *sounds* like the same that as representable, but it's
3746 // not. See def'n of `check_instantiable()` for details.
3747 check_instantiable(ccx.tcx, sp, id);
3748 }
3749
3750 pub fn lookup_def(fcx: &FnCtxt, sp: Span, id: ast::NodeId) -> ast::Def {
3751 lookup_def_ccx(fcx.ccx, sp, id)
3752 }
3753
3754 // Returns the type parameter count and the type for the given definition.
3755 pub fn ty_param_bounds_and_ty_for_def(fcx: &FnCtxt,
3756 sp: Span,
3757 defn: ast::Def)
3758 -> ty_param_bounds_and_ty {
3759 match defn {
3760 ast::DefArg(nid, _) | ast::DefLocal(nid, _) |
3761 ast::DefBinding(nid, _) => {
3762 let typ = fcx.local_ty(sp, nid);
3763 return no_params(typ);
3764 }
3765 ast::DefFn(id, _) | ast::DefStaticMethod(id, _, _) |
3766 ast::DefStatic(id, _) | ast::DefVariant(_, id, _) |
3767 ast::DefStruct(id) => {
3768 return ty::lookup_item_type(fcx.ccx.tcx, id);
3769 }
3770 ast::DefUpvar(_, inner, _, _) => {
3771 return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
3772 }
3773 ast::DefTrait(_) |
3774 ast::DefTy(_) |
3775 ast::DefPrimTy(_) |
3776 ast::DefTyParam(..)=> {
3777 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type");
3778 }
3779 ast::DefMod(..) | ast::DefForeignMod(..) => {
3780 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module");
3781 }
3782 ast::DefUse(..) => {
3783 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use");
3784 }
3785 ast::DefRegion(..) => {
3786 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region");
3787 }
3788 ast::DefTyParamBinder(..) => {
3789 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter");
3790 }
3791 ast::DefLabel(..) => {
3792 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label");
3793 }
3794 ast::DefSelfTy(..) => {
3795 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty");
3796 }
3797 ast::DefMethod(..) => {
3798 fcx.ccx.tcx.sess.span_bug(sp, "expected value but found method");
3799 }
3800 }
3801 }
3802
3803 // Instantiates the given path, which must refer to an item with the given
3804 // number of type parameters and type.
3805 pub fn instantiate_path(fcx: &FnCtxt,
3806 pth: &ast::Path,
3807 tpt: ty_param_bounds_and_ty,
3808 def: ast::Def,
3809 span: Span,
3810 node_id: ast::NodeId) {
3811 debug!(">>> instantiate_path");
3812
3813 let ty_param_count = tpt.generics.type_param_defs().len();
3814 let ty_param_req = tpt.generics.type_param_defs().iter()
3815 .take_while(|x| x.default.is_none())
3816 .len();
3817 let mut ty_substs_len = 0;
3818 for segment in pth.segments.iter() {
3819 ty_substs_len += segment.types.len()
3820 }
3821
3822 debug!("tpt={} ty_param_count={:?} ty_substs_len={:?}",
3823 tpt.repr(fcx.tcx()),
3824 ty_param_count,
3825 ty_substs_len);
3826
3827 // determine the region parameters, using the value given by the user
3828 // (if any) and otherwise using a fresh region variable
3829 let num_expected_regions = tpt.generics.region_param_defs().len();
3830 let num_supplied_regions = pth.segments.last().unwrap().lifetimes.len();
3831 let regions = if num_expected_regions == num_supplied_regions {
3832 OwnedSlice::from_vec(pth.segments.last().unwrap().lifetimes.iter().map(
3833 |l| ast_region_to_region(fcx.tcx(), l)).collect())
3834 } else {
3835 if num_supplied_regions != 0 {
3836 fcx.ccx.tcx.sess.span_err(
3837 span,
3838 format!("expected {nexpected, plural, =1{# lifetime parameter} \
3839 other{# lifetime parameters}}, \
3840 found {nsupplied, plural, =1{# lifetime parameter} \
3841 other{# lifetime parameters}}",
3842 nexpected = num_expected_regions,
3843 nsupplied = num_supplied_regions));
3844 }
3845
3846 fcx.infcx().region_vars_for_defs(span, tpt.generics.region_param_defs.as_slice())
3847 };
3848 let regions = ty::NonerasedRegions(regions);
3849
3850 // Special case: If there is a self parameter, omit it from the list of
3851 // type parameters.
3852 //
3853 // Here we calculate the "user type parameter count", which is the number
3854 // of type parameters actually manifest in the AST. This will differ from
3855 // the internal type parameter count when there are self types involved.
3856 let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def {
3857 ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
3858 let generics = generics_of_static_method_container(fcx.ccx.tcx,
3859 provenance);
3860 (ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs().len()))
3861 }
3862 _ => (ty_param_count, ty_param_req, None),
3863 };
3864
3865 // determine values for type parameters, using the values given by
3866 // the user (if any) and otherwise using fresh type variables
3867 let (tps, regions) = if ty_substs_len == 0 {
3868 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3869 } else if ty_param_count == 0 {
3870 fcx.ccx.tcx.sess.span_err
3871 (span, "this item does not take type parameters");
3872 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3873 } else if ty_substs_len > user_ty_param_count {
3874 let expected = if user_ty_param_req < user_ty_param_count {
3875 "expected at most"
3876 } else {
3877 "expected"
3878 };
3879 fcx.ccx.tcx.sess.span_err
3880 (span,
3881 format!("too many type parameters provided: {} {}, found {}",
3882 expected, user_ty_param_count, ty_substs_len));
3883 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3884 } else if ty_substs_len < user_ty_param_req {
3885 let expected = if user_ty_param_req < user_ty_param_count {
3886 "expected at least"
3887 } else {
3888 "expected"
3889 };
3890 fcx.ccx.tcx.sess.span_err
3891 (span,
3892 format!("not enough type parameters provided: {} {}, found {}",
3893 expected, user_ty_param_req, ty_substs_len));
3894 (fcx.infcx().next_ty_vars(ty_param_count), regions)
3895 } else {
3896 if ty_substs_len > user_ty_param_req
3897 && !fcx.tcx().sess.features.default_type_params.get() {
3898 fcx.tcx().sess.span_err(pth.span, "default type parameters are \
3899 experimental and possibly buggy");
3900 fcx.tcx().sess.span_note(pth.span, "add #![feature(default_type_params)] \
3901 to the crate attributes to enable");
3902 }
3903
3904 // Build up the list of type parameters, inserting the self parameter
3905 // at the appropriate position.
3906 let mut tps = Vec::new();
3907 let mut pushed = false;
3908 for (i, ty) in pth.segments.iter()
3909 .flat_map(|segment| segment.types.iter())
3910 .map(|&ast_type| fcx.to_ty(ast_type))
3911 .enumerate() {
3912 match self_parameter_index {
3913 Some(index) if index == i => {
3914 tps.push(*fcx.infcx().next_ty_vars(1).get(0));
3915 pushed = true;
3916 }
3917 _ => {}
3918 }
3919 tps.push(ty)
3920 }
3921
3922 let mut substs = substs {
3923 regions: regions,
3924 self_ty: None,
3925 tps: tps
3926 };
3927
3928 let defaults = tpt.generics.type_param_defs().iter()
3929 .enumerate().filter_map(|(i, x)| {
3930 match self_parameter_index {
3931 Some(index) if index == i => None,
3932 _ => Some(x.default)
3933 }
3934 });
3935 for (i, default) in defaults.skip(ty_substs_len).enumerate() {
3936 match self_parameter_index {
3937 Some(index) if index == i + ty_substs_len => {
3938 substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0));
3939 pushed = true;
3940 }
3941 _ => {}
3942 }
3943 match default {
3944 Some(default) => {
3945 let ty = default.subst_spanned(fcx.tcx(), &substs, Some(span));
3946 substs.tps.push(ty);
3947 }
3948 None => {
3949 fcx.tcx().sess.span_bug(span,
3950 "missing default for a not explicitely provided type param")
3951 }
3952 }
3953 }
3954
3955 // If the self parameter goes at the end, insert it there.
3956 if !pushed && self_parameter_index.is_some() {
3957 substs.tps.push(*fcx.infcx().next_ty_vars(1).get(0))
3958 }
3959
3960 assert_eq!(substs.tps.len(), ty_param_count)
3961
3962 let substs {tps, regions, ..} = substs;
3963 (tps, regions)
3964 };
3965
3966 fcx.write_ty_substs(node_id, tpt.ty, substs {
3967 regions: regions,
3968 self_ty: None,
3969 tps: tps
3970 });
3971
3972 debug!("<<<");
3973 }
3974
3975 // Resolves `typ` by a single level if `typ` is a type variable. If no
3976 // resolution is possible, then an error is reported.
3977 pub fn structurally_resolved_type(fcx: &FnCtxt, sp: Span, tp: ty::t) -> ty::t {
3978 match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
3979 Ok(t_s) if !ty::type_is_ty_var(t_s) => t_s,
3980 _ => {
3981 fcx.type_error_message(sp, |_actual| {
3982 "the type of this value must be known in this context".to_owned()
3983 }, tp, None);
3984 demand::suptype(fcx, sp, ty::mk_err(), tp);
3985 tp
3986 }
3987 }
3988 }
3989
3990 // Returns the one-level-deep structure of the given type.
3991 pub fn structure_of<'a>(fcx: &FnCtxt, sp: Span, typ: ty::t)
3992 -> &'a ty::sty {
3993 &ty::get(structurally_resolved_type(fcx, sp, typ)).sty
3994 }
3995
3996 pub fn type_is_integral(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
3997 let typ_s = structurally_resolved_type(fcx, sp, typ);
3998 return ty::type_is_integral(typ_s);
3999 }
4000
4001 pub fn type_is_uint(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4002 let typ_s = structurally_resolved_type(fcx, sp, typ);
4003 return ty::type_is_uint(typ_s);
4004 }
4005
4006 pub fn type_is_scalar(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4007 let typ_s = structurally_resolved_type(fcx, sp, typ);
4008 return ty::type_is_scalar(typ_s);
4009 }
4010
4011 pub fn type_is_char(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4012 let typ_s = structurally_resolved_type(fcx, sp, typ);
4013 return ty::type_is_char(typ_s);
4014 }
4015
4016 pub fn type_is_bare_fn(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4017 let typ_s = structurally_resolved_type(fcx, sp, typ);
4018 return ty::type_is_bare_fn(typ_s);
4019 }
4020
4021 pub fn type_is_unsafe_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4022 let typ_s = structurally_resolved_type(fcx, sp, typ);
4023 return ty::type_is_unsafe_ptr(typ_s);
4024 }
4025
4026 pub fn type_is_region_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4027 let typ_s = structurally_resolved_type(fcx, sp, typ);
4028 return ty::type_is_region_ptr(typ_s);
4029 }
4030
4031 pub fn type_is_c_like_enum(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4032 let typ_s = structurally_resolved_type(fcx, sp, typ);
4033 return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
4034 }
4035
4036 pub fn ast_expr_vstore_to_ty(fcx: &FnCtxt,
4037 e: &ast::Expr,
4038 v: ast::ExprVstore,
4039 mk_inner: || -> ty::mt)
4040 -> ty::t {
4041 match v {
4042 ast::ExprVstoreUniq => ty::mk_uniq(fcx.ccx.tcx, mk_inner().ty),
4043 ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => {
4044 match e.node {
4045 ast::ExprLit(..) => {
4046 // string literals and *empty slices* live in static memory
4047 ty::mk_rptr(fcx.ccx.tcx, ty::ReStatic, mk_inner())
4048 }
4049 ast::ExprVec(ref elements) if elements.len() == 0 => {
4050 // string literals and *empty slices* live in static memory
4051 ty::mk_rptr(fcx.ccx.tcx, ty::ReStatic, mk_inner())
4052 }
4053 ast::ExprRepeat(..) |
4054 ast::ExprVec(..) => {
4055 // vector literals are temporaries on the stack
4056 match fcx.tcx().region_maps.temporary_scope(e.id) {
4057 Some(scope) => ty::mk_rptr(fcx.ccx.tcx, ty::ReScope(scope), mk_inner()),
4058 None => ty::mk_rptr(fcx.ccx.tcx, ty::ReStatic, mk_inner()),
4059 }
4060 }
4061 _ => {
4062 fcx.ccx.tcx.sess.span_bug(
4063 e.span, format!("vstore with unexpected contents"))
4064 }
4065 }
4066 }
4067 }
4068 }
4069
4070 // Returns true if b contains a break that can exit from b
4071 pub fn may_break(cx: &ty::ctxt, id: ast::NodeId, b: ast::P<ast::Block>) -> bool {
4072 // First: is there an unlabeled break immediately
4073 // inside the loop?
4074 (loop_query(b, |e| {
4075 match *e {
4076 ast::ExprBreak(_) => true,
4077 _ => false
4078 }
4079 })) ||
4080 // Second: is there a labeled break with label
4081 // <id> nested anywhere inside the loop?
4082 (block_query(b, |e| {
4083 match e.node {
4084 ast::ExprBreak(Some(_)) => {
4085 match cx.def_map.borrow().find(&e.id) {
4086 Some(&ast::DefLabel(loop_id)) if id == loop_id => true,
4087 _ => false,
4088 }
4089 }
4090 _ => false
4091 }}))
4092 }
4093
4094 pub fn check_bounds_are_used(ccx: &CrateCtxt,
4095 span: Span,
4096 tps: &OwnedSlice<ast::TyParam>,
4097 ty: ty::t) {
4098 debug!("check_bounds_are_used(n_tps={}, ty={})",
4099 tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
4100
4101 // make a vector of booleans initially false, set to true when used
4102 if tps.len() == 0u { return; }
4103 let mut tps_used = Vec::from_elem(tps.len(), false);
4104
4105 ty::walk_ty(ty, |t| {
4106 match ty::get(t).sty {
4107 ty::ty_param(param_ty {idx, ..}) => {
4108 debug!("Found use of ty param \\#{}", idx);
4109 *tps_used.get_mut(idx) = true;
4110 }
4111 _ => ()
4112 }
4113 });
4114
4115 for (i, b) in tps_used.iter().enumerate() {
4116 if !*b {
4117 ccx.tcx.sess.span_err(
4118 span, format!("type parameter `{}` is unused",
4119 token::get_ident(tps.get(i).ident)));
4120 }
4121 }
4122 }
4123
4124 pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
4125 fn param(ccx: &CrateCtxt, n: uint) -> ty::t {
4126 ty::mk_param(ccx.tcx, n, local_def(0))
4127 }
4128
4129 let tcx = ccx.tcx;
4130 let name = token::get_ident(it.ident);
4131 let (n_tps, inputs, output) = if name.get().starts_with("atomic_") {
4132 let split : Vec<&str> = name.get().split('_').collect();
4133 assert!(split.len() >= 2, "Atomic intrinsic not correct format");
4134
4135 //We only care about the operation here
4136 match *split.get(1) {
4137 "cxchg" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)),
4138 param(ccx, 0),
4139 param(ccx, 0)),
4140 param(ccx, 0)),
4141 "load" => (1, vec!(ty::mk_imm_ptr(tcx, param(ccx, 0))),
4142 param(ccx, 0)),
4143 "store" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)),
4144 ty::mk_nil()),
4145
4146 "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
4147 "min" | "umax" | "umin" => {
4148 (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)),
4149 param(ccx, 0))
4150 }
4151 "fence" => {
4152 (0, Vec::new(), ty::mk_nil())
4153 }
4154 op => {
4155 tcx.sess.span_err(it.span,
4156 format!("unrecognized atomic operation function: `{}`",
4157 op));
4158 return;
4159 }
4160 }
4161
4162 } else {
4163 match name.get() {
4164 "abort" => (0, Vec::new(), ty::mk_bot()),
4165 "breakpoint" => (0, Vec::new(), ty::mk_nil()),
4166 "size_of" |
4167 "pref_align_of" | "min_align_of" => (1u, Vec::new(), ty::mk_uint()),
4168 "init" => (1u, Vec::new(), param(ccx, 0u)),
4169 "uninit" => (1u, Vec::new(), param(ccx, 0u)),
4170 "forget" => (1u, vec!( param(ccx, 0) ), ty::mk_nil()),
4171 "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)),
4172 "move_val_init" => {
4173 (1u,
4174 vec!(
4175 ty::mk_mut_rptr(tcx, ty::ReLateBound(it.id, ty::BrAnon(0)), param(ccx, 0)),
4176 param(ccx, 0u)
4177 ),
4178 ty::mk_nil())
4179 }
4180 "needs_drop" => (1u, Vec::new(), ty::mk_bool()),
4181 "owns_managed" => (1u, Vec::new(), ty::mk_bool()),
4182
4183 "get_tydesc" => {
4184 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4185 Ok(t) => t,
4186 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4187 };
4188 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4189 ty: tydesc_ty,
4190 mutbl: ast::MutImmutable
4191 });
4192 (1u, Vec::new(), td_ptr)
4193 }
4194 "type_id" => {
4195 let langid = ccx.tcx.lang_items.require(TypeIdLangItem);
4196 match langid {
4197 Ok(did) => (1u, Vec::new(), ty::mk_struct(ccx.tcx, did, substs {
4198 self_ty: None,
4199 tps: Vec::new(),
4200 regions: ty::NonerasedRegions(OwnedSlice::empty())
4201 }) ),
4202 Err(msg) => { tcx.sess.span_fatal(it.span, msg); }
4203 }
4204 },
4205 "visit_tydesc" => {
4206 let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
4207 Ok(t) => t,
4208 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4209 };
4210 let region = ty::ReLateBound(it.id, ty::BrAnon(0));
4211 let visitor_object_ty = match ty::visitor_object_ty(tcx, region) {
4212 Ok((_, vot)) => vot,
4213 Err(s) => { tcx.sess.span_fatal(it.span, s); }
4214 };
4215
4216 let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {
4217 ty: tydesc_ty,
4218 mutbl: ast::MutImmutable
4219 });
4220 (0, vec!( td_ptr, visitor_object_ty ), ty::mk_nil())
4221 }
4222 "offset" => {
4223 (1,
4224 vec!(
4225 ty::mk_ptr(tcx, ty::mt {
4226 ty: param(ccx, 0),
4227 mutbl: ast::MutImmutable
4228 }),
4229 ty::mk_int()
4230 ),
4231 ty::mk_ptr(tcx, ty::mt {
4232 ty: param(ccx, 0),
4233 mutbl: ast::MutImmutable
4234 }))
4235 }
4236 "copy_memory" | "copy_nonoverlapping_memory" |
4237 "volatile_copy_memory" | "volatile_copy_nonoverlapping_memory" => {
4238 (1,
4239 vec!(
4240 ty::mk_ptr(tcx, ty::mt {
4241 ty: param(ccx, 0),
4242 mutbl: ast::MutMutable
4243 }),
4244 ty::mk_ptr(tcx, ty::mt {
4245 ty: param(ccx, 0),
4246 mutbl: ast::MutImmutable
4247 }),
4248 ty::mk_uint()
4249 ),
4250 ty::mk_nil())
4251 }
4252 "set_memory" | "volatile_set_memory" => {
4253 (1,
4254 vec!(
4255 ty::mk_ptr(tcx, ty::mt {
4256 ty: param(ccx, 0),
4257 mutbl: ast::MutMutable
4258 }),
4259 ty::mk_u8(),
4260 ty::mk_uint()
4261 ),
4262 ty::mk_nil())
4263 }
4264 "sqrtf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4265 "sqrtf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4266 "powif32" => {
4267 (0,
4268 vec!( ty::mk_f32(), ty::mk_i32() ),
4269 ty::mk_f32())
4270 }
4271 "powif64" => {
4272 (0,
4273 vec!( ty::mk_f64(), ty::mk_i32() ),
4274 ty::mk_f64())
4275 }
4276 "sinf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4277 "sinf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4278 "cosf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4279 "cosf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4280 "powf32" => {
4281 (0,
4282 vec!( ty::mk_f32(), ty::mk_f32() ),
4283 ty::mk_f32())
4284 }
4285 "powf64" => {
4286 (0,
4287 vec!( ty::mk_f64(), ty::mk_f64() ),
4288 ty::mk_f64())
4289 }
4290 "expf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4291 "expf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4292 "exp2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4293 "exp2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4294 "logf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4295 "logf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4296 "log10f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4297 "log10f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4298 "log2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4299 "log2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4300 "fmaf32" => {
4301 (0,
4302 vec!( ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ),
4303 ty::mk_f32())
4304 }
4305 "fmaf64" => {
4306 (0,
4307 vec!( ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ),
4308 ty::mk_f64())
4309 }
4310 "fabsf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4311 "fabsf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4312 "copysignf32" => (0, vec!( ty::mk_f32(), ty::mk_f32() ), ty::mk_f32()),
4313 "copysignf64" => (0, vec!( ty::mk_f64(), ty::mk_f64() ), ty::mk_f64()),
4314 "floorf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4315 "floorf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4316 "ceilf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4317 "ceilf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4318 "truncf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4319 "truncf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4320 "rintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4321 "rintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4322 "nearbyintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4323 "nearbyintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4324 "roundf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()),
4325 "roundf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()),
4326 "ctpop8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()),
4327 "ctpop16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4328 "ctpop32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4329 "ctpop64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4330 "ctlz8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()),
4331 "ctlz16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4332 "ctlz32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4333 "ctlz64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4334 "cttz8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()),
4335 "cttz16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4336 "cttz32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4337 "cttz64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4338 "bswap16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()),
4339 "bswap32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()),
4340 "bswap64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()),
4341
4342 "volatile_load" =>
4343 (1, vec!( ty::mk_imm_ptr(tcx, param(ccx, 0)) ), param(ccx, 0)),
4344 "volatile_store" =>
4345 (1, vec!( ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ), ty::mk_nil()),
4346
4347 "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
4348 (0, vec!(ty::mk_i8(), ty::mk_i8()),
4349 ty::mk_tup(tcx, vec!(ty::mk_i8(), ty::mk_bool()))),
4350
4351 "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
4352 (0, vec!(ty::mk_i16(), ty::mk_i16()),
4353 ty::mk_tup(tcx, vec!(ty::mk_i16(), ty::mk_bool()))),
4354
4355 "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
4356 (0, vec!(ty::mk_i32(), ty::mk_i32()),
4357 ty::mk_tup(tcx, vec!(ty::mk_i32(), ty::mk_bool()))),
4358
4359 "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
4360 (0, vec!(ty::mk_i64(), ty::mk_i64()),
4361 ty::mk_tup(tcx, vec!(ty::mk_i64(), ty::mk_bool()))),
4362
4363 "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
4364 (0, vec!(ty::mk_u8(), ty::mk_u8()),
4365 ty::mk_tup(tcx, vec!(ty::mk_u8(), ty::mk_bool()))),
4366
4367 "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
4368 (0, vec!(ty::mk_u16(), ty::mk_u16()),
4369 ty::mk_tup(tcx, vec!(ty::mk_u16(), ty::mk_bool()))),
4370
4371 "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
4372 (0, vec!(ty::mk_u32(), ty::mk_u32()),
4373 ty::mk_tup(tcx, vec!(ty::mk_u32(), ty::mk_bool()))),
4374
4375 "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" =>
4376 (0, vec!(ty::mk_u64(), ty::mk_u64()),
4377 ty::mk_tup(tcx, vec!(ty::mk_u64(), ty::mk_bool()))),
4378
4379 ref other => {
4380 tcx.sess.span_err(it.span,
4381 format!("unrecognized intrinsic function: `{}`",
4382 *other));
4383 return;
4384 }
4385 }
4386 };
4387 let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
4388 fn_style: ast::UnsafeFn,
4389 abi: abi::RustIntrinsic,
4390 sig: FnSig {binder_id: it.id,
4391 inputs: inputs,
4392 output: output,
4393 variadic: false}
4394 });
4395 let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id));
4396 let i_n_tps = i_ty.generics.type_param_defs().len();
4397 if i_n_tps != n_tps {
4398 tcx.sess.span_err(it.span, format!("intrinsic has wrong number \
4399 of type parameters: found {}, \
4400 expected {}", i_n_tps, n_tps));
4401 } else {
4402 require_same_types(
4403 tcx, None, false, it.span, i_ty.ty, fty,
4404 || format!("intrinsic has wrong type: \
4405 expected `{}`",
4406 ppaux::ty_to_str(ccx.tcx, fty)));
4407 }
4408 }
librustc/middle/typeck/check/mod.rs:1466:1-1466:1 -fn- definition:
fn check_expr(fcx: &FnCtxt, expr: &ast::Expr) {
check_expr_with_unifier(fcx, expr, None, NoPreference, || ())
}
references:- 141899: // that they appear in call position.
1900: check_expr(fcx, f);
--
3497: declty: ty::t) {
3498: check_expr(fcx, e);
3499: let cty = fcx.expr_ty(e);
librustc/middle/typeck/check/_match.rs:
75: }
76: check_expr(fcx, arm.body);
77: let bty = fcx.node_ty(arm.body.id);
librustc/middle/typeck/check/mod.rs:
1857: for arg in args.iter().skip(expected_arg_count) {
1858: check_expr(fcx, *arg);
librustc/middle/typeck/check/mod.rs:2416:4-2416:4 -fn- definition:
fn check_struct_or_variant_fields(fcx: &FnCtxt,
struct_ty: ty::t,
span: Span,
references:- 22587: let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
2588: check_struct_or_variant_fields(fcx,
2589: enum_type,
librustc/middle/typeck/check/mod.rs:1470:1-1470:1 -fn- definition:
fn check_expr_with_lvalue_pref(fcx: &FnCtxt, expr: &ast::Expr,
lvalue_pref: LvaluePreference) {
check_expr_with_unifier(fcx, expr, None, lvalue_pref, || ())
references:- 52939: ast::ExprAssign(lhs, rhs) => {
2940: check_expr_with_lvalue_pref(fcx, lhs, PreferMutLvalue);
--
3241: ast::ExprIndex(base, idx) => {
3242: check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
3243: check_expr(fcx, idx);
librustc/middle/typeck/check/mod.rs:1356:1-1356:1 -fn- definition:
fn try_overloaded_deref(fcx: &FnCtxt,
span: Span,
method_call: Option<MethodCall>,
references:- 21335: expr_id.map(|id| MethodCall::autoderef(id, autoderefs as u32));
1336: try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
1337: }
--
2806: Some(mt) => mt.ty,
2807: None => match try_overloaded_deref(fcx, expr.span,
2808: Some(MethodCall::expr(expr.id)),
librustc/middle/typeck/check/mod.rs:344:1-344:1 -fn- definition:
fn check_bare_fn(ccx: &CrateCtxt,
decl: &ast::FnDecl,
body: &ast::Block,
references:- 2668: check_bare_fn(ccx, decl, body, it.id, fn_tpt.ty, param_env);
669: }
--
780: check_bare_fn(ccx, method.decl, method.body, method.id, fty, param_env);
781: }
librustc/middle/typeck/check/mod.rs:3976:54-3976:54 -fn- definition:
// resolution is possible, then an error is reported.
pub fn structurally_resolved_type(fcx: &FnCtxt, sp: Span, tp: ty::t) -> ty::t {
match infer::resolve_type(fcx.infcx(), tp, force_tvar) {
references:- 212101: // Callee does bot / err checking
2102: let lhs_t = structurally_resolved_type(fcx, lhs.span,
2103: fcx.expr_ty(lhs));
--
4011: pub fn type_is_char(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4012: let typ_s = structurally_resolved_type(fcx, sp, typ);
4013: return ty::type_is_char(typ_s);
--
4016: pub fn type_is_bare_fn(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4017: let typ_s = structurally_resolved_type(fcx, sp, typ);
4018: return ty::type_is_bare_fn(typ_s);
--
4026: pub fn type_is_region_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4027: let typ_s = structurally_resolved_type(fcx, sp, typ);
4028: return ty::type_is_region_ptr(typ_s);
--
4031: pub fn type_is_c_like_enum(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
4032: let typ_s = structurally_resolved_type(fcx, sp, typ);
4033: return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
librustc/middle/typeck/check/vtable.rs:
546: // e.g.: `&x as &Trait` or `box x as Box<Trait>`
547: let ty = structurally_resolved_type(fcx, ex.span,
548: fcx.expr_ty(src));
librustc/middle/typeck/check/mod.rs:
3079: let t1 = structurally_resolved_type(fcx, e.span, t_1);
3080: let te = structurally_resolved_type(fcx, e.span, t_e);
3081: let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
librustc/middle/typeck/check/mod.rs:2223:4-2223:4 -fn- definition:
fn check_user_unop(fcx: &FnCtxt,
op_str: &str,
mname: &str,
references:- 22850: ty::type_is_fp(oprnd_t)) {
2851: oprnd_t = check_user_unop(fcx, "-", "neg",
2852: tcx.lang_items.neg_trait(),
librustc/middle/typeck/check/mod.rs:171:19-171:19 -enum- definition:
pub enum FnKind {
// A do-closure.
DoBlock,
references:- 5172: pub enum FnKind {
--
254: // function return type.
255: fn_kind: FnKind,
--
2262: body: ast::P<ast::Block>,
2263: fn_kind: FnKind,
2264: expected: Option<ty::t>) {
librustc/middle/typeck/check/mod.rs:2047:4-2047:4 -fn- definition:
fn lookup_op_method(fcx: &FnCtxt,
op_ex: &ast::Expr,
self_t: ty::t,
references:- 32229: rhs_t: ty::t) -> ty::t {
2230: lookup_op_method(fcx, ex, rhs_t, token::intern(mname),
2231: trait_did, [rhs_expr], DontAutoderefReceiver, || {
--
3263: raw_base_t);
3264: let ret_ty = lookup_op_method(fcx,
3265: expr,
librustc/middle/typeck/check/mod.rs:584:1-584:1 -fn- definition:
fn check_fields_sized(tcx: &ty::ctxt,
struct_def: &ast::StructDef) {
let len = struct_def.fields.len();
references:- 2635: ast::ItemStruct(..) => {
636: check_fields_sized(ccx.tcx, ccx.tcx.map.expect_struct(it.id));
637: }
--
3614: },
3615: ast::StructVariantKind(struct_def) => check_fields_sized(ccx.tcx, struct_def),
3616: _ => {}
librustc/middle/typeck/check/mod.rs:1300:1-1300:1 -enum- definition:
pub enum LvaluePreference {
PreferMutLvalue,
NoPreference
references:- 61307: expr_id: Option<ast::NodeId>,
1308: mut lvalue_pref: LvaluePreference,
1309: should_stop: |ty::t, uint| -> Option<T>)
--
1471: fn check_expr_with_lvalue_pref(fcx: &FnCtxt, expr: &ast::Expr,
1472: lvalue_pref: LvaluePreference) {
1473: check_expr_with_unifier(fcx, expr, None, lvalue_pref, || ())
--
1701: expected: Option<ty::t>,
1702: lvalue_pref: LvaluePreference,
1703: unifier: ||) {
--
2347: expr: &ast::Expr,
2348: lvalue_pref: LvaluePreference,
2349: base: &ast::Expr,
librustc/middle/typeck/check/mod.rs:1526:23-1526:23 -fn- definition:
// method's container.
fn generics_of_static_method_container(type_context: &ty::ctxt,
provenance: ast::MethodProvenance)
references:- 21586: let generics =
1587: generics_of_static_method_container(function_context.ccx.tcx,
1588: provenance);
--
3857: ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
3858: let generics = generics_of_static_method_container(fcx.ccx.tcx,
3859: provenance);
librustc/middle/typeck/check/mod.rs:1706:4-1706:4 -fn- definition:
fn check_method_argument_types(
fcx: &FnCtxt,
sp: Span,
references:- 32077: let expected_ty = ty::mk_err();
2078: check_method_argument_types(fcx, op_ex.span,
2079: expected_ty, op_ex,
librustc/middle/typeck/check/mod.rs:4035:1-4035:1 -fn- definition:
pub fn ast_expr_vstore_to_ty(fcx: &FnCtxt,
e: &ast::Expr,
v: ast::ExprVstore,
references:- 22649: } else {
2650: ast_expr_vstore_to_ty(fcx, ev, vst, ||
2651: ty::mt{ ty: ty::mk_vec(tcx,
librustc/middle/typeck/check/mod.rs:1454:1-1454:1 -fn- definition:
fn check_expr_with_opt_hint(fcx: &FnCtxt, expr: &ast::Expr,
expected: Option<ty::t>) {
check_expr_with_unifier(fcx, expr, expected, NoPreference, || ())
references:- 32020: let then_ty = fcx.node_ty(then_blk.id);
2021: check_expr_with_opt_hint(fcx, else_expr, expected);
2022: let else_ty = fcx.expr_ty(else_expr);
--
3204: };
3205: check_expr_with_opt_hint(fcx, *e, opt_hint);
3206: let t = fcx.expr_ty(*e);
--
3466: }
3467: check_expr_with_opt_hint(fcx, e, expected);
3468: let ety = fcx.expr_ty(e);
librustc/middle/typeck/check/mod.rs:743:1-743:1 -fn- definition:
fn check_method_body(ccx: &CrateCtxt,
item_generics: &ty::Generics,
self_bound: Option<Rc<ty::TraitRef>>,
references:- 2702: Provided(m) => {
703: check_method_body(ccx, &trait_def.generics,
704: Some(trait_def.trait_ref.clone()), m);
librustc/middle/typeck/check/mod.rs:1738:4-1738:4 -fn- definition:
fn check_argument_types(fcx: &FnCtxt,
sp: Span,
fn_inputs: &[ty::t],
references:- 31935: // Call the generic checker.
1936: check_argument_types(fcx, call_expr.span, fn_sig.inputs.as_slice(), f,
1937: args, DontDerefArgs, fn_sig.variadic);
librustc/middle/typeck/check/mod.rs:3749:1-3749:1 -fn- definition:
pub fn lookup_def(fcx: &FnCtxt, sp: Span, id: ast::NodeId) -> ast::Def {
lookup_def_ccx(fcx.ccx, sp, id)
}
references:- 42680: // places: the exchange heap and the managed heap.
2681: let definition = lookup_def(fcx, path.span, place.id);
2682: let def_id = ast_util::def_id_of_def(definition);
--
2898: ast::ExprPath(ref pth) => {
2899: let defn = lookup_def(fcx, pth.span, id);
librustc/middle/typeck/check/_match.rs:
185: // Lookup the struct ctor def id
186: let s_def = lookup_def(pcx.fcx, pat.span, pat.id);
187: let s_def_id = ast_util::def_id_of_def(s_def);
librustc/middle/typeck/check/mod.rs:3509:26-3509:26 -fn- definition:
/// `check_instantiable`.
pub fn check_representable(tcx: &ty::ctxt,
sp: Span,
references:- 2613: check_representable(tcx, span, id, "struct");
614: check_instantiable(tcx, span, id);
--
3741: check_representable(ccx.tcx, sp, id, "enum");
librustc/middle/typeck/check/mod.rs:1889:4-1889:4 -fn- definition:
fn write_call(fcx: &FnCtxt, call_expr: &ast::Expr, output: ty::t) {
fcx.write_ty(call_expr.id, output);
}
references:- 22003: write_call(fcx, expr, ret_ty);
2004: }
librustc/middle/typeck/check/mod.rs:2258:4-2258:4 -fn- definition:
fn check_expr_fn(fcx: &FnCtxt,
expr: &ast::Expr,
store: ty::TraitStore,
references:- 23005: ast::ExprProc(decl, body) => {
3006: check_expr_fn(fcx,
3007: expr,
librustc/middle/typeck/check/mod.rs:3990:59-3990:59 -fn- definition:
// Returns the one-level-deep structure of the given type.
pub fn structure_of<'a>(fcx: &FnCtxt, sp: Span, typ: ty::t)
-> &'a ty::sty {
references:- 61905: // Extract the function signature from `in_fty`.
1906: let fn_sty = structure_of(fcx, f.span, fn_ty);
librustc/middle/typeck/check/_match.rs:
520: // Grab the class data that we care about.
521: let structure = structure_of(fcx, pat.span, expected);
522: let mut error_happened = false;
--
642: let (elt_type, region_var, mutbl) = match *structure_of(fcx,
643: pat.span,
--
705: };
706: match *structure_of(fcx, span, expected) {
707: ty::ty_uniq(e_inner) if pointer_kind == Send => {
librustc/middle/typeck/check/mod.rs:1885:4-1885:4 -fn- definition:
fn err_args(len: uint) -> Vec<ty::t> {
Vec::from_fn(len, |_| ty::mk_err())
}
references:- 41786: err_args(supplied_arg_count)
1787: };
--
1912: binder_id: ast::CRATE_NODE_ID,
1913: inputs: err_args(args.len()),
1914: output: ty::mk_err(),
librustc/middle/typeck/check/mod.rs:1450:1-1450:1 -fn- definition:
fn check_expr_with_hint(fcx: &FnCtxt, expr: &ast::Expr, expected: ty::t) {
check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || ())
}
references:- 23172: ast::ExprRepeat(element, count_expr) => {
3173: check_expr_with_hint(fcx, count_expr, ty::mk_uint());
3174: let count = ty::eval_repeat_count(fcx, count_expr);
librustc/middle/typeck/check/mod.rs:2087:4-2087:4 -fn- definition:
fn check_binop(fcx: &FnCtxt,
expr: &ast::Expr,
op: ast::BinOp,
references:- 22744: ast::ExprBinary(op, lhs, rhs) => {
2745: check_binop(fcx, expr, op, lhs, rhs, SimpleBinop);
--
2758: ast::ExprAssignOp(op, lhs, rhs) => {
2759: check_binop(fcx, expr, op, lhs, rhs, BinopAssignment);
librustc/middle/typeck/check/mod.rs:180:19-180:19 -struct- definition:
pub struct FnStyleState {
pub def: ast::NodeId,
pub fn_style: ast::FnStyle,
references:- 10204: };
205: FnStyleState{ def: def,
206: fn_style: fn_style,
--
234: ret_ty: ty::t,
235: ps: RefCell<FnStyleState>,
librustc/middle/typeck/check/mod.rs:3544:44-3544:44 -fn- definition:
/// is representable, but not instantiable.
pub fn check_instantiable(tcx: &ty::ctxt,
sp: Span,
references:- 23746: // not. See def'n of `check_instantiable()` for details.
3747: check_instantiable(ccx.tcx, sp, id);
3748: }
librustc/middle/typeck/check/mod.rs:156:32-156:32 -struct- definition:
/// share the inherited fields.
pub struct Inherited<'a> {
infcx: infer::InferCtxt<'a>,
references:- 7265: -> Inherited<'a> {
266: Inherited {
267: infcx: infer::new_infer_ctxt(tcx),
--
443: fn_kind: FnKind,
444: inherited: &'a Inherited<'a>) -> FnCtxt<'a>
445: {
librustc/middle/typeck/check/mod.rs:1459:1-1459:1 -fn- definition:
fn check_expr_with_opt_hint_and_lvalue_pref(fcx: &FnCtxt,
expr: &ast::Expr,
expected: Option<ty::t>,
references:- 32792: };
2793: check_expr_with_opt_hint_and_lvalue_pref(fcx, oprnd, exp_inner, lvalue_pref);
2794: let mut oprnd_t = fcx.expr_ty(oprnd);
--
2935: ast::ExprParen(a) => {
2936: check_expr_with_opt_hint_and_lvalue_pref(fcx, a, expected, lvalue_pref);
2937: fcx.write_ty(id, fcx.expr_ty(a));
librustc/middle/typeck/check/mod.rs:3638:8-3638:8 -fn- definition:
fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
match ty {
ast::TyI8 => disr as i8 as Disr == disr,
references:- 23648: attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
3649: attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
3650: }
librustc/middle/typeck/check/mod.rs:316:1-316:1 -struct- definition:
struct CheckItemTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
impl<'a> Visitor<()> for CheckItemTypesVisitor<'a> {
fn visit_item(&mut self, i: &ast::Item, _: ()) {
references:- 2335: pub fn check_item_types(ccx: &CrateCtxt, krate: &ast::Crate) {
336: let mut visit = CheckItemTypesVisitor { ccx: ccx };
337: visit::walk_crate(&mut visit, krate, ());
librustc/middle/typeck/check/mod.rs:1480:14-1480:14 -fn- definition:
// variables.
pub fn impl_self_ty(vcx: &VtableContext,
span: Span, // (potential) receiver for this impl
references:- 2librustc/middle/typeck/check/method.rs:
705: ty: impl_ty
706: } = impl_self_ty(&vcx, span, impl_did);
librustc/middle/typeck/check/vtable.rs:
365: ty: for_ty
366: } = impl_self_ty(vcx, span, impl_did);
367: match infer::mk_subty(vcx.infcx,
librustc/middle/typeck/check/mod.rs:2242:4-2242:4 -fn- definition:
fn unpack_expected<O>(
fcx: &FnCtxt,
expected: Option<ty::t>,
references:- 42269: // expected types so as to avoid capture.
2270: let expected_sty = unpack_expected(fcx,
2271: expected,
--
2860: ast::ExprAddrOf(mutbl, oprnd) => {
2861: let hint = unpack_expected(
2862: fcx, expected,
--
3190: ast::ExprTup(ref elts) => {
3191: let flds = unpack_expected(fcx, expected, |sty| {
3192: match *sty {
librustc/middle/typeck/check/mod.rs:1444:1-1444:1 -fn- definition:
fn check_expr_coercable_to_type(fcx: &FnCtxt, expr: &ast::Expr, expected: ty::t) {
check_expr_with_unifier(fcx, expr, Some(expected), NoPreference, || {
demand::coerce(fcx, expr.span, expected, expr)
references:- 33322: let local_ty = fcx.local_ty(init.span, nid);
3323: check_expr_coercable_to_type(fcx, init, local_ty)
3324: }
librustc/middle/typeck/check/mod.rs:297:1-297:1 -fn- definition:
fn blank_inherited_fields<'a>(ccx: &'a CrateCtxt<'a>) -> Inherited<'a> {
// It's kind of a kludge to manufacture a fake function context
// and statement context, but we might as well do write the code only once
references:- 23486: id: ast::NodeId) {
3487: let inh = blank_inherited_fields(ccx);
3488: let rty = ty::node_id_to_type(ccx.tcx, id);
--
3677: let inh = blank_inherited_fields(ccx);
3678: let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
librustc/middle/typeck/check/mod.rs:1436:1-1436:1 -fn- definition:
pub fn check_expr_has_type(
fcx: &FnCtxt, expr: &ast::Expr,
expected: ty::t) {
references:- 173165: for e in args.iter() {
3166: check_expr_has_type(fcx, *e, t);
3167: }
--
3175: let t: ty::t = fcx.infcx().next_ty_var();
3176: check_expr_has_type(fcx, element, t);
3177: let element_ty = fcx.expr_ty(element);
--
3373: // Check with expected type of ()
3374: check_expr_has_type(fcx, expr, ty::mk_nil());
3375: let expr_ty = fcx.expr_ty(expr);
librustc/middle/typeck/check/_match.rs:
438: ast::PatRange(begin, end) => {
439: check_expr_has_type(fcx, begin, expected);
440: check_expr_has_type(fcx, end, expected);
441: let b_ty =
librustc/middle/typeck/check/mod.rs:
2613: for e in args.iter() {
2614: check_expr_has_type(fcx, *e, t);
2615: let arg_t = fcx.expr_ty(*e);
librustc/middle/typeck/check/mod.rs:3804:39-3804:39 -fn- definition:
// number of type parameters and type.
pub fn instantiate_path(fcx: &FnCtxt,
pth: &ast::Path,
references:- 32902: let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2903: instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
2904: }
librustc/middle/typeck/check/_match.rs:
196: };
197: instantiate_path(pcx.fcx,
198: path,
librustc/middle/typeck/check/mod.rs:216:16-216:16 -enum- definition:
enum IsBinopAssignment{
SimpleBinop,
BinopAssignment,
references:- 4215: /// better messages on error.
217: enum IsBinopAssignment{
--
2091: rhs: @ast::Expr,
2092: is_binop_assignment: IsBinopAssignment) {
2093: let tcx = fcx.ccx.tcx;
librustc/middle/typeck/check/mod.rs:3398:1-3398:1 -fn- definition:
pub fn check_block_no_value(fcx: &FnCtxt, blk: &ast::Block) {
check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
let blkty = fcx.node_ty(blk.id);
references:- 32029: None => {
2030: check_block_no_value(fcx, then_blk);
2031: ty::mk_nil()
--
2964: check_expr_has_type(fcx, cond, ty::mk_bool());
2965: check_block_no_value(fcx, body);
2966: let cond_ty = fcx.expr_ty(cond);
--
2980: ast::ExprLoop(body, _) => {
2981: check_block_no_value(fcx, (body));
2982: if !may_break(tcx, expr.id, body) {
librustc/middle/typeck/check/mod.rs:4005:1-4005:1 -fn- definition:
pub fn type_is_scalar(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
let typ_s = structurally_resolved_type(fcx, sp, typ);
return ty::type_is_scalar(typ_s);
references:- 23145: }
3146: } else if !(type_is_scalar(fcx,expr.span,t_e)
3147: && t_1_is_trivial) {
librustc/middle/typeck/check/mod.rs:3493:1-3493:1 -fn- definition:
pub fn check_const_with_ty(fcx: &FnCtxt,
_: Span,
e: &ast::Expr,
references:- 23490: let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty;
3491: check_const_with_ty(&fcx, sp, e, declty);
3492: }
--
3679: let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
3680: check_const_with_ty(&fcx, e.span, e, declty);
3681: // check_expr (from check_const pass) doesn't guarantee
librustc/middle/typeck/check/mod.rs:1698:77-1698:77 -fn- definition:
/// `ty_bot`, so avoid that when err and bot need to be handled differently.
fn check_expr_with_unifier(fcx: &FnCtxt,
expr: &ast::Expr,
references:- 71463: lvalue_pref: LvaluePreference) {
1464: check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ())
1465: }
--
1472: lvalue_pref: LvaluePreference) {
1473: check_expr_with_unifier(fcx, expr, None, lvalue_pref, || ())
1474: }
librustc/middle/typeck/check/mod.rs:369:1-369:1 -struct- definition:
struct GatherLocalsVisitor<'a> {
fcx: &'a FnCtxt<'a>
}
references:- 3374: impl<'a> GatherLocalsVisitor<'a> {
375: fn assign(&mut self, nid: ast::NodeId, ty_opt: Option<ty::t>) {
--
391: impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
392: // Add explicitly-declared locals.
--
489: let mut visit = GatherLocalsVisitor { fcx: &fcx, };
490: // Add formal parameters.
librustc/middle/typeck/check/mod.rs:1519:46-1519:46 -enum- definition:
// for overloaded binary and unary operators.
pub enum DerefArgs {
DontDerefArgs,
references:- 41711: args: &[@ast::Expr],
1712: deref_args: DerefArgs) -> ty::t {
1713: // HACK(eddyb) ignore provided self (it has special typeck rules).
librustc/middle/typeck/check/method.rs:
135: supplied_tps: &'a [ty::t], // The list of types X, Y, ... .
136: deref_args: check::DerefArgs, // Whether we autopointer first.
137: check_traits: CheckTraitsFlag, // Whether we check traits only.
--
308: extension_candidates: Vec<Candidate>,
309: deref_args: check::DerefArgs,
310: check_traits: CheckTraitsFlag,
librustc/middle/typeck/check/mod.rs:
1742: args: &[@ast::Expr],
1743: deref_args: DerefArgs,
1744: variadic: bool) {
librustc/middle/typeck/check/mod.rs:436:1-436:1 -fn- definition:
fn check_fn<'a>(ccx: &'a CrateCtxt<'a>,
fn_style: ast::FnStyle,
fn_sig: &ty::FnSig,
references:- 22340: check_fn(fcx.ccx, inherited_style, &fty_sig,
2341: decl, id, body, fn_kind, fcx.inh);
librustc/middle/typeck/check/mod.rs:280:47-280:47 -fn- definition:
// Used by check_const and check_enum_variants
fn blank_fn_ctxt<'a>(ccx: &'a CrateCtxt<'a>,
inh: &'a Inherited<'a>,
references:- 23677: let inh = blank_inherited_fields(ccx);
3678: let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
3679: let declty = ty::mk_int_var(ccx.tcx, fcx.infcx().next_int_var_id());
librustc/middle/typeck/check/mod.rs:325:1-325:1 -struct- definition:
struct CheckItemSizedTypesVisitor<'a> { ccx: &'a CrateCtxt<'a> }
impl<'a> Visitor<()> for CheckItemSizedTypesVisitor<'a> {
fn visit_item(&mut self, i: &ast::Item, _: ()) {
references:- 2328: impl<'a> Visitor<()> for CheckItemSizedTypesVisitor<'a> {
329: fn visit_item(&mut self, i: &ast::Item, _: ()) {
--
341: let mut visit = CheckItemSizedTypesVisitor { ccx: ccx };
342: visit::walk_crate(&mut visit, krate, ());
librustc/middle/typeck/check/mod.rs:3629:8-3629:8 -fn- definition:
fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
match ty {
ast::TyU8 => disr as u8 as Disr == disr,
references:- 23634: ast::TyU64 => disr as u64 as Disr == disr,
3635: ast::TyU => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
3636: }
--
3647: match ty {
3648: attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
3649: attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
librustc/middle/typeck/check/mod.rs:533:1-533:1 -fn- definition:
fn span_for_field(tcx: &ty::ctxt, field: &ty::field_ty, struct_id: ast::DefId) -> Span {
assert!(field.id.krate == ast::LOCAL_CRATE);
let item = match tcx.map.find(struct_id.node) {
references:- 2570: Some(prev_field) => {
571: tcx.sess.span_err(span_for_field(tcx, f, id),
572: format!("field `{}` hides field declared in super-struct",
573: token::get_name(f.name)));
574: tcx.sess.span_note(span_for_field(tcx, prev_field, parent_id),
575: "previously declared here");
librustc/middle/typeck/check/mod.rs:3754:75-3754:75 -fn- definition:
// Returns the type parameter count and the type for the given definition.
pub fn ty_param_bounds_and_ty_for_def(fcx: &FnCtxt,
sp: Span,
references:- 22901: check_type_parameter_positions_in_path(fcx, pth, defn);
2902: let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
2903: instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
--
3770: ast::DefUpvar(_, inner, _, _) => {
3771: return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
3772: }
librustc/middle/typeck/check/mod.rs:3413:1-3413:1 -fn- definition:
pub fn check_block_with_expected(fcx: &FnCtxt,
blk: &ast::Block,
expected: Option<ty::t>) {
references:- 43399: pub fn check_block_no_value(fcx: &FnCtxt, blk: &ast::Block) {
3400: check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
3401: let blkty = fcx.node_ty(blk.id);
librustc/middle/typeck/check/mod.rs:4125:4-4125:4 -fn- definition:
fn param(ccx: &CrateCtxt, n: uint) -> ty::t {
ty::mk_param(ccx.tcx, n, local_def(0))
}
references:- 274147: "min" | "umax" | "umin" => {
4148: (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)),
4149: param(ccx, 0))
--
4169: "uninit" => (1u, Vec::new(), param(ccx, 0u)),
4170: "forget" => (1u, vec!( param(ccx, 0) ), ty::mk_nil()),
4171: "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)),
--
4255: ty::mk_ptr(tcx, ty::mt {
4256: ty: param(ccx, 0),
4257: mutbl: ast::MutMutable
--
4342: "volatile_load" =>
4343: (1, vec!( ty::mk_imm_ptr(tcx, param(ccx, 0)) ), param(ccx, 0)),
4344: "volatile_store" =>
4345: (1, vec!( ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ), ty::mk_nil()),
librustc/middle/typeck/check/mod.rs:1305:1-1305:1 -fn- definition:
pub fn autoderef<T>(fcx: &FnCtxt, sp: Span, base_ty: ty::t,
expr_id: Option<ast::NodeId>,
mut lvalue_pref: LvaluePreference,
references:- 53251: let (base_t, autoderefs, field_ty) =
3252: autoderef(fcx, expr.span, raw_base_t, Some(base.id),
3253: lvalue_pref, |base_t, _| ty::index(base_t));
librustc/middle/typeck/check/method.rs:
346: let (self_ty, autoderefs, result) =
347: check::autoderef(
348: self.fcx, span, self_ty, self_expr_id, PreferMutLvalue,
--
453: let span = self.self_expr.map_or(self.span, |e| e.span);
454: check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
455: match get(self_ty).sty {
librustc/middle/typeck/check/mod.rs:
2357: let (_, autoderefs, field_ty) =
2358: autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
2359: match ty::get(base_t).sty {
librustc/middle/typeck/check/mod.rs:222:19-222:19 -struct- definition:
pub struct FnCtxt<'a> {
// This flag is set to true if, during the writeback phase, we encounter
// a type error in this function.
references:- 100librustc/middle/typeck/check/_match.rs:
librustc/middle/typeck/check/vtable.rs:
librustc/middle/typeck/check/writeback.rs:
librustc/middle/typeck/check/regionck.rs:
librustc/middle/typeck/check/demand.rs:
librustc/middle/typeck/check/method.rs:
librustc/middle/typeck/check/vtable.rs: