Checkpoint: Added abstraction over collection of projections into user type.

I did not think I would need this in the MIR, but in general local
decls are going to need to support this. (That, or we need to be able
define a least-upper-bound for a collection of types encountered via
the pattern compilation.)
This commit is contained in:
Felix S. Klock II 2018-10-22 14:23:44 +02:00
parent 28ce99df86
commit b569caf267
13 changed files with 148 additions and 53 deletions

View File

@ -608,3 +608,4 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::UserTypeAnnotation<
}
impl_stable_hash_for!(struct mir::UserTypeProjection<'tcx> { base });
impl_stable_hash_for!(struct mir::UserTypeProjections<'tcx> { contents });

View File

@ -710,7 +710,7 @@ pub struct LocalDecl<'tcx> {
/// e.g. via `let x: T`, then we carry that type here. The MIR
/// borrow checker needs this information since it can affect
/// region inference.
pub user_ty: Option<(UserTypeProjection<'tcx>, Span)>,
pub user_ty: UserTypeProjections<'tcx>,
/// Name of the local, used in debuginfo and pretty-printing.
///
@ -882,7 +882,7 @@ impl<'tcx> LocalDecl<'tcx> {
LocalDecl {
mutability,
ty,
user_ty: None,
user_ty: UserTypeProjections::none(),
name: None,
source_info: SourceInfo {
span,
@ -903,7 +903,7 @@ impl<'tcx> LocalDecl<'tcx> {
LocalDecl {
mutability: Mutability::Mut,
ty: return_ty,
user_ty: None,
user_ty: UserTypeProjections::none(),
source_info: SourceInfo {
span,
scope: OUTERMOST_SOURCE_SCOPE,
@ -2449,6 +2449,42 @@ EnumLiftImpl! {
}
}
/// A collection of projections into user types.
///
/// They are projections because a binding can occur a part of a
/// parent pattern that has been ascribed a type.
///
/// Its a collection because there can be multiple type ascriptions on
/// the path from the root of the pattern down to the binding itself.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct UserTypeProjections<'tcx> {
pub(crate) contents: Vec<(UserTypeProjection<'tcx>, Span)>,
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for UserTypeProjections<'tcx> {
contents
}
}
impl<'tcx> UserTypeProjections<'tcx> {
pub fn none() -> Self {
UserTypeProjections { contents: vec![] }
}
pub fn from_projections(projs: impl Iterator<Item=(UserTypeProjection<'tcx>, Span)>) -> Self {
UserTypeProjections { contents: projs.collect() }
}
pub fn projections_and_spans(&self) -> impl Iterator<Item=&(UserTypeProjection<'tcx>, Span)> {
self.contents.iter()
}
pub fn projections(&self) -> impl Iterator<Item=&UserTypeProjection<'tcx>> {
self.contents.iter().map(|&(ref user_type, _span)| user_type)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct UserTypeProjection<'tcx> {
pub base: UserTypeAnnotation<'tcx>,

View File

@ -743,7 +743,7 @@ macro_rules! make_mir_visitor {
local,
source_info: *source_info,
});
if let Some((user_ty, _)) = user_ty {
for (user_ty, _) in & $($mutability)* user_ty.contents {
self.visit_user_type_projection(user_ty);
}
self.visit_source_info(source_info);

View File

@ -284,7 +284,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
if let Err(terr) = self.cx.relate_type_and_user_type(
constant.ty,
ty::Variance::Invariant,
UserTypeProjection { base: user_ty },
&UserTypeProjection { base: user_ty },
location.to_locations(),
ConstraintCategory::Boring,
) {
@ -310,12 +310,12 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
self.super_local_decl(local, local_decl);
self.sanitize_type(local_decl, local_decl.ty);
if let Some((user_ty, span)) = local_decl.user_ty {
for (user_ty, span) in local_decl.user_ty.projections_and_spans() {
if let Err(terr) = self.cx.relate_type_and_user_type(
local_decl.ty,
ty::Variance::Invariant,
user_ty,
Locations::All(span),
Locations::All(*span),
ConstraintCategory::TypeAnnotation,
) {
span_mirbug!(
@ -971,7 +971,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
&mut self,
a: Ty<'tcx>,
v: ty::Variance,
user_ty: UserTypeProjection<'tcx>,
user_ty: &UserTypeProjection<'tcx>,
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
@ -1173,7 +1173,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
if let Err(terr) = self.relate_type_and_user_type(
rv_ty,
ty::Variance::Invariant,
UserTypeProjection { base: user_ty },
&UserTypeProjection { base: user_ty },
location.to_locations(),
ConstraintCategory::Boring,
) {
@ -1226,7 +1226,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
);
};
}
StatementKind::AscribeUserType(ref place, variance, box c_ty) => {
StatementKind::AscribeUserType(ref place, variance, box ref c_ty) => {
let place_ty = place.ty(mir, tcx).to_ty(tcx);
if let Err(terr) = self.relate_type_and_user_type(
place_ty,

View File

@ -151,10 +151,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
None, remainder_span, lint_level, slice::from_ref(&pattern),
ArmHasGuard(false), None);
this.visit_bindings(&pattern, None, &mut |this, _, _, _, node, span, _, _| {
this.storage_live_binding(block, node, span, OutsideGuard);
this.schedule_drop_for_binding(node, span, OutsideGuard);
})
this.visit_bindings(
&pattern,
&PatternTypeProjections::none(),
&mut |this, _, _, _, node, span, _, _| {
this.storage_live_binding(block, node, span, OutsideGuard);
this.schedule_drop_for_binding(node, span, OutsideGuard);
})
}
// Enter the source scope, after evaluating the initializer.

View File

@ -306,7 +306,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let ptr_temp = this.local_decls.push(LocalDecl {
mutability: Mutability::Mut,
ty: ptr_ty,
user_ty: None,
user_ty: UserTypeProjections::none(),
name: None,
source_info,
visibility_scope: source_info.scope,

View File

@ -18,6 +18,7 @@ use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard};
use build::{BlockAnd, BlockAndExtension, Builder};
use build::{GuardFrame, GuardFrameLocal, LocalsForNode};
use hair::*;
use hair::pattern::PatternTypeProjections;
use rustc::hir;
use rustc::mir::*;
use rustc::ty::{self, Ty};
@ -415,7 +416,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let num_patterns = patterns.len();
self.visit_bindings(
&patterns[0],
None,
&PatternTypeProjections::none(),
&mut |this, mutability, name, mode, var, span, ty, user_ty| {
if visibility_scope.is_none() {
visibility_scope =
@ -491,7 +492,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
pub(super) fn visit_bindings(
&mut self,
pattern: &Pattern<'tcx>,
mut pattern_user_ty: Option<(PatternTypeProjection<'tcx>, Span)>,
pattern_user_ty: &PatternTypeProjections<'tcx>,
f: &mut impl FnMut(
&mut Self,
Mutability,
@ -500,7 +501,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
NodeId,
Span,
Ty<'tcx>,
Option<(PatternTypeProjection<'tcx>, Span)>,
&PatternTypeProjections<'tcx>,
),
) {
match *pattern.kind {
@ -513,20 +514,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ref subpattern,
..
} => {
match mode {
BindingMode::ByValue => { }
let pattern_ref_binding; // sidestep temp lifetime limitations.
let binding_user_ty = match mode {
BindingMode::ByValue => { pattern_user_ty }
BindingMode::ByRef(..) => {
// If this is a `ref` binding (e.g., `let ref
// x: T = ..`), then the type of `x` is not
// `T` but rather `&T`, so ignore
// `pattern_user_ty` for now.
//
// FIXME(#47184): extract or handle `pattern_user_ty` somehow
pattern_user_ty = None;
// `T` but rather `&T`.
pattern_ref_binding = pattern_user_ty.ref_binding();
&pattern_ref_binding
}
}
};
f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty);
f(self, mutability, name, mode, var, pattern.span, ty, binding_user_ty);
if let Some(subpattern) = subpattern.as_ref() {
self.visit_bindings(subpattern, pattern_user_ty, f);
}
@ -541,15 +541,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ref slice,
ref suffix,
} => {
// FIXME(#47184): extract or handle `pattern_user_ty` somehow
for subpattern in prefix.iter().chain(slice).chain(suffix) {
self.visit_bindings(subpattern, None, f);
for subpattern in prefix {
self.visit_bindings(subpattern, &pattern_user_ty.index(), f);
}
for subpattern in slice {
self.visit_bindings(subpattern, &pattern_user_ty.subslice(), f);
}
for subpattern in suffix {
self.visit_bindings(subpattern, &pattern_user_ty.index(), f);
}
}
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {}
PatternKind::Deref { ref subpattern } => {
// FIXME(#47184): extract or handle `pattern_user_ty` somehow
self.visit_bindings(subpattern, None, f);
self.visit_bindings(subpattern, &pattern_user_ty.deref(), f);
}
PatternKind::AscribeUserType { ref subpattern, user_ty, user_ty_span } => {
// This corresponds to something like
@ -557,17 +561,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// ```
// let A::<'a>(_): A<'static> = ...;
// ```
//
// FIXME(#47184): handle `pattern_user_ty` somehow
self.visit_bindings(subpattern, Some((user_ty, user_ty_span)), f)
let pattern_user_ty = pattern_user_ty.add_user_type(user_ty, user_ty_span);
self.visit_bindings(subpattern, &pattern_user_ty, f)
}
PatternKind::Leaf { ref subpatterns }
| PatternKind::Variant {
ref subpatterns, ..
} => {
// FIXME(#47184): extract or handle `pattern_user_ty` somehow
for subpattern in subpatterns {
self.visit_bindings(&subpattern.pattern, None, f);
PatternKind::Leaf { ref subpatterns } => {
for (j, subpattern) in subpatterns.iter().enumerate() {
self.visit_bindings(&subpattern.pattern, &pattern_user_ty.leaf(j), f);
}
}
PatternKind::Variant { ref subpatterns, .. } => {
for (j, subpattern) in subpatterns.iter().enumerate() {
self.visit_bindings(&subpattern.pattern, &pattern_user_ty.variant(j), f);
}
}
}
@ -1470,7 +1476,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
num_patterns: usize,
var_id: NodeId,
var_ty: Ty<'tcx>,
user_var_ty: Option<(PatternTypeProjection<'tcx>, Span)>,
user_var_ty: &PatternTypeProjections<'tcx>,
has_guard: ArmHasGuard,
opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
pat_span: Span,
@ -1489,7 +1495,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let local = LocalDecl::<'tcx> {
mutability,
ty: var_ty,
user_ty: user_var_ty.map(|(ut, sp)| (ut.user_ty(), sp)),
user_ty: user_var_ty.clone().user_ty(),
name: Some(name),
source_info,
visibility_scope,
@ -1522,7 +1528,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// See previous comment.
mutability: Mutability::Not,
ty: tcx.mk_imm_ref(tcx.types.re_empty, var_ty),
user_ty: None,
user_ty: UserTypeProjections::none(),
name: Some(name),
source_info,
visibility_scope,

View File

@ -845,7 +845,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
self.local_decls.push(LocalDecl {
mutability: Mutability::Mut,
ty,
user_ty: None,
user_ty: UserTypeProjections::none(),
source_info,
visibility_scope: source_info.scope,
name,

View File

@ -27,7 +27,8 @@ use self::cx::Cx;
pub mod cx;
pub mod pattern;
pub use self::pattern::{BindingMode, Pattern, PatternKind, PatternTypeProjection, FieldPattern};
pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
pub(crate) use self::pattern::{PatternTypeProjection, PatternTypeProjections};
mod util;

View File

@ -21,7 +21,7 @@ use const_eval::{const_field, const_variant_index};
use hair::util::UserAnnotatedTyHelpers;
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
use rustc::mir::{UserTypeAnnotation, UserTypeProjection};
use rustc::mir::{UserTypeAnnotation, UserTypeProjection, UserTypeProjections};
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty};
use rustc::ty::subst::{Substs, Kind};
@ -65,6 +65,54 @@ pub struct Pattern<'tcx> {
pub kind: Box<PatternKind<'tcx>>,
}
#[derive(Clone, Debug)]
pub(crate) struct PatternTypeProjections<'tcx> {
contents: Vec<(PatternTypeProjection<'tcx>, Span)>,
}
impl<'tcx> PatternTypeProjections<'tcx> {
pub(crate) fn user_ty(self) -> UserTypeProjections<'tcx> {
UserTypeProjections::from_projections(
self.contents.into_iter().map(|(pat_ty_proj, span)| (pat_ty_proj.user_ty(), span)))
}
pub(crate) fn none() -> Self {
PatternTypeProjections { contents: vec![] }
}
pub(crate) fn ref_binding(&self) -> Self {
// FIXME(#47184): ignore for now
PatternTypeProjections { contents: vec![] }
}
pub(crate) fn index(&self) -> Self {
unimplemented!()
}
pub(crate) fn subslice(&self) -> Self {
unimplemented!()
}
pub(crate) fn deref(&self) -> Self {
unimplemented!()
}
pub(crate) fn add_user_type(&self, user_ty: PatternTypeProjection<'tcx>, sp: Span) -> Self {
let mut new = self.clone();
new.contents.push((user_ty, sp));
new
}
pub(crate) fn leaf(&self, _index: usize) -> Self {
unimplemented!()
}
pub(crate) fn variant(&self, _index: usize) -> Self {
unimplemented!()
}
}
#[derive(Copy, Clone, Debug)]
pub struct PatternTypeProjection<'tcx>(UserTypeProjection<'tcx>);

View File

@ -142,7 +142,7 @@ fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
LocalDecl {
mutability,
ty,
user_ty: None,
user_ty: UserTypeProjections::none(),
name: None,
source_info,
visibility_scope: source_info.scope,

View File

@ -303,7 +303,7 @@ fn replace_result_variable<'tcx>(
let new_ret = LocalDecl {
mutability: Mutability::Mut,
ty: ret_ty,
user_ty: None,
user_ty: UserTypeProjections::none(),
name: None,
source_info,
visibility_scope: source_info.scope,
@ -658,7 +658,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
mir.local_decls[RETURN_PLACE] = LocalDecl {
mutability: Mutability::Mut,
ty: tcx.mk_unit(),
user_ty: None,
user_ty: UserTypeProjections::none(),
name: None,
source_info,
visibility_scope: source_info.scope,
@ -676,7 +676,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
ty: gen_ty,
mutbl: hir::Mutability::MutMutable,
}),
user_ty: None,
user_ty: UserTypeProjections::none(),
name: None,
source_info,
visibility_scope: source_info.scope,

View File

@ -502,7 +502,7 @@ fn write_scope_tree(
local,
var.ty
);
if let Some(user_ty) = var.user_ty {
for user_ty in var.user_ty.projections() {
write!(indented_var, " as {:?}", user_ty).unwrap();
}
indented_var.push_str(";");