infcx: &InferCtxt<'_, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
+ promoted: &IndexVec<Promoted, Body<'tcx>>,
mir_def_id: DefId,
universal_regions: &Rc<UniversalRegions<'tcx>>,
location_table: &LocationTable,
mir_def_id,
param_env,
body,
+ promoted,
®ion_bound_pairs,
implicit_region_bound,
&mut borrowck_context,
mir_def_id: DefId,
param_env: ty::ParamEnv<'tcx>,
body: &'a Body<'tcx>,
+ promoted: &'a IndexVec<Promoted, Body<'tcx>>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
universal_region_relations,
);
let errors_reported = {
- let mut verifier = TypeVerifier::new(&mut checker, body);
+ let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
verifier.visit_body(body);
verifier.errors_reported
};
struct TypeVerifier<'a, 'b, 'tcx> {
cx: &'a mut TypeChecker<'b, 'tcx>,
body: &'b Body<'tcx>,
+ promoted: &'b IndexVec<Promoted, Body<'tcx>>,
last_span: Span,
mir_def_id: DefId,
errors_reported: bool,
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
self.super_constant(constant, location);
- self.sanitize_constant(constant, location);
- self.sanitize_type(constant, constant.ty);
+ self.sanitize_type(constant, constant.literal.ty);
if let Some(annotation_index) = constant.user_ty {
if let Err(terr) = self.cx.relate_type_and_user_type(
- constant.ty,
+ constant.literal.ty,
ty::Variance::Invariant,
&UserTypeProjection { base: annotation_index, projs: vec![], },
location.to_locations(),
constant,
"bad constant user type {:?} vs {:?}: {:?}",
annotation,
- constant.ty,
+ constant.literal.ty,
terr,
);
}
location.to_locations(),
ConstraintCategory::Boring,
self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
- constant.ty, def_id, UserSubsts { substs, user_self_ty: None },
+ constant.literal.ty, def_id, UserSubsts { substs, user_self_ty: None },
)),
) {
span_mirbug!(
}
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
- fn new(cx: &'a mut TypeChecker<'b, 'tcx>, body: &'b Body<'tcx>) -> Self {
+ fn new(
+ cx: &'a mut TypeChecker<'b, 'tcx>,
+ body: &'b Body<'tcx>,
+ promoted: &'b IndexVec<Promoted, Body<'tcx>>,
+ ) -> Self {
TypeVerifier {
body,
+ promoted,
mir_def_id: cx.mir_def_id,
cx,
last_span: body.span,
}
}
- /// Checks that the constant's `ty` field matches up with what would be
- /// expected from its literal. Unevaluated constants and well-formed
- /// constraints are checked by `visit_constant`.
- fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
- debug!(
- "sanitize_constant(constant={:?}, location={:?})",
- constant, location
- );
-
- let literal = constant.literal;
-
- if let ConstValue::Unevaluated(..) = literal.val {
- return;
- }
-
- debug!("sanitize_constant: expected_ty={:?}", literal.ty);
-
- if let Err(terr) = self.cx.eq_types(
- literal.ty,
- constant.ty,
- location.to_locations(),
- ConstraintCategory::Boring,
- ) {
- span_mirbug!(
- self,
- constant,
- "constant {:?} should have type {:?} but has {:?} ({:?})",
- constant,
- literal.ty,
- constant.ty,
- terr,
- );
- }
- }
-
/// Checks that the types internal to the `place` match up with
/// what would be expected.
fn sanitize_place(
) -> PlaceTy<'tcx> {
debug!("sanitize_place: {:?}", place);
- place.iterate(|place_base, place_projection| {
- let mut place_ty = match place_base {
- PlaceBase::Local(index) =>
- PlaceTy::from_ty(self.body.local_decls[*index].ty),
- PlaceBase::Static(box Static { kind, ty: sty }) => {
- let sty = self.sanitize_type(place, sty);
- let check_err =
- |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
- place: &Place<'tcx>,
- ty,
- sty| {
- if let Err(terr) = verifier.cx.eq_types(
- sty,
- ty,
- location.to_locations(),
- ConstraintCategory::Boring,
- ) {
- span_mirbug!(
- verifier,
- place,
- "bad promoted type ({:?}: {:?}): {:?}",
- ty,
- sty,
- terr
- );
- };
+ let mut place_ty = match &place.base {
+ PlaceBase::Local(index) =>
+ PlaceTy::from_ty(self.body.local_decls[*index].ty),
+ PlaceBase::Static(box Static { kind, ty: sty, def_id }) => {
+ let sty = self.sanitize_type(place, sty);
+ let check_err =
+ |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
+ place: &Place<'tcx>,
+ ty,
+ sty| {
+ if let Err(terr) = verifier.cx.eq_types(
+ sty,
+ ty,
+ location.to_locations(),
+ ConstraintCategory::Boring,
+ ) {
+ span_mirbug!(
+ verifier,
+ place,
+ "bad promoted type ({:?}: {:?}): {:?}",
+ ty,
+ sty,
+ terr
+ );
};
- match kind {
- StaticKind::Promoted(promoted) => {
- if !self.errors_reported {
- let promoted_body = &self.body.promoted[*promoted];
- self.sanitize_promoted(promoted_body, location);
-
- let promoted_ty = promoted_body.return_ty();
- check_err(self, place, promoted_ty, sty);
- }
+ };
+ match kind {
+ StaticKind::Promoted(promoted, _) => {
+ if !self.errors_reported {
+ let promoted_body = &self.promoted[*promoted];
+ self.sanitize_promoted(promoted_body, location);
+
+ let promoted_ty = promoted_body.return_ty();
+ check_err(self, place, promoted_ty, sty);
}
- StaticKind::Static(def_id) => {
- let ty = self.tcx().type_of(*def_id);
- let ty = self.cx.normalize(ty, location);
+ }
+ StaticKind::Static => {
+ let ty = self.tcx().type_of(*def_id);
+ let ty = self.cx.normalize(ty, location);
- check_err(self, place, ty, sty);
- }
+ check_err(self, place, ty, sty);
}
- PlaceTy::from_ty(sty)
}
- };
+ PlaceTy::from_ty(sty)
+ }
+ };
- // FIXME use place_projection.is_empty() when is available
- if place.projection.is_none() {
- if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
- let is_promoted = match place {
- Place {
- base: PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(_),
- ..
- }),
- projection: None,
- } => true,
- _ => false,
- };
+ if place.projection.is_empty() {
+ if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
+ let is_promoted = match place {
+ Place {
+ base: PlaceBase::Static(box Static {
+ kind: StaticKind::Promoted(..),
+ ..
+ }),
+ projection: box [],
+ } => true,
+ _ => false,
+ };
- if !is_promoted {
- let tcx = self.tcx();
- let trait_ref = ty::TraitRef {
- def_id: tcx.lang_items().copy_trait().unwrap(),
- substs: tcx.mk_substs_trait(place_ty.ty, &[]),
- };
+ if !is_promoted {
+ let tcx = self.tcx();
+ let trait_ref = ty::TraitRef {
+ def_id: tcx.lang_items().copy_trait().unwrap(),
+ substs: tcx.mk_substs_trait(place_ty.ty, &[]),
+ };
- // In order to have a Copy operand, the type T of the
- // value must be Copy. Note that we prove that T: Copy,
- // rather than using the `is_copy_modulo_regions`
- // test. This is important because
- // `is_copy_modulo_regions` ignores the resulting region
- // obligations and assumes they pass. This can result in
- // bounds from Copy impls being unsoundly ignored (e.g.,
- // #29149). Note that we decide to use Copy before knowing
- // whether the bounds fully apply: in effect, the rule is
- // that if a value of some type could implement Copy, then
- // it must.
- self.cx.prove_trait_ref(
- trait_ref,
- location.to_locations(),
- ConstraintCategory::CopyBound,
- );
- }
+ // In order to have a Copy operand, the type T of the
+ // value must be Copy. Note that we prove that T: Copy,
+ // rather than using the `is_copy_modulo_regions`
+ // test. This is important because
+ // `is_copy_modulo_regions` ignores the resulting region
+ // obligations and assumes they pass. This can result in
+ // bounds from Copy impls being unsoundly ignored (e.g.,
+ // #29149). Note that we decide to use Copy before knowing
+ // whether the bounds fully apply: in effect, the rule is
+ // that if a value of some type could implement Copy, then
+ // it must.
+ self.cx.prove_trait_ref(
+ trait_ref,
+ location.to_locations(),
+ ConstraintCategory::CopyBound,
+ );
}
}
+ }
- for proj in place_projection {
- if place_ty.variant_index.is_none() {
- if place_ty.ty.references_error() {
- assert!(self.errors_reported);
- return PlaceTy::from_ty(self.tcx().types.err);
- }
+ for elem in place.projection.iter() {
+ if place_ty.variant_index.is_none() {
+ if place_ty.ty.references_error() {
+ assert!(self.errors_reported);
+ return PlaceTy::from_ty(self.tcx().types.err);
}
- place_ty = self.sanitize_projection(place_ty, &proj.elem, place, location)
}
+ place_ty = self.sanitize_projection(place_ty, elem, place, location)
+ }
- place_ty
- })
+ place_ty
}
fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) {
let category = match *place {
Place {
base: PlaceBase::Local(RETURN_PLACE),
- projection: None,
+ projection: box [],
} => if let BorrowCheckContext {
universal_regions:
UniversalRegions {
},
Place {
base: PlaceBase::Local(l),
- projection: None,
+ projection: box [],
} if !body.local_decls[l].is_user_variable.is_some() => {
ConstraintCategory::Boring
}
let category = match *dest {
Place {
base: PlaceBase::Local(RETURN_PLACE),
- projection: None,
+ projection: box [],
} => {
if let BorrowCheckContext {
universal_regions:
}
Place {
base: PlaceBase::Local(l),
- projection: None,
+ projection: box [],
} if !body.local_decls[l].is_user_variable.is_some() => {
ConstraintCategory::Boring
}
// *p`, where the `p` has type `&'b mut Foo`, for example, we
// need to ensure that `'b: 'a`.
- let mut borrowed_projection = &borrowed_place.projection;
-
debug!(
"add_reborrow_constraint({:?}, {:?}, {:?})",
location, borrow_region, borrowed_place
);
- while let Some(box proj) = borrowed_projection {
- debug!("add_reborrow_constraint - iteration {:?}", borrowed_projection);
+ for (i, elem) in borrowed_place.projection.iter().enumerate().rev() {
+ debug!("add_reborrow_constraint - iteration {:?}", elem);
+ let proj_base = &borrowed_place.projection[..i];
- match proj.elem {
+ match elem {
ProjectionElem::Deref => {
let tcx = self.infcx.tcx;
- let base_ty = Place::ty_from(&borrowed_place.base, &proj.base, body, tcx).ty;
+ let base_ty = Place::ty_from(&borrowed_place.base, proj_base, body, tcx).ty;
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
match base_ty.sty {
// other field access
}
}
-
- // The "propagate" case. We need to check that our base is valid
- // for the borrow's lifetime.
- borrowed_projection = &proj.base;
}
}