Skip to content

Commit

Permalink
Rollup merge of #97351 - b-naber:adt-const-params-structural-match-vi…
Browse files Browse the repository at this point in the history
…olation, r=michaelwoerister

Output correct type responsible for structural match violation

Previously we included the outermost type that caused a structural match violation in the error message and stated that that type must be annotated with `#[derive(Eq, PartialEq)]` even if it already had that annotation. This PR outputs the correct type in the error message.

Fixes #97278
  • Loading branch information
Dylan-DPC committed May 25, 2022
2 parents 0067078 + 86e8bbe commit 8a3ad49
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 30 deletions.
18 changes: 9 additions & 9 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Expand Up @@ -121,27 +121,27 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {

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| {
with_no_trimmed_paths!(match non_sm_ty {
traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt),
traits::NonStructuralMatchTy::Dynamic => {
with_no_trimmed_paths!(match non_sm_ty.kind {
traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt),
traits::NonStructuralMatchTyKind::Dynamic => {
"trait objects cannot be used in patterns".to_string()
}
traits::NonStructuralMatchTy::Opaque => {
traits::NonStructuralMatchTyKind::Opaque => {
"opaque types cannot be used in patterns".to_string()
}
traits::NonStructuralMatchTy::Closure => {
traits::NonStructuralMatchTyKind::Closure => {
"closures cannot be used in patterns".to_string()
}
traits::NonStructuralMatchTy::Generator => {
traits::NonStructuralMatchTyKind::Generator => {
"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")
}
traits::NonStructuralMatchTy::Projection => {
traits::NonStructuralMatchTyKind::Projection => {
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")
}
})
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/mod.rs
Expand Up @@ -62,7 +62,7 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapError;
pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
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::{
elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span,
elaborate_trait_ref, elaborate_trait_refs,
Expand Down
32 changes: 23 additions & 9 deletions compiler/rustc_trait_selection/src/traits/structural_match.rs
Expand Up @@ -11,7 +11,13 @@ use rustc_span::Span;
use std::ops::ControlFlow;

#[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>),
Param,
Dynamic,
Expand Down Expand Up @@ -137,25 +143,32 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
let (adt_def, substs) = match *ty.kind() {
ty::Adt(adt_def, substs) => (adt_def, substs),
ty::Param(_) => {
return ControlFlow::Break(NonStructuralMatchTy::Param);
let kind = NonStructuralMatchTyKind::Param;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
}
ty::Dynamic(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Dynamic);
let kind = NonStructuralMatchTyKind::Dynamic;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
}
ty::Foreign(_) => {
return ControlFlow::Break(NonStructuralMatchTy::Foreign);
let kind = NonStructuralMatchTyKind::Foreign;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
}
ty::Opaque(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Opaque);
let kind = NonStructuralMatchTyKind::Opaque;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
}
ty::Projection(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Projection);
let kind = NonStructuralMatchTyKind::Projection;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
}
ty::Closure(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Closure);
let kind = NonStructuralMatchTyKind::Closure;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
}
ty::Generator(..) | ty::GeneratorWitness(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Generator);
let kind = NonStructuralMatchTyKind::Generator;
return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
}
ty::RawPtr(..) => {
// structural-match ignores substructure of
Expand Down Expand Up @@ -215,7 +228,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {

if !self.type_marked_structural(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
Expand Down
24 changes: 15 additions & 9 deletions compiler/rustc_typeck/src/check/wfcheck.rs
Expand Up @@ -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
// issue: we just special-case the message for type parameters to make it
// clearer.
Expand All @@ -853,19 +855,23 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
)
.emit();
} else {
struct_span_err!(
let mut diag = struct_span_err!(
tcx.sess,
hir_ty.span,
E0741,
"`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
the type of a const parameter",
ty,
)
.span_label(
hir_ty.span,
format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
)
.emit();
non_structural_match_ty.ty,
);

if ty == non_structural_match_ty.ty {
diag.span_label(
hir_ty.span,
format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
);
}

diag.emit();
}
}
} else {
Expand Down
@@ -1,8 +1,8 @@
error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
error[E0741]: `(dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
--> $DIR/issue-63322-forbid-dyn.rs:9:18
|
LL | fn test<const T: &'static dyn A>() {
| ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq`
| ^^^^^^^^^^^^^^

error: aborting due to previous error

Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/const-generics/issues/issue-97278.rs
@@ -0,0 +1,14 @@
#![feature(adt_const_params)]
#![allow(incomplete_features)]

use std::sync::Arc;

#[derive(PartialEq, Eq)]
enum Bar {
Bar(Arc<i32>)
}

fn test<const BAR: Bar>() {}
//~^ ERROR `Arc<i32>` must be annotated with `#[derive(PartialEq, Eq)]`

fn main() {}
9 changes: 9 additions & 0 deletions src/test/ui/const-generics/issues/issue-97278.stderr
@@ -0,0 +1,9 @@
error[E0741]: `Arc<i32>` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
--> $DIR/issue-97278.rs:11:20
|
LL | fn test<const BAR: Bar>() {}
| ^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0741`.

0 comments on commit 8a3ad49

Please sign in to comment.