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.
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.
11 //! This pass type-checks the MIR to ensure it is not broken.
12 #![allow(unreachable_code)]
14 use rustc
::infer
::{self, InferCtxt, InferOk}
;
16 use rustc
::ty
::fold
::TypeFoldable
;
17 use rustc
::ty
::{self, Ty, TyCtxt, TypeVariants}
;
18 use rustc
::middle
::const_val
::ConstVal
;
20 use rustc
::mir
::tcx
::LvalueTy
;
21 use rustc
::mir
::transform
::{MirPass, MirSource}
;
22 use rustc
::mir
::visit
::Visitor
;
25 use syntax_pos
::{Span, DUMMY_SP}
;
27 use rustc_data_structures
::fx
::FxHashSet
;
28 use rustc_data_structures
::indexed_vec
::Idx
;
30 fn mirbug(tcx
: TyCtxt
, span
: Span
, msg
: &str) {
31 tcx
.sess
.diagnostic().span_bug(span
, msg
);
34 macro_rules
! span_mirbug
{
35 ($context
:expr
, $elem
:expr
, $
($message
:tt
)*) => ({
36 mirbug($context
.tcx(), $context
.last_span
,
37 &format
!("broken MIR ({:?}): {}", $elem
, format
!($
($message
)*)))
41 macro_rules
! span_mirbug_and_err
{
42 ($context
:expr
, $elem
:expr
, $
($message
:tt
)*) => ({
44 span_mirbug
!($context
, $elem
, $
($message
)*);
50 enum FieldAccessError
{
51 OutOfRange { field_count: usize }
54 /// Verifies that MIR types are sane to not crash further checks.
56 /// The sanitize_XYZ methods here take an MIR object and compute its
57 /// type, calling `span_mirbug` and returning an error type if there
59 struct TypeVerifier
<'a
, 'b
: 'a
, 'gcx
: 'b
+'tcx
, 'tcx
: 'b
> {
60 cx
: &'a
mut TypeChecker
<'b
, 'gcx
, 'tcx
>,
66 impl<'a
, 'b
, 'gcx
, 'tcx
> Visitor
<'tcx
> for TypeVerifier
<'a
, 'b
, 'gcx
, 'tcx
> {
67 fn visit_span(&mut self, span
: &Span
) {
68 if *span
!= DUMMY_SP
{
69 self.last_span
= *span
;
73 fn visit_lvalue(&mut self,
74 lvalue
: &Lvalue
<'tcx
>,
75 _context
: visit
::LvalueContext
,
77 self.sanitize_lvalue(lvalue
, location
);
80 fn visit_constant(&mut self, constant
: &Constant
<'tcx
>, location
: Location
) {
81 self.super_constant(constant
, location
);
82 self.sanitize_type(constant
, constant
.ty
);
85 fn visit_rvalue(&mut self, rvalue
: &Rvalue
<'tcx
>, location
: Location
) {
86 self.super_rvalue(rvalue
, location
);
87 let rval_ty
= rvalue
.ty(self.mir
, self.tcx());
88 self.sanitize_type(rvalue
, rval_ty
);
91 fn visit_local_decl(&mut self, local_decl
: &LocalDecl
<'tcx
>) {
92 self.super_local_decl(local_decl
);
93 self.sanitize_type(local_decl
, local_decl
.ty
);
96 fn visit_mir(&mut self, mir
: &Mir
<'tcx
>) {
97 self.sanitize_type(&"return type", mir
.return_ty
);
98 for local_decl
in &mir
.local_decls
{
99 self.sanitize_type(local_decl
, local_decl
.ty
);
101 if self.errors_reported
{
108 impl<'a
, 'b
, 'gcx
, 'tcx
> TypeVerifier
<'a
, 'b
, 'gcx
, 'tcx
> {
109 fn new(cx
: &'a
mut TypeChecker
<'b
, 'gcx
, 'tcx
>, mir
: &'a Mir
<'tcx
>) -> Self {
114 errors_reported
: false
118 fn tcx(&self) -> TyCtxt
<'a
, 'gcx
, 'tcx
> {
122 fn sanitize_type(&mut self, parent
: &fmt
::Debug
, ty
: Ty
<'tcx
>) -> Ty
<'tcx
> {
123 if ty
.needs_infer() || ty
.has_escaping_regions() || ty
.references_error() {
124 span_mirbug_and_err
!(self, parent
, "bad type {:?}", ty
)
130 fn sanitize_lvalue(&mut self, lvalue
: &Lvalue
<'tcx
>, location
: Location
) -> LvalueTy
<'tcx
> {
131 debug
!("sanitize_lvalue: {:?}", lvalue
);
133 Lvalue
::Local(index
) => LvalueTy
::Ty { ty: self.mir.local_decls[index].ty }
,
134 Lvalue
::Static(box Static { def_id, ty: sty }
) => {
135 let sty
= self.sanitize_type(lvalue
, sty
);
136 let ty
= self.tcx().type_of(def_id
);
137 let ty
= self.cx
.normalize(&ty
);
138 if let Err(terr
) = self.cx
.eq_types(self.last_span
, ty
, sty
) {
140 self, lvalue
, "bad static type ({:?}: {:?}): {:?}",
143 LvalueTy
::Ty { ty: sty }
146 Lvalue
::Projection(ref proj
) => {
147 let base_ty
= self.sanitize_lvalue(&proj
.base
, location
);
148 if let LvalueTy
::Ty { ty }
= base_ty
{
149 if ty
.references_error() {
150 assert
!(self.errors_reported
);
151 return LvalueTy
::Ty { ty: self.tcx().types.err }
;
154 self.sanitize_projection(base_ty
, &proj
.elem
, lvalue
, location
)
159 fn sanitize_projection(&mut self,
160 base
: LvalueTy
<'tcx
>,
161 pi
: &LvalueElem
<'tcx
>,
162 lvalue
: &Lvalue
<'tcx
>,
165 debug
!("sanitize_projection: {:?} {:?} {:?}", base
, pi
, lvalue
);
166 let tcx
= self.tcx();
167 let base_ty
= base
.to_ty(tcx
);
168 let span
= self.last_span
;
170 ProjectionElem
::Deref
=> {
171 let deref_ty
= base_ty
.builtin_deref(true, ty
::LvaluePreference
::NoPreference
);
173 ty
: deref_ty
.map(|t
| t
.ty
).unwrap_or_else(|| {
174 span_mirbug_and_err
!(
175 self, lvalue
, "deref of non-pointer {:?}", base_ty
)
179 ProjectionElem
::Index(ref i
) => {
180 self.visit_operand(i
, location
);
181 let index_ty
= i
.ty(self.mir
, tcx
);
182 if index_ty
!= tcx
.types
.usize {
184 ty
: span_mirbug_and_err
!(self, i
, "index by non-usize {:?}", i
)
188 ty
: base_ty
.builtin_index().unwrap_or_else(|| {
189 span_mirbug_and_err
!(
190 self, lvalue
, "index of non-array {:?}", base_ty
)
195 ProjectionElem
::ConstantIndex { .. }
=> {
196 // consider verifying in-bounds
198 ty
: base_ty
.builtin_index().unwrap_or_else(|| {
199 span_mirbug_and_err
!(
200 self, lvalue
, "index of non-array {:?}", base_ty
)
204 ProjectionElem
::Subslice { from, to }
=> {
206 ty
: match base_ty
.sty
{
207 ty
::TyArray(inner
, size
) => {
208 let min_size
= (from
as usize) + (to
as usize);
209 if let Some(rest_size
) = size
.checked_sub(min_size
) {
210 tcx
.mk_array(inner
, rest_size
)
212 span_mirbug_and_err
!(
213 self, lvalue
, "taking too-small slice of {:?}", base_ty
)
216 ty
::TySlice(..) => base_ty
,
218 span_mirbug_and_err
!(
219 self, lvalue
, "slice of non-array {:?}", base_ty
)
224 ProjectionElem
::Downcast(adt_def1
, index
) =>
226 ty
::TyAdt(adt_def
, substs
) if adt_def
.is_enum() && adt_def
== adt_def1
=> {
227 if index
>= adt_def
.variants
.len() {
229 ty
: span_mirbug_and_err
!(
232 "cast to variant #{:?} but enum only has {:?}",
234 adt_def
.variants
.len())
245 ty
: span_mirbug_and_err
!(
246 self, lvalue
, "can't downcast {:?} as {:?}",
250 ProjectionElem
::Field(field
, fty
) => {
251 let fty
= self.sanitize_type(lvalue
, fty
);
252 match self.field_ty(lvalue
, base
, field
) {
254 if let Err(terr
) = self.cx
.eq_types(span
, ty
, fty
) {
256 self, lvalue
, "bad field access ({:?}: {:?}): {:?}",
260 Err(FieldAccessError
::OutOfRange { field_count }
) => {
262 self, lvalue
, "accessed field #{} but variant only has {}",
263 field
.index(), field_count
)
266 LvalueTy
::Ty { ty: fty }
271 fn error(&mut self) -> Ty
<'tcx
> {
272 self.errors_reported
= true;
276 fn field_ty(&mut self,
278 base_ty
: LvalueTy
<'tcx
>,
280 -> Result
<Ty
<'tcx
>, FieldAccessError
>
282 let tcx
= self.tcx();
284 let (variant
, substs
) = match base_ty
{
285 LvalueTy
::Downcast { adt_def, substs, variant_index }
=> {
286 (&adt_def
.variants
[variant_index
], substs
)
288 LvalueTy
::Ty { ty }
=> match ty
.sty
{
289 ty
::TyAdt(adt_def
, substs
) if adt_def
.is_univariant() => {
290 (&adt_def
.variants
[0], substs
)
292 ty
::TyClosure(def_id
, substs
) => {
293 return match substs
.upvar_tys(def_id
, tcx
).nth(field
.index()) {
295 None
=> Err(FieldAccessError
::OutOfRange
{
296 field_count
: substs
.upvar_tys(def_id
, tcx
).count()
300 ty
::TyTuple(tys
, _
) => {
301 return match tys
.get(field
.index()) {
303 None
=> Err(FieldAccessError
::OutOfRange
{
304 field_count
: tys
.len()
308 _
=> return Ok(span_mirbug_and_err
!(
309 self, parent
, "can't project out of {:?}", base_ty
))
313 if let Some(field
) = variant
.fields
.get(field
.index()) {
314 Ok(self.cx
.normalize(&field
.ty(tcx
, substs
)))
316 Err(FieldAccessError
::OutOfRange { field_count: variant.fields.len() }
)
321 pub struct TypeChecker
<'a
, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
> {
322 infcx
: &'a InferCtxt
<'a
, 'gcx
, 'tcx
>,
323 param_env
: ty
::ParamEnv
<'gcx
>,
324 fulfillment_cx
: traits
::FulfillmentContext
<'tcx
>,
326 body_id
: ast
::NodeId
,
327 reported_errors
: FxHashSet
<(Ty
<'tcx
>, Span
)>,
330 impl<'a
, 'gcx
, 'tcx
> TypeChecker
<'a
, 'gcx
, 'tcx
> {
331 fn new(infcx
: &'a InferCtxt
<'a
, 'gcx
, 'tcx
>,
332 body_id
: ast
::NodeId
,
333 param_env
: ty
::ParamEnv
<'gcx
>)
337 fulfillment_cx
: traits
::FulfillmentContext
::new(),
341 reported_errors
: FxHashSet(),
345 fn misc(&self, span
: Span
) -> traits
::ObligationCause
<'tcx
> {
346 traits
::ObligationCause
::misc(span
, self.body_id
)
349 pub fn register_infer_ok_obligations
<T
>(&mut self, infer_ok
: InferOk
<'tcx
, T
>) -> T
{
350 for obligation
in infer_ok
.obligations
{
351 self.fulfillment_cx
.register_predicate_obligation(self.infcx
, obligation
);
356 fn sub_types(&mut self, sub
: Ty
<'tcx
>, sup
: Ty
<'tcx
>)
357 -> infer
::UnitResult
<'tcx
>
359 self.infcx
.at(&self.misc(self.last_span
), self.param_env
)
361 .map(|ok
| self.register_infer_ok_obligations(ok
))
364 fn eq_types(&mut self, span
: Span
, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>)
365 -> infer
::UnitResult
<'tcx
>
367 self.infcx
.at(&self.misc(span
), self.param_env
)
369 .map(|ok
| self.register_infer_ok_obligations(ok
))
372 fn tcx(&self) -> TyCtxt
<'a
, 'gcx
, 'tcx
> {
376 fn check_stmt(&mut self, mir
: &Mir
<'tcx
>, stmt
: &Statement
<'tcx
>) {
377 debug
!("check_stmt: {:?}", stmt
);
378 let tcx
= self.tcx();
380 StatementKind
::Assign(ref lv
, ref rv
) => {
381 let lv_ty
= lv
.ty(mir
, tcx
).to_ty(tcx
);
382 let rv_ty
= rv
.ty(mir
, tcx
);
383 if let Err(terr
) = self.sub_types(rv_ty
, lv_ty
) {
384 span_mirbug
!(self, stmt
, "bad assignment ({:?} = {:?}): {:?}",
388 StatementKind
::SetDiscriminant{ ref lvalue, variant_index }
=> {
389 let lvalue_type
= lvalue
.ty(mir
, tcx
).to_ty(tcx
);
390 let adt
= match lvalue_type
.sty
{
391 TypeVariants
::TyAdt(adt
, _
) if adt
.is_enum() => adt
,
393 span_bug
!(stmt
.source_info
.span
,
394 "bad set discriminant ({:?} = {:?}): lhs is not an enum",
399 if variant_index
>= adt
.variants
.len() {
400 span_bug
!(stmt
.source_info
.span
,
401 "bad set discriminant ({:?} = {:?}): value of of range",
406 StatementKind
::StorageLive(ref lv
) |
407 StatementKind
::StorageDead(ref lv
) => {
409 Lvalue
::Local(_
) => {}
411 span_mirbug
!(self, stmt
, "bad lvalue: expected local");
415 StatementKind
::InlineAsm { .. }
|
416 StatementKind
::EndRegion(_
) |
417 StatementKind
::Nop
=> {}
421 fn check_terminator(&mut self,
423 term
: &Terminator
<'tcx
>) {
424 debug
!("check_terminator: {:?}", term
);
425 let tcx
= self.tcx();
427 TerminatorKind
::Goto { .. }
|
428 TerminatorKind
::Resume
|
429 TerminatorKind
::Return
|
430 TerminatorKind
::Unreachable
|
431 TerminatorKind
::Drop { .. }
=> {
432 // no checks needed for these
436 TerminatorKind
::DropAndReplace
{
441 let lv_ty
= location
.ty(mir
, tcx
).to_ty(tcx
);
442 let rv_ty
= value
.ty(mir
, tcx
);
443 if let Err(terr
) = self.sub_types(rv_ty
, lv_ty
) {
444 span_mirbug
!(self, term
, "bad DropAndReplace ({:?} = {:?}): {:?}",
448 TerminatorKind
::SwitchInt { ref discr, switch_ty, .. }
=> {
449 let discr_ty
= discr
.ty(mir
, tcx
);
450 if let Err(terr
) = self.sub_types(discr_ty
, switch_ty
) {
451 span_mirbug
!(self, term
, "bad SwitchInt ({:?} on {:?}): {:?}",
452 switch_ty
, discr_ty
, terr
);
454 if !switch_ty
.is_integral() && !switch_ty
.is_char() &&
457 span_mirbug
!(self, term
, "bad SwitchInt discr ty {:?}",switch_ty
);
459 // FIXME: check the values
461 TerminatorKind
::Call { ref func, ref args, ref destination, .. }
=> {
462 let func_ty
= func
.ty(mir
, tcx
);
463 debug
!("check_terminator: call, func_ty={:?}", func_ty
);
464 let sig
= match func_ty
.sty
{
465 ty
::TyFnDef(..) | ty
::TyFnPtr(_
) => func_ty
.fn_sig(tcx
),
467 span_mirbug
!(self, term
, "call to non-function {:?}", func_ty
);
471 let sig
= tcx
.erase_late_bound_regions(&sig
);
472 let sig
= self.normalize(&sig
);
473 self.check_call_dest(mir
, term
, &sig
, destination
);
475 if self.is_box_free(func
) {
476 self.check_box_free_inputs(mir
, term
, &sig
, args
);
478 self.check_call_inputs(mir
, term
, &sig
, args
);
481 TerminatorKind
::Assert { ref cond, ref msg, .. }
=> {
482 let cond_ty
= cond
.ty(mir
, tcx
);
483 if cond_ty
!= tcx
.types
.bool
{
484 span_mirbug
!(self, term
, "bad Assert ({:?}, not bool", cond_ty
);
487 if let AssertMessage
::BoundsCheck { ref len, ref index }
= *msg
{
488 if len
.ty(mir
, tcx
) != tcx
.types
.usize {
489 span_mirbug
!(self, len
, "bounds-check length non-usize {:?}", len
)
491 if index
.ty(mir
, tcx
) != tcx
.types
.usize {
492 span_mirbug
!(self, index
, "bounds-check index non-usize {:?}", index
)
499 fn check_call_dest(&mut self,
501 term
: &Terminator
<'tcx
>,
502 sig
: &ty
::FnSig
<'tcx
>,
503 destination
: &Option
<(Lvalue
<'tcx
>, BasicBlock
)>) {
504 let tcx
= self.tcx();
506 Some((ref dest
, _
)) => {
507 let dest_ty
= dest
.ty(mir
, tcx
).to_ty(tcx
);
508 if let Err(terr
) = self.sub_types(sig
.output(), dest_ty
) {
509 span_mirbug
!(self, term
,
510 "call dest mismatch ({:?} <- {:?}): {:?}",
511 dest_ty
, sig
.output(), terr
);
515 // FIXME(canndrew): This is_never should probably be an is_uninhabited
516 if !sig
.output().is_never() {
517 span_mirbug
!(self, term
, "call to converging function {:?} w/o dest", sig
);
523 fn check_call_inputs(&mut self,
525 term
: &Terminator
<'tcx
>,
526 sig
: &ty
::FnSig
<'tcx
>,
527 args
: &[Operand
<'tcx
>])
529 debug
!("check_call_inputs({:?}, {:?})", sig
, args
);
530 if args
.len() < sig
.inputs().len() ||
531 (args
.len() > sig
.inputs().len() && !sig
.variadic
) {
532 span_mirbug
!(self, term
, "call to {:?} with wrong # of args", sig
);
534 for (n
, (fn_arg
, op_arg
)) in sig
.inputs().iter().zip(args
).enumerate() {
535 let op_arg_ty
= op_arg
.ty(mir
, self.tcx());
536 if let Err(terr
) = self.sub_types(op_arg_ty
, fn_arg
) {
537 span_mirbug
!(self, term
, "bad arg #{:?} ({:?} <- {:?}): {:?}",
538 n
, fn_arg
, op_arg_ty
, terr
);
543 fn is_box_free(&self, operand
: &Operand
<'tcx
>) -> bool
{
545 &Operand
::Constant(box Constant
{
546 literal
: Literal
::Value
{
547 value
: ConstVal
::Function(def_id
, _
), ..
550 Some(def_id
) == self.tcx().lang_items
.box_free_fn()
556 fn check_box_free_inputs(&mut self,
558 term
: &Terminator
<'tcx
>,
559 sig
: &ty
::FnSig
<'tcx
>,
560 args
: &[Operand
<'tcx
>])
562 debug
!("check_box_free_inputs");
564 // box_free takes a Box as a pointer. Allow for that.
566 if sig
.inputs().len() != 1 {
567 span_mirbug
!(self, term
, "box_free should take 1 argument");
571 let pointee_ty
= match sig
.inputs()[0].sty
{
572 ty
::TyRawPtr(mt
) => mt
.ty
,
574 span_mirbug
!(self, term
, "box_free should take a raw ptr");
580 span_mirbug
!(self, term
, "box_free called with wrong # of args");
584 let ty
= args
[0].ty(mir
, self.tcx());
585 let arg_ty
= match ty
.sty
{
586 ty
::TyRawPtr(mt
) => mt
.ty
,
587 ty
::TyAdt(def
, _
) if def
.is_box() => ty
.boxed_ty(),
589 span_mirbug
!(self, term
, "box_free called with bad arg ty");
594 if let Err(terr
) = self.sub_types(arg_ty
, pointee_ty
) {
595 span_mirbug
!(self, term
, "bad box_free arg ({:?} <- {:?}): {:?}",
596 pointee_ty
, arg_ty
, terr
);
600 fn check_iscleanup(&mut self, mir
: &Mir
<'tcx
>, block
: &BasicBlockData
<'tcx
>)
602 let is_cleanup
= block
.is_cleanup
;
603 self.last_span
= block
.terminator().source_info
.span
;
604 match block
.terminator().kind
{
605 TerminatorKind
::Goto { target }
=>
606 self.assert_iscleanup(mir
, block
, target
, is_cleanup
),
607 TerminatorKind
::SwitchInt { ref targets, .. }
=> {
608 for target
in targets
{
609 self.assert_iscleanup(mir
, block
, *target
, is_cleanup
);
612 TerminatorKind
::Resume
=> {
614 span_mirbug
!(self, block
, "resume on non-cleanup block!")
617 TerminatorKind
::Return
=> {
619 span_mirbug
!(self, block
, "return on cleanup block")
622 TerminatorKind
::Unreachable
=> {}
623 TerminatorKind
::Drop { target, unwind, .. }
|
624 TerminatorKind
::DropAndReplace { target, unwind, .. }
|
625 TerminatorKind
::Assert { target, cleanup: unwind, .. }
=> {
626 self.assert_iscleanup(mir
, block
, target
, is_cleanup
);
627 if let Some(unwind
) = unwind
{
629 span_mirbug
!(self, block
, "unwind on cleanup block")
631 self.assert_iscleanup(mir
, block
, unwind
, true);
634 TerminatorKind
::Call { ref destination, cleanup, .. }
=> {
635 if let &Some((_
, target
)) = destination
{
636 self.assert_iscleanup(mir
, block
, target
, is_cleanup
);
638 if let Some(cleanup
) = cleanup
{
640 span_mirbug
!(self, block
, "cleanup on cleanup block")
642 self.assert_iscleanup(mir
, block
, cleanup
, true);
648 fn assert_iscleanup(&mut self,
654 if mir
[bb
].is_cleanup
!= iscleanuppad
{
655 span_mirbug
!(self, ctxt
, "cleanuppad mismatch: {:?} should be {:?}",
660 fn check_local(&mut self, mir
: &Mir
<'gcx
>, local
: Local
, local_decl
: &LocalDecl
<'gcx
>) {
661 match mir
.local_kind(local
) {
662 LocalKind
::ReturnPointer
| LocalKind
::Arg
=> {
663 // return values of normal functions are required to be
664 // sized by typeck, but return values of ADT constructors are
665 // not because we don't include a `Self: Sized` bounds on them.
667 // Unbound parts of arguments were never required to be Sized
668 // - maybe we should make that a warning.
671 LocalKind
::Var
| LocalKind
::Temp
=> {}
674 let span
= local_decl
.source_info
.span
;
675 let ty
= local_decl
.ty
;
676 if !ty
.is_sized(self.tcx().global_tcx(), self.param_env
, span
) {
677 // in current MIR construction, all non-control-flow rvalue
678 // expressions evaluate through `as_temp` or `into` a return
679 // slot or local, so to find all unsized rvalues it is enough
680 // to check all temps, return slots and locals.
681 if let None
= self.reported_errors
.replace((ty
, span
)) {
682 span_err
!(self.tcx().sess
, span
, E0161
,
683 "cannot move a value of type {0}: the size of {0} \
684 cannot be statically determined", ty
);
689 fn typeck_mir(&mut self, mir
: &Mir
<'gcx
>) {
690 self.last_span
= mir
.span
;
691 debug
!("run_on_mir: {:?}", mir
.span
);
693 for (local
, local_decl
) in mir
.local_decls
.iter_enumerated() {
694 self.check_local(mir
, local
, local_decl
);
697 for block
in mir
.basic_blocks() {
698 for stmt
in &block
.statements
{
699 if stmt
.source_info
.span
!= DUMMY_SP
{
700 self.last_span
= stmt
.source_info
.span
;
702 self.check_stmt(mir
, stmt
);
705 self.check_terminator(mir
, block
.terminator());
706 self.check_iscleanup(mir
, block
);
711 fn normalize
<T
>(&mut self, value
: &T
) -> T
712 where T
: fmt
::Debug
+ TypeFoldable
<'tcx
>
714 let mut selcx
= traits
::SelectionContext
::new(self.infcx
);
715 let cause
= traits
::ObligationCause
::misc(self.last_span
, ast
::CRATE_NODE_ID
);
716 let traits
::Normalized { value, obligations }
=
717 traits
::normalize(&mut selcx
, self.param_env
, cause
, value
);
719 debug
!("normalize: value={:?} obligations={:?}",
723 let mut fulfill_cx
= &mut self.fulfillment_cx
;
724 for obligation
in obligations
{
725 fulfill_cx
.register_predicate_obligation(self.infcx
, obligation
);
731 fn verify_obligations(&mut self, mir
: &Mir
<'tcx
>) {
732 self.last_span
= mir
.span
;
733 if let Err(e
) = self.fulfillment_cx
.select_all_or_error(self.infcx
) {
734 span_mirbug
!(self, "", "errors selecting obligation: {:?}",
740 pub struct TypeckMir
;
743 pub fn new() -> Self {
748 impl MirPass
for TypeckMir
{
749 fn run_pass
<'a
, 'tcx
>(&self,
750 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
752 mir
: &mut Mir
<'tcx
>) {
753 let item_id
= src
.item_id();
754 let def_id
= tcx
.hir
.local_def_id(item_id
);
755 debug
!("run_pass: {:?}", def_id
);
757 if tcx
.sess
.err_count() > 0 {
758 // compiling a broken program can obviously result in a
759 // broken MIR, so try not to report duplicate errors.
762 let param_env
= tcx
.param_env(def_id
);
763 tcx
.infer_ctxt().enter(|infcx
| {
764 let mut checker
= TypeChecker
::new(&infcx
, item_id
, param_env
);
766 let mut verifier
= TypeVerifier
::new(&mut checker
, mir
);
767 verifier
.visit_mir(mir
);
768 if verifier
.errors_reported
{
769 // don't do further checks to avoid ICEs
773 checker
.typeck_mir(mir
);
774 checker
.verify_obligations(mir
);