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}
;
15 use rustc
::traits
::{self, Reveal}
;
16 use rustc
::ty
::fold
::TypeFoldable
;
17 use rustc
::ty
::{self, Ty, TyCtxt, TypeVariants}
;
18 use rustc
::mir
::repr
::*;
19 use rustc
::mir
::tcx
::LvalueTy
;
20 use rustc
::mir
::transform
::{MirPass, MirSource, Pass}
;
21 use rustc
::mir
::visit
::{self, Visitor}
;
23 use syntax_pos
::{Span, DUMMY_SP}
;
25 use rustc_data_structures
::indexed_vec
::Idx
;
27 macro_rules
! span_mirbug
{
28 ($context
:expr
, $elem
:expr
, $
($message
:tt
)*) => ({
29 $context
.tcx().sess
.span_warn(
31 &format
!("broken MIR ({:?}): {}", $elem
, format
!($
($message
)*))
36 macro_rules
! span_mirbug_and_err
{
37 ($context
:expr
, $elem
:expr
, $
($message
:tt
)*) => ({
39 $context
.tcx().sess
.span_warn(
41 &format
!("broken MIR ({:?}): {:?}", $elem
, format
!($
($message
)*))
48 enum FieldAccessError
{
49 OutOfRange { field_count: usize }
52 /// Verifies that MIR types are sane to not crash further checks.
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
57 struct TypeVerifier
<'a
, 'b
: 'a
, 'gcx
: 'b
+'tcx
, 'tcx
: 'b
> {
58 cx
: &'a
mut TypeChecker
<'b
, 'gcx
, 'tcx
>,
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
;
71 fn visit_lvalue(&mut self, lvalue
: &Lvalue
<'tcx
>, _context
: visit
::LvalueContext
) {
72 self.sanitize_lvalue(lvalue
);
75 fn visit_constant(&mut self, constant
: &Constant
<'tcx
>) {
76 self.super_constant(constant
);
77 self.sanitize_type(constant
, constant
.ty
);
80 fn visit_rvalue(&mut self, rvalue
: &Rvalue
<'tcx
>) {
81 self.super_rvalue(rvalue
);
82 if let Some(ty
) = rvalue
.ty(self.mir
, self.tcx()) {
83 self.sanitize_type(rvalue
, ty
);
87 fn visit_mir(&mut self, mir
: &Mir
<'tcx
>) {
88 self.sanitize_type(&"return type", mir
.return_ty
);
89 for var_decl
in &mir
.var_decls
{
90 self.sanitize_type(var_decl
, var_decl
.ty
);
92 for (n
, arg_decl
) in mir
.arg_decls
.iter().enumerate() {
93 self.sanitize_type(&(n
, arg_decl
), arg_decl
.ty
);
95 for (n
, tmp_decl
) in mir
.temp_decls
.iter().enumerate() {
96 self.sanitize_type(&(n
, tmp_decl
), tmp_decl
.ty
);
98 if self.errors_reported
{
105 impl<'a
, 'b
, 'gcx
, 'tcx
> TypeVerifier
<'a
, 'b
, 'gcx
, 'tcx
> {
106 fn new(cx
: &'a
mut TypeChecker
<'b
, 'gcx
, 'tcx
>, mir
: &'a Mir
<'tcx
>) -> Self {
111 errors_reported
: false
115 fn tcx(&self) -> TyCtxt
<'a
, 'gcx
, 'tcx
> {
119 fn sanitize_type(&mut self, parent
: &fmt
::Debug
, ty
: Ty
<'tcx
>) -> Ty
<'tcx
> {
120 if ty
.needs_infer() || ty
.has_escaping_regions() || ty
.references_error() {
121 span_mirbug_and_err
!(self, parent
, "bad type {:?}", ty
)
127 fn sanitize_lvalue(&mut self, lvalue
: &Lvalue
<'tcx
>) -> LvalueTy
<'tcx
> {
128 debug
!("sanitize_lvalue: {:?}", lvalue
);
130 Lvalue
::Var(index
) => LvalueTy
::Ty { ty: self.mir.var_decls[index].ty }
,
131 Lvalue
::Temp(index
) => LvalueTy
::Ty { ty: self.mir.temp_decls[index].ty }
,
132 Lvalue
::Arg(index
) => LvalueTy
::Ty { ty: self.mir.arg_decls[index].ty }
,
133 Lvalue
::Static(def_id
) =>
134 LvalueTy
::Ty { ty: self.tcx().lookup_item_type(def_id).ty }
,
135 Lvalue
::ReturnPointer
=> {
136 LvalueTy
::Ty { ty: self.mir.return_ty }
138 Lvalue
::Projection(ref proj
) => {
139 let base_ty
= self.sanitize_lvalue(&proj
.base
);
140 if let LvalueTy
::Ty { ty }
= base_ty
{
141 if ty
.references_error() {
142 assert
!(self.errors_reported
);
143 return LvalueTy
::Ty { ty: self.tcx().types.err }
;
146 self.sanitize_projection(base_ty
, &proj
.elem
, lvalue
)
151 fn sanitize_projection(&mut self,
152 base
: LvalueTy
<'tcx
>,
153 pi
: &LvalueElem
<'tcx
>,
154 lvalue
: &Lvalue
<'tcx
>)
156 debug
!("sanitize_projection: {:?} {:?} {:?}", base
, pi
, lvalue
);
157 let tcx
= self.tcx();
158 let base_ty
= base
.to_ty(tcx
);
159 let span
= self.last_span
;
161 ProjectionElem
::Deref
=> {
162 let deref_ty
= base_ty
.builtin_deref(true, ty
::LvaluePreference
::NoPreference
);
164 ty
: deref_ty
.map(|t
| t
.ty
).unwrap_or_else(|| {
165 span_mirbug_and_err
!(
166 self, lvalue
, "deref of non-pointer {:?}", base_ty
)
170 ProjectionElem
::Index(ref i
) => {
171 self.visit_operand(i
);
172 let index_ty
= i
.ty(self.mir
, tcx
);
173 if index_ty
!= tcx
.types
.usize {
175 ty
: span_mirbug_and_err
!(self, i
, "index by non-usize {:?}", i
)
179 ty
: base_ty
.builtin_index().unwrap_or_else(|| {
180 span_mirbug_and_err
!(
181 self, lvalue
, "index of non-array {:?}", base_ty
)
186 ProjectionElem
::ConstantIndex { .. }
=> {
187 // consider verifying in-bounds
189 ty
: base_ty
.builtin_index().unwrap_or_else(|| {
190 span_mirbug_and_err
!(
191 self, lvalue
, "index of non-array {:?}", base_ty
)
195 ProjectionElem
::Subslice { from, to }
=> {
197 ty
: match base_ty
.sty
{
198 ty
::TyArray(inner
, size
) => {
199 let min_size
= (from
as usize) + (to
as usize);
200 if let Some(rest_size
) = size
.checked_sub(min_size
) {
201 tcx
.mk_array(inner
, rest_size
)
203 span_mirbug_and_err
!(
204 self, lvalue
, "taking too-small slice of {:?}", base_ty
)
207 ty
::TySlice(..) => base_ty
,
209 span_mirbug_and_err
!(
210 self, lvalue
, "slice of non-array {:?}", base_ty
)
215 ProjectionElem
::Downcast(adt_def1
, index
) =>
217 ty
::TyEnum(adt_def
, substs
) if adt_def
== adt_def1
=> {
218 if index
>= adt_def
.variants
.len() {
220 ty
: span_mirbug_and_err
!(
223 "cast to variant #{:?} but enum only has {:?}",
225 adt_def
.variants
.len())
236 ty
: span_mirbug_and_err
!(
237 self, lvalue
, "can't downcast {:?} as {:?}",
241 ProjectionElem
::Field(field
, fty
) => {
242 let fty
= self.sanitize_type(lvalue
, fty
);
243 match self.field_ty(lvalue
, base
, field
) {
245 if let Err(terr
) = self.cx
.eq_types(span
, ty
, fty
) {
247 self, lvalue
, "bad field access ({:?}: {:?}): {:?}",
251 Err(FieldAccessError
::OutOfRange { field_count }
) => {
253 self, lvalue
, "accessed field #{} but variant only has {}",
254 field
.index(), field_count
)
257 LvalueTy
::Ty { ty: fty }
262 fn error(&mut self) -> Ty
<'tcx
> {
263 self.errors_reported
= true;
267 fn field_ty(&mut self,
269 base_ty
: LvalueTy
<'tcx
>,
271 -> Result
<Ty
<'tcx
>, FieldAccessError
>
273 let tcx
= self.tcx();
275 let (variant
, substs
) = match base_ty
{
276 LvalueTy
::Downcast { adt_def, substs, variant_index }
=> {
277 (&adt_def
.variants
[variant_index
], substs
)
279 LvalueTy
::Ty { ty }
=> match ty
.sty
{
280 ty
::TyStruct(adt_def
, substs
) | ty
::TyEnum(adt_def
, substs
)
281 if adt_def
.is_univariant() => {
282 (&adt_def
.variants
[0], substs
)
284 ty
::TyTuple(tys
) | ty
::TyClosure(_
, ty
::ClosureSubsts
{
287 return match tys
.get(field
.index()) {
289 None
=> Err(FieldAccessError
::OutOfRange
{
290 field_count
: tys
.len()
294 _
=> return Ok(span_mirbug_and_err
!(
295 self, parent
, "can't project out of {:?}", base_ty
))
299 if let Some(field
) = variant
.fields
.get(field
.index()) {
300 Ok(self.cx
.normalize(&field
.ty(tcx
, substs
)))
302 Err(FieldAccessError
::OutOfRange { field_count: variant.fields.len() }
)
307 pub struct TypeChecker
<'a
, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
> {
308 infcx
: &'a InferCtxt
<'a
, 'gcx
, 'tcx
>,
309 fulfillment_cx
: traits
::FulfillmentContext
<'tcx
>,
313 impl<'a
, 'gcx
, 'tcx
> TypeChecker
<'a
, 'gcx
, 'tcx
> {
314 fn new(infcx
: &'a InferCtxt
<'a
, 'gcx
, 'tcx
>) -> Self {
317 fulfillment_cx
: traits
::FulfillmentContext
::new(),
322 fn sub_types(&self, span
: Span
, sup
: Ty
<'tcx
>, sub
: Ty
<'tcx
>)
323 -> infer
::UnitResult
<'tcx
>
325 self.infcx
.sub_types(false, infer
::TypeOrigin
::Misc(span
), sup
, sub
)
326 // FIXME(#32730) propagate obligations
327 .map(|InferOk { obligations, .. }
| assert
!(obligations
.is_empty()))
330 fn eq_types(&self, span
: Span
, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>)
331 -> infer
::UnitResult
<'tcx
>
333 self.infcx
.eq_types(false, infer
::TypeOrigin
::Misc(span
), a
, b
)
334 // FIXME(#32730) propagate obligations
335 .map(|InferOk { obligations, .. }
| assert
!(obligations
.is_empty()))
338 fn tcx(&self) -> TyCtxt
<'a
, 'gcx
, 'tcx
> {
342 fn check_stmt(&mut self, mir
: &Mir
<'tcx
>, stmt
: &Statement
<'tcx
>) {
343 debug
!("check_stmt: {:?}", stmt
);
344 let tcx
= self.tcx();
346 StatementKind
::Assign(ref lv
, ref rv
) => {
347 let lv_ty
= lv
.ty(mir
, tcx
).to_ty(tcx
);
348 let rv_ty
= rv
.ty(mir
, tcx
);
349 if let Some(rv_ty
) = rv_ty
{
350 if let Err(terr
) = self.sub_types(self.last_span
, rv_ty
, lv_ty
) {
351 span_mirbug
!(self, stmt
, "bad assignment ({:?} = {:?}): {:?}",
354 // FIXME: rvalue with undeterminable type - e.g. inline
358 StatementKind
::SetDiscriminant{ ref lvalue, variant_index }
=> {
359 let lvalue_type
= lvalue
.ty(mir
, tcx
).to_ty(tcx
);
360 let adt
= match lvalue_type
.sty
{
361 TypeVariants
::TyEnum(adt
, _
) => adt
,
363 span_bug
!(stmt
.source_info
.span
,
364 "bad set discriminant ({:?} = {:?}): lhs is not an enum",
369 if variant_index
>= adt
.variants
.len() {
370 span_bug
!(stmt
.source_info
.span
,
371 "bad set discriminant ({:?} = {:?}): value of of range",
376 StatementKind
::StorageLive(ref lv
) |
377 StatementKind
::StorageDead(ref lv
) => {
379 Lvalue
::Temp(_
) | Lvalue
::Var(_
) => {}
381 span_mirbug
!(self, stmt
, "bad lvalue: expected temp or var");
388 fn check_terminator(&mut self,
390 term
: &Terminator
<'tcx
>) {
391 debug
!("check_terminator: {:?}", term
);
392 let tcx
= self.tcx();
394 TerminatorKind
::Goto { .. }
|
395 TerminatorKind
::Resume
|
396 TerminatorKind
::Return
|
397 TerminatorKind
::Unreachable
|
398 TerminatorKind
::Drop { .. }
=> {
399 // no checks needed for these
403 TerminatorKind
::DropAndReplace
{
408 let lv_ty
= location
.ty(mir
, tcx
).to_ty(tcx
);
409 let rv_ty
= value
.ty(mir
, tcx
);
410 if let Err(terr
) = self.sub_types(self.last_span
, rv_ty
, lv_ty
) {
411 span_mirbug
!(self, term
, "bad DropAndReplace ({:?} = {:?}): {:?}",
416 TerminatorKind
::If { ref cond, .. }
=> {
417 let cond_ty
= cond
.ty(mir
, tcx
);
421 span_mirbug
!(self, term
, "bad If ({:?}, not bool", cond_ty
);
425 TerminatorKind
::SwitchInt { ref discr, switch_ty, .. }
=> {
426 let discr_ty
= discr
.ty(mir
, tcx
).to_ty(tcx
);
427 if let Err(terr
) = self.sub_types(self.last_span
, discr_ty
, switch_ty
) {
428 span_mirbug
!(self, term
, "bad SwitchInt ({:?} on {:?}): {:?}",
429 switch_ty
, discr_ty
, terr
);
431 if !switch_ty
.is_integral() && !switch_ty
.is_char() &&
434 span_mirbug
!(self, term
, "bad SwitchInt discr ty {:?}",switch_ty
);
436 // FIXME: check the values
438 TerminatorKind
::Switch { ref discr, adt_def, ref targets }
=> {
439 let discr_ty
= discr
.ty(mir
, tcx
).to_ty(tcx
);
442 if def
== adt_def
&& adt_def
.variants
.len() == targets
.len()
445 span_mirbug
!(self, term
, "bad Switch ({:?} on {:?})",
450 TerminatorKind
::Call { ref func, ref args, ref destination, .. }
=> {
451 let func_ty
= func
.ty(mir
, tcx
);
452 debug
!("check_terminator: call, func_ty={:?}", func_ty
);
453 let func_ty
= match func_ty
.sty
{
454 ty
::TyFnDef(_
, _
, func_ty
) | ty
::TyFnPtr(func_ty
) => func_ty
,
456 span_mirbug
!(self, term
, "call to non-function {:?}", func_ty
);
460 let sig
= tcx
.erase_late_bound_regions(&func_ty
.sig
);
461 let sig
= self.normalize(&sig
);
462 self.check_call_dest(mir
, term
, &sig
, destination
);
464 if self.is_box_free(func
) {
465 self.check_box_free_inputs(mir
, term
, &sig
, args
);
467 self.check_call_inputs(mir
, term
, &sig
, args
);
470 TerminatorKind
::Assert { ref cond, ref msg, .. }
=> {
471 let cond_ty
= cond
.ty(mir
, tcx
);
472 if cond_ty
!= tcx
.types
.bool
{
473 span_mirbug
!(self, term
, "bad Assert ({:?}, not bool", cond_ty
);
476 if let AssertMessage
::BoundsCheck { ref len, ref index }
= *msg
{
477 if len
.ty(mir
, tcx
) != tcx
.types
.usize {
478 span_mirbug
!(self, len
, "bounds-check length non-usize {:?}", len
)
480 if index
.ty(mir
, tcx
) != tcx
.types
.usize {
481 span_mirbug
!(self, index
, "bounds-check index non-usize {:?}", index
)
488 fn check_call_dest(&self,
490 term
: &Terminator
<'tcx
>,
491 sig
: &ty
::FnSig
<'tcx
>,
492 destination
: &Option
<(Lvalue
<'tcx
>, BasicBlock
)>) {
493 let tcx
= self.tcx();
495 Some((ref dest
, _
)) => {
496 let dest_ty
= dest
.ty(mir
, tcx
).to_ty(tcx
);
497 if let Err(terr
) = self.sub_types(self.last_span
, sig
.output
, dest_ty
) {
498 span_mirbug
!(self, term
,
499 "call dest mismatch ({:?} <- {:?}): {:?}",
500 dest_ty
, sig
.output
, terr
);
504 // FIXME(canndrew): This is_never should probably be an is_uninhabited
505 if !sig
.output
.is_never() {
506 span_mirbug
!(self, term
, "call to converging function {:?} w/o dest", sig
);
512 fn check_call_inputs(&self,
514 term
: &Terminator
<'tcx
>,
515 sig
: &ty
::FnSig
<'tcx
>,
516 args
: &[Operand
<'tcx
>])
518 debug
!("check_call_inputs({:?}, {:?})", sig
, args
);
519 if args
.len() < sig
.inputs
.len() ||
520 (args
.len() > sig
.inputs
.len() && !sig
.variadic
) {
521 span_mirbug
!(self, term
, "call to {:?} with wrong # of args", sig
);
523 for (n
, (fn_arg
, op_arg
)) in sig
.inputs
.iter().zip(args
).enumerate() {
524 let op_arg_ty
= op_arg
.ty(mir
, self.tcx());
525 if let Err(terr
) = self.sub_types(self.last_span
, op_arg_ty
, fn_arg
) {
526 span_mirbug
!(self, term
, "bad arg #{:?} ({:?} <- {:?}): {:?}",
527 n
, fn_arg
, op_arg_ty
, terr
);
532 fn is_box_free(&self, operand
: &Operand
<'tcx
>) -> bool
{
534 &Operand
::Constant(Constant
{
535 literal
: Literal
::Item { def_id, .. }
, ..
537 Some(def_id
) == self.tcx().lang_items
.box_free_fn()
543 fn check_box_free_inputs(&self,
545 term
: &Terminator
<'tcx
>,
546 sig
: &ty
::FnSig
<'tcx
>,
547 args
: &[Operand
<'tcx
>])
549 debug
!("check_box_free_inputs");
551 // box_free takes a Box as a pointer. Allow for that.
553 if sig
.inputs
.len() != 1 {
554 span_mirbug
!(self, term
, "box_free should take 1 argument");
558 let pointee_ty
= match sig
.inputs
[0].sty
{
559 ty
::TyRawPtr(mt
) => mt
.ty
,
561 span_mirbug
!(self, term
, "box_free should take a raw ptr");
567 span_mirbug
!(self, term
, "box_free called with wrong # of args");
571 let arg_ty
= match args
[0].ty(mir
, self.tcx()).sty
{
572 ty
::TyRawPtr(mt
) => mt
.ty
,
575 span_mirbug
!(self, term
, "box_free called with bad arg ty");
580 if let Err(terr
) = self.sub_types(self.last_span
, arg_ty
, pointee_ty
) {
581 span_mirbug
!(self, term
, "bad box_free arg ({:?} <- {:?}): {:?}",
582 pointee_ty
, arg_ty
, terr
);
586 fn check_iscleanup(&mut self, mir
: &Mir
<'tcx
>, block
: &BasicBlockData
<'tcx
>)
588 let is_cleanup
= block
.is_cleanup
;
589 self.last_span
= block
.terminator().source_info
.span
;
590 match block
.terminator().kind
{
591 TerminatorKind
::Goto { target }
=>
592 self.assert_iscleanup(mir
, block
, target
, is_cleanup
),
593 TerminatorKind
::If { targets: (on_true, on_false), .. }
=> {
594 self.assert_iscleanup(mir
, block
, on_true
, is_cleanup
);
595 self.assert_iscleanup(mir
, block
, on_false
, is_cleanup
);
597 TerminatorKind
::Switch { ref targets, .. }
|
598 TerminatorKind
::SwitchInt { ref targets, .. }
=> {
599 for target
in targets
{
600 self.assert_iscleanup(mir
, block
, *target
, is_cleanup
);
603 TerminatorKind
::Resume
=> {
605 span_mirbug
!(self, block
, "resume on non-cleanup block!")
608 TerminatorKind
::Return
=> {
610 span_mirbug
!(self, block
, "return on cleanup block")
613 TerminatorKind
::Unreachable
=> {}
614 TerminatorKind
::Drop { target, unwind, .. }
|
615 TerminatorKind
::DropAndReplace { target, unwind, .. }
|
616 TerminatorKind
::Assert { target, cleanup: unwind, .. }
=> {
617 self.assert_iscleanup(mir
, block
, target
, is_cleanup
);
618 if let Some(unwind
) = unwind
{
620 span_mirbug
!(self, block
, "unwind on cleanup block")
622 self.assert_iscleanup(mir
, block
, unwind
, true);
625 TerminatorKind
::Call { ref destination, cleanup, .. }
=> {
626 if let &Some((_
, target
)) = destination
{
627 self.assert_iscleanup(mir
, block
, target
, is_cleanup
);
629 if let Some(cleanup
) = cleanup
{
631 span_mirbug
!(self, block
, "cleanup on cleanup block")
633 self.assert_iscleanup(mir
, block
, cleanup
, true);
639 fn assert_iscleanup(&mut self,
645 if mir
[bb
].is_cleanup
!= iscleanuppad
{
646 span_mirbug
!(self, ctxt
, "cleanuppad mismatch: {:?} should be {:?}",
651 fn typeck_mir(&mut self, mir
: &Mir
<'tcx
>) {
652 self.last_span
= mir
.span
;
653 debug
!("run_on_mir: {:?}", mir
.span
);
654 for block
in mir
.basic_blocks() {
655 for stmt
in &block
.statements
{
656 if stmt
.source_info
.span
!= DUMMY_SP
{
657 self.last_span
= stmt
.source_info
.span
;
659 self.check_stmt(mir
, stmt
);
662 self.check_terminator(mir
, block
.terminator());
663 self.check_iscleanup(mir
, block
);
668 fn normalize
<T
>(&mut self, value
: &T
) -> T
669 where T
: fmt
::Debug
+ TypeFoldable
<'tcx
>
671 let mut selcx
= traits
::SelectionContext
::new(self.infcx
);
672 let cause
= traits
::ObligationCause
::misc(self.last_span
, 0);
673 let traits
::Normalized { value, obligations }
=
674 traits
::normalize(&mut selcx
, cause
, value
);
676 debug
!("normalize: value={:?} obligations={:?}",
680 let mut fulfill_cx
= &mut self.fulfillment_cx
;
681 for obligation
in obligations
{
682 fulfill_cx
.register_predicate_obligation(self.infcx
, obligation
);
688 fn verify_obligations(&mut self, mir
: &Mir
<'tcx
>) {
689 self.last_span
= mir
.span
;
690 if let Err(e
) = self.fulfillment_cx
.select_all_or_error(self.infcx
) {
691 span_mirbug
!(self, "", "errors selecting obligation: {:?}",
697 pub struct TypeckMir
;
700 pub fn new() -> Self {
705 impl<'tcx
> MirPass
<'tcx
> for TypeckMir
{
706 fn run_pass
<'a
>(&mut self, tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
707 src
: MirSource
, mir
: &mut Mir
<'tcx
>) {
708 if tcx
.sess
.err_count() > 0 {
709 // compiling a broken program can obviously result in a
710 // broken MIR, so try not to report duplicate errors.
713 let param_env
= ty
::ParameterEnvironment
::for_item(tcx
, src
.item_id());
714 tcx
.infer_ctxt(None
, Some(param_env
), Reveal
::NotSpecializable
).enter(|infcx
| {
715 let mut checker
= TypeChecker
::new(&infcx
);
717 let mut verifier
= TypeVerifier
::new(&mut checker
, mir
);
718 verifier
.visit_mir(mir
);
719 if verifier
.errors_reported
{
720 // don't do further checks to avoid ICEs
724 checker
.typeck_mir(mir
);
725 checker
.verify_obligations(mir
);
730 impl Pass
for TypeckMir
{