diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 238145c5c6ee4..6e007b181f2c2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -65,6 +65,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::{Item, ItemKind, Node}; use rustc_middle::dep_graph::DepContext; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ self, error::TypeError, @@ -1736,6 +1737,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; if should_suggest_fixes { + self.suggest_tuple_pattern(cause, &exp_found, diag); self.suggest_as_ref_where_appropriate(span, &exp_found, diag); self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag); self.suggest_await_on_expect_found(cause, span, &exp_found, diag); @@ -1766,6 +1768,73 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.note_error_origin(diag, cause, exp_found, terr); } + fn suggest_tuple_pattern( + &self, + cause: &ObligationCause<'tcx>, + exp_found: &ty::error::ExpectedFound>, + diag: &mut Diagnostic, + ) { + // Heavily inspired by `FnCtxt::suggest_compatible_variants`, with + // some modifications due to that being in typeck and this being in infer. + if let ObligationCauseCode::Pattern { .. } = cause.code() { + if let ty::Adt(expected_adt, substs) = exp_found.expected.kind() { + let compatible_variants: Vec<_> = expected_adt + .variants() + .iter() + .filter(|variant| { + variant.fields.len() == 1 && variant.ctor_kind == hir::def::CtorKind::Fn + }) + .filter_map(|variant| { + let sole_field = &variant.fields[0]; + let sole_field_ty = sole_field.ty(self.tcx, substs); + if same_type_modulo_infer(sole_field_ty, exp_found.found) { + let variant_path = + with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id)); + // FIXME #56861: DRYer prelude filtering + if let Some(path) = variant_path.strip_prefix("std::prelude::") { + if let Some((_, path)) = path.split_once("::") { + return Some(path.to_string()); + } + } + Some(variant_path) + } else { + None + } + }) + .collect(); + match &compatible_variants[..] { + [] => {} + [variant] => { + diag.multipart_suggestion_verbose( + &format!("try wrapping the pattern in `{}`", variant), + vec![ + (cause.span.shrink_to_lo(), format!("{}(", variant)), + (cause.span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } + _ => { + // More than one matching variant. + diag.multipart_suggestions( + &format!( + "try wrapping the pattern in a variant of `{}`", + self.tcx.def_path_str(expected_adt.did()) + ), + compatible_variants.into_iter().map(|variant| { + vec![ + (cause.span.shrink_to_lo(), format!("{}(", variant)), + (cause.span.shrink_to_hi(), ")".to_string()), + ] + }), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option>> { if let ty::Opaque(def_id, substs) = ty.kind() { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 58e5c9315c30c..7f5ab8e4f42fa 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -268,10 +268,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_ty: Ty<'tcx>, ) { if let ty::Adt(expected_adt, substs) = expected.kind() { - if !expected_adt.is_enum() { - return; - } - // If the expression is of type () and it's the return expression of a block, // we suggest adding a separate return expression instead. // (To avoid things like suggesting `Ok(while .. { .. })`.) @@ -336,7 +332,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let compatible_variants: Vec = expected_adt .variants() .iter() - .filter(|variant| variant.fields.len() == 1) + .filter(|variant| { + variant.fields.len() == 1 && variant.ctor_kind == hir::def::CtorKind::Fn + }) .filter_map(|variant| { let sole_field = &variant.fields[0]; let sole_field_ty = sole_field.ty(self.tcx, substs); diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 1a0538f861a1e..208d5a80c5a69 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -104,6 +104,7 @@ use super::{Custom, ErrorData, ErrorKind, SimpleMessage}; use alloc::boxed::Box; +use core::marker::PhantomData; use core::mem::{align_of, size_of}; use core::ptr::NonNull; @@ -114,8 +115,17 @@ const TAG_CUSTOM: usize = 0b01; const TAG_OS: usize = 0b10; const TAG_SIMPLE: usize = 0b11; +/// The internal representation. +/// +/// See the module docs for more, this is just a way to hack in a check that we +/// indeed are not unwind-safe. +/// +/// ```compile_fail,E0277 +/// fn is_unwind_safe() {} +/// is_unwind_safe::(); +/// ``` #[repr(transparent)] -pub(super) struct Repr(NonNull<()>); +pub(super) struct Repr(NonNull<()>, PhantomData>>); // All the types `Repr` stores internally are Send + Sync, and so is it. unsafe impl Send for Repr {} @@ -145,7 +155,7 @@ impl Repr { // box, and `TAG_CUSTOM` just... isn't zero -- it's `0b01`). Therefore, // `TAG_CUSTOM + p` isn't zero and so `tagged` can't be, and the // `new_unchecked` is safe. - let res = Self(unsafe { NonNull::new_unchecked(tagged) }); + let res = Self(unsafe { NonNull::new_unchecked(tagged) }, PhantomData); // quickly smoke-check we encoded the right thing (This generally will // only run in libstd's tests, unless the user uses -Zbuild-std) debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed"); @@ -156,7 +166,7 @@ impl Repr { pub(super) fn new_os(code: i32) -> Self { let utagged = ((code as usize) << 32) | TAG_OS; // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0. - let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }); + let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData); // quickly smoke-check we encoded the right thing (This generally will // only run in libstd's tests, unless the user uses -Zbuild-std) debug_assert!( @@ -170,7 +180,7 @@ impl Repr { pub(super) fn new_simple(kind: ErrorKind) -> Self { let utagged = ((kind as usize) << 32) | TAG_SIMPLE; // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0. - let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }); + let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData); // quickly smoke-check we encoded the right thing (This generally will // only run in libstd's tests, unless the user uses -Zbuild-std) debug_assert!( @@ -184,7 +194,7 @@ impl Repr { #[inline] pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self { // Safety: References are never null. - Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) }) + Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) }, PhantomData) } #[inline] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index b6edf8bca0a23..d3c8d864b0c10 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1417,6 +1417,15 @@ impl From for Stdio { /// For proper error reporting of failed processes, print the value of `ExitStatus` or /// `ExitStatusError` using their implementations of [`Display`](crate::fmt::Display). /// +/// # Differences from `ExitStatus` +/// +/// `ExitCode` is intended for terminating the currently running process, via +/// the `Termination` trait, in contrast to [`ExitStatus`], which represents the +/// termination of a child process. These APIs are separate due to platform +/// compatibility differences and their expected usage; it is not generally +/// possible to exactly reproduce an ExitStatus from a child for the current +/// process after the fact. +/// /// [`status`]: Command::status /// [`wait`]: Child::wait // @@ -1649,8 +1658,16 @@ impl fmt::Display for ExitStatusError { #[unstable(feature = "exit_status_error", issue = "84908")] impl crate::error::Error for ExitStatusError {} -/// This type represents the status code a process can return to its -/// parent under normal termination. +/// This type represents the status code the current process can return +/// to its parent under normal termination. +/// +/// `ExitCode` is intended to be consumed only by the standard library (via +/// [`Termination::report()`]), and intentionally does not provide accessors like +/// `PartialEq`, `Eq`, or `Hash`. Instead the standard library provides the +/// canonical `SUCCESS` and `FAILURE` exit codes as well as `From for +/// ExitCode` for constructing other arbitrary exit codes. +/// +/// # Portability /// /// Numeric values used in this type don't have portable meanings, and /// different platforms may mask different amounts of them. @@ -1661,52 +1678,78 @@ impl crate::error::Error for ExitStatusError {} /// [`SUCCESS`]: ExitCode::SUCCESS /// [`FAILURE`]: ExitCode::FAILURE /// -/// **Warning**: While various forms of this were discussed in [RFC #1937], -/// it was ultimately cut from that RFC, and thus this type is more subject -/// to change even than the usual unstable item churn. +/// # Differences from `ExitStatus` +/// +/// `ExitCode` is intended for terminating the currently running process, via +/// the `Termination` trait, in contrast to [`ExitStatus`], which represents the +/// termination of a child process. These APIs are separate due to platform +/// compatibility differences and their expected usage; it is not generally +/// possible to exactly reproduce an ExitStatus from a child for the current +/// process after the fact. +/// +/// # Examples +/// +/// `ExitCode` can be returned from the `main` function of a crate, as it implements +/// [`Termination`]: +/// +/// ``` +/// use std::process::ExitCode; +/// # fn check_foo() -> bool { true } /// -/// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937 +/// fn main() -> ExitCode { +/// if !check_foo() { +/// return ExitCode::from(42); +/// } +/// +/// ExitCode::SUCCESS +/// } +/// ``` #[derive(Clone, Copy, Debug)] -#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] +#[stable(feature = "process_exitcode", since = "1.60.0")] pub struct ExitCode(imp::ExitCode); -#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] +#[stable(feature = "process_exitcode", since = "1.60.0")] impl ExitCode { - /// The canonical ExitCode for successful termination on this platform. + /// The canonical `ExitCode` for successful termination on this platform. /// /// Note that a `()`-returning `main` implicitly results in a successful /// termination, so there's no need to return this from `main` unless /// you're also returning other possible codes. - #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] + #[stable(feature = "process_exitcode", since = "1.60.0")] pub const SUCCESS: ExitCode = ExitCode(imp::ExitCode::SUCCESS); - /// The canonical ExitCode for unsuccessful termination on this platform. + /// The canonical `ExitCode` for unsuccessful termination on this platform. /// /// If you're only returning this and `SUCCESS` from `main`, consider /// instead returning `Err(_)` and `Ok(())` respectively, which will /// return the same codes (but will also `eprintln!` the error). - #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] + #[stable(feature = "process_exitcode", since = "1.60.0")] pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE); } impl ExitCode { - // This should not be stabilized when stabilizing ExitCode, we don't know that i32 will serve + // This is private/perma-unstable because ExitCode is opaque; we don't know that i32 will serve // all usecases, for example windows seems to use u32, unix uses the 8-15th bits of an i32, we // likely want to isolate users anything that could restrict the platform specific // representation of an ExitCode // // More info: https://internals.rust-lang.org/t/mini-pre-rfc-redesigning-process-exitstatus/5426 - /// Convert an ExitCode into an i32 - #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] + /// Convert an `ExitCode` into an i32 + #[unstable( + feature = "process_exitcode_internals", + reason = "exposed only for libstd", + issue = "none" + )] #[inline] + #[doc(hidden)] pub fn to_i32(self) -> i32 { self.0.as_i32() } } -#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] +#[stable(feature = "process_exitcode", since = "1.60.0")] impl From for ExitCode { - /// Construct an exit code from an arbitrary u8 value. + /// Construct an `ExitCode` from an arbitrary u8 value. fn from(code: u8) -> Self { ExitCode(imp::ExitCode::from(code)) } @@ -2049,7 +2092,7 @@ pub fn id() -> u32 { /// standard library's runtime for convenience. Other runtimes are not required /// to provide similar functionality. #[cfg_attr(not(test), lang = "termination")] -#[unstable(feature = "termination_trait_lib", issue = "43301")] +#[stable(feature = "termination_trait_lib", since = "1.60.0")] #[rustc_on_unimplemented( message = "`main` has invalid return type `{Self}`", label = "`main` can only return types that implement `{Termination}`" @@ -2057,10 +2100,11 @@ pub fn id() -> u32 { pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. + #[stable(feature = "termination_trait_lib", since = "1.60.0")] fn report(self) -> ExitCode; } -#[unstable(feature = "termination_trait_lib", issue = "43301")] +#[stable(feature = "termination_trait_lib", since = "1.60.0")] impl Termination for () { #[inline] fn report(self) -> ExitCode { @@ -2068,7 +2112,7 @@ impl Termination for () { } } -#[unstable(feature = "termination_trait_lib", issue = "43301")] +#[stable(feature = "termination_trait_lib", since = "1.60.0")] impl Termination for Result<(), E> { fn report(self) -> ExitCode { match self { @@ -2078,14 +2122,14 @@ impl Termination for Result<(), E> { } } -#[unstable(feature = "termination_trait_lib", issue = "43301")] +#[stable(feature = "termination_trait_lib", since = "1.60.0")] impl Termination for ! { fn report(self) -> ExitCode { self } } -#[unstable(feature = "termination_trait_lib", issue = "43301")] +#[stable(feature = "termination_trait_lib", since = "1.60.0")] impl Termination for Result { fn report(self) -> ExitCode { let Err(err) = self; @@ -2094,7 +2138,7 @@ impl Termination for Result { } } -#[unstable(feature = "termination_trait_lib", issue = "43301")] +#[stable(feature = "termination_trait_lib", since = "1.60.0")] impl Termination for Result { fn report(self) -> ExitCode { let Err(err) = self; @@ -2102,7 +2146,7 @@ impl Termination for Result { } } -#[unstable(feature = "termination_trait_lib", issue = "43301")] +#[stable(feature = "termination_trait_lib", since = "1.60.0")] impl Termination for ExitCode { #[inline] fn report(self) -> ExitCode { diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 088e3a23ea4d9..889f7cb9db941 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -19,8 +19,7 @@ #![feature(bench_black_box)] #![feature(internal_output_capture)] #![feature(staged_api)] -#![feature(termination_trait_lib)] -#![feature(process_exitcode_placeholder)] +#![feature(process_exitcode_internals)] #![feature(test)] #![feature(total_cmp)] diff --git a/src/test/ui/did_you_mean/compatible-variants-in-pat.rs b/src/test/ui/did_you_mean/compatible-variants-in-pat.rs new file mode 100644 index 0000000000000..09e12dab2d3fc --- /dev/null +++ b/src/test/ui/did_you_mean/compatible-variants-in-pat.rs @@ -0,0 +1,41 @@ +enum Foo { + Bar(Bar), +} +struct Bar { + x: i32, +} + +fn a(f: Foo) { + match f { + Bar { x } => { + //~^ ERROR mismatched types + //~| HELP try wrapping + } + } +} + +struct S; + +fn b(s: Option) { + match s { + S => { + //~^ ERROR mismatched types + //~| HELP try wrapping + //~| HELP introduce a new binding instead + } + _ => {} + } +} + +fn c(s: Result) { + match s { + S => { + //~^ ERROR mismatched types + //~| HELP try wrapping + //~| HELP introduce a new binding instead + } + _ => {} + } +} + +fn main() {} diff --git a/src/test/ui/did_you_mean/compatible-variants-in-pat.stderr b/src/test/ui/did_you_mean/compatible-variants-in-pat.stderr new file mode 100644 index 0000000000000..a4c77e08efe19 --- /dev/null +++ b/src/test/ui/did_you_mean/compatible-variants-in-pat.stderr @@ -0,0 +1,68 @@ +error[E0308]: mismatched types + --> $DIR/compatible-variants-in-pat.rs:10:9 + | +LL | match f { + | - this expression has type `Foo` +LL | Bar { x } => { + | ^^^^^^^^^ expected enum `Foo`, found struct `Bar` + | +help: try wrapping the pattern in `Foo::Bar` + | +LL | Foo::Bar(Bar { x }) => { + | +++++++++ + + +error[E0308]: mismatched types + --> $DIR/compatible-variants-in-pat.rs:21:9 + | +LL | struct S; + | --------- unit struct defined here +... +LL | match s { + | - this expression has type `Option` +LL | S => { + | ^ + | | + | expected enum `Option`, found struct `S` + | `S` is interpreted as a unit struct, not a new binding + | + = note: expected enum `Option` + found struct `S` +help: try wrapping the pattern in `Some` + | +LL | Some(S) => { + | +++++ + +help: introduce a new binding instead + | +LL | other_s => { + | ~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/compatible-variants-in-pat.rs:32:9 + | +LL | struct S; + | --------- unit struct defined here +... +LL | match s { + | - this expression has type `Result` +LL | S => { + | ^ + | | + | expected enum `Result`, found struct `S` + | `S` is interpreted as a unit struct, not a new binding + | + = note: expected enum `Result` + found struct `S` +help: try wrapping the pattern in a variant of `Result` + | +LL | Ok(S) => { + | +++ + +LL | Err(S) => { + | ++++ + +help: introduce a new binding instead + | +LL | other_s => { + | ~~~~~~~ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/did_you_mean/compatible-variants.rs b/src/test/ui/did_you_mean/compatible-variants.rs index b078064b26745..5d7c611980f1c 100644 --- a/src/test/ui/did_you_mean/compatible-variants.rs +++ b/src/test/ui/did_you_mean/compatible-variants.rs @@ -64,3 +64,27 @@ fn main() { //~^ ERROR mismatched types //~| HELP try wrapping } + +enum A { + B { b: B}, +} + +struct A2(B); + +enum B { + Fst, + Snd, +} + +fn foo() { + // We don't want to suggest `A::B(B::Fst)` here. + let a: A = B::Fst; + //~^ ERROR mismatched types +} + +fn bar() { + // But we _do_ want to suggest `A2(B::Fst)` here! + let a: A2 = B::Fst; + //~^ ERROR mismatched types + //~| HELP try wrapping +} diff --git a/src/test/ui/did_you_mean/compatible-variants.stderr b/src/test/ui/did_you_mean/compatible-variants.stderr index 51c1bf97c4e2c..a8cb5d6d3e849 100644 --- a/src/test/ui/did_you_mean/compatible-variants.stderr +++ b/src/test/ui/did_you_mean/compatible-variants.stderr @@ -190,6 +190,27 @@ help: try wrapping the expression in `Some` LL | let _ = Foo { bar: Some(bar) }; | ++++++++++ + -error: aborting due to 11 previous errors +error[E0308]: mismatched types + --> $DIR/compatible-variants.rs:81:16 + | +LL | let a: A = B::Fst; + | - ^^^^^^ expected enum `A`, found enum `B` + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/compatible-variants.rs:87:17 + | +LL | let a: A2 = B::Fst; + | -- ^^^^^^ expected struct `A2`, found enum `B` + | | + | expected due to this + | +help: try wrapping the expression in `A2` + | +LL | let a: A2 = A2(B::Fst); + | +++ + + +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-12552.stderr b/src/test/ui/issues/issue-12552.stderr index 3d8852ca748af..4b027eba2c25e 100644 --- a/src/test/ui/issues/issue-12552.stderr +++ b/src/test/ui/issues/issue-12552.stderr @@ -8,6 +8,10 @@ LL | Some(k) => match k { | = note: expected enum `Result<_, {integer}>` found enum `Option<_>` +help: try wrapping the pattern in `Ok` + | +LL | Ok(Some(k)) => match k { + | +++ + error[E0308]: mismatched types --> $DIR/issue-12552.rs:9:5 @@ -20,6 +24,10 @@ LL | None => () | = note: expected enum `Result<_, {integer}>` found enum `Option<_>` +help: try wrapping the pattern in `Ok` + | +LL | Ok(None) => () + | +++ + error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-3680.stderr b/src/test/ui/issues/issue-3680.stderr index e8fafa76b919b..29ba44f136afa 100644 --- a/src/test/ui/issues/issue-3680.stderr +++ b/src/test/ui/issues/issue-3680.stderr @@ -8,6 +8,10 @@ LL | Err(_) => () | = note: expected enum `Option<_>` found enum `Result<_, _>` +help: try wrapping the pattern in `Some` + | +LL | Some(Err(_)) => () + | +++++ + error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5358-1.stderr b/src/test/ui/issues/issue-5358-1.stderr index d1bc279c7589a..9d5b8d9d3fc1b 100644 --- a/src/test/ui/issues/issue-5358-1.stderr +++ b/src/test/ui/issues/issue-5358-1.stderr @@ -8,6 +8,10 @@ LL | Either::Right(_) => {} | = note: expected struct `S` found enum `Either<_, _>` +help: try wrapping the pattern in `S` + | +LL | S(Either::Right(_)) => {} + | ++ + help: you might have meant to use field `0` whose type is `Either` | LL | match S(Either::Left(5)).0 { diff --git a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-exitcode.rs b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-exitcode.rs index 9c2270bf82752..6d4c1562053b6 100644 --- a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-exitcode.rs +++ b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-exitcode.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(process_exitcode_placeholder)] use std::process::ExitCode; diff --git a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs index 79cfba011c017..c06a135dcbc20 100644 --- a/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs +++ b/src/test/ui/rfcs/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs @@ -1,4 +1,3 @@ // run-pass -#![feature(termination_trait_lib)] fn main() -> impl std::process::Termination { } diff --git a/src/test/ui/suggestions/derive-clone-for-eq.fixed b/src/test/ui/suggestions/derive-clone-for-eq.fixed new file mode 100644 index 0000000000000..f07784d53b3a3 --- /dev/null +++ b/src/test/ui/suggestions/derive-clone-for-eq.fixed @@ -0,0 +1,18 @@ +// run-rustfix +// https://github.com/rust-lang/rust/issues/79076 + +use std::cmp::PartialEq; + +#[derive(Clone, Eq)] //~ ERROR [E0277] +pub struct Struct(T); + +impl PartialEq for Struct +where + U: Into> + Clone +{ + fn eq(&self, _other: &U) -> bool { + todo!() + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/derive-clone-for-eq.rs b/src/test/ui/suggestions/derive-clone-for-eq.rs new file mode 100644 index 0000000000000..15c0d4659fbbe --- /dev/null +++ b/src/test/ui/suggestions/derive-clone-for-eq.rs @@ -0,0 +1,18 @@ +// run-rustfix +// https://github.com/rust-lang/rust/issues/79076 + +use std::cmp::PartialEq; + +#[derive(Clone, Eq)] //~ ERROR [E0277] +pub struct Struct(T); + +impl PartialEq for Struct +where + U: Into> + Clone +{ + fn eq(&self, _other: &U) -> bool { + todo!() + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/derive-clone-for-eq.stderr b/src/test/ui/suggestions/derive-clone-for-eq.stderr new file mode 100644 index 0000000000000..55a23c031d5bc --- /dev/null +++ b/src/test/ui/suggestions/derive-clone-for-eq.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `T: Clone` is not satisfied + --> $DIR/derive-clone-for-eq.rs:6:17 + | +LL | #[derive(Clone, Eq)] + | ^^ the trait `Clone` is not implemented for `T` + | +note: required because of the requirements on the impl of `PartialEq` for `Struct` + --> $DIR/derive-clone-for-eq.rs:9:19 + | +LL | impl PartialEq for Struct + | ^^^^^^^^^^^^ ^^^^^^^^^ +note: required by a bound in `Eq` + --> $SRC_DIR/core/src/cmp.rs:LL:COL + | +LL | pub trait Eq: PartialEq { + | ^^^^^^^^^^^^^^^ required by this bound in `Eq` + = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider restricting type parameter `T` + | +LL | pub struct Struct(T); + | +++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.