1
Fork 0

give correct error message on structural match violation

This commit is contained in:
b-naber 2022-05-24 13:00:46 +02:00
parent c186f7c079
commit e2e425e8d2
4 changed files with 48 additions and 28 deletions

View file

@ -121,27 +121,27 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> { fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| { traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| {
with_no_trimmed_paths!(match non_sm_ty { with_no_trimmed_paths!(match non_sm_ty.kind {
traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt), traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt),
traits::NonStructuralMatchTy::Dynamic => { traits::NonStructuralMatchTyKind::Dynamic => {
"trait objects cannot be used in patterns".to_string() "trait objects cannot be used in patterns".to_string()
} }
traits::NonStructuralMatchTy::Opaque => { traits::NonStructuralMatchTyKind::Opaque => {
"opaque types cannot be used in patterns".to_string() "opaque types cannot be used in patterns".to_string()
} }
traits::NonStructuralMatchTy::Closure => { traits::NonStructuralMatchTyKind::Closure => {
"closures cannot be used in patterns".to_string() "closures cannot be used in patterns".to_string()
} }
traits::NonStructuralMatchTy::Generator => { traits::NonStructuralMatchTyKind::Generator => {
"generators cannot be used in patterns".to_string() "generators cannot be used in patterns".to_string()
} }
traits::NonStructuralMatchTy::Param => { traits::NonStructuralMatchTyKind::Param => {
bug!("use of a constant whose type is a parameter inside a pattern") bug!("use of a constant whose type is a parameter inside a pattern")
} }
traits::NonStructuralMatchTy::Projection => { traits::NonStructuralMatchTyKind::Projection => {
bug!("use of a constant whose type is a projection inside a pattern") bug!("use of a constant whose type is a projection inside a pattern")
} }
traits::NonStructuralMatchTy::Foreign => { traits::NonStructuralMatchTyKind::Foreign => {
bug!("use of a value of a foreign type inside a pattern") bug!("use of a value of a foreign type inside a pattern")
} }
}) })

View file

@ -62,7 +62,7 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapError;
pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_match::search_for_structural_match_violation;
pub use self::structural_match::NonStructuralMatchTy; pub use self::structural_match::{NonStructuralMatchTy, NonStructuralMatchTyKind};
pub use self::util::{ pub use self::util::{
elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span, elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span,
elaborate_trait_ref, elaborate_trait_refs, elaborate_trait_ref, elaborate_trait_refs,

View file

@ -11,7 +11,13 @@ use rustc_span::Span;
use std::ops::ControlFlow; use std::ops::ControlFlow;
#[derive(Debug)] #[derive(Debug)]
pub enum NonStructuralMatchTy<'tcx> { pub struct NonStructuralMatchTy<'tcx> {
pub ty: Ty<'tcx>,
pub kind: NonStructuralMatchTyKind<'tcx>,
}
#[derive(Debug)]
pub enum NonStructuralMatchTyKind<'tcx> {
Adt(AdtDef<'tcx>), Adt(AdtDef<'tcx>),
Param, Param,
Dynamic, Dynamic,
@ -137,25 +143,32 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
let (adt_def, substs) = match *ty.kind() { let (adt_def, substs) = match *ty.kind() {
ty::Adt(adt_def, substs) => (adt_def, substs), ty::Adt(adt_def, substs) => (adt_def, substs),
ty::Param(_) => { ty::Param(_) => {
return ControlFlow::Break(NonStructuralMatchTy::Param); let kind = NonStructuralMatchTyKind::Param;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
} }
ty::Dynamic(..) => { ty::Dynamic(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Dynamic); let kind = NonStructuralMatchTyKind::Dynamic;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
} }
ty::Foreign(_) => { ty::Foreign(_) => {
return ControlFlow::Break(NonStructuralMatchTy::Foreign); let kind = NonStructuralMatchTyKind::Foreign;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
} }
ty::Opaque(..) => { ty::Opaque(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Opaque); let kind = NonStructuralMatchTyKind::Opaque;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
} }
ty::Projection(..) => { ty::Projection(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Projection); let kind = NonStructuralMatchTyKind::Projection;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
} }
ty::Closure(..) => { ty::Closure(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Closure); let kind = NonStructuralMatchTyKind::Closure;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
} }
ty::Generator(..) | ty::GeneratorWitness(..) => { ty::Generator(..) | ty::GeneratorWitness(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Generator); let kind = NonStructuralMatchTyKind::Generator;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
} }
ty::RawPtr(..) => { ty::RawPtr(..) => {
// structural-match ignores substructure of // structural-match ignores substructure of
@ -215,7 +228,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
if !self.type_marked_structural(ty) { if !self.type_marked_structural(ty) {
debug!("Search found ty: {:?}", ty); debug!("Search found ty: {:?}", ty);
return ControlFlow::Break(NonStructuralMatchTy::Adt(adt_def)); let kind = NonStructuralMatchTyKind::Adt(adt_def);
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
} }
// structural-match does not care about the // structural-match does not care about the

View file

@ -827,7 +827,9 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
); );
} }
if traits::search_for_structural_match_violation(param.span, tcx, ty).is_some() { if let Some(non_structural_match_ty) =
traits::search_for_structural_match_violation(param.span, tcx, ty)
{
// We use the same error code in both branches, because this is really the same // We use the same error code in both branches, because this is really the same
// issue: we just special-case the message for type parameters to make it // issue: we just special-case the message for type parameters to make it
// clearer. // clearer.
@ -853,19 +855,23 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
) )
.emit(); .emit();
} else { } else {
struct_span_err!( let mut diag = struct_span_err!(
tcx.sess, tcx.sess,
hir_ty.span, hir_ty.span,
E0741, E0741,
"`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \ "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
the type of a const parameter", the type of a const parameter",
ty, non_structural_match_ty.ty,
) );
.span_label(
hir_ty.span, if ty == non_structural_match_ty.ty {
format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"), diag.span_label(
) hir_ty.span,
.emit(); format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
);
}
diag.emit();
} }
} }
} else { } else {