Make it have the semantics of subtype.
op.hash_stable(hcx, hasher);
places.hash_stable(hcx, hasher);
}
- mir::StatementKind::UserAssertTy(ref c_ty, ref local) => {
+ mir::StatementKind::AscribeUserType(ref place, ref c_ty) => {
+ place.hash_stable(hcx, hasher);
c_ty.hash_stable(hcx, hasher);
- local.hash_stable(hcx, hasher);
}
mir::StatementKind::Nop => {}
mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
/// (The starting point(s) arise implicitly from borrows.)
EndRegion(region::Scope),
- /// Encodes a user's type assertion. These need to be preserved intact so that NLL can respect
- /// them. For example:
+ /// Encodes a user's type ascription. These need to be preserved
+ /// intact so that NLL can respect them. For example:
///
- /// let (a, b): (T, U) = y;
+ /// let a: T = y;
///
- /// Here we would insert a `UserAssertTy<(T, U)>(y)` instruction to check that the type of `y`
- /// is the right thing.
- ///
- /// `CanonicalTy` is used to capture "inference variables" from the user's types. For example:
- ///
- /// let x: Vec<_> = ...;
- /// let y: &u32 = ...;
- ///
- /// would result in `Vec<?0>` and `&'?0 u32` respectively (where `?0` is a canonicalized
- /// variable).
- UserAssertTy(CanonicalTy<'tcx>, Local),
+ /// Here we would insert a `AscribeUserType` that ensures that the
+ /// type `Y` of `y` is a subtype of `T` (`Y <: T`).
+ AscribeUserType(Place<'tcx>, CanonicalTy<'tcx>),
/// No-op. Useful for deleting instructions without affecting statement indices.
Nop,
ref outputs,
ref inputs,
} => write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs),
- UserAssertTy(ref c_ty, ref local) => {
- write!(fmt, "UserAssertTy({:?}, {:?})", c_ty, local)
+ AscribeUserType(ref place, ref c_ty) => {
+ write!(fmt, "AscribeUserType({:?}, {:?})", place, c_ty)
}
Nop => write!(fmt, "nop"),
}
(StatementKind::InlineAsm) { asm, outputs, inputs },
(StatementKind::Validate)(a, b),
(StatementKind::EndRegion)(a),
- (StatementKind::UserAssertTy)(a, b),
+ (StatementKind::AscribeUserType)(a, b),
(StatementKind::Nop),
}
}
self.super_operand(operand, location);
}
- fn visit_user_assert_ty(&mut self,
- c_ty: & $($mutability)* CanonicalTy<'tcx>,
- local: & $($mutability)* Local,
- location: Location) {
- self.super_user_assert_ty(c_ty, local, location);
+ fn visit_ascribe_user_ty(&mut self,
+ place: & $($mutability)* Place<'tcx>,
+ c_ty: & $($mutability)* CanonicalTy<'tcx>,
+ location: Location) {
+ self.super_ascribe_user_ty(place, c_ty, location);
}
fn visit_place(&mut self,
self.visit_operand(input, location);
}
}
- StatementKind::UserAssertTy(ref $($mutability)* c_ty,
- ref $($mutability)* local) => {
- self.visit_user_assert_ty(c_ty, local, location);
+ StatementKind::AscribeUserType(
+ ref $($mutability)* place,
+ ref $($mutability)* c_ty,
+ ) => {
+ self.visit_ascribe_user_ty(place, c_ty, location);
}
StatementKind::Nop => {}
}
}
}
- fn super_user_assert_ty(&mut self,
- c_ty: & $($mutability)* CanonicalTy<'tcx>,
- local: & $($mutability)* Local,
- location: Location) {
+ fn super_ascribe_user_ty(&mut self,
+ place: & $($mutability)* Place<'tcx>,
+ c_ty: & $($mutability)* CanonicalTy<'tcx>,
+ location: Location) {
+ self.visit_place(place, PlaceContext::Validate, location);
self.visit_canonical_ty(c_ty);
- self.visit_local(local, PlaceContext::Validate, location);
}
fn super_place(&mut self,
/// belongs, but it may not exist if it's a tuple field (`tuple.0`).
field_indices: ItemLocalMap<usize>,
- /// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in
- /// MIR.
+ /// Stores the canonicalized types provided by the user. See also
+ /// `AscribeUserType` statement in MIR.
user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
/// Stores the types for various nodes in the AST. Note that this table
mir::StatementKind::ReadForMatch(_) |
mir::StatementKind::EndRegion(_) |
mir::StatementKind::Validate(..) |
- mir::StatementKind::UserAssertTy(..) |
+ mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => bx,
}
}
// flow_state already handled).
}
StatementKind::Nop
- | StatementKind::UserAssertTy(..)
+ | StatementKind::AscribeUserType(..)
| StatementKind::Validate(..)
| StatementKind::StorageLive(..) => {
- // `Nop`, `UserAssertTy`, `Validate`, and `StorageLive` are irrelevant
+ // `Nop`, `AscribeUserType`, `Validate`, and `StorageLive` are irrelevant
// to borrow check.
}
StatementKind::StorageDead(local) => {
use rustc::mir::visit::TyContext;
use rustc::mir::visit::Visitor;
use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
-use rustc::mir::{Local, Statement, Terminator};
+use rustc::mir::{Statement, Terminator};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::Substs;
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, RegionVid};
self.super_terminator(block, terminator, location);
}
- fn visit_user_assert_ty(
+ fn visit_ascribe_user_ty(
&mut self,
+ _place: &Place<'tcx>,
_c_ty: &CanonicalTy<'tcx>,
- _local: &Local,
_location: Location,
) {
}
// EndRegion matters to older NLL/MIR AST borrowck, not to alias NLL
StatementKind::EndRegion(..) |
StatementKind::Nop |
- StatementKind::UserAssertTy(..) |
+ StatementKind::AscribeUserType(..) |
StatementKind::Validate(..) |
StatementKind::StorageLive(..) => {
- // `Nop`, `UserAssertTy`, `Validate`, and `StorageLive` are irrelevant
+ // `Nop`, `AscribeUserType`, `Validate`, and `StorageLive` are irrelevant
// to borrow check.
}
StatementKind::StorageDead(local) => {
use rustc::ty::subst::Substs;
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
-use rustc::mir::{BasicBlock, Local, Location, Mir, Statement, StatementKind};
+use rustc::mir::{BasicBlock, Location, Mir, Place, Statement, StatementKind};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
debug!("visit_closure_substs: substs={:?}", substs);
}
- fn visit_user_assert_ty(&mut self, _c_ty: &mut CanonicalTy<'tcx>, _local: &mut Local,
- _location: Location) {
+ fn visit_ascribe_user_ty(
+ &mut self,
+ _place: &mut Place<'tcx>,
+ _c_ty: &mut CanonicalTy<'tcx>,
+ _location: Location,
+ ) {
// User-assert-ty statements represent types that the user added explicitly.
// We don't want to erase the regions from these types: rather, we want to
// add them as constraints at type-check time.
if let Some(user_ty) = constant.user_ty {
if let Err(terr) =
self.cx
- .eq_canonical_type_and_type(user_ty, constant.ty, location.boring())
+ .eq_user_type_and_type(user_ty, constant.ty, location.boring())
{
span_mirbug!(
self,
)
}
- fn eq_canonical_type_and_type(
+ fn sub_type_and_user_type(
+ &mut self,
+ a: Ty<'tcx>,
+ b: CanonicalTy<'tcx>,
+ locations: Locations,
+ ) -> Fallible<()> {
+ relate_tys::sub_type_and_user_type(
+ self.infcx,
+ a,
+ b,
+ locations,
+ self.borrowck_context.as_mut().map(|x| &mut **x),
+ )
+ }
+
+ fn eq_user_type_and_type(
&mut self,
a: CanonicalTy<'tcx>,
b: Ty<'tcx>,
locations: Locations,
) -> Fallible<()> {
- relate_tys::eq_canonical_type_and_type(
+ relate_tys::eq_user_type_and_type(
self.infcx,
a,
b,
}
if let Some(user_ty) = self.rvalue_user_ty(rv) {
- if let Err(terr) = self.eq_canonical_type_and_type(
+ if let Err(terr) = self.eq_user_type_and_type(
user_ty,
rv_ty,
location.boring(),
);
};
}
- StatementKind::UserAssertTy(c_ty, local) => {
- let local_ty = mir.local_decls()[local].ty;
- if let Err(terr) = self.eq_canonical_type_and_type(c_ty, local_ty, Locations::All) {
+ StatementKind::AscribeUserType(ref place, c_ty) => {
+ let place_ty = place.ty(mir, tcx).to_ty(tcx);
+ if let Err(terr) = self.sub_type_and_user_type(place_ty, c_ty, Locations::All) {
span_mirbug!(
self,
stmt,
- "bad type assert ({:?} = {:?}): {:?}",
+ "bad type assert ({:?} <: {:?}): {:?}",
+ place_ty,
c_ty,
- local_ty,
terr
);
}
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::IndexVec;
+/// Adds sufficient constraints to ensure that `a <: b`.
pub(super) fn sub_types<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: Ty<'tcx>,
Ok(())
}
+/// Adds sufficient constraints to ensure that `a == b`.
pub(super) fn eq_types<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: Ty<'tcx>,
Ok(())
}
-pub(super) fn eq_canonical_type_and_type<'tcx>(
+/// Adds sufficient constraints to ensure that `a <: b`, where `b` is
+/// a user-given type (which means it may have canonical variables
+/// encoding things like `_`).
+pub(super) fn sub_type_and_user_type<'tcx>(
+ infcx: &InferCtxt<'_, '_, 'tcx>,
+ a: Ty<'tcx>,
+ b: CanonicalTy<'tcx>,
+ locations: Locations,
+ borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
+) -> Fallible<()> {
+ debug!(
+ "sub_type_and_user_type(a={:?}, b={:?}, locations={:?})",
+ a, b, locations
+ );
+ let Canonical {
+ variables: b_variables,
+ value: b_value,
+ } = b;
+
+ // (*) The `TypeRelating` code assumes that the "canonical variables"
+ // appear in the "a" side, so start with `Contravariant` ambient
+ // variance to get the right relationship.
+
+ TypeRelating::new(
+ infcx,
+ ty::Variance::Contravariant, // (*)
+ locations,
+ borrowck_context,
+ b_variables,
+ ).relate(&b_value, &a)?;
+ Ok(())
+}
+
+/// Adds sufficient constraints to ensure that `a <: b`, where `b` is
+/// a user-given type (which means it may have canonical variables
+/// encoding things like `_`).
+pub(super) fn eq_user_type_and_type<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: CanonicalTy<'tcx>,
b: Ty<'tcx>,
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
) -> Fallible<()> {
debug!(
- "eq_canonical_type_and_type(a={:?}, b={:?}, locations={:?})",
+ "eq_user_type_and_type(a={:?}, b={:?}, locations={:?})",
a, b, locations
);
let Canonical {
variables: a_variables,
value: a_value,
} = a;
+
+ // (*) The `TypeRelating` code assumes that the "canonical variables"
+ // appear in the "a" side, so start with `Contravariant` ambient
+ // variance to get the right relationship.
+
TypeRelating::new(
infcx,
- ty::Variance::Invariant,
+ ty::Variance::Invariant, // (*)
locations,
borrowck_context,
a_variables,
mir::StatementKind::SetDiscriminant { .. } |
mir::StatementKind::StorageLive(..) |
mir::StatementKind::Validate(..) |
- mir::StatementKind::UserAssertTy(..) |
+ mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => {}
}
}
StatementKind::EndRegion(_) |
StatementKind::Validate(..) |
- StatementKind::UserAssertTy(..) |
+ StatementKind::AscribeUserType(..) |
StatementKind::Nop => {}
}
}
}
EndRegion(..) => {}
- UserAssertTy(..) => {}
+ AscribeUserType(..) => {}
// Defined to do nothing. These are added by optimization passes, to avoid changing the
// size of MIR constantly.
StatementKind::StorageDead(..) |
StatementKind::EndRegion(..) |
StatementKind::Validate(..) |
- StatementKind::UserAssertTy(..) |
+ StatementKind::AscribeUserType(..) |
StatementKind::Nop => {
// safe (at least as emitted during MIR construction)
}
//!
//! - `CleanEndRegions`, that reduces the set of `EndRegion` statements
//! in the MIR.
-//! - `CleanUserAssertTy`, that replaces all `UserAssertTy` statements
+//! - `CleanAscribeUserType`, that replaces all `AscribeUserType` statements
//! with `Nop`.
//!
//! The `CleanEndRegions` "pass" is actually implemented as two
//! MIR and removes any `EndRegion` that is applied to a region that
//! was not seen in the previous pass.
//!
-//! The `CleanUserAssertTy` pass runs at a distinct time from the
-//! `CleanEndRegions` pass. It is important that the `CleanUserAssertTy`
+//! The `CleanAscribeUserType` pass runs at a distinct time from the
+//! `CleanEndRegions` pass. It is important that the `CleanAscribeUserType`
//! pass runs after the MIR borrowck so that the NLL type checker can
-//! perform the type assertion when it encounters the `UserAssertTy`
+//! perform the type assertion when it encounters the `AscribeUserType`
//! statements.
use rustc_data_structures::fx::FxHashSet;
}
}
-pub struct CleanUserAssertTy;
+pub struct CleanAscribeUserType;
-pub struct DeleteUserAssertTy;
+pub struct DeleteAscribeUserType;
-impl MirPass for CleanUserAssertTy {
+impl MirPass for CleanAscribeUserType {
fn run_pass<'a, 'tcx>(&self,
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
_source: MirSource,
mir: &mut Mir<'tcx>) {
- let mut delete = DeleteUserAssertTy;
+ let mut delete = DeleteAscribeUserType;
delete.visit_mir(mir);
}
}
-impl<'tcx> MutVisitor<'tcx> for DeleteUserAssertTy {
+impl<'tcx> MutVisitor<'tcx> for DeleteAscribeUserType {
fn visit_statement(&mut self,
block: BasicBlock,
statement: &mut Statement<'tcx>,
location: Location) {
- if let StatementKind::UserAssertTy(..) = statement.kind {
+ if let StatementKind::AscribeUserType(..) = statement.kind {
statement.make_nop();
}
self.super_statement(block, statement, location);
simplify_branches::SimplifyBranches::new("initial"),
remove_noop_landing_pads::RemoveNoopLandingPads,
simplify::SimplifyCfg::new("early-opt"),
- // Remove all `UserAssertTy` statements.
- cleanup_post_borrowck::CleanUserAssertTy,
+ // Remove all `AscribeUserType` statements.
+ cleanup_post_borrowck::CleanAscribeUserType,
// These next passes must be executed together
add_call_guards::CriticalCallEdges,
StatementKind::InlineAsm {..} |
StatementKind::EndRegion(_) |
StatementKind::Validate(..) |
- StatementKind::UserAssertTy(..) |
+ StatementKind::AscribeUserType(..) |
StatementKind::Nop => {}
}
});
StatementKind::StorageLive(_) |
StatementKind::StorageDead(_) |
StatementKind::EndRegion(_) |
- StatementKind::UserAssertTy(..) |
+ StatementKind::AscribeUserType(..) |
StatementKind::Nop => {
// These are all nops in a landing pad (there's some
// borrowck interaction between EndRegion and storage
mir::StatementKind::InlineAsm { .. } |
mir::StatementKind::EndRegion(_) |
mir::StatementKind::Validate(..) |
- mir::StatementKind::UserAssertTy(..) |
+ mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => continue,
mir::StatementKind::SetDiscriminant{ .. } =>
span_bug!(stmt.source_info.span,
StatementKind::StorageLive(..) => "StatementKind::StorageLive",
StatementKind::StorageDead(..) => "StatementKind::StorageDead",
StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm",
- StatementKind::UserAssertTy(..) => "StatementKind::UserAssertTy",
+ StatementKind::AscribeUserType(..) => "StatementKind::AscribeUserType",
StatementKind::Nop => "StatementKind::Nop",
}, &statement.kind);
self.super_statement(block, statement, location);
// _2 = move _3;
// StorageDead(_3);
// StorageLive(_4);
-// UserAssertTy(Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> }, _4);
+// AscribeUserType(_4, Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> });
// _4 = std::option::Option<std::boxed::Box<u32>>::None;
// StorageLive(_5);
// StorageLive(_6);