Skip to content

Commit

Permalink
add the AscribeUserType statement kind
Browse files Browse the repository at this point in the history
Make it have the semantics of subtype.
  • Loading branch information
nikomatsakis committed Sep 10, 2018
1 parent 22f9bcc commit dd3cc96
Show file tree
Hide file tree
Showing 22 changed files with 134 additions and 78 deletions.
4 changes: 2 additions & 2 deletions src/librustc/ich/impls_mir.rs
Expand Up @@ -255,9 +255,9 @@ for mir::StatementKind<'gcx> {
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 } => {
Expand Down
26 changes: 9 additions & 17 deletions src/librustc/mir/mod.rs
Expand Up @@ -1636,22 +1636,14 @@ pub enum StatementKind<'tcx> {
/// (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,
Expand Down Expand Up @@ -1728,8 +1720,8 @@ impl<'tcx> Debug for Statement<'tcx> {
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"),
}
Expand Down Expand Up @@ -2652,7 +2644,7 @@ EnumTypeFoldableImpl! {
(StatementKind::InlineAsm) { asm, outputs, inputs },
(StatementKind::Validate)(a, b),
(StatementKind::EndRegion)(a),
(StatementKind::UserAssertTy)(a, b),
(StatementKind::AscribeUserType)(a, b),
(StatementKind::Nop),
}
}
Expand Down
28 changes: 15 additions & 13 deletions src/librustc/mir/visit.rs
Expand Up @@ -144,11 +144,11 @@ macro_rules! make_mir_visitor {
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,
Expand Down Expand Up @@ -386,9 +386,11 @@ macro_rules! make_mir_visitor {
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 => {}
}
Expand Down Expand Up @@ -629,12 +631,12 @@ macro_rules! make_mir_visitor {
}
}

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,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/ty/context.rs
Expand Up @@ -356,8 +356,8 @@ pub struct TypeckTables<'tcx> {
/// 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
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_codegen_llvm/mir/statement.rs
Expand Up @@ -92,7 +92,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
mir::StatementKind::ReadForMatch(_) |
mir::StatementKind::EndRegion(_) |
mir::StatementKind::Validate(..) |
mir::StatementKind::UserAssertTy(..) |
mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => bx,
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/borrow_check/mod.rs
Expand Up @@ -535,10 +535,10 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
// 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) => {
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_mir/borrow_check/nll/constraint_generation.rs
Expand Up @@ -17,7 +17,7 @@ use rustc::infer::InferCtxt;
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};
Expand Down Expand Up @@ -175,10 +175,10 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
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,
) {
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/borrow_check/nll/invalidation.rs
Expand Up @@ -144,10 +144,10 @@ impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tc
// 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) => {
Expand Down
10 changes: 7 additions & 3 deletions src/librustc_mir/borrow_check/nll/renumber.rs
Expand Up @@ -10,7 +10,7 @@

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};

Expand Down Expand Up @@ -112,8 +112,12 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
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.
Expand Down
33 changes: 24 additions & 9 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Expand Up @@ -248,7 +248,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
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,
Expand Down Expand Up @@ -850,13 +850,28 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
)
}

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,
Expand Down Expand Up @@ -905,7 +920,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}

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(),
Expand Down Expand Up @@ -955,15 +970,15 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
);
};
}
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
);
}
Expand Down
49 changes: 46 additions & 3 deletions src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
Expand Up @@ -22,6 +22,7 @@ use rustc::ty::{self, CanonicalTy, CanonicalVar, RegionVid, Ty, TyCtxt};
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>,
Expand All @@ -40,6 +41,7 @@ pub(super) fn sub_types<'tcx>(
Ok(())
}

/// Adds sufficient constraints to ensure that `a == b`.
pub(super) fn eq_types<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: Ty<'tcx>,
Expand All @@ -58,24 +60,65 @@ pub(super) fn eq_types<'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>,
locations: Locations,
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,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/dataflow/impls/borrows.rs
Expand Up @@ -338,7 +338,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
mir::StatementKind::SetDiscriminant { .. } |
mir::StatementKind::StorageLive(..) |
mir::StatementKind::Validate(..) |
mir::StatementKind::UserAssertTy(..) |
mir::StatementKind::AscribeUserType(..) |
mir::StatementKind::Nop => {}

}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/dataflow/move_paths/builder.rs
Expand Up @@ -304,7 +304,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
}
StatementKind::EndRegion(_) |
StatementKind::Validate(..) |
StatementKind::UserAssertTy(..) |
StatementKind::AscribeUserType(..) |
StatementKind::Nop => {}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/interpret/step.rs
Expand Up @@ -159,7 +159,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
}

EndRegion(..) => {}
UserAssertTy(..) => {}
AscribeUserType(..) => {}

// Defined to do nothing. These are added by optimization passes, to avoid changing the
// size of MIR constantly.
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/transform/check_unsafety.rs
Expand Up @@ -114,7 +114,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
StatementKind::StorageDead(..) |
StatementKind::EndRegion(..) |
StatementKind::Validate(..) |
StatementKind::UserAssertTy(..) |
StatementKind::AscribeUserType(..) |
StatementKind::Nop => {
// safe (at least as emitted during MIR construction)
}
Expand Down

0 comments on commit dd3cc96

Please sign in to comment.