Search for generic parameters when finding non-structural_match types
This commit is contained in:
parent
bbd53deaeb
commit
133cd2cfaf
5 changed files with 42 additions and 26 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue