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::*;
span: pattern.span,
match_pairs: vec![MatchPair::new(discriminant_place.clone(), pattern)],
bindings: vec![],
+ ascriptions: vec![],
guard,
arm_index,
pat_index,
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
}
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
}
+ PatternKind::AscribeUserType { ref subpattern, .. } |
PatternKind::Deref { ref subpattern } => {
self.visit_bindings(subpattern, f);
}
// ...these bindings established...
bindings: Vec<Binding<'tcx>>,
+ // ...these types asserted...
+ ascriptions: Vec<Ascription<'tcx>>,
+
// ...and the guard must be evaluated...
guard: Option<Guard<'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...
//! 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::*;
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(())
}
}
+ PatternKind::AscribeUserType { .. } |
PatternKind::Array { .. } |
PatternKind::Slice { .. } |
PatternKind::Wild |
PatternKind::Array { .. } |
PatternKind::Wild |
PatternKind::Binding { .. } |
+ PatternKind::AscribeUserType { .. } |
PatternKind::Leaf { .. } |
PatternKind::Deref { .. } => {
// don't know how to add these patterns to a switch
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,
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,
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),
},
init_scope: region::Scope,
/// `let <PAT> = ...`
+ ///
+ /// if a type is included, it is added as an ascription pattern
pattern: Pattern<'tcx>,
/// let pat: ty = <INIT> ...
-> Option<Vec<Constructor<'tcx>>>
{
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, .. } => {
let pat = &r[0];
let head: Option<Vec<&Pattern>> = 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())
}
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};
pub enum PatternKind<'tcx> {
Wild,
+ AscribeUserType {
+ user_ty: CanonicalTy<'tcx>,
+ subpattern: Pattern<'tcx>,
+ },
+
/// x, ref x, x @ P, etc
Binding {
mutability: Mutability,
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,
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> {
fn super_fold_with<F: PatternFolder<'tcx>>(&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,