about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFelix S. Klock II <pnkfelix@pnkfx.org>2019-10-25 11:39:12 +0200
committerFelix S. Klock II <pnkfelix@pnkfx.org>2019-10-25 11:39:12 +0200
commit620083ad16d02686c3af2fb78ea65dc5b2d4584c (patch)
tree277e8dca840abd0090fe8ca13a8f348baf9ef002
parent4f7b922afe7cca0ecdd4dd1124935d89122cb904 (diff)
downloadrust-620083ad16d02686c3af2fb78ea65dc5b2d4584c.tar.gz
rust-620083ad16d02686c3af2fb78ea65dc5b2d4584c.zip
refactoring: move const_to_pat code into its own submodule.
-rw-r--r--src/librustc_mir/hair/pattern/const_to_pat.rs216
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs206
2 files changed, 217 insertions, 205 deletions
diff --git a/src/librustc_mir/hair/pattern/const_to_pat.rs b/src/librustc_mir/hair/pattern/const_to_pat.rs
new file mode 100644
index 00000000000..c92bbce98d0
--- /dev/null
+++ b/src/librustc_mir/hair/pattern/const_to_pat.rs
@@ -0,0 +1,216 @@
+use crate::const_eval::const_variant_index;
+
+use rustc::hir;
+use rustc::lint;
+use rustc::mir::Field;
+use rustc::traits::{ObligationCause, PredicateObligation};
+use rustc::ty;
+
+use rustc_index::vec::Idx;
+
+use syntax::symbol::sym;
+use syntax_pos::Span;
+
+use super::{FieldPat, Pat, PatCtxt, PatKind};
+
+impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
+    /// Converts an evaluated constant to a pattern (if possible).
+    /// This means aggregate values (like structs and enums) are converted
+    /// to a pattern that matches the value (as if you'd compared via structural equality).
+    pub(super) fn const_to_pat(
+        &self,
+        instance: ty::Instance<'tcx>,
+        cv: &'tcx ty::Const<'tcx>,
+        id: hir::HirId,
+        span: Span,
+    ) -> Pat<'tcx> {
+        // This method is just a warpper handling a validity check; the heavy lifting is
+        // performed by the recursive const_to_pat_inner method, which is not meant to be
+        // invoked except by this method.
+        //
+        // once indirect_structural_match is a full fledged error, this
+        // level of indirection can be eliminated
+
+        debug!("const_to_pat: cv={:#?} id={:?}", cv, id);
+        debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span);
+
+        let mut saw_error = false;
+        let inlined_const_as_pat = self.const_to_pat_inner(instance, cv, id, span, &mut saw_error);
+
+        if self.include_lint_checks && !saw_error {
+            // If we were able to successfully convert the const to some pat, double-check
+            // that the type of the const obeys `#[structural_match]` constraint.
+            if let Some(non_sm_ty) = ty::search_for_structural_match_violation(self.tcx, cv.ty) {
+                let msg = match non_sm_ty {
+                    ty::NonStructuralMatchTy::Adt(adt_def) => {
+                        let path = self.tcx.def_path_str(adt_def.did);
+                        format!(
+                            "to use a constant of type `{}` in a pattern, \
+                             `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
+                            path,
+                            path,
+                        )
+                    }
+                    ty::NonStructuralMatchTy::Param => {
+                        bug!("use of constant whose type is a parameter inside a pattern");
+                    }
+                };
+
+                // before issuing lint, double-check there even *is* a
+                // semantic PartialEq for us to dispatch to.
+                //
+                // (If there isn't, then we can safely issue a hard
+                // error, because that's never worked, due to compiler
+                // using PartialEq::eq in this scenario in the past.)
+
+                let ty_is_partial_eq: bool = {
+                    let partial_eq_trait_id = self.tcx.lang_items().eq_trait().unwrap();
+                    let obligation: PredicateObligation<'_> =
+                        self.tcx.predicate_for_trait_def(self.param_env,
+                                                         ObligationCause::misc(span, id),
+                                                         partial_eq_trait_id,
+                                                         0,
+                                                         cv.ty,
+                                                         &[]);
+                    self.tcx
+                        .infer_ctxt()
+                        .enter(|infcx| infcx.predicate_may_hold(&obligation))
+                };
+
+                if !ty_is_partial_eq {
+                    // span_fatal avoids ICE from resolution of non-existent method (rare case).
+                    self.tcx.sess.span_fatal(span, &msg);
+                } else {
+                    self.tcx.lint_hir(lint::builtin::INDIRECT_STRUCTURAL_MATCH, id, span, &msg);
+                }
+            }
+        }
+
+        inlined_const_as_pat
+    }
+
+    /// Recursive helper for `const_to_pat`; invoke that (instead of calling this directly).
+    fn const_to_pat_inner(
+        &self,
+        instance: ty::Instance<'tcx>,
+        cv: &'tcx ty::Const<'tcx>,
+        id: hir::HirId,
+        span: Span,
+        // This tracks if we signal some hard error for a given const
+        // value, so that we will not subsequently issue an irrelevant
+        // lint for the same const value.
+        saw_const_match_error: &mut bool,
+    ) -> Pat<'tcx> {
+
+        let mut adt_subpattern = |i, variant_opt| {
+            let field = Field::new(i);
+            let val = crate::const_eval::const_field(
+                self.tcx, self.param_env, variant_opt, field, cv
+            );
+            self.const_to_pat_inner(instance, val, id, span, saw_const_match_error)
+        };
+        let mut adt_subpatterns = |n, variant_opt| {
+            (0..n).map(|i| {
+                let field = Field::new(i);
+                FieldPat {
+                    field,
+                    pattern: adt_subpattern(i, variant_opt),
+                }
+            }).collect::<Vec<_>>()
+        };
+
+
+        let kind = match cv.ty.kind {
+            ty::Float(_) => {
+                self.tcx.lint_hir(
+                    ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+                    id,
+                    span,
+                    "floating-point types cannot be used in patterns",
+                );
+                PatKind::Constant {
+                    value: cv,
+                }
+            }
+            ty::Adt(adt_def, _) if adt_def.is_union() => {
+                // Matching on union fields is unsafe, we can't hide it in constants
+                *saw_const_match_error = true;
+                self.tcx.sess.span_err(span, "cannot use unions in constant patterns");
+                PatKind::Wild
+            }
+            // keep old code until future-compat upgraded to errors.
+            ty::Adt(adt_def, _) if !self.tcx.has_attr(adt_def.did, sym::structural_match) => {
+                let path = self.tcx.def_path_str(adt_def.did);
+                let msg = format!(
+                    "to use a constant of type `{}` in a pattern, \
+                     `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
+                    path,
+                    path,
+                );
+                *saw_const_match_error = true;
+                self.tcx.sess.span_err(span, &msg);
+                PatKind::Wild
+            }
+            // keep old code until future-compat upgraded to errors.
+            ty::Ref(_, ty::TyS { kind: ty::Adt(adt_def, _), .. }, _)
+            if !self.tcx.has_attr(adt_def.did, sym::structural_match) => {
+                // HACK(estebank): Side-step ICE #53708, but anything other than erroring here
+                // would be wrong. Returnging `PatKind::Wild` is not technically correct.
+                let path = self.tcx.def_path_str(adt_def.did);
+                let msg = format!(
+                    "to use a constant of type `{}` in a pattern, \
+                     `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
+                    path,
+                    path,
+                );
+                *saw_const_match_error = true;
+                self.tcx.sess.span_err(span, &msg);
+                PatKind::Wild
+            }
+            ty::Adt(adt_def, substs) if adt_def.is_enum() => {
+                let variant_index = const_variant_index(self.tcx, self.param_env, cv);
+                let subpatterns = adt_subpatterns(
+                    adt_def.variants[variant_index].fields.len(),
+                    Some(variant_index),
+                );
+                PatKind::Variant {
+                    adt_def,
+                    substs,
+                    variant_index,
+                    subpatterns,
+                }
+            }
+            ty::Adt(adt_def, _) => {
+                let struct_var = adt_def.non_enum_variant();
+                PatKind::Leaf {
+                    subpatterns: adt_subpatterns(struct_var.fields.len(), None),
+                }
+            }
+            ty::Tuple(fields) => {
+                PatKind::Leaf {
+                    subpatterns: adt_subpatterns(fields.len(), None),
+                }
+            }
+            ty::Array(_, n) => {
+                PatKind::Array {
+                    prefix: (0..n.eval_usize(self.tcx, self.param_env))
+                        .map(|i| adt_subpattern(i as usize, None))
+                        .collect(),
+                    slice: None,
+                    suffix: Vec::new(),
+                }
+            }
+            _ => {
+                PatKind::Constant {
+                    value: cv,
+                }
+            }
+        };
+
+        Pat {
+            span,
+            ty: cv.ty,
+            kind: Box::new(kind),
+        }
+    }
+}
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 98e286e61e9..331770003b6 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -2,19 +2,16 @@
 
 mod _match;
 mod check_match;
+mod const_to_pat;
 
 pub(crate) use self::check_match::check_match;
 
-use crate::const_eval::const_variant_index;
-
 use crate::hair::util::UserAnnotatedTyHelpers;
 use crate::hair::constant::*;
 
-use rustc::lint;
 use rustc::mir::{Field, BorrowKind, Mutability};
 use rustc::mir::{UserTypeProjection};
 use rustc::mir::interpret::{GlobalId, ConstValue, get_slice_bytes, sign_extend};
-use rustc::traits::{ObligationCause, PredicateObligation};
 use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree};
 use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations};
 use rustc::ty::subst::{SubstsRef, GenericArg};
@@ -29,7 +26,6 @@ use rustc_index::vec::Idx;
 use std::cmp::Ordering;
 use std::fmt;
 use syntax::ast;
-use syntax::symbol::sym;
 use syntax_pos::Span;
 
 #[derive(Clone, Debug)]
@@ -972,206 +968,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             _ => span_bug!(expr.span, "not a literal: {:?}", expr),
         }
     }
-
-    /// Converts an evaluated constant to a pattern (if possible).
-    /// This means aggregate values (like structs and enums) are converted
-    /// to a pattern that matches the value (as if you'd compared via structural equality).
-    fn const_to_pat(
-        &self,
-        instance: ty::Instance<'tcx>,
-        cv: &'tcx ty::Const<'tcx>,
-        id: hir::HirId,
-        span: Span,
-    ) -> Pat<'tcx> {
-        // This method is just a warpper handling a validity check; the heavy lifting is
-        // performed by the recursive const_to_pat_inner method, which is not meant to be
-        // invoked except by this method.
-        //
-        // once indirect_structural_match is a full fledged error, this
-        // level of indirection can be eliminated
-
-        debug!("const_to_pat: cv={:#?} id={:?}", cv, id);
-        debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span);
-
-        let mut saw_error = false;
-        let inlined_const_as_pat = self.const_to_pat_inner(instance, cv, id, span, &mut saw_error);
-
-        if self.include_lint_checks && !saw_error {
-            // If we were able to successfully convert the const to some pat, double-check
-            // that the type of the const obeys `#[structural_match]` constraint.
-            if let Some(non_sm_ty) = ty::search_for_structural_match_violation(self.tcx, cv.ty) {
-                let msg = match non_sm_ty {
-                    ty::NonStructuralMatchTy::Adt(adt_def) => {
-                        let path = self.tcx.def_path_str(adt_def.did);
-                        format!(
-                            "to use a constant of type `{}` in a pattern, \
-                             `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                            path,
-                            path,
-                        )
-                    }
-                    ty::NonStructuralMatchTy::Param => {
-                        bug!("use of constant whose type is a parameter inside a pattern");
-                    }
-                };
-
-                // before issuing lint, double-check there even *is* a
-                // semantic PartialEq for us to dispatch to.
-                //
-                // (If there isn't, then we can safely issue a hard
-                // error, because that's never worked, due to compiler
-                // using PartialEq::eq in this scenario in the past.)
-
-                let ty_is_partial_eq: bool = {
-                    let partial_eq_trait_id = self.tcx.lang_items().eq_trait().unwrap();
-                    let obligation: PredicateObligation<'_> =
-                        self.tcx.predicate_for_trait_def(self.param_env,
-                                                         ObligationCause::misc(span, id),
-                                                         partial_eq_trait_id,
-                                                         0,
-                                                         cv.ty,
-                                                         &[]);
-                    self.tcx
-                        .infer_ctxt()
-                        .enter(|infcx| infcx.predicate_may_hold(&obligation))
-                };
-
-                if !ty_is_partial_eq {
-                    // span_fatal avoids ICE from resolution of non-existent method (rare case).
-                    self.tcx.sess.span_fatal(span, &msg);
-                } else {
-                    self.tcx.lint_hir(lint::builtin::INDIRECT_STRUCTURAL_MATCH, id, span, &msg);
-                }
-            }
-        }
-
-        inlined_const_as_pat
-    }
-
-    /// Recursive helper for `const_to_pat`; invoke that (instead of calling this directly).
-    fn const_to_pat_inner(
-        &self,
-        instance: ty::Instance<'tcx>,
-        cv: &'tcx ty::Const<'tcx>,
-        id: hir::HirId,
-        span: Span,
-        // This tracks if we signal some hard error for a given const
-        // value, so that we will not subsequently issue an irrelevant
-        // lint for the same const value.
-        saw_const_match_error: &mut bool,
-    ) -> Pat<'tcx> {
-
-        let mut adt_subpattern = |i, variant_opt| {
-            let field = Field::new(i);
-            let val = crate::const_eval::const_field(
-                self.tcx, self.param_env, variant_opt, field, cv
-            );
-            self.const_to_pat_inner(instance, val, id, span, saw_const_match_error)
-        };
-        let mut adt_subpatterns = |n, variant_opt| {
-            (0..n).map(|i| {
-                let field = Field::new(i);
-                FieldPat {
-                    field,
-                    pattern: adt_subpattern(i, variant_opt),
-                }
-            }).collect::<Vec<_>>()
-        };
-
-
-        let kind = match cv.ty.kind {
-            ty::Float(_) => {
-                self.tcx.lint_hir(
-                    ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
-                    id,
-                    span,
-                    "floating-point types cannot be used in patterns",
-                );
-                PatKind::Constant {
-                    value: cv,
-                }
-            }
-            ty::Adt(adt_def, _) if adt_def.is_union() => {
-                // Matching on union fields is unsafe, we can't hide it in constants
-                *saw_const_match_error = true;
-                self.tcx.sess.span_err(span, "cannot use unions in constant patterns");
-                PatKind::Wild
-            }
-            // keep old code until future-compat upgraded to errors.
-            ty::Adt(adt_def, _) if !self.tcx.has_attr(adt_def.did, sym::structural_match) => {
-                let path = self.tcx.def_path_str(adt_def.did);
-                let msg = format!(
-                    "to use a constant of type `{}` in a pattern, \
-                     `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                    path,
-                    path,
-                );
-                *saw_const_match_error = true;
-                self.tcx.sess.span_err(span, &msg);
-                PatKind::Wild
-            }
-            // keep old code until future-compat upgraded to errors.
-            ty::Ref(_, ty::TyS { kind: ty::Adt(adt_def, _), .. }, _)
-            if !self.tcx.has_attr(adt_def.did, sym::structural_match) => {
-                // HACK(estebank): Side-step ICE #53708, but anything other than erroring here
-                // would be wrong. Returnging `PatKind::Wild` is not technically correct.
-                let path = self.tcx.def_path_str(adt_def.did);
-                let msg = format!(
-                    "to use a constant of type `{}` in a pattern, \
-                     `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                    path,
-                    path,
-                );
-                *saw_const_match_error = true;
-                self.tcx.sess.span_err(span, &msg);
-                PatKind::Wild
-            }
-            ty::Adt(adt_def, substs) if adt_def.is_enum() => {
-                let variant_index = const_variant_index(self.tcx, self.param_env, cv);
-                let subpatterns = adt_subpatterns(
-                    adt_def.variants[variant_index].fields.len(),
-                    Some(variant_index),
-                );
-                PatKind::Variant {
-                    adt_def,
-                    substs,
-                    variant_index,
-                    subpatterns,
-                }
-            }
-            ty::Adt(adt_def, _) => {
-                let struct_var = adt_def.non_enum_variant();
-                PatKind::Leaf {
-                    subpatterns: adt_subpatterns(struct_var.fields.len(), None),
-                }
-            }
-            ty::Tuple(fields) => {
-                PatKind::Leaf {
-                    subpatterns: adt_subpatterns(fields.len(), None),
-                }
-            }
-            ty::Array(_, n) => {
-                PatKind::Array {
-                    prefix: (0..n.eval_usize(self.tcx, self.param_env))
-                        .map(|i| adt_subpattern(i as usize, None))
-                        .collect(),
-                    slice: None,
-                    suffix: Vec::new(),
-                }
-            }
-            _ => {
-                PatKind::Constant {
-                    value: cv,
-                }
-            }
-        };
-
-        Pat {
-            span,
-            ty: cv.ty,
-            kind: Box::new(kind),
-        }
-    }
 }
 
 impl UserAnnotatedTyHelpers<'tcx> for PatCtxt<'_, 'tcx> {