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};
26 use rustc::traits::query::NoSolution;
27 use rustc::traits::{self, Normalized, TraitEngine};
28 use rustc::ty::error::TypeError;
29 use rustc::ty::fold::TypeFoldable;
30 use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
33 use syntax_pos::{Span, DUMMY_SP};
34 use transform::{MirPass, MirSource};
35 use util::liveness::LivenessResults;
37 use rustc_data_structures::fx::FxHashSet;
38 use rustc_data_structures::indexed_vec::Idx;
40 macro_rules! span_mirbug {
41 ($context:expr, $elem:expr, $($message:tt)*) => ({
42 $crate::borrow_check::nll::type_check::mirbug(
46 "broken MIR in {:?} ({:?}): {}",
49 format_args!($($message)*),
55 macro_rules! span_mirbug_and_err {
56 ($context:expr, $elem:expr, $($message:tt)*) => ({
58 span_mirbug!($context, $elem, $($message)*);
67 /// Type checks the given `mir` in the context of the inference
68 /// context `infcx`. Returns any region constraints that have yet to
69 /// be proven. This result is includes liveness constraints that
70 /// ensure that regions appearing in the types of all local variables
71 /// are live at all points where that local variable may later be
74 /// This phase of type-check ought to be infallible -- this is because
75 /// the original, HIR-based type-check succeeded. So if any errors
76 /// occur here, we will get a `bug!` reported.
80 /// - `infcx` -- inference context to use
81 /// - `param_env` -- parameter environment to use for trait solving
82 /// - `mir` -- MIR to type-check
83 /// - `mir_def_id` -- DefId from which the MIR is derived (must be local)
84 /// - `region_bound_pairs` -- the implied outlives obligations between type parameters
85 /// and lifetimes (e.g., `&'a T` implies `T: 'a`)
86 /// - `implicit_region_bound` -- a region which all generic parameters are assumed
87 /// to outlive; should represent the fn body
88 /// - `input_tys` -- fully liberated, but **not** normalized, expected types of the arguments;
89 /// the types of the input parameters found in the MIR itself will be equated with these
90 /// - `output_ty` -- fully liberaetd, but **not** normalized, expected return type;
91 /// the type for the RETURN_PLACE will be equated with this
92 /// - `liveness` -- results of a liveness computation on the MIR; used to create liveness
93 /// constraints for the regions in the types of variables
94 /// - `flow_inits` -- results of a maybe-init dataflow analysis
95 /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
96 pub(crate) fn type_check<'gcx, 'tcx>(
97 infcx: &InferCtxt<'_, 'gcx, 'tcx>,
98 param_env: ty::ParamEnv<'gcx>,
101 universal_regions: &UniversalRegions<'tcx>,
102 liveness: &LivenessResults,
103 flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
104 move_data: &MoveData<'tcx>,
105 ) -> MirTypeckRegionConstraints<'tcx> {
106 let body_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap();
107 let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
113 &universal_regions.region_bound_pairs,
114 Some(implicit_region_bound),
116 liveness::generate(cx, mir, liveness, flow_inits, move_data);
118 cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions);
123 fn type_check_internal<'gcx, 'tcx>(
124 infcx: &InferCtxt<'_, 'gcx, 'tcx>,
125 body_id: ast::NodeId,
126 param_env: ty::ParamEnv<'gcx>,
128 region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
129 implicit_region_bound: Option<ty::Region<'tcx>>,
130 extra: &mut dyn FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>),
131 ) -> MirTypeckRegionConstraints<'tcx> {
132 let mut checker = TypeChecker::new(
137 implicit_region_bound,
139 let errors_reported = {
140 let mut verifier = TypeVerifier::new(&mut checker, mir);
141 verifier.visit_mir(mir);
142 verifier.errors_reported
145 if !errors_reported {
146 // if verifier failed, don't do further checks to avoid ICEs
147 checker.typeck_mir(mir);
155 fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
156 // We sometimes see MIR failures (notably predicate failures) due to
157 // the fact that we check rvalue sized predicates here. So use `delay_span_bug`
158 // to avoid reporting bugs in those cases.
159 tcx.sess.diagnostic().delay_span_bug(span, msg);
162 enum FieldAccessError {
163 OutOfRange { field_count: usize },
166 /// Verifies that MIR types are sane to not crash further checks.
168 /// The sanitize_XYZ methods here take an MIR object and compute its
169 /// type, calling `span_mirbug` and returning an error type if there
171 struct TypeVerifier<'a, 'b: 'a, 'gcx: 'b + 'tcx, 'tcx: 'b> {
172 cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>,
175 body_id: ast::NodeId,
176 errors_reported: bool,
179 impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
180 fn visit_span(&mut self, span: &Span) {
181 if *span != DUMMY_SP {
182 self.last_span = *span;
186 fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
187 self.sanitize_place(place, location, context);
190 fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
191 self.super_constant(constant, location);
192 self.sanitize_constant(constant, location);
193 self.sanitize_type(constant, constant.ty);
196 fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
197 self.super_rvalue(rvalue, location);
198 let rval_ty = rvalue.ty(self.mir, self.tcx());
199 self.sanitize_type(rvalue, rval_ty);
202 fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
203 self.super_local_decl(local, local_decl);
204 self.sanitize_type(local_decl, local_decl.ty);
207 fn visit_mir(&mut self, mir: &Mir<'tcx>) {
208 self.sanitize_type(&"return type", mir.return_ty());
209 for local_decl in &mir.local_decls {
210 self.sanitize_type(local_decl, local_decl.ty);
212 if self.errors_reported {
219 impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
220 fn new(cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
226 errors_reported: false,
230 fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
234 fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
235 if ty.has_escaping_regions() || ty.references_error() {
236 span_mirbug_and_err!(self, parent, "bad type {:?}", ty)
242 /// Checks that the constant's `ty` field matches up with what
243 /// would be expected from its literal.
244 fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
246 "sanitize_constant(constant={:?}, location={:?})",
250 let expected_ty = match constant.literal {
251 Literal::Value { value } => {
252 // FIXME(#46702) -- We need some way to get the predicates
253 // associated with the "pre-evaluated" form of the
254 // constant. For example, consider that the constant
255 // may have associated constant projections (`<Foo as
256 // Trait<'a, 'b>>::SOME_CONST`) that impose
257 // constraints on `'a` and `'b`. These constraints
258 // would be lost if we just look at the normalized
260 if let ty::TyFnDef(def_id, substs) = value.ty.sty {
261 let tcx = self.tcx();
262 let type_checker = &mut self.cx;
264 // FIXME -- For now, use the substitutions from
265 // `value.ty` rather than `value.val`. The
266 // renumberer will rewrite them to independent
267 // sets of regions; in principle, we ought to
268 // derive the type of the `value.val` from "first
269 // principles" and equate with value.ty, but as we
270 // are transitioning to the miri-based system, we
271 // don't have a handy function for that, so for
272 // now we just ignore `value.val` regions.
274 let instantiated_predicates =
275 tcx.predicates_of(def_id).instantiate(tcx, substs);
277 type_checker.normalize(&instantiated_predicates.predicates, location);
278 type_checker.prove_predicates(predicates, location);
284 Literal::Promoted { .. } => {
285 // FIXME -- promoted MIR return types reference
286 // various "free regions" (e.g., scopes and things)
287 // that they ought not to do. We have to figure out
288 // how best to handle that -- probably we want treat
289 // promoted MIR much like closures, renumbering all
290 // their free regions and propagating constraints
291 // upwards. We have the same acyclic guarantees, so
292 // that should be possible. But for now, ignore them.
294 // let promoted_mir = &self.mir.promoted[index];
295 // promoted_mir.return_ty()
300 debug!("sanitize_constant: expected_ty={:?}", expected_ty);
302 if let Err(terr) = self.cx
303 .eq_types(expected_ty, constant.ty, location.at_self())
308 "constant {:?} should have type {:?} but has {:?} ({:?})",
317 /// Checks that the types internal to the `place` match up with
318 /// what would be expected.
323 context: PlaceContext,
325 debug!("sanitize_place: {:?}", place);
326 let place_ty = match *place {
327 Place::Local(index) => PlaceTy::Ty {
328 ty: self.mir.local_decls[index].ty,
330 Place::Static(box Static { def_id, ty: sty }) => {
331 let sty = self.sanitize_type(place, sty);
332 let ty = self.tcx().type_of(def_id);
333 let ty = self.cx.normalize(&ty, location);
334 if let Err(terr) = self.cx.eq_types(ty, sty, location.at_self()) {
338 "bad static type ({:?}: {:?}): {:?}",
344 PlaceTy::Ty { ty: sty }
346 Place::Projection(ref proj) => {
347 let base_context = if context.is_mutating_use() {
348 PlaceContext::Projection(Mutability::Mut)
350 PlaceContext::Projection(Mutability::Not)
352 let base_ty = self.sanitize_place(&proj.base, location, base_context);
353 if let PlaceTy::Ty { ty } = base_ty {
354 if ty.references_error() {
355 assert!(self.errors_reported);
357 ty: self.tcx().types.err,
361 self.sanitize_projection(base_ty, &proj.elem, place, location)
364 if let PlaceContext::Copy = context {
365 let tcx = self.tcx();
366 let trait_ref = ty::TraitRef {
367 def_id: tcx.lang_items().copy_trait().unwrap(),
368 substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]),
371 // In order to have a Copy operand, the type T of the value must be Copy. Note that we
372 // prove that T: Copy, rather than using the type_moves_by_default test. This is
373 // important because type_moves_by_default ignores the resulting region obligations and
374 // assumes they pass. This can result in bounds from Copy impls being unsoundly ignored
375 // (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds
376 // fully apply: in effect, the rule is that if a value of some type could implement
377 // Copy, then it must.
378 self.cx.prove_trait_ref(trait_ref, location);
383 fn sanitize_projection(
386 pi: &PlaceElem<'tcx>,
390 debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place);
391 let tcx = self.tcx();
392 let base_ty = base.to_ty(tcx);
394 ProjectionElem::Deref => {
395 let deref_ty = base_ty.builtin_deref(true);
397 ty: deref_ty.map(|t| t.ty).unwrap_or_else(|| {
398 span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty)
402 ProjectionElem::Index(i) => {
403 let index_ty = Place::Local(i).ty(self.mir, tcx).to_ty(tcx);
404 if index_ty != tcx.types.usize {
406 ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i),
410 ty: base_ty.builtin_index().unwrap_or_else(|| {
411 span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty)
416 ProjectionElem::ConstantIndex { .. } => {
417 // consider verifying in-bounds
419 ty: base_ty.builtin_index().unwrap_or_else(|| {
420 span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty)
424 ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
425 ty: match base_ty.sty {
426 ty::TyArray(inner, size) => {
427 let size = size.val.unwrap_u64();
428 let min_size = (from as u64) + (to as u64);
429 if let Some(rest_size) = size.checked_sub(min_size) {
430 tcx.mk_array(inner, rest_size)
432 span_mirbug_and_err!(
435 "taking too-small slice of {:?}",
440 ty::TySlice(..) => base_ty,
441 _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty),
444 ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty {
445 ty::TyAdt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => {
446 if index >= adt_def.variants.len() {
448 ty: span_mirbug_and_err!(
451 "cast to variant #{:?} but enum only has {:?}",
453 adt_def.variants.len()
460 variant_index: index,
465 ty: span_mirbug_and_err!(
468 "can't downcast {:?} as {:?}",
474 ProjectionElem::Field(field, fty) => {
475 let fty = self.sanitize_type(place, fty);
476 match self.field_ty(place, base, field, location) {
477 Ok(ty) => if let Err(terr) = self.cx.eq_types(ty, fty, location.at_self()) {
481 "bad field access ({:?}: {:?}): {:?}",
487 Err(FieldAccessError::OutOfRange { field_count }) => span_mirbug!(
490 "accessed field #{} but variant only has {}",
495 PlaceTy::Ty { ty: fty }
500 fn error(&mut self) -> Ty<'tcx> {
501 self.errors_reported = true;
507 parent: &dyn fmt::Debug,
508 base_ty: PlaceTy<'tcx>,
511 ) -> Result<Ty<'tcx>, FieldAccessError> {
512 let tcx = self.tcx();
514 let (variant, substs) = match base_ty {
519 } => (&adt_def.variants[variant_index], substs),
520 PlaceTy::Ty { ty } => match ty.sty {
521 ty::TyAdt(adt_def, substs) if !adt_def.is_enum() => (&adt_def.variants[0], substs),
522 ty::TyClosure(def_id, substs) => {
523 return match substs.upvar_tys(def_id, tcx).nth(field.index()) {
525 None => Err(FieldAccessError::OutOfRange {
526 field_count: substs.upvar_tys(def_id, tcx).count(),
530 ty::TyGenerator(def_id, substs, _) => {
531 // Try pre-transform fields first (upvars and current state)
532 if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field.index()) {
536 // Then try `field_tys` which contains all the fields, but it
537 // requires the final optimized MIR.
538 return match substs.field_tys(def_id, tcx).nth(field.index()) {
540 None => Err(FieldAccessError::OutOfRange {
541 field_count: substs.field_tys(def_id, tcx).count(),
545 ty::TyTuple(tys) => {
546 return match tys.get(field.index()) {
548 None => Err(FieldAccessError::OutOfRange {
549 field_count: tys.len(),
554 return Ok(span_mirbug_and_err!(
557 "can't project out of {:?}",
564 if let Some(field) = variant.fields.get(field.index()) {
565 Ok(self.cx.normalize(&field.ty(tcx, substs), location))
567 Err(FieldAccessError::OutOfRange {
568 field_count: variant.fields.len(),
574 /// The MIR type checker. Visits the MIR and enforces all the
575 /// constraints needed for it to be valid and well-typed. Along the
576 /// way, it accrues region constraints -- these can later be used by
577 /// NLL region checking.
578 struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
579 infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
580 param_env: ty::ParamEnv<'gcx>,
582 body_id: ast::NodeId,
583 region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
584 implicit_region_bound: Option<ty::Region<'tcx>>,
585 reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
586 constraints: MirTypeckRegionConstraints<'tcx>,
589 /// A collection of region constraints that must be satisfied for the
590 /// program to be considered well-typed.
592 pub(crate) struct MirTypeckRegionConstraints<'tcx> {
593 /// In general, the type-checker is not responsible for enforcing
594 /// liveness constraints; this job falls to the region inferencer,
595 /// which performs a liveness analysis. However, in some limited
596 /// cases, the MIR type-checker creates temporary regions that do
597 /// not otherwise appear in the MIR -- in particular, the
598 /// late-bound regions that it instantiates at call-sites -- and
599 /// hence it must report on their liveness constraints.
600 pub liveness_set: Vec<(ty::Region<'tcx>, Location, Cause)>,
602 /// During the course of type-checking, we will accumulate region
603 /// constraints due to performing subtyping operations or solving
604 /// traits. These are accumulated into this vector for later use.
605 pub outlives_sets: Vec<OutlivesSet<'tcx>>,
608 /// Outlives relationships between regions and types created at a
609 /// particular point within the control-flow graph.
610 pub struct OutlivesSet<'tcx> {
611 /// The locations associated with these constraints.
612 pub locations: Locations,
614 /// Constraints generated. In terms of the NLL RFC, when you have
615 /// a constraint `R1: R2 @ P`, the data in there specifies things
617 pub data: RegionConstraintData<'tcx>,
620 #[derive(Copy, Clone, Debug)]
621 pub struct Locations {
622 /// The location in the MIR that generated these constraints.
623 /// This is intended for error reporting and diagnosis; the
624 /// constraints may *take effect* at a distinct spot.
625 pub from_location: Location,
627 /// The constraints must be met at this location. In terms of the
628 /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field
629 /// is the `P` value.
630 pub at_location: Location,
633 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
635 infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
636 body_id: ast::NodeId,
637 param_env: ty::ParamEnv<'gcx>,
638 region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
639 implicit_region_bound: Option<ty::Region<'tcx>>,
647 implicit_region_bound,
648 reported_errors: FxHashSet(),
649 constraints: MirTypeckRegionConstraints::default(),
653 fn misc(&self, span: Span) -> traits::ObligationCause<'tcx> {
654 traits::ObligationCause::misc(span, self.body_id)
657 fn fully_perform_op<OP, R>(
659 locations: Locations,
661 ) -> Result<R, TypeError<'tcx>>
663 OP: FnOnce(&mut Self) -> InferResult<'tcx, R>,
665 let mut fulfill_cx = TraitEngine::new(self.infcx.tcx);
666 let InferOk { value, obligations } = self.infcx.commit_if_ok(|_| op(self))?;
667 fulfill_cx.register_predicate_obligations(self.infcx, obligations);
668 if let Err(e) = fulfill_cx.select_all_or_error(self.infcx) {
669 span_mirbug!(self, "", "errors selecting obligation: {:?}", e);
672 self.infcx.process_registered_region_obligations(
673 self.region_bound_pairs,
674 self.implicit_region_bound,
679 let data = self.infcx.take_and_reset_region_constraints();
680 if !data.is_empty() {
682 "fully_perform_op: constraints generated at {:?} are {:#?}",
687 .push(OutlivesSet { locations, data });
697 locations: Locations,
698 ) -> UnitResult<'tcx> {
699 self.fully_perform_op(locations, |this| {
701 .at(&this.misc(this.last_span), this.param_env)
706 fn eq_types(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, locations: Locations) -> UnitResult<'tcx> {
707 self.fully_perform_op(locations, |this| {
709 .at(&this.misc(this.last_span), this.param_env)
714 fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
718 fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Location) {
719 debug!("check_stmt: {:?}", stmt);
720 let tcx = self.tcx();
722 StatementKind::Assign(ref place, ref rv) => {
723 let place_ty = place.ty(mir, tcx).to_ty(tcx);
724 let rv_ty = rv.ty(mir, tcx);
726 self.sub_types(rv_ty, place_ty, location.at_successor_within_block())
731 "bad assignment ({:?} = {:?}): {:?}",
737 self.check_rvalue(mir, rv, location);
739 StatementKind::SetDiscriminant {
743 let place_type = place.ty(mir, tcx).to_ty(tcx);
744 let adt = match place_type.sty {
745 TypeVariants::TyAdt(adt, _) if adt.is_enum() => adt,
748 stmt.source_info.span,
749 "bad set discriminant ({:?} = {:?}): lhs is not an enum",
755 if variant_index >= adt.variants.len() {
757 stmt.source_info.span,
758 "bad set discriminant ({:?} = {:?}): value of of range",
764 StatementKind::UserAssertTy(ref c_ty, ref local) => {
765 let local_ty = mir.local_decls()[*local].ty;
766 let (ty, _) = self.infcx
767 .instantiate_canonical_with_fresh_inference_vars(stmt.source_info.span, c_ty);
769 "check_stmt: user_assert_ty ty={:?} local_ty={:?}",
772 if let Err(terr) = self.eq_types(ty, local_ty, location.at_self()) {
776 "bad type assert ({:?} = {:?}): {:?}",
783 StatementKind::StorageLive(_)
784 | StatementKind::StorageDead(_)
785 | StatementKind::InlineAsm { .. }
786 | StatementKind::EndRegion(_)
787 | StatementKind::Validate(..)
788 | StatementKind::Nop => {}
795 term: &Terminator<'tcx>,
796 term_location: Location,
798 debug!("check_terminator: {:?}", term);
799 let tcx = self.tcx();
801 TerminatorKind::Goto { .. }
802 | TerminatorKind::Resume
803 | TerminatorKind::Abort
804 | TerminatorKind::Return
805 | TerminatorKind::GeneratorDrop
806 | TerminatorKind::Unreachable
807 | TerminatorKind::Drop { .. }
808 | TerminatorKind::FalseEdges { .. }
809 | TerminatorKind::FalseUnwind { .. } => {
810 // no checks needed for these
813 TerminatorKind::DropAndReplace {
819 let place_ty = location.ty(mir, tcx).to_ty(tcx);
820 let rv_ty = value.ty(mir, tcx);
822 let locations = Locations {
823 from_location: term_location,
824 at_location: target.start_location(),
826 if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) {
830 "bad DropAndReplace ({:?} = {:?}): {:?}",
837 // Subtle: this assignment occurs at the start of
838 // *both* blocks, so we need to ensure that it holds
839 // at both locations.
840 if let Some(unwind) = unwind {
841 let locations = Locations {
842 from_location: term_location,
843 at_location: unwind.start_location(),
845 if let Err(terr) = self.sub_types(rv_ty, place_ty, locations) {
849 "bad DropAndReplace ({:?} = {:?}): {:?}",
857 TerminatorKind::SwitchInt {
862 let discr_ty = discr.ty(mir, tcx);
863 if let Err(terr) = self.sub_types(discr_ty, switch_ty, term_location.at_self()) {
867 "bad SwitchInt ({:?} on {:?}): {:?}",
873 if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() {
874 span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty);
876 // FIXME: check the values
878 TerminatorKind::Call {
884 let func_ty = func.ty(mir, tcx);
885 debug!("check_terminator: call, func_ty={:?}", func_ty);
886 let sig = match func_ty.sty {
887 ty::TyFnDef(..) | ty::TyFnPtr(_) => func_ty.fn_sig(tcx),
889 span_mirbug!(self, term, "call to non-function {:?}", func_ty);
893 let (sig, map) = self.infcx.replace_late_bound_regions_with_fresh_var(
894 term.source_info.span,
895 LateBoundRegionConversionTime::FnCall,
898 let sig = self.normalize(&sig, term_location);
899 self.check_call_dest(mir, term, &sig, destination, term_location);
901 self.prove_predicates(
902 sig.inputs().iter().map(|ty| ty::Predicate::WellFormed(ty)),
906 // The ordinary liveness rules will ensure that all
907 // regions in the type of the callee are live here. We
908 // then further constrain the late-bound regions that
909 // were instantiated at the call site to be live as
910 // well. The resulting is that all the input (and
911 // output) types in the signature must be live, since
912 // all the inputs that fed into it were live.
913 for &late_bound_region in map.values() {
914 self.constraints.liveness_set.push((
917 Cause::LiveOther(term_location),
921 self.check_call_inputs(mir, term, &sig, args, term_location);
923 TerminatorKind::Assert {
924 ref cond, ref msg, ..
926 let cond_ty = cond.ty(mir, tcx);
927 if cond_ty != tcx.types.bool {
928 span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
931 if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
932 if len.ty(mir, tcx) != tcx.types.usize {
933 span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
935 if index.ty(mir, tcx) != tcx.types.usize {
936 span_mirbug!(self, index, "bounds-check index non-usize {:?}", index)
940 TerminatorKind::Yield { ref value, .. } => {
941 let value_ty = value.ty(mir, tcx);
943 None => span_mirbug!(self, term, "yield in non-generator"),
945 if let Err(terr) = self.sub_types(value_ty, ty, term_location.at_self()) {
949 "type of yield value is {:?}, but the yield type is {:?}: {:?}",
964 term: &Terminator<'tcx>,
965 sig: &ty::FnSig<'tcx>,
966 destination: &Option<(Place<'tcx>, BasicBlock)>,
967 term_location: Location,
969 let tcx = self.tcx();
971 Some((ref dest, target_block)) => {
972 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
973 let locations = Locations {
974 from_location: term_location,
975 at_location: target_block.start_location(),
977 if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) {
981 "call dest mismatch ({:?} <- {:?}): {:?}",
989 // FIXME(canndrew): This is_never should probably be an is_uninhabited
990 if !sig.output().is_never() {
991 span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
997 fn check_call_inputs(
1000 term: &Terminator<'tcx>,
1001 sig: &ty::FnSig<'tcx>,
1002 args: &[Operand<'tcx>],
1003 term_location: Location,
1005 debug!("check_call_inputs({:?}, {:?})", sig, args);
1006 if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.variadic) {
1007 span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
1009 for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
1010 let op_arg_ty = op_arg.ty(mir, self.tcx());
1011 if let Err(terr) = self.sub_types(op_arg_ty, fn_arg, term_location.at_self()) {
1015 "bad arg #{:?} ({:?} <- {:?}): {:?}",
1025 fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>) {
1026 let is_cleanup = block_data.is_cleanup;
1027 self.last_span = block_data.terminator().source_info.span;
1028 match block_data.terminator().kind {
1029 TerminatorKind::Goto { target } => {
1030 self.assert_iscleanup(mir, block_data, target, is_cleanup)
1032 TerminatorKind::SwitchInt { ref targets, .. } => for target in targets {
1033 self.assert_iscleanup(mir, block_data, *target, is_cleanup);
1035 TerminatorKind::Resume => if !is_cleanup {
1036 span_mirbug!(self, block_data, "resume on non-cleanup block!")
1038 TerminatorKind::Abort => if !is_cleanup {
1039 span_mirbug!(self, block_data, "abort on non-cleanup block!")
1041 TerminatorKind::Return => if is_cleanup {
1042 span_mirbug!(self, block_data, "return on cleanup block")
1044 TerminatorKind::GeneratorDrop { .. } => if is_cleanup {
1045 span_mirbug!(self, block_data, "generator_drop in cleanup block")
1047 TerminatorKind::Yield { resume, drop, .. } => {
1049 span_mirbug!(self, block_data, "yield in cleanup block")
1051 self.assert_iscleanup(mir, block_data, resume, is_cleanup);
1052 if let Some(drop) = drop {
1053 self.assert_iscleanup(mir, block_data, drop, is_cleanup);
1056 TerminatorKind::Unreachable => {}
1057 TerminatorKind::Drop { target, unwind, .. }
1058 | TerminatorKind::DropAndReplace { target, unwind, .. }
1059 | TerminatorKind::Assert {
1064 self.assert_iscleanup(mir, block_data, target, is_cleanup);
1065 if let Some(unwind) = unwind {
1067 span_mirbug!(self, block_data, "unwind on cleanup block")
1069 self.assert_iscleanup(mir, block_data, unwind, true);
1072 TerminatorKind::Call {
1077 if let &Some((_, target)) = destination {
1078 self.assert_iscleanup(mir, block_data, target, is_cleanup);
1080 if let Some(cleanup) = cleanup {
1082 span_mirbug!(self, block_data, "cleanup on cleanup block")
1084 self.assert_iscleanup(mir, block_data, cleanup, true);
1087 TerminatorKind::FalseEdges {
1089 ref imaginary_targets,
1091 self.assert_iscleanup(mir, block_data, real_target, is_cleanup);
1092 for target in imaginary_targets {
1093 self.assert_iscleanup(mir, block_data, *target, is_cleanup);
1096 TerminatorKind::FalseUnwind {
1100 self.assert_iscleanup(mir, block_data, real_target, is_cleanup);
1101 if let Some(unwind) = unwind {
1106 "cleanup in cleanup block via false unwind"
1109 self.assert_iscleanup(mir, block_data, unwind, true);
1115 fn assert_iscleanup(
1118 ctxt: &dyn fmt::Debug,
1122 if mir[bb].is_cleanup != iscleanuppad {
1126 "cleanuppad mismatch: {:?} should be {:?}",
1133 fn check_local(&mut self, mir: &Mir<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) {
1134 match mir.local_kind(local) {
1135 LocalKind::ReturnPointer | LocalKind::Arg => {
1136 // return values of normal functions are required to be
1137 // sized by typeck, but return values of ADT constructors are
1138 // not because we don't include a `Self: Sized` bounds on them.
1140 // Unbound parts of arguments were never required to be Sized
1141 // - maybe we should make that a warning.
1144 LocalKind::Var | LocalKind::Temp => {}
1147 let span = local_decl.source_info.span;
1148 let ty = local_decl.ty;
1150 // Erase the regions from `ty` to get a global type. The
1151 // `Sized` bound in no way depends on precise regions, so this
1152 // shouldn't affect `is_sized`.
1153 let gcx = self.tcx().global_tcx();
1154 let erased_ty = gcx.lift(&self.tcx().erase_regions(&ty)).unwrap();
1155 if !erased_ty.is_sized(gcx.at(span), self.param_env) {
1156 // in current MIR construction, all non-control-flow rvalue
1157 // expressions evaluate through `as_temp` or `into` a return
1158 // slot or local, so to find all unsized rvalues it is enough
1159 // to check all temps, return slots and locals.
1160 if let None = self.reported_errors.replace((ty, span)) {
1165 "cannot move a value of type {0}: the size of {0} \
1166 cannot be statically determined",
1173 fn aggregate_field_ty(
1175 ak: &AggregateKind<'tcx>,
1178 ) -> Result<Ty<'tcx>, FieldAccessError> {
1179 let tcx = self.tcx();
1182 AggregateKind::Adt(def, variant_index, substs, active_field_index) => {
1183 let variant = &def.variants[variant_index];
1184 let adj_field_index = active_field_index.unwrap_or(field_index);
1185 if let Some(field) = variant.fields.get(adj_field_index) {
1186 Ok(self.normalize(&field.ty(tcx, substs), location))
1188 Err(FieldAccessError::OutOfRange {
1189 field_count: variant.fields.len(),
1193 AggregateKind::Closure(def_id, substs) => {
1194 match substs.upvar_tys(def_id, tcx).nth(field_index) {
1196 None => Err(FieldAccessError::OutOfRange {
1197 field_count: substs.upvar_tys(def_id, tcx).count(),
1201 AggregateKind::Generator(def_id, substs, _) => {
1202 // Try pre-transform fields first (upvars and current state)
1203 if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field_index) {
1206 // Then try `field_tys` which contains all the fields, but it
1207 // requires the final optimized MIR.
1208 match substs.field_tys(def_id, tcx).nth(field_index) {
1210 None => Err(FieldAccessError::OutOfRange {
1211 field_count: substs.field_tys(def_id, tcx).count(),
1216 AggregateKind::Array(ty) => Ok(ty),
1217 AggregateKind::Tuple => {
1218 unreachable!("This should have been covered in check_rvalues");
1223 fn check_rvalue(&mut self, mir: &Mir<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
1224 let tcx = self.tcx();
1227 Rvalue::Aggregate(ak, ops) => {
1228 self.check_aggregate_rvalue(mir, rvalue, ak, ops, location)
1231 Rvalue::Repeat(operand, len) => if *len > 1 {
1232 let operand_ty = operand.ty(mir, tcx);
1234 let trait_ref = ty::TraitRef {
1235 def_id: tcx.lang_items().copy_trait().unwrap(),
1236 substs: tcx.mk_substs_trait(operand_ty, &[]),
1239 self.prove_trait_ref(trait_ref, location);
1242 Rvalue::NullaryOp(_, ty) => {
1243 let trait_ref = ty::TraitRef {
1244 def_id: tcx.lang_items().sized_trait().unwrap(),
1245 substs: tcx.mk_substs_trait(ty, &[]),
1248 self.prove_trait_ref(trait_ref, location);
1251 Rvalue::Cast(cast_kind, op, ty) => match cast_kind {
1252 CastKind::ReifyFnPointer => {
1253 let fn_sig = op.ty(mir, tcx).fn_sig(tcx);
1255 // The type that we see in the fcx is like
1256 // `foo::<'a, 'b>`, where `foo` is the path to a
1257 // function definition. When we extract the
1258 // signature, it comes from the `fn_sig` query,
1259 // and hence may contain unnormalized results.
1260 let fn_sig = self.normalize(&fn_sig, location);
1262 let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
1264 if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
1268 "equating {:?} with {:?} yields {:?}",
1276 CastKind::ClosureFnPointer => {
1277 let sig = match op.ty(mir, tcx).sty {
1278 ty::TyClosure(def_id, substs) => {
1279 substs.closure_sig_ty(def_id, tcx).fn_sig(tcx)
1283 let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig);
1285 if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
1289 "equating {:?} with {:?} yields {:?}",
1297 CastKind::UnsafeFnPointer => {
1298 let fn_sig = op.ty(mir, tcx).fn_sig(tcx);
1300 // The type that we see in the fcx is like
1301 // `foo::<'a, 'b>`, where `foo` is the path to a
1302 // function definition. When we extract the
1303 // signature, it comes from the `fn_sig` query,
1304 // and hence may contain unnormalized results.
1305 let fn_sig = self.normalize(&fn_sig, location);
1307 let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
1309 if let Err(terr) = self.eq_types(ty_fn_ptr_from, ty, location.at_self()) {
1313 "equating {:?} with {:?} yields {:?}",
1321 CastKind::Unsize => {
1322 let trait_ref = ty::TraitRef {
1323 def_id: tcx.lang_items().coerce_unsized_trait().unwrap(),
1324 substs: tcx.mk_substs_trait(op.ty(mir, tcx), &[ty]),
1327 self.prove_trait_ref(trait_ref, location);
1330 CastKind::Misc => {}
1333 // FIXME: These other cases have to be implemented in future PRs
1337 | Rvalue::BinaryOp(..)
1338 | Rvalue::CheckedBinaryOp(..)
1339 | Rvalue::UnaryOp(..)
1340 | Rvalue::Discriminant(..) => {}
1344 fn check_aggregate_rvalue(
1347 rvalue: &Rvalue<'tcx>,
1348 aggregate_kind: &AggregateKind<'tcx>,
1349 operands: &[Operand<'tcx>],
1352 let tcx = self.tcx();
1354 self.prove_aggregate_predicates(aggregate_kind, location);
1356 if *aggregate_kind == AggregateKind::Tuple {
1357 // tuple rvalue field type is always the type of the op. Nothing to check here.
1361 for (i, operand) in operands.iter().enumerate() {
1362 let field_ty = match self.aggregate_field_ty(aggregate_kind, i, location) {
1363 Ok(field_ty) => field_ty,
1364 Err(FieldAccessError::OutOfRange { field_count }) => {
1368 "accessed field #{} but variant only has {}",
1375 let operand_ty = operand.ty(mir, tcx);
1377 self.sub_types(operand_ty, field_ty, location.at_successor_within_block())
1382 "{:?} is not a subtype of {:?}: {:?}",
1391 fn prove_aggregate_predicates(
1393 aggregate_kind: &AggregateKind<'tcx>,
1396 let tcx = self.tcx();
1399 "prove_aggregate_predicates(aggregate_kind={:?}, location={:?})",
1400 aggregate_kind, location
1403 let instantiated_predicates = match aggregate_kind {
1404 AggregateKind::Adt(def, _, substs, _) => {
1405 tcx.predicates_of(def.did).instantiate(tcx, substs)
1408 // For closures, we have some **extra requirements** we
1410 // have to check. In particular, in their upvars and
1411 // signatures, closures often reference various regions
1412 // from the surrounding function -- we call those the
1413 // closure's free regions. When we borrow-check (and hence
1414 // region-check) closures, we may find that the closure
1415 // requires certain relationships between those free
1416 // regions. However, because those free regions refer to
1417 // portions of the CFG of their caller, the closure is not
1418 // in a position to verify those relationships. In that
1419 // case, the requirements get "propagated" to us, and so
1420 // we have to solve them here where we instantiate the
1423 // Despite the opacity of the previous parapgrah, this is
1424 // actually relatively easy to understand in terms of the
1425 // desugaring. A closure gets desugared to a struct, and
1426 // these extra requirements are basically like where
1427 // clauses on the struct.
1428 AggregateKind::Closure(def_id, substs) => {
1429 if let Some(closure_region_requirements) = tcx.mir_borrowck(*def_id) {
1430 closure_region_requirements.apply_requirements(
1439 tcx.predicates_of(*def_id).instantiate(tcx, substs.substs)
1442 AggregateKind::Generator(def_id, substs, _) => {
1443 tcx.predicates_of(*def_id).instantiate(tcx, substs.substs)
1446 AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
1449 let predicates = self.normalize(&instantiated_predicates.predicates, location);
1450 debug!("prove_aggregate_predicates: predicates={:?}", predicates);
1451 self.prove_predicates(predicates, location);
1454 fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location) {
1455 self.prove_predicates(
1456 Some(ty::Predicate::Trait(
1457 trait_ref.to_poly_trait_ref().to_poly_trait_predicate(),
1463 fn prove_predicates<T>(&mut self, predicates: T, location: Location)
1465 T: IntoIterator<Item = ty::Predicate<'tcx>>,
1468 let predicates = predicates.into_iter();
1471 "prove_predicates(predicates={:?}, location={:?})",
1472 predicates.clone().collect::<Vec<_>>(),
1475 self.fully_perform_op(location.at_self(), |this| {
1476 let cause = this.misc(this.last_span);
1477 let obligations = predicates
1479 .map(|p| traits::Obligation::new(cause.clone(), this.param_env, p))
1488 fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
1489 self.last_span = mir.span;
1490 debug!("run_on_mir: {:?}", mir.span);
1492 for (local, local_decl) in mir.local_decls.iter_enumerated() {
1493 self.check_local(mir, local, local_decl);
1496 for (block, block_data) in mir.basic_blocks().iter_enumerated() {
1497 let mut location = Location {
1501 for stmt in &block_data.statements {
1502 if stmt.source_info.span != DUMMY_SP {
1503 self.last_span = stmt.source_info.span;
1505 self.check_stmt(mir, stmt, location);
1506 location.statement_index += 1;
1509 self.check_terminator(mir, block_data.terminator(), location);
1510 self.check_iscleanup(mir, block_data);
1514 fn normalize<T>(&mut self, value: &T, location: Location) -> T
1516 T: fmt::Debug + TypeFoldable<'tcx>,
1518 debug!("normalize(value={:?}, location={:?})", value, location);
1519 self.fully_perform_op(location.at_self(), |this| {
1520 let Normalized { value, obligations } = this.infcx
1521 .at(&this.misc(this.last_span), this.param_env)
1523 .unwrap_or_else(|NoSolution| {
1526 "normalization of `{:?}` failed at {:?}",
1531 Ok(InferOk { value, obligations })
1536 pub struct TypeckMir;
1538 impl MirPass for TypeckMir {
1539 fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
1540 let def_id = src.def_id;
1541 let id = tcx.hir.as_local_node_id(def_id).unwrap();
1542 debug!("run_pass: {:?}", def_id);
1544 // When NLL is enabled, the borrow checker runs the typeck
1545 // itself, so we don't need this MIR pass anymore.
1546 if tcx.use_mir_borrowck() {
1550 if tcx.sess.err_count() > 0 {
1551 // compiling a broken program can obviously result in a
1552 // broken MIR, so try not to report duplicate errors.
1555 let param_env = tcx.param_env(def_id);
1556 tcx.infer_ctxt().enter(|infcx| {
1557 let _ = type_check_internal(&infcx, id, param_env, mir, &[], None, &mut |_| ());
1559 // For verification purposes, we just ignore the resulting
1560 // region constraint sets. Not our problem. =)
1566 /// Creates a `Locations` where `self` is both the from-location
1567 /// and the at-location. This means that any required region
1568 /// relationships must hold upon entering the statement/terminator
1569 /// indicated by `self`. This is typically used when processing
1570 /// "inputs" to the given location.
1571 fn at_self(self) -> Locations;
1573 /// Creates a `Locations` where `self` is the from-location and
1574 /// its successor within the block is the at-location. This means
1575 /// that any required region relationships must hold only upon
1576 /// **exiting** the statement/terminator indicated by `self`. This
1577 /// is for example used when you have a `place = rv` statement: it
1578 /// indicates that the `typeof(rv) <: typeof(place)` as of the
1579 /// **next** statement.
1580 fn at_successor_within_block(self) -> Locations;
1583 impl AtLocation for Location {
1584 fn at_self(self) -> Locations {
1586 from_location: self,
1591 fn at_successor_within_block(self) -> Locations {
1593 from_location: self,
1594 at_location: self.successor_within_block(),