From 7bdad89f950d374c128edffacd9872f7dbc72f78 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Wed, 9 Feb 2022 15:12:17 -0800 Subject: [PATCH 1/9] Stabilize Termination and ExitCode --- library/std/src/process.rs | 63 +++++++++++++------ library/test/src/lib.rs | 3 +- .../termination-trait-for-exitcode.rs | 1 - .../termination-trait-for-impl-termination.rs | 1 - 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 1f04890539604..a39793d9c220c 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1404,6 +1404,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 // @@ -1636,8 +1645,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. @@ -1648,23 +1665,26 @@ 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` /// -/// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937 +/// `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. #[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. /// /// 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. @@ -1672,7 +1692,7 @@ impl ExitCode { /// 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); } @@ -1684,14 +1704,18 @@ impl 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")] + #[unstable( + feature = "process_exitcode_internals", + reason = "exposed only for libstd", + issue = "none" + )] #[inline] 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. fn from(code: u8) -> Self { @@ -2031,7 +2055,7 @@ pub fn id() -> u32 { /// The default implementations are returning `libc::EXIT_SUCCESS` to indicate /// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. #[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}`" @@ -2039,10 +2063,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 { @@ -2050,7 +2075,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 { @@ -2060,14 +2085,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; @@ -2076,7 +2101,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; @@ -2084,7 +2109,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 8fc2b4ed748c2..ff923528c39ce 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/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 { } From b898ad499f7a2c806e8df0bfde6fbe3f3c5cb925 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 23 Mar 2022 17:09:44 -0700 Subject: [PATCH 2/9] Ensure io::Error's bitpacked repr doesn't accidentally impl UnwindSafe --- library/std/src/io/error/repr_bitpacked.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 1a0538f861a1e..e8070dc419b43 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; @@ -115,7 +116,7 @@ const TAG_OS: usize = 0b10; const TAG_SIMPLE: usize = 0b11; #[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 +146,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 +157,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 +171,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 +185,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] From 09d83e292dcb6630c1e8c08734062524466db66e Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 23 Mar 2022 17:29:19 -0700 Subject: [PATCH 3/9] Add a `compile_fail` doctest to check that `io::Error: !UnwindSafe` --- library/std/src/io/error/repr_bitpacked.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index e8070dc419b43..06614d9f4d16e 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -115,6 +115,15 @@ 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 +/// fn is_unwind_safe() {} +/// is_unwind_safe::(); +/// ``` #[repr(transparent)] pub(super) struct Repr(NonNull<()>, PhantomData>>); From dd6683fcda991536c54d419a6ecc710f21226225 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 27 Mar 2022 16:09:38 -0700 Subject: [PATCH 4/9] suggest wrapping patterns with compatible enum variants --- .../src/infer/error_reporting/mod.rs | 69 +++++++++++++++++++ .../compatible-variants-in-pat.rs | 41 +++++++++++ .../compatible-variants-in-pat.stderr | 68 ++++++++++++++++++ src/test/ui/issues/issue-12552.stderr | 8 +++ src/test/ui/issues/issue-3680.stderr | 4 ++ src/test/ui/issues/issue-5358-1.stderr | 4 ++ 6 files changed, 194 insertions(+) create mode 100644 src/test/ui/did_you_mean/compatible-variants-in-pat.rs create mode 100644 src/test/ui/did_you_mean/compatible-variants-in-pat.stderr 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/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/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 { From 07776c111f07b887cd46b752870cd3fd76b2ba7c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 27 Mar 2022 16:05:14 -0700 Subject: [PATCH 5/9] do not suggest enum tuple variant for named field variant --- compiler/rustc_typeck/src/check/demand.rs | 4 +++- src/test/ui/did_you_mean/compatible-variants.rs | 15 +++++++++++++++ .../ui/did_you_mean/compatible-variants.stderr | 10 +++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 58e5c9315c30c..17b08fe1e4039 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -336,7 +336,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/src/test/ui/did_you_mean/compatible-variants.rs b/src/test/ui/did_you_mean/compatible-variants.rs index b078064b26745..d9457cf5e3251 100644 --- a/src/test/ui/did_you_mean/compatible-variants.rs +++ b/src/test/ui/did_you_mean/compatible-variants.rs @@ -64,3 +64,18 @@ fn main() { //~^ ERROR mismatched types //~| HELP try wrapping } + +enum A { + B { b: 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 +} \ No newline at end of file diff --git a/src/test/ui/did_you_mean/compatible-variants.stderr b/src/test/ui/did_you_mean/compatible-variants.stderr index 51c1bf97c4e2c..6224af3976b91 100644 --- a/src/test/ui/did_you_mean/compatible-variants.stderr +++ b/src/test/ui/did_you_mean/compatible-variants.stderr @@ -190,6 +190,14 @@ 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:79:16 + | +LL | let a: A = B::Fst; + | - ^^^^^^ expected enum `A`, found enum `B` + | | + | expected due to this + +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0308`. From fc289a07960b652632f5b050b4a865975f356694 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 27 Mar 2022 16:15:26 -0700 Subject: [PATCH 6/9] suggest wrapping in struct tuples as well --- compiler/rustc_typeck/src/check/demand.rs | 4 ---- src/test/ui/did_you_mean/compatible-variants.rs | 11 ++++++++++- .../ui/did_you_mean/compatible-variants.stderr | 17 +++++++++++++++-- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 17b08fe1e4039..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 .. { .. })`.) diff --git a/src/test/ui/did_you_mean/compatible-variants.rs b/src/test/ui/did_you_mean/compatible-variants.rs index d9457cf5e3251..5d7c611980f1c 100644 --- a/src/test/ui/did_you_mean/compatible-variants.rs +++ b/src/test/ui/did_you_mean/compatible-variants.rs @@ -69,6 +69,8 @@ enum A { B { b: B}, } +struct A2(B); + enum B { Fst, Snd, @@ -78,4 +80,11 @@ fn foo() { // We don't want to suggest `A::B(B::Fst)` here. let a: A = B::Fst; //~^ ERROR mismatched types -} \ No newline at end of file +} + +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 6224af3976b91..a8cb5d6d3e849 100644 --- a/src/test/ui/did_you_mean/compatible-variants.stderr +++ b/src/test/ui/did_you_mean/compatible-variants.stderr @@ -191,13 +191,26 @@ LL | let _ = Foo { bar: Some(bar) }; | ++++++++++ + error[E0308]: mismatched types - --> $DIR/compatible-variants.rs:79:16 + --> $DIR/compatible-variants.rs:81:16 | LL | let a: A = B::Fst; | - ^^^^^^ expected enum `A`, found enum `B` | | | expected due to this -error: aborting due to 12 previous errors +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`. From 97c58e8a87b0218a54dd0d58df03ffbc6d7fa10c Mon Sep 17 00:00:00 2001 From: Noa Date: Sun, 27 Mar 2022 18:38:01 -0500 Subject: [PATCH 7/9] Touch up ExitCode docs --- library/std/src/process.rs | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index a39793d9c220c..aea67873ed05f 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1648,8 +1648,8 @@ impl crate::error::Error for ExitStatusError {} /// 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 +/// `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. @@ -1673,13 +1673,31 @@ impl crate::error::Error for ExitStatusError {} /// 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 } +/// +/// fn main() -> ExitCode { +/// if !check_foo() { +/// return ExitCode::from(42); +/// } +/// +/// ExitCode::SUCCESS +/// } +/// ``` #[derive(Clone, Copy, Debug)] #[stable(feature = "process_exitcode", since = "1.60.0")] pub struct ExitCode(imp::ExitCode); #[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 @@ -1687,7 +1705,7 @@ impl ExitCode { #[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 @@ -1697,19 +1715,20 @@ impl ExitCode { } 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 + /// 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() } @@ -1717,7 +1736,7 @@ impl ExitCode { #[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)) } From 0eea3346d215e76e6de283a2c3d9674a1e762452 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 29 Mar 2022 10:17:27 -0700 Subject: [PATCH 8/9] diagnostics: regression test for derive bounds Closes #79076 --- .../ui/suggestions/derive-clone-for-eq.fixed | 18 +++++++++++++ .../ui/suggestions/derive-clone-for-eq.rs | 18 +++++++++++++ .../ui/suggestions/derive-clone-for-eq.stderr | 25 +++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 src/test/ui/suggestions/derive-clone-for-eq.fixed create mode 100644 src/test/ui/suggestions/derive-clone-for-eq.rs create mode 100644 src/test/ui/suggestions/derive-clone-for-eq.stderr 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`. From 3ac93abfb220ad3fc0614787a5644e63c162f0d6 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 29 Mar 2022 11:45:49 -0700 Subject: [PATCH 9/9] Indicate the correct error code in the `compile_fail` block. Co-authored-by: Mara Bos --- library/std/src/io/error/repr_bitpacked.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 06614d9f4d16e..208d5a80c5a69 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -120,7 +120,7 @@ const TAG_SIMPLE: usize = 0b11; /// 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 +/// ```compile_fail,E0277 /// fn is_unwind_safe() {} /// is_unwind_safe::(); /// ```