1 //! Validation of patterns/matches.
7 pub(crate) use self::check_match::check_match;
9 use crate::hair::constant::*;
10 use crate::hair::util::UserAnnotatedTyHelpers;
12 use rustc::hir::def::{CtorKind, CtorOf, DefKind, Res};
13 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
14 use rustc::hir::ptr::P;
15 use rustc::hir::{self, RangeEnd};
16 use rustc::mir::interpret::{get_slice_bytes, sign_extend, ConstValue, ErrorHandled};
17 use rustc::mir::UserTypeProjection;
18 use rustc::mir::{BorrowKind, Field, Mutability};
19 use rustc::ty::layout::VariantIdx;
20 use rustc::ty::subst::{GenericArg, SubstsRef};
21 use rustc::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType};
22 use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations};
24 use rustc_index::vec::Idx;
26 use std::cmp::Ordering;
29 use syntax_pos::{Span, DUMMY_SP};
31 use rustc_error_codes::*;
33 #[derive(Clone, Debug)]
34 pub enum PatternError {
35 AssocConstInPattern(Span),
36 StaticInPattern(Span),
41 #[derive(Copy, Clone, Debug)]
42 pub enum BindingMode {
47 #[derive(Clone, Debug)]
48 pub struct FieldPat<'tcx> {
50 pub pattern: Pat<'tcx>,
53 #[derive(Clone, Debug)]
54 pub struct Pat<'tcx> {
57 pub kind: Box<PatKind<'tcx>>,
60 impl<'tcx> Pat<'tcx> {
61 pub(crate) fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
62 Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
66 #[derive(Copy, Clone, Debug, PartialEq)]
67 pub struct PatTyProj<'tcx> {
68 pub user_ty: CanonicalUserType<'tcx>,
71 impl<'tcx> PatTyProj<'tcx> {
72 pub(crate) fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
73 Self { user_ty: user_annotation }
76 pub(crate) fn user_ty(
78 annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
79 inferred_ty: Ty<'tcx>,
81 ) -> UserTypeProjection {
83 base: annotations.push(CanonicalUserTypeAnnotation {
85 user_ty: self.user_ty,
93 #[derive(Copy, Clone, Debug, PartialEq)]
94 pub struct Ascription<'tcx> {
95 pub user_ty: PatTyProj<'tcx>,
96 /// Variance to use when relating the type `user_ty` to the **type of the value being
97 /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
98 /// have a type that is some subtype of the ascribed type.
100 /// Note that this variance does not apply for any bindings within subpatterns. The type
101 /// assigned to those bindings must be exactly equal to the `user_ty` given here.
103 /// The only place where this field is not `Covariant` is when matching constants, where
104 /// we currently use `Contravariant` -- this is because the constant type just needs to
105 /// be "comparable" to the type of the input value. So, for example:
108 /// match x { "foo" => .. }
111 /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
112 /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
113 /// of the old type-check for now. See #57280 for details.
114 pub variance: ty::Variance,
115 pub user_ty_span: Span,
118 #[derive(Clone, Debug)]
119 pub enum PatKind<'tcx> {
123 ascription: Ascription<'tcx>,
124 subpattern: Pat<'tcx>,
127 /// `x`, `ref x`, `x @ P`, etc.
129 mutability: Mutability,
134 subpattern: Option<Pat<'tcx>>,
137 /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
138 /// multiple variants.
140 adt_def: &'tcx AdtDef,
141 substs: SubstsRef<'tcx>,
142 variant_index: VariantIdx,
143 subpatterns: Vec<FieldPat<'tcx>>,
146 /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
147 /// a single variant.
149 subpatterns: Vec<FieldPat<'tcx>>,
152 /// `box P`, `&P`, `&mut P`, etc.
154 subpattern: Pat<'tcx>,
158 value: &'tcx ty::Const<'tcx>,
161 Range(PatRange<'tcx>),
163 /// Matches against a slice, checking the length and extracting elements.
164 /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
165 /// e.g., `&[ref xs @ ..]`.
167 prefix: Vec<Pat<'tcx>>,
168 slice: Option<Pat<'tcx>>,
169 suffix: Vec<Pat<'tcx>>,
172 /// Fixed match against an array; irrefutable.
174 prefix: Vec<Pat<'tcx>>,
175 slice: Option<Pat<'tcx>>,
176 suffix: Vec<Pat<'tcx>>,
179 /// An or-pattern, e.g. `p | q`.
180 /// Invariant: `pats.len() >= 2`.
182 pats: Vec<Pat<'tcx>>,
186 #[derive(Copy, Clone, Debug, PartialEq)]
187 pub struct PatRange<'tcx> {
188 pub lo: &'tcx ty::Const<'tcx>,
189 pub hi: &'tcx ty::Const<'tcx>,
193 impl<'tcx> fmt::Display for Pat<'tcx> {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 // Printing lists is a chore.
196 let mut first = true;
197 let mut start_or_continue = |s| {
205 let mut start_or_comma = || start_or_continue(", ");
208 PatKind::Wild => write!(f, "_"),
209 PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
210 PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
211 let is_mut = match mode {
212 BindingMode::ByValue => mutability == Mutability::Mut,
213 BindingMode::ByRef(bk) => {
216 BorrowKind::Mut { .. } => true,
224 write!(f, "{}", name)?;
225 if let Some(ref subpattern) = *subpattern {
226 write!(f, " @ {}", subpattern)?;
230 PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
231 let variant = match *self.kind {
232 PatKind::Variant { adt_def, variant_index, .. } => {
233 Some(&adt_def.variants[variant_index])
236 if let ty::Adt(adt, _) = self.ty.kind {
238 Some(&adt.variants[VariantIdx::new(0)])
248 if let Some(variant) = variant {
249 write!(f, "{}", variant.ident)?;
251 // Only for Adt we can have `S {...}`,
252 // which we handle separately here.
253 if variant.ctor_kind == CtorKind::Fictive {
257 for p in subpatterns {
258 if let PatKind::Wild = *p.pattern.kind {
261 let name = variant.fields[p.field.index()].ident;
262 write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
266 if printed < variant.fields.len() {
267 write!(f, "{}..", start_or_comma())?;
270 return write!(f, " }}");
274 let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
275 if num_fields != 0 || variant.is_none() {
277 for i in 0..num_fields {
278 write!(f, "{}", start_or_comma())?;
280 // Common case: the field is where we expect it.
281 if let Some(p) = subpatterns.get(i) {
282 if p.field.index() == i {
283 write!(f, "{}", p.pattern)?;
288 // Otherwise, we have to go looking for it.
289 if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
290 write!(f, "{}", p.pattern)?;
300 PatKind::Deref { ref subpattern } => {
302 ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
303 ty::Ref(_, _, mutbl) => {
304 write!(f, "&{}", mutbl.prefix_str())?;
306 _ => bug!("{} is a bad Deref pattern type", self.ty),
308 write!(f, "{}", subpattern)
310 PatKind::Constant { value } => write!(f, "{}", value),
311 PatKind::Range(PatRange { lo, hi, end }) => {
312 write!(f, "{}", lo)?;
313 write!(f, "{}", end)?;
316 PatKind::Slice { ref prefix, ref slice, ref suffix }
317 | PatKind::Array { ref prefix, ref slice, ref suffix } => {
320 write!(f, "{}{}", start_or_comma(), p)?;
322 if let Some(ref slice) = *slice {
323 write!(f, "{}", start_or_comma())?;
326 _ => write!(f, "{}", slice)?,
331 write!(f, "{}{}", start_or_comma(), p)?;
335 PatKind::Or { ref pats } => {
337 write!(f, "{}{}", start_or_continue(" | "), pat)?;
345 pub struct PatCtxt<'a, 'tcx> {
346 pub tcx: TyCtxt<'tcx>,
347 pub param_env: ty::ParamEnv<'tcx>,
348 pub tables: &'a ty::TypeckTables<'tcx>,
349 pub substs: SubstsRef<'tcx>,
350 pub errors: Vec<PatternError>,
351 include_lint_checks: bool,
354 impl<'a, 'tcx> Pat<'tcx> {
357 param_env_and_substs: ty::ParamEnvAnd<'tcx, SubstsRef<'tcx>>,
358 tables: &'a ty::TypeckTables<'tcx>,
361 let mut pcx = PatCtxt::new(tcx, param_env_and_substs, tables);
362 let result = pcx.lower_pattern(pat);
363 if !pcx.errors.is_empty() {
364 let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
365 tcx.sess.delay_span_bug(pat.span, &msg);
367 debug!("Pat::from_hir({:?}) = {:?}", pat, result);
372 impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
375 param_env_and_substs: ty::ParamEnvAnd<'tcx, SubstsRef<'tcx>>,
376 tables: &'a ty::TypeckTables<'tcx>,
380 param_env: param_env_and_substs.param_env,
382 substs: param_env_and_substs.value,
384 include_lint_checks: false,
388 pub fn include_lint_checks(&mut self) -> &mut Self {
389 self.include_lint_checks = true;
393 pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pat<'tcx> {
394 // When implicit dereferences have been inserted in this pattern, the unadjusted lowered
395 // pattern has the type that results *after* dereferencing. For example, in this code:
398 // match &&Some(0i32) {
399 // Some(n) => { ... },
404 // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
405 // determined in rustc_typeck::check::match). The adjustments would be
407 // `vec![&&Option<i32>, &Option<i32>]`.
409 // Applying the adjustments, we want to instead output `&&Some(n)` (as a HAIR pattern). So
410 // we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the
411 // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
412 // gets the least-dereferenced type).
413 let unadjusted_pat = self.lower_pattern_unadjusted(pat);
414 self.tables.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
417 debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
421 kind: Box::new(PatKind::Deref { subpattern: pat }),
429 expr: &'tcx hir::Expr,
430 ) -> (PatKind<'tcx>, Option<Ascription<'tcx>>) {
431 match self.lower_lit(expr) {
432 PatKind::AscribeUserType {
433 ascription: lo_ascription,
434 subpattern: Pat { kind: box kind, .. },
435 } => (kind, Some(lo_ascription)),
436 kind => (kind, None),
440 fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pat<'tcx> {
441 let mut ty = self.tables.node_type(pat.hir_id);
443 if let ty::Error = ty.kind {
444 // Avoid ICEs (e.g., #50577 and #50585).
445 return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) };
448 let kind = match pat.kind {
449 hir::PatKind::Wild => PatKind::Wild,
451 hir::PatKind::Lit(ref value) => self.lower_lit(value),
453 hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
454 let (lo, lo_ascription) = self.lower_range_expr(lo_expr);
455 let (hi, hi_ascription) = self.lower_range_expr(hi_expr);
457 let mut kind = match (lo, hi) {
458 (PatKind::Constant { value: lo }, PatKind::Constant { value: hi }) => {
459 assert_eq!(lo.ty, ty);
460 assert_eq!(hi.ty, ty);
461 let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty);
463 (RangeEnd::Excluded, Some(Ordering::Less)) => {
464 PatKind::Range(PatRange { lo, hi, end })
466 (RangeEnd::Excluded, _) => {
471 "lower range bound must be less than upper",
475 (RangeEnd::Included, Some(Ordering::Equal)) => {
476 PatKind::Constant { value: lo }
478 (RangeEnd::Included, Some(Ordering::Less)) => {
479 PatKind::Range(PatRange { lo, hi, end })
481 (RangeEnd::Included, _) => {
482 let mut err = struct_span_err!(
486 "lower range bound must be less than or equal to upper"
488 err.span_label(lo_expr.span, "lower bound larger than upper bound");
489 if self.tcx.sess.teach(&err.get_code().unwrap()) {
491 "When matching against a range, the compiler \
492 verifies that the range is non-empty. Range \
493 patterns include both end-points, so this is \
494 equivalent to requiring the start of the range \
495 to be less than or equal to the end of the range.",
504 self.tcx.sess.delay_span_bug(
507 "found bad range pattern `{:?}` outside of error recovery",
516 // If we are handling a range with associated constants (e.g.
517 // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
518 // constants somewhere. Have them on the range pattern.
519 for ascription in &[lo_ascription, hi_ascription] {
520 if let Some(ascription) = ascription {
521 kind = PatKind::AscribeUserType {
522 ascription: *ascription,
523 subpattern: Pat { span: pat.span, ty, kind: Box::new(kind) },
531 hir::PatKind::Path(ref qpath) => {
532 return self.lower_path(qpath, pat.hir_id, pat.span);
535 hir::PatKind::Ref(ref subpattern, _) | hir::PatKind::Box(ref subpattern) => {
536 PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
539 hir::PatKind::Slice(ref prefix, ref slice, ref suffix) => {
540 self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
543 hir::PatKind::Tuple(ref pats, ddpos) => {
544 let tys = match ty.kind {
545 ty::Tuple(ref tys) => tys,
546 _ => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty),
548 let subpatterns = self.lower_tuple_subpats(pats, tys.len(), ddpos);
549 PatKind::Leaf { subpatterns }
552 hir::PatKind::Binding(_, id, ident, ref sub) => {
554 *self.tables.pat_binding_modes().get(pat.hir_id).expect("missing binding mode");
555 let (mutability, mode) = match bm {
556 ty::BindByValue(mutbl) => (mutbl, BindingMode::ByValue),
557 ty::BindByReference(hir::Mutability::Mut) => (
559 BindingMode::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false }),
561 ty::BindByReference(hir::Mutability::Not) => {
562 (Mutability::Not, BindingMode::ByRef(BorrowKind::Shared))
566 // A ref x pattern is the same node used for x, and as such it has
567 // x's type, which is &T, where we want T (the type being matched).
569 if let ty::BindByReference(_) = bm {
570 if let ty::Ref(_, rty, _) = ty.kind {
573 bug!("`ref {}` has wrong type {}", ident, ty);
583 subpattern: self.lower_opt_pattern(sub),
587 hir::PatKind::TupleStruct(ref qpath, ref pats, ddpos) => {
588 let res = self.tables.qpath_res(qpath, pat.hir_id);
589 let adt_def = match ty.kind {
590 ty::Adt(adt_def, _) => adt_def,
591 _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT {:?}", ty),
593 let variant_def = adt_def.variant_of_res(res);
594 let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos);
595 self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
598 hir::PatKind::Struct(ref qpath, ref fields, _) => {
599 let res = self.tables.qpath_res(qpath, pat.hir_id);
600 let subpatterns = fields
602 .map(|field| FieldPat {
603 field: Field::new(self.tcx.field_index(field.hir_id, self.tables)),
604 pattern: self.lower_pattern(&field.pat),
608 self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
611 hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) },
614 Pat { span: pat.span, ty, kind: Box::new(kind) }
617 fn lower_tuple_subpats(
619 pats: &'tcx [P<hir::Pat>],
621 gap_pos: Option<usize>,
622 ) -> Vec<FieldPat<'tcx>> {
624 .enumerate_and_adjust(expected_len, gap_pos)
625 .map(|(i, subpattern)| FieldPat {
626 field: Field::new(i),
627 pattern: self.lower_pattern(subpattern),
632 fn lower_patterns(&mut self, pats: &'tcx [P<hir::Pat>]) -> Vec<Pat<'tcx>> {
633 pats.iter().map(|p| self.lower_pattern(p)).collect()
636 fn lower_opt_pattern(&mut self, pat: &'tcx Option<P<hir::Pat>>) -> Option<Pat<'tcx>> {
637 pat.as_ref().map(|p| self.lower_pattern(p))
640 fn slice_or_array_pattern(
644 prefix: &'tcx [P<hir::Pat>],
645 slice: &'tcx Option<P<hir::Pat>>,
646 suffix: &'tcx [P<hir::Pat>],
648 let prefix = self.lower_patterns(prefix);
649 let slice = self.lower_opt_pattern(slice);
650 let suffix = self.lower_patterns(suffix);
652 // Matching a slice, `[T]`.
653 ty::Slice(..) => PatKind::Slice { prefix, slice, suffix },
654 // Fixed-length array, `[T; len]`.
655 ty::Array(_, len) => {
656 let len = len.eval_usize(self.tcx, self.param_env);
657 assert!(len >= prefix.len() as u64 + suffix.len() as u64);
658 PatKind::Array { prefix, slice, suffix }
660 _ => span_bug!(span, "bad slice pattern type {:?}", ty),
664 fn lower_variant_or_leaf(
670 subpatterns: Vec<FieldPat<'tcx>>,
672 let res = match res {
673 Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
674 let variant_id = self.tcx.parent(variant_ctor_id).unwrap();
675 Res::Def(DefKind::Variant, variant_id)
680 let mut kind = match res {
681 Res::Def(DefKind::Variant, variant_id) => {
682 let enum_id = self.tcx.parent(variant_id).unwrap();
683 let adt_def = self.tcx.adt_def(enum_id);
684 if adt_def.is_enum() {
685 let substs = match ty.kind {
686 ty::Adt(_, substs) | ty::FnDef(_, substs) => substs,
688 // Avoid ICE (#50585)
689 return PatKind::Wild;
691 _ => bug!("inappropriate type for def: {:?}", ty),
696 variant_index: adt_def.variant_index_with_id(variant_id),
700 PatKind::Leaf { subpatterns }
704 Res::Def(DefKind::Struct, _)
705 | Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
706 | Res::Def(DefKind::Union, _)
707 | Res::Def(DefKind::TyAlias, _)
708 | Res::Def(DefKind::AssocTy, _)
710 | Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
713 self.errors.push(PatternError::NonConstPath(span));
718 if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
719 debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
720 kind = PatKind::AscribeUserType {
721 subpattern: Pat { span, ty, kind: Box::new(kind) },
722 ascription: Ascription {
723 user_ty: PatTyProj::from_user_type(user_ty),
725 variance: ty::Variance::Covariant,
733 /// Takes a HIR Path. If the path is a constant, evaluates it and feeds
734 /// it to `const_to_pat`. Any other path (like enum variants without fields)
735 /// is converted to the corresponding pattern via `lower_variant_or_leaf`.
736 fn lower_path(&mut self, qpath: &hir::QPath, id: hir::HirId, span: Span) -> Pat<'tcx> {
737 let ty = self.tables.node_type(id);
738 let res = self.tables.qpath_res(qpath, id);
739 let is_associated_const = match res {
740 Res::Def(DefKind::AssocConst, _) => true,
743 let kind = match res {
744 Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
745 let substs = self.tables.node_substs(id);
746 match self.tcx.const_eval_resolve(self.param_env, def_id, substs, Some(span)) {
748 let pattern = self.const_to_pat(value, id, span);
749 if !is_associated_const {
753 let user_provided_types = self.tables().user_provided_types();
754 return if let Some(u_ty) = user_provided_types.get(id) {
755 let user_ty = PatTyProj::from_user_type(*u_ty);
758 kind: Box::new(PatKind::AscribeUserType {
760 ascription: Ascription {
761 /// Note that use `Contravariant` here. See the
762 /// `variance` field documentation for details.
763 variance: ty::Variance::Contravariant,
774 Err(ErrorHandled::TooGeneric) => {
775 self.errors.push(if is_associated_const {
776 PatternError::AssocConstInPattern(span)
778 PatternError::StaticInPattern(span)
783 self.tcx.sess.span_err(span, "could not evaluate constant pattern");
788 _ => self.lower_variant_or_leaf(res, id, span, ty, vec![]),
791 Pat { span, ty, kind: Box::new(kind) }
794 /// Converts literals, paths and negation of literals to patterns.
795 /// The special case for negation exists to allow things like `-128_i8`
796 /// which would overflow if we tried to evaluate `128_i8` and then negate
798 fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatKind<'tcx> {
800 hir::ExprKind::Lit(ref lit) => {
801 let ty = self.tables.expr_ty(expr);
802 match lit_to_const(&lit.node, self.tcx, ty, false) {
803 Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span).kind,
804 Err(LitToConstError::UnparseableFloat) => {
805 self.errors.push(PatternError::FloatBug);
808 Err(LitToConstError::Reported) => PatKind::Wild,
811 hir::ExprKind::Path(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind,
812 hir::ExprKind::Unary(hir::UnNeg, ref expr) => {
813 let ty = self.tables.expr_ty(expr);
814 let lit = match expr.kind {
815 hir::ExprKind::Lit(ref lit) => lit,
816 _ => span_bug!(expr.span, "not a literal: {:?}", expr),
818 match lit_to_const(&lit.node, self.tcx, ty, true) {
819 Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span).kind,
820 Err(LitToConstError::UnparseableFloat) => {
821 self.errors.push(PatternError::FloatBug);
824 Err(LitToConstError::Reported) => PatKind::Wild,
827 _ => span_bug!(expr.span, "not a literal: {:?}", expr),
832 impl UserAnnotatedTyHelpers<'tcx> for PatCtxt<'_, 'tcx> {
833 fn tcx(&self) -> TyCtxt<'tcx> {
837 fn tables(&self) -> &ty::TypeckTables<'tcx> {
842 pub trait PatternFoldable<'tcx>: Sized {
843 fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
844 self.super_fold_with(folder)
847 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self;
850 pub trait PatternFolder<'tcx>: Sized {
851 fn fold_pattern(&mut self, pattern: &Pat<'tcx>) -> Pat<'tcx> {
852 pattern.super_fold_with(self)
855 fn fold_pattern_kind(&mut self, kind: &PatKind<'tcx>) -> PatKind<'tcx> {
856 kind.super_fold_with(self)
860 impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<T> {
861 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
862 let content: T = (**self).fold_with(folder);
867 impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec<T> {
868 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
869 self.iter().map(|t| t.fold_with(folder)).collect()
873 impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
874 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
875 self.as_ref().map(|t| t.fold_with(folder))
879 macro_rules! CloneImpls {
880 (<$lt_tcx:tt> $($ty:ty),+) => {
882 impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty {
883 fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self {
892 Span, Field, Mutability, ast::Name, hir::HirId, usize, ty::Const<'tcx>,
893 Region<'tcx>, Ty<'tcx>, BindingMode, &'tcx AdtDef,
894 SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
895 UserTypeProjection, PatTyProj<'tcx>
898 impl<'tcx> PatternFoldable<'tcx> for FieldPat<'tcx> {
899 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
900 FieldPat { field: self.field.fold_with(folder), pattern: self.pattern.fold_with(folder) }
904 impl<'tcx> PatternFoldable<'tcx> for Pat<'tcx> {
905 fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
906 folder.fold_pattern(self)
909 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
911 ty: self.ty.fold_with(folder),
912 span: self.span.fold_with(folder),
913 kind: self.kind.fold_with(folder),
918 impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
919 fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
920 folder.fold_pattern_kind(self)
923 fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
925 PatKind::Wild => PatKind::Wild,
926 PatKind::AscribeUserType {
928 ascription: Ascription { variance, ref user_ty, user_ty_span },
929 } => PatKind::AscribeUserType {
930 subpattern: subpattern.fold_with(folder),
931 ascription: Ascription {
932 user_ty: user_ty.fold_with(folder),
937 PatKind::Binding { mutability, name, mode, var, ty, ref subpattern } => {
939 mutability: mutability.fold_with(folder),
940 name: name.fold_with(folder),
941 mode: mode.fold_with(folder),
942 var: var.fold_with(folder),
943 ty: ty.fold_with(folder),
944 subpattern: subpattern.fold_with(folder),
947 PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
949 adt_def: adt_def.fold_with(folder),
950 substs: substs.fold_with(folder),
952 subpatterns: subpatterns.fold_with(folder),
955 PatKind::Leaf { ref subpatterns } => {
956 PatKind::Leaf { subpatterns: subpatterns.fold_with(folder) }
958 PatKind::Deref { ref subpattern } => {
959 PatKind::Deref { subpattern: subpattern.fold_with(folder) }
961 PatKind::Constant { value } => PatKind::Constant { value },
962 PatKind::Range(range) => PatKind::Range(range),
963 PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice {
964 prefix: prefix.fold_with(folder),
965 slice: slice.fold_with(folder),
966 suffix: suffix.fold_with(folder),
968 PatKind::Array { ref prefix, ref slice, ref suffix } => PatKind::Array {
969 prefix: prefix.fold_with(folder),
970 slice: slice.fold_with(folder),
971 suffix: suffix.fold_with(folder),
973 PatKind::Or { ref pats } => PatKind::Or { pats: pats.fold_with(folder) },
978 pub fn compare_const_vals<'tcx>(
980 a: &'tcx ty::Const<'tcx>,
981 b: &'tcx ty::Const<'tcx>,
982 param_env: ty::ParamEnv<'tcx>,
984 ) -> Option<Ordering> {
985 trace!("compare_const_vals: {:?}, {:?}", a, b);
987 let from_bool = |v: bool| v.then_some(Ordering::Equal);
989 let fallback = || from_bool(a == b);
991 // Use the fallback if any type differs
992 if a.ty != b.ty || a.ty != ty {
996 let a_bits = a.try_eval_bits(tcx, param_env, ty);
997 let b_bits = b.try_eval_bits(tcx, param_env, ty);
999 if let (Some(a), Some(b)) = (a_bits, b_bits) {
1000 use ::rustc_apfloat::Float;
1001 return match ty.kind {
1002 ty::Float(ast::FloatTy::F32) => {
1003 let l = ::rustc_apfloat::ieee::Single::from_bits(a);
1004 let r = ::rustc_apfloat::ieee::Single::from_bits(b);
1007 ty::Float(ast::FloatTy::F64) => {
1008 let l = ::rustc_apfloat::ieee::Double::from_bits(a);
1009 let r = ::rustc_apfloat::ieee::Double::from_bits(b);
1013 use rustc::ty::layout::{Integer, IntegerExt};
1014 use syntax::attr::SignedInt;
1015 let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
1016 let a = sign_extend(a, size);
1017 let b = sign_extend(b, size);
1018 Some((a as i128).cmp(&(b as i128)))
1020 _ => Some(a.cmp(&b)),
1024 if let ty::Str = ty.kind {
1025 match (a.val, b.val) {
1027 ty::ConstKind::Value(a_val @ ConstValue::Slice { .. }),
1028 ty::ConstKind::Value(b_val @ ConstValue::Slice { .. }),
1030 let a_bytes = get_slice_bytes(&tcx, a_val);
1031 let b_bytes = get_slice_bytes(&tcx, b_val);
1032 return from_bool(a_bytes == b_bytes);