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 borrow_check::nll::region_infer::Cause;
15 use borrow_check::nll::region_infer::ClosureRegionRequirementsExt;
16 use borrow_check::nll::universal_regions::UniversalRegions;
17 use dataflow::move_paths::MoveData;
18 use dataflow::FlowAtLocation;
19 use dataflow::MaybeInitializedPlaces;
20 use rustc::hir::def_id::DefId;
21 use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
22 use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
23 use rustc::mir::tcx::PlaceTy;
24 use rustc::mir::visit::{PlaceContext, Visitor};
25 use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
27 use rustc::traits::query::NoSolution;
28 use rustc::traits::{self, Normalized, TraitEngine};
29 use rustc::ty::error::TypeError;
30 use rustc::ty::fold::TypeFoldable;
31 use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
34 use syntax_pos::{Span, DUMMY_SP};
35 use transform::{MirPass, MirSource};
36 use util::liveness::LivenessResults;
38 use rustc_data_structures::fx::FxHashSet;
39 use rustc_data_structures::indexed_vec::Idx;
41 macro_rules! span_mirbug {
42 ($context:expr, $elem:expr, $($message:tt)*) => ({
43 $crate::borrow_check::nll::type_check::mirbug(
47 "broken MIR in {:?} ({:?}): {}",
50 format_args!($($message)*),
56 macro_rules! span_mirbug_and_err {
57 ($context:expr, $elem:expr, $($message:tt)*) => ({
59 span_mirbug!($context, $elem, $($message)*);
68 /// Type checks the given `mir` in the context of the inference
69 /// context `infcx`. Returns any region constraints that have yet to
70 /// be proven. This result is includes liveness constraints that
71 /// ensure that regions appearing in the types of all local variables
72 /// are live at all points where that local variable may later be
75 /// This phase of type-check ought to be infallible -- this is because
76 /// the original, HIR-based type-check succeeded. So if any errors
77 /// occur here, we will get a `bug!` reported.
81 /// - `infcx` -- inference context to use
82 /// - `param_env` -- parameter environment to use for trait solving
83 /// - `mir` -- MIR to type-check
84 /// - `mir_def_id` -- DefId from which the MIR is derived (must be local)
85 /// - `region_bound_pairs` -- the implied outlives obligations between type parameters
86 /// and lifetimes (e.g., `&'a T` implies `T: 'a`)
87 /// - `implicit_region_bound` -- a region which all generic parameters are assumed
88 /// to outlive; should represent the fn body
89 /// - `input_tys` -- fully liberated, but **not** normalized, expected types of the arguments;
90 /// the types of the input parameters found in the MIR itself will be equated with these
91 /// - `output_ty` -- fully liberaetd, but **not** normalized, expected return type;
92 /// the type for the RETURN_PLACE will be equated with this
93 /// - `liveness` -- results of a liveness computation on the MIR; used to create liveness
94 /// constraints for the regions in the types of variables
95 /// - `flow_inits` -- results of a maybe-init dataflow analysis
96 /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
97 pub(crate) fn type_check<'gcx, 'tcx>(
98 infcx: &InferCtxt<'_, 'gcx, 'tcx>,
99 param_env: ty::ParamEnv<'gcx>,
102 universal_regions: &UniversalRegions<'tcx>,
103 liveness: &LivenessResults,
104 flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
105 move_data: &MoveData<'tcx>,
106 ) -> MirTypeckRegionConstraints<'tcx> {
107 let body_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap();
108 let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
114 &universal_regions.region_bound_pairs,
115 Some(implicit_region_bound),
117 liveness::generate(cx, mir, liveness, flow_inits, move_data);
119 cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions);
124 fn type_check_internal<'gcx, 'tcx>(
125 infcx: &InferCtxt<'_, 'gcx, 'tcx>,
126 body_id: ast::NodeId,
127 param_env: ty::ParamEnv<'gcx>,
129 region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
130 implicit_region_bound: Option<ty::Region<'tcx>>,
131 extra: &mut dyn FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>),
132 ) -> MirTypeckRegionConstraints<'tcx> {
133 let mut checker = TypeChecker::new(
138 implicit_region_bound,
140 let errors_reported = {
141 let mut verifier = TypeVerifier::new(&mut checker, mir);
142 verifier.visit_mir(mir);
143 verifier.errors_reported
146 if !errors_reported {
147 // if verifier failed, don't do further checks to avoid ICEs
148 checker.typeck_mir(mir);
156 fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
157 // We sometimes see MIR failures (notably predicate failures) due to
158 // the fact that we check rvalue sized predicates here. So use `delay_span_bug`
159 // to avoid reporting bugs in those cases.
160 tcx.sess.diagnostic().delay_span_bug(span, msg);
163 enum FieldAccessError {
164 OutOfRange { field_count: usize },
167 /// Verifies that MIR types are sane to not crash further checks.
169 /// The sanitize_XYZ methods here take an MIR object and compute its
170 /// type, calling `span_mirbug` and returning an error type if there
172 struct TypeVerifier<'a, 'b: 'a, 'gcx: 'b + 'tcx, 'tcx: 'b> {
173 cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>,
176 body_id: ast::NodeId,
177 errors_reported: bool,
180 impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
181 fn visit_span(&mut self, span: &Span) {
182 if *span != DUMMY_SP {
183 self.last_span = *span;
187 fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
188 self.sanitize_place(place, location, context);
191 fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
192 self.super_constant(constant, location);
193 self.sanitize_constant(constant, location);
194 self.sanitize_type(constant, constant.ty);
197 fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
198 self.super_rvalue(rvalue, location);
199 let rval_ty = rvalue.ty(self.mir, self.tcx());
200 self.sanitize_type(rvalue, rval_ty);
203 fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
204 self.super_local_decl(local, local_decl);
205 self.sanitize_type(local_decl, local_decl.ty);
208 fn visit_mir(&mut self, mir: &Mir<'tcx>) {
209 self.sanitize_type(&"return type", mir.return_ty());
210 for local_decl in &mir.local_decls {
211 self.sanitize_type(local_decl, local_decl.ty);
213 if self.errors_reported {
220 impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
221 fn new(cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
227 errors_reported: false,
231 fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
235 fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
236 if ty.has_escaping_regions() || ty.references_error() {
237 span_mirbug_and_err!(self, parent, "bad type {:?}", ty)
243 /// Checks that the constant's `ty` field matches up with what
244 /// would be expected from its literal.
245 fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
247 "sanitize_constant(constant={:?}, location={:?})",
251 let expected_ty = match constant.literal {
252 Literal::Value { value } => {
253 // FIXME(#46702) -- We need some way to get the predicates
254 // associated with the "pre-evaluated" form of the
255 // constant. For example, consider that the constant
256 // may have associated constant projections (`<Foo as
257 // Trait<'a, 'b>>::SOME_CONST`) that impose
258 // constraints on `'a` and `'b`. These constraints
259 // would be lost if we just look at the normalized
261 if let ty::TyFnDef(def_id, substs) = value.ty.sty {
262 let tcx = self.tcx();
263 let type_checker = &mut self.cx;
265 // FIXME -- For now, use the substitutions from
266 // `value.ty` rather than `value.val`. The
267 // renumberer will rewrite them to independent
268 // sets of regions; in principle, we ought to
269 // derive the type of the `value.val` from "first
270 // principles" and equate with value.ty, but as we
271 // are transitioning to the miri-based system, we
272 // don't have a handy function for that, so for
273 // now we just ignore `value.val` regions.
275 let instantiated_predicates =
276 tcx.predicates_of(def_id).instantiate(tcx, substs);
278 type_checker.normalize(&instantiated_predicates.predicates, location);
279 type_checker.prove_predicates(predicates, location);
285 Literal::Promoted { .. } => {
286 // FIXME -- promoted MIR return types reference
287 // various "free regions" (e.g., scopes and things)
288 // that they ought not to do. We have to figure out
289 // how best to handle that -- probably we want treat
290 // promoted MIR much like closures, renumbering all
291 // their free regions and propagating constraints
292 // upwards. We have the same acyclic guarantees, so
293 // that should be possible. But for now, ignore them.
295 // let promoted_mir = &self.mir.promoted[index];
296 // promoted_mir.return_ty()
301 debug!("sanitize_constant: expected_ty={:?}", expected_ty);
303 if let Err(terr) = self.cx
304 .eq_types(expected_ty, constant.ty, location.at_self())
309 "constant {:?} should have type {:?} but has {:?} ({:?})",
318 /// Checks that the types internal to the `place` match up with
319 /// what would be expected.
324 context: PlaceContext,
326 debug!("sanitize_place: {:?}", place);
327 let place_ty = match *place {
328 Place::Local(index) => PlaceTy::Ty {
329 ty: self.mir.local_decls[index].ty,
331 Place::Static(box Static { def_id, ty: sty }) => {
332 let sty = self.sanitize_type(place, sty);
333 let ty = self.tcx().type_of(def_id);
334 let ty = self.cx.normalize(&ty, location);
335 if let Err(terr) = self.cx.eq_types(ty, sty, location.at_self()) {
339 "bad static type ({:?}: {:?}): {:?}",
345 PlaceTy::Ty { ty: sty }
347 Place::Projection(ref proj) => {
348 let base_context = if context.is_mutating_use() {
349 PlaceContext::Projection(Mutability::Mut)
351 PlaceContext::Projection(Mutability::Not)
353 let base_ty = self.sanitize_place(&proj.base, location, base_context);
354 if let PlaceTy::Ty { ty } = base_ty {
355 if ty.references_error() {
356 assert!(self.errors_reported);
358 ty: self.tcx().types.err,
362 self.sanitize_projection(base_ty, &proj.elem, place, location)
365 if let PlaceContext::Copy = context {
366 let tcx = self.tcx();
367 let trait_ref = ty::TraitRef {
368 def_id: tcx.lang_items().copy_trait().unwrap(),
369 substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]),
372 // In order to have a Copy operand, the type T of the value must be Copy. Note that we
373 // prove that T: Copy, rather than using the type_moves_by_default test. This is
374 // important because type_moves_by_default ignores the resulting region obligations and
375 // assumes they pass. This can result in bounds from Copy impls being unsoundly ignored
376 // (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds
377 // fully apply: in effect, the rule is that if a value of some type could implement
378 // Copy, then it must.
379 self.cx.prove_trait_ref(trait_ref, location);
384 fn sanitize_projection(
387 pi: &PlaceElem<'tcx>,
391 debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place);
392 let tcx = self.tcx();
393 let base_ty = base.to_ty(tcx);
395 ProjectionElem::Deref => {
396 let deref_ty = base_ty.builtin_deref(true);
398 ty: deref_ty.map(|t| t.ty).unwrap_or_else(|| {
399 span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty)
403 ProjectionElem::Index(i) => {
404 let index_ty = Place::Local(i).ty(self.mir, tcx).to_ty(tcx);
405 if index_ty != tcx.types.usize {
407 ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i),
411 ty: base_ty.builtin_index().unwrap_or_else(|| {
412 span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty)
417 ProjectionElem::ConstantIndex { .. } => {
418 // consider verifying in-bounds
420 ty: base_ty.builtin_index().unwrap_or_else(|| {
421 span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty)
425 ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
426 ty: match base_ty.sty {
427 ty::TyArray(inner, size) => {
428 let size = size.val.unwrap_u64();
429 let min_size = (from as u64) + (to as u64);
430 if let Some(rest_size) = size.checked_sub(min_size) {
431 tcx.mk_array(inner, rest_size)
433 span_mirbug_and_err!(
436 "taking too-small slice of {:?}",
441 ty::TySlice(..) => base_ty,
442 _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty),
445 ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty {
446 ty::TyAdt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => {
447 if index >= adt_def.variants.len() {
449 ty: span_mirbug_and_err!(
452 "cast to variant #{:?} but enum only has {:?}",
454 adt_def.variants.len()
461 variant_index: index,
466 ty: span_mirbug_and_err!(
469 "can't downcast {:?} as {:?}",
475 ProjectionElem::Field(field, fty) => {
476 let fty = self.sanitize_type(place, fty);
477 match self.field_ty(place, base, field, location) {
478 Ok(ty) => if let Err(terr) = self.cx.eq_types(ty, fty, location.at_self()) {
482 "bad field access ({:?}: {:?}): {:?}",
488 Err(FieldAccessError::OutOfRange { field_count }) => span_mirbug!(
491 "accessed field #{} but variant only has {}",
496 PlaceTy::Ty { ty: fty }
501 fn error(&mut self) -> Ty<'tcx> {
502 self.errors_reported = true;
508 parent: &dyn fmt::Debug,
509 base_ty: PlaceTy<'tcx>,
512 ) -> Result<Ty<'tcx>, FieldAccessError> {
513 let tcx = self.tcx();
515 let (variant, substs) = match base_ty {
520 } => (&adt_def.variants[variant_index], substs),
521 PlaceTy::Ty { ty } => match ty.sty {
522 ty::TyAdt(adt_def, substs) if !adt_def.is_enum() => (&adt_def.variants[0], substs),
523 ty::TyClosure(def_id, substs) => {
524 return match substs.upvar_tys(def_id, tcx).nth(field.index()) {
526 None => Err(FieldAccessError::OutOfRange {
527 field_count: substs.upvar_tys(def_id, tcx).count(),
531 ty::TyGenerator(def_id, substs, _) => {
532 // Try pre-transform fields first (upvars and current state)
533 if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field.index()) {
537 // Then try `field_tys` which contains all the fields, but it
538 // requires the final optimized MIR.
539 return match substs.field_tys(def_id, tcx).nth(field.index()) {
541 None => Err(FieldAccessError::OutOfRange {
542 field_count: substs.field_tys(def_id, tcx).count(),
546 ty::TyTuple(tys) => {
547 return match tys.get(field.index()) {
549 None => Err(FieldAccessError::OutOfRange {
550 field_count: tys.len(),
555 return Ok(span_mirbug_and_err!(
558 "can't project out of {:?}",
565 if let Some(field) = variant.fields.get(field.index()) {
566 Ok(self.cx.normalize(&field.ty(tcx, substs), location))
568 Err(FieldAccessError::OutOfRange {
569 field_count: variant.fields.len(),
575 /// The MIR type checker. Visits the MIR and enforces all the
576 /// constraints needed for it to be valid and well-typed. Along the
577 /// way, it accrues region constraints -- these can later be used by
578 /// NLL region checking.
579 struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
580 infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
581 param_env: ty::ParamEnv<'gcx>,
583 body_id: ast::NodeId,
584 region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
585 implicit_region_bound: Option<ty::Region<'tcx>>,
586 reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
587 constraints: MirTypeckRegionConstraints<'tcx>,
590 /// A collection of region constraints that must be satisfied for the
591 /// program to be considered well-typed.
593 pub(crate) struct MirTypeckRegionConstraints<'tcx> {
594 /// In general, the type-checker is not responsible for enforcing
595 /// liveness constraints; this job falls to the region inferencer,
596 /// which performs a liveness analysis. However, in some limited
597 /// cases, the MIR type-checker creates temporary regions that do
598 /// not otherwise appear in the MIR -- in particular, the
599 /// late-bound regions that it instantiates at call-sites -- and
600 /// hence it must report on their liveness constraints.
601 pub liveness_set: Vec<(ty::Region<'tcx>, Location, Cause)>,
603 /// During the course of type-checking, we will accumulate region
604 /// constraints due to performing subtyping operations or solving
605 /// traits. These are accumulated into this vector for later use.
606 pub outlives_sets: Vec<OutlivesSet<'tcx>>,
609 /// Outlives relationships between regions and types created at a
610 /// particular point within the control-flow graph.
611 pub struct OutlivesSet<'tcx> {
612 /// The locations associated with these constraints.
613 pub locations: Locations,
615 /// Constraints generated. In terms of the NLL RFC, when you have
616 /// a constraint `R1: R2 @ P`, the data in there specifies things
618 pub data: RegionConstraintData<'tcx>,
621 #[derive(Copy, Clone, Debug)]
622 pub struct Locations {
623 /// The location in the MIR that generated these constraints.
624 /// This is intended for error reporting and diagnosis; the
625 /// constraints may *take effect* at a distinct spot.
626 pub from_location: Location,
628 /// The constraints must be met at this location. In terms of the
629 /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field
630 /// is the `P` value.
631 pub at_location: Location,
634 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
636 infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
637 body_id: ast::NodeId,
638 param_env: ty::ParamEnv<'gcx>,
639 region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
640 implicit_region_bound: Option<ty::Region<'tcx>>,
648 implicit_region_bound,
649 reported_errors: FxHashSet(),
650 constraints: MirTypeckRegionConstraints::default(),
654 fn misc(&self, span: Span) -> traits::ObligationCause<'tcx> {
655 traits::ObligationCause::misc(span, self.body_id)
658 fn fully_perform_op<OP, R>(
660 locations: Locations,
662 ) -> Result<R, TypeError<'tcx>>
664 OP: FnOnce(&mut Self) -> InferResult<'tcx, R>,
666 let mut fulfill_cx = TraitEngine::new(self.infcx.tcx);
667 let InferOk { value, obligations } = self.infcx.commit_if_ok(|_| op(self))?;
668 fulfill_cx.register_predicate_obligations(self.infcx, obligations);
669 if let Err(e) = fulfill_cx.select_all_or_error(self.infcx) {
670 span_mirbug!(self, "", "errors selecting obligation: {:?}", e);
673 self.infcx.process_registered_region_obligations(
674 self.region_bound_pairs,
675 self.implicit_region_bound,
680 let data = self.infcx.take_and_reset_region_constraints();
681 if !data.is_empty() {
683 "fully_perform_op: constraints generated at {:?} are {:#?}",
688 .push(OutlivesSet { locations, data });
698 locations: Locations,
699 ) -> UnitResult<'tcx> {
700 self.fully_perform_op(locations, |this| {
702 .at(&this.misc(this.last_span), this.param_env)
707 fn eq_types(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, locations: Locations) -> UnitResult<'tcx> {
708 self.fully_perform_op(locations, |this| {
710 .at(&this.misc(this.last_span), this.param_env)
715 fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
719 fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Location) {
720 debug!("check_stmt: {:?}", stmt);
721 let tcx = self.tcx();
723 StatementKind::Assign(ref place, ref rv) => {
724 let place_ty = place.ty(mir, tcx).to_ty(tcx);
725 let rv_ty = rv.ty(mir, tcx);
727 self.sub_types(rv_ty, place_ty, location.at_successor_within_block())
732 "bad assignment ({:?} = {:?}): {:?}",
738 self.check_rvalue(mir, rv, location);
740 StatementKind::SetDiscriminant {
744 let place_type = place.ty(mir, tcx).to_ty(tcx);
745 let adt = match place_type.sty {
746 TypeVariants::TyAdt(adt, _) if adt.is_enum() => adt,
749 stmt.source_info.span,
750 "bad set discriminant ({:?} = {:?}): lhs is not an enum",
756 if variant_index >= adt.variants.len() {
758 stmt.source_info.span,
759 "bad set discriminant ({:?} = {:?}): value of of range",
765 StatementKind::UserAssertTy(ref c_ty, ref local) => {
766 let local_ty = mir.local_decls()[*local].ty;
767 let (ty, _) = self.infcx
768 .instantiate_canonical_with_fresh_inference_vars(stmt.source_info.span, c_ty);
770 "check_stmt: user_assert_ty ty={:?} local_ty={:?}",
773 if let Err(terr) = self.eq_types(ty, local_ty, location.at_self()) {
777 "bad type assert ({:?} = {:?}): {:?}",
784 StatementKind::StorageLive(_)
785 | StatementKind::StorageDead(_)
786 | StatementKind::InlineAsm { .. }
787 | StatementKind::EndRegion(_)
788 | StatementKind::Validate(..)
789 | StatementKind::Nop => {}
796 term: &Terminator<'tcx>,
797 term_location: Location,
799 debug!("check_terminator: {:?}", term);
800 let tcx = self.tcx();
802 TerminatorKind::Goto { .. }
803 | TerminatorKind::Resume
804 | TerminatorKind::Abort
805 | TerminatorKind::Return
806 | TerminatorKind::GeneratorDrop
807 | TerminatorKind::Unreachable
808 | TerminatorKind::Drop { .. }
809 | TerminatorKind::FalseEdges { .. }
810 | TerminatorKind::FalseUnwind { .. } => {
811 // no checks needed for these
814 TerminatorKind::DropAndReplace {
820 let place_ty = location.ty(mir, tcx).to_ty(tcx);
821 let rv_ty = value.ty(mir, tcx);
823 let locations = Locations {
824 from_location: term_location,
825 at_location: target.start_location(),
827 if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) {
831 "bad DropAndReplace ({:?} = {:?}): {:?}",
838 // Subtle: this assignment occurs at the start of
839 // *both* blocks, so we need to ensure that it holds
840 // at both locations.
841 if let Some(unwind) = unwind {
842 let locations = Locations {
843 from_location: term_location,
844 at_location: unwind.start_location(),
846 if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) {
850 "bad DropAndReplace ({:?} = {:?}): {:?}",
858 TerminatorKind::SwitchInt {
863 let discr_ty = discr.ty(mir, tcx);
864 if let Err(terr) = self.sub_types(discr_ty, switch_ty, term_location.at_self()) {
868 "bad SwitchInt ({:?} on {:?}): {:?}",
874 if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() {
875 span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty);
877 // FIXME: check the values
879 TerminatorKind::Call {
885 let func_ty = func.ty(mir, tcx);
886 debug!("check_terminator: call, func_ty={:?}", func_ty);
887 let sig = match func_ty.sty {
888 ty::TyFnDef(..) | ty::TyFnPtr(_) => func_ty.fn_sig(tcx),
890 span_mirbug!(self, term, "call to non-function {:?}", func_ty);
894 let (sig, map) = self.infcx.replace_late_bound_regions_with_fresh_var(
895 term.source_info.span,
896 LateBoundRegionConversionTime::FnCall,
899 let sig = self.normalize(&sig, term_location);
900 self.check_call_dest(mir, term, &sig, destination, term_location);
902 self.prove_predicates(
903 sig.inputs().iter().map(|ty| ty::Predicate::WellFormed(ty)),
907 // The ordinary liveness rules will ensure that all
908 // regions in the type of the callee are live here. We
909 // then further constrain the late-bound regions that
910 // were instantiated at the call site to be live as
911 // well. The resulting is that all the input (and
912 // output) types in the signature must be live, since
913 // all the inputs that fed into it were live.
914 for &late_bound_region in map.values() {
915 self.constraints.liveness_set.push((
918 Cause::LiveOther(term_location),
922 self.check_call_inputs(mir, term, &sig, args, term_location);
924 TerminatorKind::Assert {
925 ref cond, ref msg, ..
927 let cond_ty = cond.ty(mir, tcx);
928 if cond_ty != tcx.types.bool {
929 span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
932 if let BoundsCheck { ref len, ref index } = *msg {
933 if len.ty(mir, tcx) != tcx.types.usize {
934 span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
936 if index.ty(mir, tcx) != tcx.types.usize {
937 span_mirbug!(self, index, "bounds-check index non-usize {:?}", index)
941 TerminatorKind::Yield { ref value, .. } => {
942 let value_ty = value.ty(mir, tcx);
944 None => span_mirbug!(self, term, "yield in non-generator"),
946 if let Err(terr) = self.sub_types(value_ty, ty, term_location.at_self()) {
950 "type of yield value is {:?}, but the yield type is {:?}: {:?}",
965 term: &Terminator<'tcx>,
966 sig: &ty::FnSig<'tcx>,
967 destination: &Option<(Place<'tcx>, BasicBlock)>,
968 term_location: Location,
970 let tcx = self.tcx();
972 Some((ref dest, target_block)) => {
973 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
974 let locations = Locations {
975 from_location: term_location,
976 at_location: target_block.start_location(),
978 if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) {
982 "call dest mismatch ({:?} <- {:?}): {:?}",
990 // FIXME(canndrew): This is_never should probably be an is_uninhabited
991 if !sig.output().is_never() {
992 span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
998 fn check_call_inputs(
1001 term: &Terminator<'tcx>,
1002 sig: &ty::FnSig<'tcx>,
1003 args: &[Operand<'tcx>],
1004 term_location: Location,
1006 debug!("check_call_inputs({:?}, {:?})", sig, args);
1007 if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.variadic) {
1008 span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
1010 for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
1011 let op_arg_ty = op_arg.ty(mir, self.tcx());
1012 if let Err(terr) = self.sub_types(op_arg_ty, fn_arg, term_location.at_self()) {
1016 "bad arg #{:?} ({:?} <- {:?}): {:?}",
1026 fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>) {
1027 let is_cleanup = block_data.is_cleanup;
1028 self.last_span = block_data.terminator().source_info.span;
1029 match block_data.terminator().kind {
1030 TerminatorKind::Goto { target } => {
1031 self.assert_iscleanup(mir, block_data, target, is_cleanup)
1033 TerminatorKind::SwitchInt { ref targets, .. } => for target in targets {
1034 self.assert_iscleanup(mir, block_data, *target, is_cleanup);
1036 TerminatorKind::Resume => if !is_cleanup {
1037 span_mirbug!(self, block_data, "resume on non-cleanup block!")
1039 TerminatorKind::Abort => if !is_cleanup {
1040 span_mirbug!(self, block_data, "abort on non-cleanup block!")
1042 TerminatorKind::Return => if is_cleanup {
1043 span_mirbug!(self, block_data, "return on cleanup block")
1045 TerminatorKind::GeneratorDrop { .. } => if is_cleanup {
1046 span_mirbug!(self, block_data, "generator_drop in cleanup block")
1048 TerminatorKind::Yield { resume, drop, .. } => {
1050 span_mirbug!(self, block_data, "yield in cleanup block")
1052 self.assert_iscleanup(mir, block_data, resume, is_cleanup);
1053 if let Some(drop) = drop {
1054 self.assert_iscleanup(mir, block_data, drop, is_cleanup);
1057 TerminatorKind::Unreachable => {}
1058 TerminatorKind::Drop { target, unwind, .. }
1059 | TerminatorKind::DropAndReplace { target, unwind, .. }
1060 | TerminatorKind::Assert {
1065 self.assert_iscleanup(mir, block_data, target, is_cleanup);
1066 if let Some(unwind) = unwind {
1068 span_mirbug!(self, block_data, "unwind on cleanup block")
1070 self.assert_iscleanup(mir, block_data, unwind, true);
1073 TerminatorKind::Call {
1078 if let &Some((_, target)) = destination {
1079 self.assert_iscleanup(mir, block_data, target, is_cleanup);
1081 if let Some(cleanup) = cleanup {
1083 span_mirbug!(self, block_data, "cleanup on cleanup block")
1085 self.assert_iscleanup(mir, block_data, cleanup, true);
1088 TerminatorKind::FalseEdges {
1090 ref imaginary_targets,
1092 self.assert_iscleanup(mir, block_data, real_target, is_cleanup);
1093 for target in imaginary_targets {
1094 self.assert_iscleanup(mir, block_data, *target, is_cleanup);
1097 TerminatorKind::FalseUnwind {
1101 self.assert_iscleanup(mir, block_data, real_target, is_cleanup);
1102 if let Some(unwind) = unwind {
1107 "cleanup in cleanup block via false unwind"
1110 self.assert_iscleanup(mir, block_data, unwind, true);
1116 fn assert_iscleanup(
1119 ctxt: &dyn fmt::Debug,
1123 if mir[bb].is_cleanup != iscleanuppad {
1127 "cleanuppad mismatch: {:?} should be {:?}",
1134 fn check_local(&mut self, mir: &Mir<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) {
1135 match mir.local_kind(local) {
1136 LocalKind::ReturnPointer | LocalKind::Arg => {
1137 // return values of normal functions are required to be
1138 // sized by typeck, but return values of ADT constructors are
1139 // not because we don't include a `Self: Sized` bounds on them.
1141 // Unbound parts of arguments were never required to be Sized
1142 // - maybe we should make that a warning.
1145 LocalKind::Var | LocalKind::Temp => {}
1148 let span = local_decl.source_info.span;
1149 let ty = local_decl.ty;
1151 // Erase the regions from `ty` to get a global type. The
1152 // `Sized` bound in no way depends on precise regions, so this
1153 // shouldn't affect `is_sized`.
1154 let gcx = self.tcx().global_tcx();
1155 let erased_ty = gcx.lift(&self.tcx().erase_regions(&ty)).unwrap();
1156 if !erased_ty.is_sized(gcx.at(span), self.param_env) {
1157 // in current MIR construction, all non-control-flow rvalue
1158 // expressions evaluate through `as_temp` or `into` a return
1159 // slot or local, so to find all unsized rvalues it is enough
1160 // to check all temps, return slots and locals.
1161 if let None = self.reported_errors.replace((ty, span)) {
1166 "cannot move a value of type {0}: the size of {0} \
1167 cannot be statically determined",
1174 fn aggregate_field_ty(
1176 ak: &AggregateKind<'tcx>,
1179 ) -> Result<Ty<'tcx>, FieldAccessError> {
1180 let tcx = self.tcx();
1183 AggregateKind::Adt(def, variant_index, substs, active_field_index) => {
1184 let variant = &def.variants[variant_index];
1185 let adj_field_index = active_field_index.unwrap_or(field_index);
1186 if let Some(field) = variant.fields.get(adj_field_index) {
1187 Ok(self.normalize(&field.ty(tcx, substs), location))
1189 Err(FieldAccessError::OutOfRange {
1190 field_count: variant.fields.len(),
1194 AggregateKind::Closure(def_id, substs) => {
1195 match substs.upvar_tys(def_id, tcx).nth(field_index) {
1197 None => Err(FieldAccessError::OutOfRange {
1198 field_count: substs.upvar_tys(def_id, tcx).count(),
1202 AggregateKind::Generator(def_id, substs, _) => {
1203 // Try pre-transform fields first (upvars and current state)
1204 if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field_index) {
1207 // Then try `field_tys` which contains all the fields, but it
1208 // requires the final optimized MIR.
1209 match substs.field_tys(def_id, tcx).nth(field_index) {
1211 None => Err(FieldAccessError::OutOfRange {
1212 field_count: substs.field_tys(def_id, tcx).count(),
1217 AggregateKind::Array(ty) => Ok(ty),
1218 AggregateKind::Tuple => {
1219 unreachable!("This should have been covered in check_rvalues");
1224 fn check_rvalue(&mut self, mir: &Mir<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
1225 let tcx = self.tcx();
1228 Rvalue::Aggregate(ak, ops) => {
1229 self.check_aggregate_rvalue(mir, rvalue, ak, ops, location)
1232 Rvalue::Repeat(operand, len) => if *len > 1 {
1233 let operand_ty = operand.ty(mir, tcx);
1235 let trait_ref = ty::TraitRef {
1236 def_id: tcx.lang_items().copy_trait().unwrap(),
1237 substs: tcx.mk_substs_trait(operand_ty, &[]),
1240 self.prove_trait_ref(trait_ref, location);
1243 Rvalue::NullaryOp(_, ty) => {
1244 let trait_ref = ty::TraitRef {
1245 def_id: tcx.lang_items().sized_trait().unwrap(),
1246 substs: tcx.mk_substs_trait(ty, &[]),
1249 self.prove_trait_ref(trait_ref, location);
1252 Rvalue::Cast(cast_kind, op, ty) => match cast_kind {
1253 CastKind::ReifyFnPointer => {
1254 let fn_sig = op.ty(mir, tcx).fn_sig(tcx);
1256 // The type that we see in the fcx is like
1257 // `foo::<'a, 'b>`, where `foo` is the path to a
1258 // function definition. When we extract the
1259 // signature, it comes from the `fn_sig` query,
1260 // and hence may contain unnormalized results.
1261 let fn_sig = self.normalize(&fn_sig, location);
1263 let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
1265 if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
1269 "equating {:?} with {:?} yields {:?}",
1277 CastKind::ClosureFnPointer => {
1278 let sig = match op.ty(mir, tcx).sty {
1279 ty::TyClosure(def_id, substs) => {
1280 substs.closure_sig_ty(def_id, tcx).fn_sig(tcx)
1284 let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig);
1286 if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
1290 "equating {:?} with {:?} yields {:?}",
1298 CastKind::UnsafeFnPointer => {
1299 let fn_sig = op.ty(mir, tcx).fn_sig(tcx);
1301 // The type that we see in the fcx is like
1302 // `foo::<'a, 'b>`, where `foo` is the path to a
1303 // function definition. When we extract the
1304 // signature, it comes from the `fn_sig` query,
1305 // and hence may contain unnormalized results.
1306 let fn_sig = self.normalize(&fn_sig, location);
1308 let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
1310 if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
1314 "equating {:?} with {:?} yields {:?}",
1322 CastKind::Unsize => {
1323 let trait_ref = ty::TraitRef {
1324 def_id: tcx.lang_items().coerce_unsized_trait().unwrap(),
1325 substs: tcx.mk_substs_trait(op.ty(mir, tcx), &[ty]),
1328 self.prove_trait_ref(trait_ref, location);
1331 CastKind::Misc => {}
1334 // FIXME: These other cases have to be implemented in future PRs
1338 | Rvalue::BinaryOp(..)
1339 | Rvalue::CheckedBinaryOp(..)
1340 | Rvalue::UnaryOp(..)
1341 | Rvalue::Discriminant(..) => {}
1345 fn check_aggregate_rvalue(
1348 rvalue: &Rvalue<'tcx>,
1349 aggregate_kind: &AggregateKind<'tcx>,
1350 operands: &[Operand<'tcx>],
1353 let tcx = self.tcx();
1355 self.prove_aggregate_predicates(aggregate_kind, location);
1357 if *aggregate_kind == AggregateKind::Tuple {
1358 // tuple rvalue field type is always the type of the op. Nothing to check here.
1362 for (i, operand) in operands.iter().enumerate() {
1363 let field_ty = match self.aggregate_field_ty(aggregate_kind, i, location) {
1364 Ok(field_ty) => field_ty,
1365 Err(FieldAccessError::OutOfRange { field_count }) => {
1369 "accessed field #{} but variant only has {}",
1376 let operand_ty = operand.ty(mir, tcx);
1378 self.sub_types(operand_ty, field_ty, location.at_successor_within_block())
1383 "{:?} is not a subtype of {:?}: {:?}",
1392 fn prove_aggregate_predicates(
1394 aggregate_kind: &AggregateKind<'tcx>,
1397 let tcx = self.tcx();
1400 "prove_aggregate_predicates(aggregate_kind={:?}, location={:?})",
1401 aggregate_kind, location
1404 let instantiated_predicates = match aggregate_kind {
1405 AggregateKind::Adt(def, _, substs, _) => {
1406 tcx.predicates_of(def.did).instantiate(tcx, substs)
1409 // For closures, we have some **extra requirements** we
1411 // have to check. In particular, in their upvars and
1412 // signatures, closures often reference various regions
1413 // from the surrounding function -- we call those the
1414 // closure's free regions. When we borrow-check (and hence
1415 // region-check) closures, we may find that the closure
1416 // requires certain relationships between those free
1417 // regions. However, because those free regions refer to
1418 // portions of the CFG of their caller, the closure is not
1419 // in a position to verify those relationships. In that
1420 // case, the requirements get "propagated" to us, and so
1421 // we have to solve them here where we instantiate the
1424 // Despite the opacity of the previous parapgrah, this is
1425 // actually relatively easy to understand in terms of the
1426 // desugaring. A closure gets desugared to a struct, and
1427 // these extra requirements are basically like where
1428 // clauses on the struct.
1429 AggregateKind::Closure(def_id, substs) => {
1430 if let Some(closure_region_requirements) =
1431 tcx.mir_borrowck(*def_id).closure_requirements
1433 closure_region_requirements.apply_requirements(
1442 tcx.predicates_of(*def_id).instantiate(tcx, substs.substs)
1445 AggregateKind::Generator(def_id, substs, _) => {
1446 tcx.predicates_of(*def_id).instantiate(tcx, substs.substs)
1449 AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
1452 let predicates = self.normalize(&instantiated_predicates.predicates, location);
1453 debug!("prove_aggregate_predicates: predicates={:?}", predicates);
1454 self.prove_predicates(predicates, location);
1457 fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location) {
1458 self.prove_predicates(
1459 Some(ty::Predicate::Trait(
1460 trait_ref.to_poly_trait_ref().to_poly_trait_predicate(),
1466 fn prove_predicates<T>(&mut self, predicates: T, location: Location)
1468 T: IntoIterator<Item = ty::Predicate<'tcx>>,
1471 let predicates = predicates.into_iter();
1474 "prove_predicates(predicates={:?}, location={:?})",
1475 predicates.clone().collect::<Vec<_>>(),
1478 self.fully_perform_op(location.at_self(), |this| {
1479 let cause = this.misc(this.last_span);
1480 let obligations = predicates
1482 .map(|p| traits::Obligation::new(cause.clone(), this.param_env, p))
1491 fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
1492 self.last_span = mir.span;
1493 debug!("run_on_mir: {:?}", mir.span);
1495 for (local, local_decl) in mir.local_decls.iter_enumerated() {
1496 self.check_local(mir, local, local_decl);
1499 for (block, block_data) in mir.basic_blocks().iter_enumerated() {
1500 let mut location = Location {
1504 for stmt in &block_data.statements {
1505 if stmt.source_info.span != DUMMY_SP {
1506 self.last_span = stmt.source_info.span;
1508 self.check_stmt(mir, stmt, location);
1509 location.statement_index += 1;
1512 self.check_terminator(mir, block_data.terminator(), location);
1513 self.check_iscleanup(mir, block_data);
1517 fn normalize<T>(&mut self, value: &T, location: Location) -> T
1519 T: fmt::Debug + TypeFoldable<'tcx>,
1521 debug!("normalize(value={:?}, location={:?})", value, location);
1522 self.fully_perform_op(location.at_self(), |this| {
1523 let Normalized { value, obligations } = this.infcx
1524 .at(&this.misc(this.last_span), this.param_env)
1526 .unwrap_or_else(|NoSolution| {
1529 "normalization of `{:?}` failed at {:?}",
1534 Ok(InferOk { value, obligations })
1539 pub struct TypeckMir;
1541 impl MirPass for TypeckMir {
1542 fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
1543 let def_id = src.def_id;
1544 let id = tcx.hir.as_local_node_id(def_id).unwrap();
1545 debug!("run_pass: {:?}", def_id);
1547 // When NLL is enabled, the borrow checker runs the typeck
1548 // itself, so we don't need this MIR pass anymore.
1549 if tcx.use_mir_borrowck() {
1553 if tcx.sess.err_count() > 0 {
1554 // compiling a broken program can obviously result in a
1555 // broken MIR, so try not to report duplicate errors.
1558 let param_env = tcx.param_env(def_id);
1559 tcx.infer_ctxt().enter(|infcx| {
1560 let _ = type_check_internal(&infcx, id, param_env, mir, &[], None, &mut |_| ());
1562 // For verification purposes, we just ignore the resulting
1563 // region constraint sets. Not our problem. =)
1569 /// Creates a `Locations` where `self` is both the from-location
1570 /// and the at-location. This means that any required region
1571 /// relationships must hold upon entering the statement/terminator
1572 /// indicated by `self`. This is typically used when processing
1573 /// "inputs" to the given location.
1574 fn at_self(self) -> Locations;
1576 /// Creates a `Locations` where `self` is the from-location and
1577 /// its successor within the block is the at-location. This means
1578 /// that any required region relationships must hold only upon
1579 /// **exiting** the statement/terminator indicated by `self`. This
1580 /// is for example used when you have a `place = rv` statement: it
1581 /// indicates that the `typeof(rv) <: typeof(place)` as of the
1582 /// **next** statement.
1583 fn at_successor_within_block(self) -> Locations;
1586 impl AtLocation for Location {
1587 fn at_self(self) -> Locations {
1589 from_location: self,
1594 fn at_successor_within_block(self) -> Locations {
1596 from_location: self,
1597 at_location: self.successor_within_block(),