From 50754d05138a93434397245746d0dcdfbf29e2a4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 31 Aug 2018 18:34:15 -0400 Subject: [PATCH] add a `AscribeUserType` pattern, largely ignored --- src/librustc_mir/build/matches/mod.rs | 18 +++++++++++++++++- src/librustc_mir/build/matches/simplify.rs | 14 +++++++++++++- src/librustc_mir/build/matches/test.rs | 4 ++++ src/librustc_mir/hair/cx/block.rs | 18 +++++++++++++++--- src/librustc_mir/hair/mod.rs | 2 ++ src/librustc_mir/hair/pattern/_match.rs | 4 ++++ src/librustc_mir/hair/pattern/mod.rs | 18 ++++++++++++++++-- 7 files changed, 71 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index f46e3a9f1fd84..21b837f1db93e 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -19,7 +19,7 @@ use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard}; use build::scope::{CachedBlock, DropKind}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::bitvec::BitArray; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, CanonicalTy, Ty}; use rustc::mir::*; use rustc::hir; use hair::*; @@ -168,6 +168,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: pattern.span, match_pairs: vec![MatchPair::new(discriminant_place.clone(), pattern)], bindings: vec![], + ascriptions: vec![], guard, arm_index, pat_index, @@ -253,6 +254,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: irrefutable_pat.span, match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)], bindings: vec![], + ascriptions: vec![], guard: None, // since we don't call `match_candidates`, next fields is unused @@ -398,6 +400,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => { } + PatternKind::AscribeUserType { ref subpattern, .. } | PatternKind::Deref { ref subpattern } => { self.visit_bindings(subpattern, f); } @@ -429,6 +432,9 @@ pub struct Candidate<'pat, 'tcx:'pat> { // ...these bindings established... bindings: Vec>, + // ...these types asserted... + ascriptions: Vec>, + // ...and the guard must be evaluated... guard: Option>, @@ -454,6 +460,16 @@ struct Binding<'tcx> { binding_mode: BindingMode<'tcx>, } +/// Indicates that the type of `source` must be a subtype of the +/// user-given type `user_ty`; this is basically a no-op but can +/// influence region inference. +#[derive(Clone, Debug)] +struct Ascription<'tcx> { + span: Span, + source: Place<'tcx>, + user_ty: CanonicalTy<'tcx>, +} + #[derive(Clone, Debug)] pub struct MatchPair<'pat, 'tcx:'pat> { // this place... diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 147b8cc2175af..14da8e9083892 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -23,7 +23,7 @@ //! testing a value against a constant. use build::{BlockAnd, BlockAndExtension, Builder}; -use build::matches::{Binding, MatchPair, Candidate}; +use build::matches::{Ascription, Binding, MatchPair, Candidate}; use hair::*; use rustc::mir::*; @@ -63,6 +63,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { candidate: &mut Candidate<'pat, 'tcx>) -> Result<(), MatchPair<'pat, 'tcx>> { match *match_pair.pattern.kind { + PatternKind::AscribeUserType { ref subpattern, user_ty } => { + candidate.ascriptions.push(Ascription { + span: match_pair.pattern.span, + user_ty, + source: match_pair.place.clone(), + }); + + candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern)); + + Ok(()) + } + PatternKind::Wild => { // nothing left to do Ok(()) diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 4a0b4b0c88580..2c606ebf322a8 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -96,6 +96,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } + PatternKind::AscribeUserType { .. } | PatternKind::Array { .. } | PatternKind::Slice { .. } | PatternKind::Wild | @@ -138,6 +139,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Array { .. } | PatternKind::Wild | PatternKind::Binding { .. } | + PatternKind::AscribeUserType { .. } | PatternKind::Leaf { .. } | PatternKind::Deref { .. } => { // don't know how to add these patterns to a switch @@ -638,6 +640,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: candidate.span, match_pairs: other_match_pairs, bindings: candidate.bindings.clone(), + ascriptions: candidate.ascriptions.clone(), guard: candidate.guard.clone(), arm_index: candidate.arm_index, pat_index: candidate.pat_index, @@ -702,6 +705,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: candidate.span, match_pairs: all_match_pairs, bindings: candidate.bindings.clone(), + ascriptions: candidate.ascriptions.clone(), guard: candidate.guard.clone(), arm_index: candidate.arm_index, pat_index: candidate.pat_index, diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 6c8b5d97b6ff3..85a9734a60101 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -76,14 +76,26 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, first_statement_index: region::FirstStatementIndex::new(index), }); - let ty = local.ty.clone().map(|ty| ty.hir_id); - let pattern = cx.pattern_from_hir(&local.pat); + let mut pattern = cx.pattern_from_hir(&local.pat); + + if let Some(ty) = &local.ty { + if let Some(user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) { + pattern = Pattern { + ty: pattern.ty, + span: pattern.span, + kind: Box::new(PatternKind::AscribeUserType { + user_ty: *user_ty, + subpattern: pattern + }) + }; + } + } + result.push(StmtRef::Mirror(Box::new(Stmt { kind: StmtKind::Let { remainder_scope: remainder_scope, init_scope: region::Scope::Node(hir_id.local_id), pattern, - ty, initializer: local.init.to_ref(), lint_level: cx.lint_level_of(local.id), }, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 0fd130c9041f8..d86aee5431267 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -94,6 +94,8 @@ pub enum StmtKind<'tcx> { init_scope: region::Scope, /// `let = ...` + /// + /// if a type is included, it is added as an ascription pattern pattern: Pattern<'tcx>, /// let pat: ty = ... diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index d7fbbc88cc16d..a29c81e38e5a4 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -1235,6 +1235,7 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt, -> Option>> { match *pat.kind { + PatternKind::AscribeUserType { ref subpattern, .. } => pat_constructors(cx, subpattern, pcx), PatternKind::Binding { .. } | PatternKind::Wild => None, PatternKind::Leaf { .. } | PatternKind::Deref { .. } => Some(vec![Single]), PatternKind::Variant { adt_def, variant_index, .. } => { @@ -1606,6 +1607,9 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( let pat = &r[0]; let head: Option> = match *pat.kind { + PatternKind::AscribeUserType { ref subpattern, .. } => + specialize(cx, ::std::slice::from_ref(&subpattern), constructor, wild_patterns), + PatternKind::Binding { .. } | PatternKind::Wild => { Some(wild_patterns.to_owned()) } diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 384ee0079dc84..cd44869211a7d 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -20,7 +20,7 @@ use interpret::{const_field, const_variant_index}; use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend}; -use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; +use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region}; use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; use rustc::hir::def::{Def, CtorKind}; @@ -66,6 +66,11 @@ pub struct Pattern<'tcx> { pub enum PatternKind<'tcx> { Wild, + AscribeUserType { + user_ty: CanonicalTy<'tcx>, + subpattern: Pattern<'tcx>, + }, + /// x, ref x, x @ P, etc Binding { mutability: Mutability, @@ -125,6 +130,8 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self.kind { PatternKind::Wild => write!(f, "_"), + PatternKind::AscribeUserType { ref subpattern, .. } => + write!(f, "{}: _", subpattern), PatternKind::Binding { mutability, name, mode, ref subpattern, .. } => { let is_mut = match mode { BindingMode::ByValue => mutability == Mutability::Mut, @@ -939,7 +946,7 @@ macro_rules! CloneImpls { CloneImpls!{ <'tcx> Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>, Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef, - &'tcx Substs<'tcx>, &'tcx Kind<'tcx> + &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, CanonicalTy<'tcx> } impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> { @@ -973,6 +980,13 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { match *self { PatternKind::Wild => PatternKind::Wild, + PatternKind::AscribeUserType { + ref subpattern, + user_ty, + } => PatternKind::AscribeUserType { + subpattern: subpattern.fold_with(folder), + user_ty: user_ty.fold_with(folder), + }, PatternKind::Binding { mutability, name,