diff options
| author | varkor <github@varkor.com> | 2019-10-20 18:17:42 +0100 |
|---|---|---|
| committer | varkor <github@varkor.com> | 2019-10-22 12:26:32 +0100 |
| commit | 133cd2cfaf244c130e2e0d681090ca117bcba94e (patch) | |
| tree | 08ba9c66c833011a5451fe5338834c7b7e087cff | |
| parent | bbd53deaeb79e78162524e18ca29211745e2d18e (diff) | |
| download | rust-133cd2cfaf244c130e2e0d681090ca117bcba94e.tar.gz rust-133cd2cfaf244c130e2e0d681090ca117bcba94e.zip | |
Search for generic parameters when finding non-`structural_match` types
| -rw-r--r-- | src/librustc/ty/mod.rs | 32 | ||||
| -rw-r--r-- | src/librustc_mir/hair/pattern/mod.rs | 24 | ||||
| -rw-r--r-- | src/librustc_typeck/collect.rs | 4 | ||||
| -rw-r--r-- | src/librustc_typeck/error_codes.rs | 4 | ||||
| -rw-r--r-- | src/test/ui/const-generics/forbid-non-structural_match-types.stderr | 4 |
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`. |
