]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/type_check.rs
Auto merge of #40163 - arielb1:normalization-1702, r=nikomatsakis
[rust.git] / src / librustc_mir / transform / type_check.rs
1 // Copyright 2016 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 //! This pass type-checks the MIR to ensure it is not broken.
12 #![allow(unreachable_code)]
13
14 use rustc::infer::{self, InferCtxt, InferOk};
15 use rustc::traits::{self, Reveal};
16 use rustc::ty::fold::TypeFoldable;
17 use rustc::ty::{self, Ty, TyCtxt, TypeVariants};
18 use rustc::mir::*;
19 use rustc::mir::tcx::LvalueTy;
20 use rustc::mir::transform::{MirPass, MirSource, Pass};
21 use rustc::mir::visit::Visitor;
22 use std::fmt;
23 use syntax::ast;
24 use syntax_pos::{Span, DUMMY_SP};
25
26 use rustc_data_structures::indexed_vec::Idx;
27
28 fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
29     tcx.sess.diagnostic().span_bug(span, msg);
30 }
31
32 macro_rules! span_mirbug {
33     ($context:expr, $elem:expr, $($message:tt)*) => ({
34         mirbug($context.tcx(), $context.last_span,
35                &format!("broken MIR ({:?}): {}", $elem, format!($($message)*)))
36     })
37 }
38
39 macro_rules! span_mirbug_and_err {
40     ($context:expr, $elem:expr, $($message:tt)*) => ({
41         {
42             span_mirbug!($context, $elem, $($message)*);
43             $context.error()
44         }
45     })
46 }
47
48 enum FieldAccessError {
49     OutOfRange { field_count: usize }
50 }
51
52 /// Verifies that MIR types are sane to not crash further checks.
53 ///
54 /// The sanitize_XYZ methods here take an MIR object and compute its
55 /// type, calling `span_mirbug` and returning an error type if there
56 /// is a problem.
57 struct TypeVerifier<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
58     cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>,
59     mir: &'a Mir<'tcx>,
60     last_span: Span,
61     errors_reported: bool
62 }
63
64 impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
65     fn visit_span(&mut self, span: &Span) {
66         if *span != DUMMY_SP {
67             self.last_span = *span;
68         }
69     }
70
71     fn visit_lvalue(&mut self,
72                     lvalue: &Lvalue<'tcx>,
73                     _context: visit::LvalueContext,
74                     location: Location) {
75         self.sanitize_lvalue(lvalue, location);
76     }
77
78     fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
79         self.super_constant(constant, location);
80         self.sanitize_type(constant, constant.ty);
81     }
82
83     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
84         self.super_rvalue(rvalue, location);
85         let rval_ty = rvalue.ty(self.mir, self.tcx());
86         self.sanitize_type(rvalue, rval_ty);
87     }
88
89     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
90         self.sanitize_type(&"return type", mir.return_ty);
91         for local_decl in &mir.local_decls {
92             self.sanitize_type(local_decl, local_decl.ty);
93         }
94         if self.errors_reported {
95             return;
96         }
97         self.super_mir(mir);
98     }
99 }
100
101 impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
102     fn new(cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
103         TypeVerifier {
104             cx: cx,
105             mir: mir,
106             last_span: mir.span,
107             errors_reported: false
108         }
109     }
110
111     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
112         self.cx.infcx.tcx
113     }
114
115     fn sanitize_type(&mut self, parent: &fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
116         if ty.needs_infer() || ty.has_escaping_regions() || ty.references_error() {
117             span_mirbug_and_err!(self, parent, "bad type {:?}", ty)
118         } else {
119             ty
120         }
121     }
122
123     fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> {
124         debug!("sanitize_lvalue: {:?}", lvalue);
125         match *lvalue {
126             Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty },
127             Lvalue::Static(box Static { def_id, ty: sty }) => {
128                 let sty = self.sanitize_type(lvalue, sty);
129                 let ty = self.tcx().item_type(def_id);
130                 let ty = self.cx.normalize(&ty);
131                 if let Err(terr) = self.cx.eq_types(self.last_span, ty, sty) {
132                     span_mirbug!(
133                         self, lvalue, "bad static type ({:?}: {:?}): {:?}",
134                         ty, sty, terr);
135                 }
136                 LvalueTy::Ty { ty: sty }
137
138             },
139             Lvalue::Projection(ref proj) => {
140                 let base_ty = self.sanitize_lvalue(&proj.base, location);
141                 if let LvalueTy::Ty { ty } = base_ty {
142                     if ty.references_error() {
143                         assert!(self.errors_reported);
144                         return LvalueTy::Ty { ty: self.tcx().types.err };
145                     }
146                 }
147                 self.sanitize_projection(base_ty, &proj.elem, lvalue, location)
148             }
149         }
150     }
151
152     fn sanitize_projection(&mut self,
153                            base: LvalueTy<'tcx>,
154                            pi: &LvalueElem<'tcx>,
155                            lvalue: &Lvalue<'tcx>,
156                            location: Location)
157                            -> LvalueTy<'tcx> {
158         debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue);
159         let tcx = self.tcx();
160         let base_ty = base.to_ty(tcx);
161         let span = self.last_span;
162         match *pi {
163             ProjectionElem::Deref => {
164                 let deref_ty = base_ty.builtin_deref(true, ty::LvaluePreference::NoPreference);
165                 LvalueTy::Ty {
166                     ty: deref_ty.map(|t| t.ty).unwrap_or_else(|| {
167                         span_mirbug_and_err!(
168                             self, lvalue, "deref of non-pointer {:?}", base_ty)
169                     })
170                 }
171             }
172             ProjectionElem::Index(ref i) => {
173                 self.visit_operand(i, location);
174                 let index_ty = i.ty(self.mir, tcx);
175                 if index_ty != tcx.types.usize {
176                     LvalueTy::Ty {
177                         ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)
178                     }
179                 } else {
180                     LvalueTy::Ty {
181                         ty: base_ty.builtin_index().unwrap_or_else(|| {
182                             span_mirbug_and_err!(
183                                 self, lvalue, "index of non-array {:?}", base_ty)
184                         })
185                     }
186                 }
187             }
188             ProjectionElem::ConstantIndex { .. } => {
189                 // consider verifying in-bounds
190                 LvalueTy::Ty {
191                     ty: base_ty.builtin_index().unwrap_or_else(|| {
192                         span_mirbug_and_err!(
193                             self, lvalue, "index of non-array {:?}", base_ty)
194                     })
195                 }
196             }
197             ProjectionElem::Subslice { from, to } => {
198                 LvalueTy::Ty {
199                     ty: match base_ty.sty {
200                         ty::TyArray(inner, size) => {
201                             let min_size = (from as usize) + (to as usize);
202                             if let Some(rest_size) = size.checked_sub(min_size) {
203                                 tcx.mk_array(inner, rest_size)
204                             } else {
205                                 span_mirbug_and_err!(
206                                     self, lvalue, "taking too-small slice of {:?}", base_ty)
207                             }
208                         }
209                         ty::TySlice(..) => base_ty,
210                         _ => {
211                             span_mirbug_and_err!(
212                                 self, lvalue, "slice of non-array {:?}", base_ty)
213                         }
214                     }
215                 }
216             }
217             ProjectionElem::Downcast(adt_def1, index) =>
218                 match base_ty.sty {
219                     ty::TyAdt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => {
220                         if index >= adt_def.variants.len() {
221                             LvalueTy::Ty {
222                                 ty: span_mirbug_and_err!(
223                                     self,
224                                     lvalue,
225                                     "cast to variant #{:?} but enum only has {:?}",
226                                     index,
227                                     adt_def.variants.len())
228                             }
229                         } else {
230                             LvalueTy::Downcast {
231                                 adt_def: adt_def,
232                                 substs: substs,
233                                 variant_index: index
234                             }
235                         }
236                     }
237                     _ => LvalueTy::Ty {
238                         ty: span_mirbug_and_err!(
239                             self, lvalue, "can't downcast {:?} as {:?}",
240                             base_ty, adt_def1)
241                     }
242                 },
243             ProjectionElem::Field(field, fty) => {
244                 let fty = self.sanitize_type(lvalue, fty);
245                 match self.field_ty(lvalue, base, field) {
246                     Ok(ty) => {
247                         if let Err(terr) = self.cx.eq_types(span, ty, fty) {
248                             span_mirbug!(
249                                 self, lvalue, "bad field access ({:?}: {:?}): {:?}",
250                                 ty, fty, terr);
251                         }
252                     }
253                     Err(FieldAccessError::OutOfRange { field_count }) => {
254                         span_mirbug!(
255                             self, lvalue, "accessed field #{} but variant only has {}",
256                             field.index(), field_count)
257                     }
258                 }
259                 LvalueTy::Ty { ty: fty }
260             }
261         }
262     }
263
264     fn error(&mut self) -> Ty<'tcx> {
265         self.errors_reported = true;
266         self.tcx().types.err
267     }
268
269     fn field_ty(&mut self,
270                 parent: &fmt::Debug,
271                 base_ty: LvalueTy<'tcx>,
272                 field: Field)
273                 -> Result<Ty<'tcx>, FieldAccessError>
274     {
275         let tcx = self.tcx();
276
277         let (variant, substs) = match base_ty {
278             LvalueTy::Downcast { adt_def, substs, variant_index } => {
279                 (&adt_def.variants[variant_index], substs)
280             }
281             LvalueTy::Ty { ty } => match ty.sty {
282                 ty::TyAdt(adt_def, substs) if adt_def.is_univariant() => {
283                         (&adt_def.variants[0], substs)
284                     }
285                 ty::TyClosure(def_id, substs) => {
286                     return match substs.upvar_tys(def_id, tcx).nth(field.index()) {
287                         Some(ty) => Ok(ty),
288                         None => Err(FieldAccessError::OutOfRange {
289                             field_count: substs.upvar_tys(def_id, tcx).count()
290                         })
291                     }
292                 }
293                 ty::TyTuple(tys, _) => {
294                     return match tys.get(field.index()) {
295                         Some(&ty) => Ok(ty),
296                         None => Err(FieldAccessError::OutOfRange {
297                             field_count: tys.len()
298                         })
299                     }
300                 }
301                 _ => return Ok(span_mirbug_and_err!(
302                     self, parent, "can't project out of {:?}", base_ty))
303             }
304         };
305
306         if let Some(field) = variant.fields.get(field.index()) {
307             Ok(self.cx.normalize(&field.ty(tcx, substs)))
308         } else {
309             Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() })
310         }
311     }
312 }
313
314 pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
315     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
316     fulfillment_cx: traits::FulfillmentContext<'tcx>,
317     last_span: Span,
318     body_id: ast::NodeId,
319 }
320
321 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
322     fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, body_id: ast::NodeId) -> Self {
323         TypeChecker {
324             infcx: infcx,
325             fulfillment_cx: traits::FulfillmentContext::new(),
326             last_span: DUMMY_SP,
327             body_id: body_id,
328         }
329     }
330
331     fn misc(&self, span: Span) -> traits::ObligationCause<'tcx> {
332         traits::ObligationCause::misc(span, self.body_id)
333     }
334
335     pub fn register_infer_ok_obligations<T>(&mut self, infer_ok: InferOk<'tcx, T>) -> T {
336         for obligation in infer_ok.obligations {
337             self.fulfillment_cx.register_predicate_obligation(self.infcx, obligation);
338         }
339         infer_ok.value
340     }
341
342     fn sub_types(&mut self, sup: Ty<'tcx>, sub: Ty<'tcx>)
343                  -> infer::UnitResult<'tcx>
344     {
345         self.infcx.sub_types(false, &self.misc(self.last_span), sup, sub)
346             .map(|ok| self.register_infer_ok_obligations(ok))
347     }
348
349     fn eq_types(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
350                 -> infer::UnitResult<'tcx>
351     {
352         self.infcx.eq_types(false, &self.misc(span), a, b)
353             .map(|ok| self.register_infer_ok_obligations(ok))
354     }
355
356     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
357         self.infcx.tcx
358     }
359
360     fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>) {
361         debug!("check_stmt: {:?}", stmt);
362         let tcx = self.tcx();
363         match stmt.kind {
364             StatementKind::Assign(ref lv, ref rv) => {
365                 let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
366                 let rv_ty = rv.ty(mir, tcx);
367                 if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
368                     span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
369                                  lv_ty, rv_ty, terr);
370                 }
371             }
372             StatementKind::SetDiscriminant{ ref lvalue, variant_index } => {
373                 let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx);
374                 let adt = match lvalue_type.sty {
375                     TypeVariants::TyAdt(adt, _) if adt.is_enum() => adt,
376                     _ => {
377                         span_bug!(stmt.source_info.span,
378                                   "bad set discriminant ({:?} = {:?}): lhs is not an enum",
379                                   lvalue,
380                                   variant_index);
381                     }
382                 };
383                 if variant_index >= adt.variants.len() {
384                      span_bug!(stmt.source_info.span,
385                                "bad set discriminant ({:?} = {:?}): value of of range",
386                                lvalue,
387                                variant_index);
388                 };
389             }
390             StatementKind::StorageLive(ref lv) |
391             StatementKind::StorageDead(ref lv) => {
392                 match *lv {
393                     Lvalue::Local(_) => {}
394                     _ => {
395                         span_mirbug!(self, stmt, "bad lvalue: expected local");
396                     }
397                 }
398             }
399             StatementKind::InlineAsm { .. } |
400             StatementKind::Nop => {}
401         }
402     }
403
404     fn check_terminator(&mut self,
405                         mir: &Mir<'tcx>,
406                         term: &Terminator<'tcx>) {
407         debug!("check_terminator: {:?}", term);
408         let tcx = self.tcx();
409         match term.kind {
410             TerminatorKind::Goto { .. } |
411             TerminatorKind::Resume |
412             TerminatorKind::Return |
413             TerminatorKind::Unreachable |
414             TerminatorKind::Drop { .. } => {
415                 // no checks needed for these
416             }
417
418
419             TerminatorKind::DropAndReplace {
420                 ref location,
421                 ref value,
422                 ..
423             } => {
424                 let lv_ty = location.ty(mir, tcx).to_ty(tcx);
425                 let rv_ty = value.ty(mir, tcx);
426                 if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
427                     span_mirbug!(self, term, "bad DropAndReplace ({:?} = {:?}): {:?}",
428                                  lv_ty, rv_ty, terr);
429                 }
430             }
431             TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
432                 let discr_ty = discr.ty(mir, tcx);
433                 if let Err(terr) = self.sub_types(discr_ty, switch_ty) {
434                     span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}",
435                                  switch_ty, discr_ty, terr);
436                 }
437                 if !switch_ty.is_integral() && !switch_ty.is_char() &&
438                     !switch_ty.is_bool()
439                 {
440                     span_mirbug!(self, term, "bad SwitchInt discr ty {:?}",switch_ty);
441                 }
442                 // FIXME: check the values
443             }
444             TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
445                 let func_ty = func.ty(mir, tcx);
446                 debug!("check_terminator: call, func_ty={:?}", func_ty);
447                 let sig = match func_ty.sty {
448                     ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => sig,
449                     _ => {
450                         span_mirbug!(self, term, "call to non-function {:?}", func_ty);
451                         return;
452                     }
453                 };
454                 let sig = tcx.erase_late_bound_regions(&sig);
455                 let sig = self.normalize(&sig);
456                 self.check_call_dest(mir, term, &sig, destination);
457
458                 if self.is_box_free(func) {
459                     self.check_box_free_inputs(mir, term, &sig, args);
460                 } else {
461                     self.check_call_inputs(mir, term, &sig, args);
462                 }
463             }
464             TerminatorKind::Assert { ref cond, ref msg, .. } => {
465                 let cond_ty = cond.ty(mir, tcx);
466                 if cond_ty != tcx.types.bool {
467                     span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
468                 }
469
470                 if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
471                     if len.ty(mir, tcx) != tcx.types.usize {
472                         span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
473                     }
474                     if index.ty(mir, tcx) != tcx.types.usize {
475                         span_mirbug!(self, index, "bounds-check index non-usize {:?}", index)
476                     }
477                 }
478             }
479         }
480     }
481
482     fn check_call_dest(&mut self,
483                        mir: &Mir<'tcx>,
484                        term: &Terminator<'tcx>,
485                        sig: &ty::FnSig<'tcx>,
486                        destination: &Option<(Lvalue<'tcx>, BasicBlock)>) {
487         let tcx = self.tcx();
488         match *destination {
489             Some((ref dest, _)) => {
490                 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
491                 if let Err(terr) = self.sub_types(sig.output(), dest_ty) {
492                     span_mirbug!(self, term,
493                                  "call dest mismatch ({:?} <- {:?}): {:?}",
494                                  dest_ty, sig.output(), terr);
495                 }
496             },
497             None => {
498                 // FIXME(canndrew): This is_never should probably be an is_uninhabited
499                 if !sig.output().is_never() {
500                     span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
501                 }
502             },
503         }
504     }
505
506     fn check_call_inputs(&mut self,
507                          mir: &Mir<'tcx>,
508                          term: &Terminator<'tcx>,
509                          sig: &ty::FnSig<'tcx>,
510                          args: &[Operand<'tcx>])
511     {
512         debug!("check_call_inputs({:?}, {:?})", sig, args);
513         if args.len() < sig.inputs().len() ||
514            (args.len() > sig.inputs().len() && !sig.variadic) {
515             span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
516         }
517         for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
518             let op_arg_ty = op_arg.ty(mir, self.tcx());
519             if let Err(terr) = self.sub_types(op_arg_ty, fn_arg) {
520                 span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}",
521                              n, fn_arg, op_arg_ty, terr);
522             }
523         }
524     }
525
526     fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
527         match operand {
528             &Operand::Constant(Constant {
529                 literal: Literal::Item { def_id, .. }, ..
530             }) => {
531                 Some(def_id) == self.tcx().lang_items.box_free_fn()
532             }
533             _ => false,
534         }
535     }
536
537     fn check_box_free_inputs(&mut self,
538                              mir: &Mir<'tcx>,
539                              term: &Terminator<'tcx>,
540                              sig: &ty::FnSig<'tcx>,
541                              args: &[Operand<'tcx>])
542     {
543         debug!("check_box_free_inputs");
544
545         // box_free takes a Box as a pointer. Allow for that.
546
547         if sig.inputs().len() != 1 {
548             span_mirbug!(self, term, "box_free should take 1 argument");
549             return;
550         }
551
552         let pointee_ty = match sig.inputs()[0].sty {
553             ty::TyRawPtr(mt) => mt.ty,
554             _ => {
555                 span_mirbug!(self, term, "box_free should take a raw ptr");
556                 return;
557             }
558         };
559
560         if args.len() != 1 {
561             span_mirbug!(self, term, "box_free called with wrong # of args");
562             return;
563         }
564
565         let ty = args[0].ty(mir, self.tcx());
566         let arg_ty = match ty.sty {
567             ty::TyRawPtr(mt) => mt.ty,
568             ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(),
569             _ => {
570                 span_mirbug!(self, term, "box_free called with bad arg ty");
571                 return;
572             }
573         };
574
575         if let Err(terr) = self.sub_types(arg_ty, pointee_ty) {
576             span_mirbug!(self, term, "bad box_free arg ({:?} <- {:?}): {:?}",
577                          pointee_ty, arg_ty, terr);
578         }
579     }
580
581     fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block: &BasicBlockData<'tcx>)
582     {
583         let is_cleanup = block.is_cleanup;
584         self.last_span = block.terminator().source_info.span;
585         match block.terminator().kind {
586             TerminatorKind::Goto { target } =>
587                 self.assert_iscleanup(mir, block, target, is_cleanup),
588             TerminatorKind::SwitchInt { ref targets, .. } => {
589                 for target in targets {
590                     self.assert_iscleanup(mir, block, *target, is_cleanup);
591                 }
592             }
593             TerminatorKind::Resume => {
594                 if !is_cleanup {
595                     span_mirbug!(self, block, "resume on non-cleanup block!")
596                 }
597             }
598             TerminatorKind::Return => {
599                 if is_cleanup {
600                     span_mirbug!(self, block, "return on cleanup block")
601                 }
602             }
603             TerminatorKind::Unreachable => {}
604             TerminatorKind::Drop { target, unwind, .. } |
605             TerminatorKind::DropAndReplace { target, unwind, .. } |
606             TerminatorKind::Assert { target, cleanup: unwind, .. } => {
607                 self.assert_iscleanup(mir, block, target, is_cleanup);
608                 if let Some(unwind) = unwind {
609                     if is_cleanup {
610                         span_mirbug!(self, block, "unwind on cleanup block")
611                     }
612                     self.assert_iscleanup(mir, block, unwind, true);
613                 }
614             }
615             TerminatorKind::Call { ref destination, cleanup, .. } => {
616                 if let &Some((_, target)) = destination {
617                     self.assert_iscleanup(mir, block, target, is_cleanup);
618                 }
619                 if let Some(cleanup) = cleanup {
620                     if is_cleanup {
621                         span_mirbug!(self, block, "cleanup on cleanup block")
622                     }
623                     self.assert_iscleanup(mir, block, cleanup, true);
624                 }
625             }
626         }
627     }
628
629     fn assert_iscleanup(&mut self,
630                         mir: &Mir<'tcx>,
631                         ctxt: &fmt::Debug,
632                         bb: BasicBlock,
633                         iscleanuppad: bool)
634     {
635         if mir[bb].is_cleanup != iscleanuppad {
636             span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}",
637                          bb, iscleanuppad);
638         }
639     }
640
641     fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
642         self.last_span = mir.span;
643         debug!("run_on_mir: {:?}", mir.span);
644         for block in mir.basic_blocks() {
645             for stmt in &block.statements {
646                 if stmt.source_info.span != DUMMY_SP {
647                     self.last_span = stmt.source_info.span;
648                 }
649                 self.check_stmt(mir, stmt);
650             }
651
652             self.check_terminator(mir, block.terminator());
653             self.check_iscleanup(mir, block);
654         }
655     }
656
657
658     fn normalize<T>(&mut self, value: &T) -> T
659         where T: fmt::Debug + TypeFoldable<'tcx>
660     {
661         let mut selcx = traits::SelectionContext::new(self.infcx);
662         let cause = traits::ObligationCause::misc(self.last_span, ast::CRATE_NODE_ID);
663         let traits::Normalized { value, obligations } =
664             traits::normalize(&mut selcx, cause, value);
665
666         debug!("normalize: value={:?} obligations={:?}",
667                value,
668                obligations);
669
670         let mut fulfill_cx = &mut self.fulfillment_cx;
671         for obligation in obligations {
672             fulfill_cx.register_predicate_obligation(self.infcx, obligation);
673         }
674
675         value
676     }
677
678     fn verify_obligations(&mut self, mir: &Mir<'tcx>) {
679         self.last_span = mir.span;
680         if let Err(e) = self.fulfillment_cx.select_all_or_error(self.infcx) {
681             span_mirbug!(self, "", "errors selecting obligation: {:?}",
682                          e);
683         }
684     }
685 }
686
687 pub struct TypeckMir;
688
689 impl TypeckMir {
690     pub fn new() -> Self {
691         TypeckMir
692     }
693 }
694
695 impl<'tcx> MirPass<'tcx> for TypeckMir {
696     fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
697                     src: MirSource, mir: &mut Mir<'tcx>) {
698         debug!("run_pass: {}", tcx.node_path_str(src.item_id()));
699
700         if tcx.sess.err_count() > 0 {
701             // compiling a broken program can obviously result in a
702             // broken MIR, so try not to report duplicate errors.
703             return;
704         }
705         let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
706         tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
707             let mut checker = TypeChecker::new(&infcx, src.item_id());
708             {
709                 let mut verifier = TypeVerifier::new(&mut checker, mir);
710                 verifier.visit_mir(mir);
711                 if verifier.errors_reported {
712                     // don't do further checks to avoid ICEs
713                     return;
714                 }
715             }
716             checker.typeck_mir(mir);
717             checker.verify_obligations(mir);
718         });
719     }
720 }
721
722 impl Pass for TypeckMir {
723 }