about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2019-10-20 18:17:42 +0100
committervarkor <github@varkor.com>2019-10-22 12:26:32 +0100
commit133cd2cfaf244c130e2e0d681090ca117bcba94e (patch)
tree08ba9c66c833011a5451fe5338834c7b7e087cff
parentbbd53deaeb79e78162524e18ca29211745e2d18e (diff)
downloadrust-133cd2cfaf244c130e2e0d681090ca117bcba94e.tar.gz
rust-133cd2cfaf244c130e2e0d681090ca117bcba94e.zip
Search for generic parameters when finding non-`structural_match` types
-rw-r--r--src/librustc/ty/mod.rs32
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs24
-rw-r--r--src/librustc_typeck/collect.rs4
-rw-r--r--src/librustc_typeck/error_codes.rs4
-rw-r--r--src/test/ui/const-generics/forbid-non-structural_match-types.stderr4
5 files changed, 42 insertions, 26 deletions
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 77d8141c968..6c512a0238e 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -3393,9 +3393,15 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
     fn_like.asyncness()
 }
 
+pub enum NonStructuralMatchTy<'tcx> {
+    Adt(&'tcx AdtDef),
+    Param,
+}
+
 /// This method traverses the structure of `ty`, trying to find an
 /// instance of an ADT (i.e. struct or enum) that was declared without
-/// the `#[structural_match]` attribute.
+/// the `#[structural_match]` attribute, or a generic type parameter
+/// (which cannot be determined to be `structural_match`).
 ///
 /// The "structure of a type" includes all components that would be
 /// considered when doing a pattern match on a constant of that
@@ -3417,10 +3423,10 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
 /// For more background on why Rust has this requirement, and issues
 /// that arose when the requirement was not enforced completely, see
 /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
-pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
-                                                 ty: Ty<'tcx>)
-                                                 -> Option<&'tcx AdtDef>
-{
+pub fn search_for_structural_match_violation<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Option<NonStructuralMatchTy<'tcx>> {
     let mut search = Search { tcx, found: None, seen: FxHashSet::default() };
     ty.visit_with(&mut search);
     return search.found;
@@ -3428,11 +3434,11 @@ pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
     struct Search<'tcx> {
         tcx: TyCtxt<'tcx>,
 
-        // records the first ADT we find without `#[structural_match`
-        found: Option<&'tcx AdtDef>,
+        // Records the first ADT or type parameter we find without `#[structural_match`.
+        found: Option<NonStructuralMatchTy<'tcx>>,
 
-        // tracks ADT's previously encountered during search, so that
-        // we will not recur on them again.
+        // Tracks ADTs previously encountered during search, so that
+        // we will not recurse on them again.
         seen: FxHashSet<hir::def_id::DefId>,
     }
 
@@ -3442,6 +3448,10 @@ pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
 
             let (adt_def, substs) = match ty.kind {
                 ty::Adt(adt_def, substs) => (adt_def, substs),
+                ty::Param(_) => {
+                    self.found = Some(NonStructuralMatchTy::Param);
+                    return true; // Stop visiting.
+                }
                 ty::RawPtr(..) => {
                     // `#[structural_match]` ignores substructure of
                     // `*const _`/`*mut _`, so skip super_visit_with
@@ -3468,9 +3478,9 @@ pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
             };
 
             if !self.tcx.has_attr(adt_def.did, sym::structural_match) {
-                self.found = Some(&adt_def);
+                self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
                 debug!("Search found adt_def: {:?}", adt_def);
-                return true // Halt visiting!
+                return true; // Stop visiting.
             }
 
             if !self.seen.insert(adt_def.did) {
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index d9968812218..98e286e61e9 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -999,15 +999,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         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(adt_def) = ty::search_for_adt_without_structural_match(self.tcx, cv.ty) {
-
-                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,
-                );
+            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.
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index d6162c0bc0e..08fb5ae1676 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1532,11 +1532,11 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
                         );
                     };
                 }
-                if ty::search_for_adt_without_structural_match(tcx, ty).is_some() {
+                if ty::search_for_structural_match_violation(tcx, ty).is_some() {
                     struct_span_err!(
                         tcx.sess,
                         hir_ty.span,
-                        E0739,
+                        E0740,
                         "the types of const generic parameters must derive `PartialEq` and `Eq`",
                     ).span_label(
                         hir_ty.span,
diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs
index 5d1afcaef91..2cf6951c375 100644
--- a/src/librustc_typeck/error_codes.rs
+++ b/src/librustc_typeck/error_codes.rs
@@ -4978,11 +4978,11 @@ the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
 [RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
 "##,
 
-E0739: r##"
+E0740: r##"
 Only `structural_match` types (that is, types that derive `PartialEq` and `Eq`)
 may be used as the types of const generic parameters.
 
-```compile_fail,E0739
+```compile_fail,E0740
 #![feature(const_generics)]
 
 struct A;
diff --git a/src/test/ui/const-generics/forbid-non-structural_match-types.stderr b/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
index 9ab6c69521b..c870d9b1db4 100644
--- a/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
+++ b/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
@@ -6,7 +6,7 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0739]: the types of const generic parameters must derive `PartialEq` and `Eq`
+error[E0740]: the types of const generic parameters must derive `PartialEq` and `Eq`
   --> $DIR/forbid-non-structural_match-types.rs:11:19
    |
 LL | struct D<const X: C>;
@@ -14,4 +14,4 @@ LL | struct D<const X: C>;
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0739`.
+For more information about this error, try `rustc --explain E0740`.