Skip to content

Commit 133cd2c

Browse files
committed
Search for generic parameters when finding non-structural_match types
1 parent bbd53de commit 133cd2c

File tree

5 files changed

+42
-26
lines changed

5 files changed

+42
-26
lines changed

src/librustc/ty/mod.rs

+21-11
Original file line numberDiff line numberDiff line change
@@ -3393,9 +3393,15 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
33933393
fn_like.asyncness()
33943394
}
33953395

3396+
pub enum NonStructuralMatchTy<'tcx> {
3397+
Adt(&'tcx AdtDef),
3398+
Param,
3399+
}
3400+
33963401
/// This method traverses the structure of `ty`, trying to find an
33973402
/// instance of an ADT (i.e. struct or enum) that was declared without
3398-
/// the `#[structural_match]` attribute.
3403+
/// the `#[structural_match]` attribute, or a generic type parameter
3404+
/// (which cannot be determined to be `structural_match`).
33993405
///
34003406
/// The "structure of a type" includes all components that would be
34013407
/// considered when doing a pattern match on a constant of that
@@ -3417,22 +3423,22 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
34173423
/// For more background on why Rust has this requirement, and issues
34183424
/// that arose when the requirement was not enforced completely, see
34193425
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
3420-
pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
3421-
ty: Ty<'tcx>)
3422-
-> Option<&'tcx AdtDef>
3423-
{
3426+
pub fn search_for_structural_match_violation<'tcx>(
3427+
tcx: TyCtxt<'tcx>,
3428+
ty: Ty<'tcx>,
3429+
) -> Option<NonStructuralMatchTy<'tcx>> {
34243430
let mut search = Search { tcx, found: None, seen: FxHashSet::default() };
34253431
ty.visit_with(&mut search);
34263432
return search.found;
34273433

34283434
struct Search<'tcx> {
34293435
tcx: TyCtxt<'tcx>,
34303436

3431-
// records the first ADT we find without `#[structural_match`
3432-
found: Option<&'tcx AdtDef>,
3437+
// Records the first ADT or type parameter we find without `#[structural_match`.
3438+
found: Option<NonStructuralMatchTy<'tcx>>,
34333439

3434-
// tracks ADT's previously encountered during search, so that
3435-
// we will not recur on them again.
3440+
// Tracks ADTs previously encountered during search, so that
3441+
// we will not recurse on them again.
34363442
seen: FxHashSet<hir::def_id::DefId>,
34373443
}
34383444

@@ -3442,6 +3448,10 @@ pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
34423448

34433449
let (adt_def, substs) = match ty.kind {
34443450
ty::Adt(adt_def, substs) => (adt_def, substs),
3451+
ty::Param(_) => {
3452+
self.found = Some(NonStructuralMatchTy::Param);
3453+
return true; // Stop visiting.
3454+
}
34453455
ty::RawPtr(..) => {
34463456
// `#[structural_match]` ignores substructure of
34473457
// `*const _`/`*mut _`, so skip super_visit_with
@@ -3468,9 +3478,9 @@ pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
34683478
};
34693479

34703480
if !self.tcx.has_attr(adt_def.did, sym::structural_match) {
3471-
self.found = Some(&adt_def);
3481+
self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
34723482
debug!("Search found adt_def: {:?}", adt_def);
3473-
return true // Halt visiting!
3483+
return true; // Stop visiting.
34743484
}
34753485

34763486
if !self.seen.insert(adt_def.did) {

src/librustc_mir/hair/pattern/mod.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -999,15 +999,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
999999
if self.include_lint_checks && !saw_error {
10001000
// If we were able to successfully convert the const to some pat, double-check
10011001
// that the type of the const obeys `#[structural_match]` constraint.
1002-
if let Some(adt_def) = ty::search_for_adt_without_structural_match(self.tcx, cv.ty) {
1003-
1004-
let path = self.tcx.def_path_str(adt_def.did);
1005-
let msg = format!(
1006-
"to use a constant of type `{}` in a pattern, \
1007-
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
1008-
path,
1009-
path,
1010-
);
1002+
if let Some(non_sm_ty) = ty::search_for_structural_match_violation(self.tcx, cv.ty) {
1003+
let msg = match non_sm_ty {
1004+
ty::NonStructuralMatchTy::Adt(adt_def) => {
1005+
let path = self.tcx.def_path_str(adt_def.did);
1006+
format!(
1007+
"to use a constant of type `{}` in a pattern, \
1008+
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
1009+
path,
1010+
path,
1011+
)
1012+
}
1013+
ty::NonStructuralMatchTy::Param => {
1014+
bug!("use of constant whose type is a parameter inside a pattern");
1015+
}
1016+
};
10111017

10121018
// before issuing lint, double-check there even *is* a
10131019
// semantic PartialEq for us to dispatch to.

src/librustc_typeck/collect.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1532,11 +1532,11 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
15321532
);
15331533
};
15341534
}
1535-
if ty::search_for_adt_without_structural_match(tcx, ty).is_some() {
1535+
if ty::search_for_structural_match_violation(tcx, ty).is_some() {
15361536
struct_span_err!(
15371537
tcx.sess,
15381538
hir_ty.span,
1539-
E0739,
1539+
E0740,
15401540
"the types of const generic parameters must derive `PartialEq` and `Eq`",
15411541
).span_label(
15421542
hir_ty.span,

src/librustc_typeck/error_codes.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4978,11 +4978,11 @@ the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
49784978
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
49794979
"##,
49804980

4981-
E0739: r##"
4981+
E0740: r##"
49824982
Only `structural_match` types (that is, types that derive `PartialEq` and `Eq`)
49834983
may be used as the types of const generic parameters.
49844984
4985-
```compile_fail,E0739
4985+
```compile_fail,E0740
49864986
#![feature(const_generics)]
49874987
49884988
struct A;

src/test/ui/const-generics/forbid-non-structural_match-types.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ LL | #![feature(const_generics)]
66
|
77
= note: `#[warn(incomplete_features)]` on by default
88

9-
error[E0739]: the types of const generic parameters must derive `PartialEq` and `Eq`
9+
error[E0740]: the types of const generic parameters must derive `PartialEq` and `Eq`
1010
--> $DIR/forbid-non-structural_match-types.rs:11:19
1111
|
1212
LL | struct D<const X: C>;
1313
| ^ `C` doesn't derive both `PartialEq` and `Eq`
1414

1515
error: aborting due to previous error
1616

17-
For more information about this error, try `rustc --explain E0739`.
17+
For more information about this error, try `rustc --explain E0740`.

0 commit comments

Comments
 (0)