From b569caf267c595d2c2988941fb39f4718cadfdcc Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 22 Oct 2018 14:23:44 +0200 Subject: [PATCH] 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.) --- src/librustc/ich/impls_mir.rs | 1 + src/librustc/mir/mod.rs | 42 +++++++++++- src/librustc/mir/visit.rs | 2 +- .../borrow_check/nll/type_check/mod.rs | 12 ++-- src/librustc_mir/build/block.rs | 11 ++-- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 66 ++++++++++--------- src/librustc_mir/build/mod.rs | 2 +- src/librustc_mir/hair/mod.rs | 3 +- src/librustc_mir/hair/pattern/mod.rs | 50 +++++++++++++- src/librustc_mir/shim.rs | 2 +- src/librustc_mir/transform/generator.rs | 6 +- src/librustc_mir/util/pretty.rs | 2 +- 13 files changed, 148 insertions(+), 53 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 94b85247bb8..724481da681 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -608,3 +608,4 @@ impl<'a, 'gcx> HashStable> for mir::UserTypeAnnotation< } impl_stable_hash_for!(struct mir::UserTypeProjection<'tcx> { base }); +impl_stable_hash_for!(struct mir::UserTypeProjections<'tcx> { contents }); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d2f67a74420..f96c3b432d6 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -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, Span)>) -> Self { + UserTypeProjections { contents: projs.collect() } + } + + pub fn projections_and_spans(&self) -> impl Iterator, Span)> { + self.contents.iter() + } + + pub fn projections(&self) -> impl Iterator> { + 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>, diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index acca7ddcd3f..61eb565fb9a 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -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); diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 708f2f3ad33..828907ddc63 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -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, diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index b754d63f718..aa383a123b6 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -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. diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 4f5ed34a461..d2913872fca 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -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, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 9bfb6d4e6de..5479ccb2d84 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -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>, 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, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 6ea4628de24..5b4001f0652 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -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, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 888c14194c6..8a24851de81 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -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; diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 57b2638cc8d..7a04c6e39df 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -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>, } + +#[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>); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index d8f627fcf4d..6c32690cdb3 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -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, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index c2ae6832cc0..5889fabee9d 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -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, diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 25bd02ff6dc..c74492fe649 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -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(";");