Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make typeck aware of uninhabited types #100288

Closed
wants to merge 10 commits into from

Conversation

camsteffen
Copy link
Contributor

@camsteffen camsteffen commented Aug 8, 2022

It was previously assumed in #85556 that we can't check if an expression has an uninhabited type in typeck. So an unreachable_code case was added to the liveness pass instead. This PR moves that case back into typeck. It just requires adding cycle_delay_bug to the uninhabited query.

Incidentally this leads to some new cases for unreachable_code. But it should simply be consistent with how ! is currently handled.

My original motivation is to remove a blocker to doing some refactoring on liveness.

r? rust-lang/compiler

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Aug 8, 2022
@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 8, 2022
@camsteffen
Copy link
Contributor Author

I'm not entirely confident in the test changes tbh. Maybe a few corner cases need some ironing.

@rust-log-analyzer

This comment has been minimized.

@camsteffen camsteffen force-pushed the uninhabited-typeck branch 4 times, most recently from 026ab44 to df073c7 Compare August 9, 2022 02:00
@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Contributor

bors commented Aug 9, 2022

☔ The latest upstream changes (presumably #100304) made this pull request unmergeable. Please resolve the merge conflicts.

@camsteffen camsteffen changed the title Make typeck more aware of uninhabitable types Make typeck aware of uninhabited types Aug 9, 2022
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

compiler/rustc_typeck/src/check/check.rs Outdated Show resolved Hide resolved
compiler/rustc_typeck/src/lib.rs Outdated Show resolved Hide resolved
@rust-log-analyzer

This comment has been minimized.

@camsteffen camsteffen force-pushed the uninhabited-typeck branch 2 times, most recently from 6af9e16 to 2d81d20 Compare August 10, 2022 00:09
@bors
Copy link
Contributor

bors commented Aug 18, 2022

☔ The latest upstream changes (presumably #98655) made this pull request unmergeable. Please resolve the merge conflicts.

@rust-log-analyzer

This comment has been minimized.

@cjgillot
Copy link
Contributor

How does this PR articulate with #100720?

@camsteffen
Copy link
Contributor Author

There are a number of queries that are susceptible to cycle errors if they run on an infinitely recursive (unrepresentable) ADT. adt_sized_constraint and type_uninhabited_from are a couple such queries. There are multiple ways to solve the cycle error problem for a given query:

  1. Ensure the query never runs on unrepresentable types. (this PR stops rustc before bodies are type-checked, so that type_implemented_from remains guarded from unrepresentable types)
  2. Implement Value::from_cycle_error to have a fallback (adt_sized_constraint currently does this)
  3. Add if !is_representable(field_id) { return <fallback> }. (this is an idea I had that prompted me to do Rewrite representability #100720)

So we can either be conservative and try to guard queries from unrepresentable types as much as possible (halt rustc early), or go the other direction and try to recover-and-continue as much as possible for unrepresentable types. Or maybe the right balance is somewhere in the middle. I'm not quite sure.

In any case, it might make sense to try and merge #100720 first on its own, and then we can think about how other parts of the compiler may or may not use the new is_representable query. Though I think it might also be fine to merge this PR first. They are only tangentially related.

@camsteffen
Copy link
Contributor Author

camsteffen commented Aug 20, 2022

Removed the early exit and instead added from_cycle_error for type_uninhabited_from. This feels much less invasive and also makes this PR pretty much completely orthoganal to #100720.

@rustbot rustbot added the A-testsuite Area: The testsuite used to check the correctness of rustc label Oct 23, 2022
@rust-log-analyzer

This comment has been minimized.

@camsteffen
Copy link
Contributor Author

Bumped into #103220. I may need help with this one.

@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-llvm-13 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
..............................................iii....................................... 13640/13707
...................................................................
failures:

---- [ui] src/test/ui/deriving/deriving-all-codegen.rs#unpretty stdout ----


1104         unsafe { ::core::intrinsics::unreachable() }
1106 }
1106 }
- impl ::core::marker::StructuralPartialEq for Void {}
1108 #[automatically_derived]
+ impl ::core::marker::StructuralPartialEq for Void { }
+ #[automatically_derived]
1109 impl ::core::cmp::PartialEq for Void {
1110     #[inline]
1111     fn eq(&self, other: &Void) -> bool {

1112         unsafe { ::core::intrinsics::unreachable() }
1114 }
1114 }
- impl ::core::marker::StructuralEq for Void {}
1116 #[automatically_derived]
+ impl ::core::marker::StructuralEq for Void { }
+ #[automatically_derived]
1117 impl ::core::cmp::Eq for Void {
Some tests failed in compiletest suite=ui mode=ui host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu
1119     #[doc(hidden)]


1167         ::core::hash::Hash::hash(&self.y, state)
1169 }
1169 }
- impl ::core::marker::StructuralPartialEq for WithUninhabited {}
1171 #[automatically_derived]
+ impl ::core::marker::StructuralPartialEq for WithUninhabited { }
+ #[automatically_derived]
1172 impl ::core::cmp::PartialEq for WithUninhabited {
1173     #[inline]
1174     fn eq(&self, other: &WithUninhabited) -> bool {

1175         self.x == other.x && self.v == other.v && self.y == other.y
1177 }
1177 }
- impl ::core::marker::StructuralEq for WithUninhabited {}
1179 #[automatically_derived]
+ impl ::core::marker::StructuralEq for WithUninhabited { }
+ #[automatically_derived]
1180 impl ::core::cmp::Eq for WithUninhabited {
1182     #[doc(hidden)]

1263         }
1264     }
1264     }
1265 }
- impl ::core::marker::StructuralPartialEq for EnumWithUninhabited {}
1267 #[automatically_derived]
+ impl ::core::marker::StructuralPartialEq for EnumWithUninhabited { }
+ #[automatically_derived]
1268 impl ::core::cmp::PartialEq for EnumWithUninhabited {
1269     #[inline]
1270     fn eq(&self, other: &EnumWithUninhabited) -> bool {
1282             }
1283     }
1284 }
1284 }
- impl ::core::marker::StructuralEq for EnumWithUninhabited {}
+ #[automatically_derived]
+ impl ::core::marker::StructuralEq for EnumWithUninhabited { }
1286 #[automatically_derived]
1287 impl ::core::cmp::Eq for EnumWithUninhabited {


The actual stdout differed from the expected stdout.
The actual stdout differed from the expected stdout.
Actual stdout saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/deriving/deriving-all-codegen.unpretty/deriving-all-codegen.unpretty.stdout
To only update this specific test, also pass `--test-args deriving/deriving-all-codegen.rs`


error in revision `unpretty`: 1 errors occurred comparing output.
status: exit status: 0
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/deriving/deriving-all-codegen.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--cfg" "unpretty" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/deriving/deriving-all-codegen.unpretty" "-A" "unused" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2021" "-Zunpretty=expanded" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/deriving/deriving-all-codegen.unpretty/auxiliary"
#![feature(prelude_import)]
// check-pass
// edition:2021
// revisions: check unpretty
// revisions: check unpretty
// [unpretty] compile-flags: -Zunpretty=expanded
//
// This test checks the code generated for all[*] the builtin derivable traits
// on a variety of structs and enums. It protects against accidental changes to
// the generated code, and makes deliberate changes to the generated code
// easier to review.
//
// [*] It excludes `Copy` in some cases, because that changes the code
// generated for `Clone`.
//
// [*] It excludes `RustcEncodable` and `RustDecodable`, which are obsolete and
// also require the `rustc_serialize` crate.
#![crate_type = "lib"]
#![warn(unused)]
#[prelude_import]
use std::prelude::rust_2021::*;
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
// test that lints are not triggerred in derived code
// Empty struct.
pub struct Empty;
#[automatically_derived]
impl ::core::clone::Clone for Empty {
impl ::core::clone::Clone for Empty {
    #[inline]
    fn clone(&self) -> Empty { *self }
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::Copy for Empty { }
#[automatically_derived]
impl ::core::fmt::Debug for Empty {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "Empty")
}
#[automatically_derived]
impl ::core::default::Default for Empty {
    #[inline]
    #[inline]
    fn default() -> Empty { Empty {} }
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for Empty {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Empty { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Empty {
    #[inline]
    fn eq(&self, other: &Empty) -> bool { true }
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for Empty { }
#[automatically_derived]
impl ::core::cmp::Eq for Empty {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Empty {
    #[inline]
    fn partial_cmp(&self, other: &Empty)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::option::Option::Some(::core::cmp::Ordering::Equal)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for Empty {
    #[inline]
    fn cmp(&self, other: &Empty) -> ::core::cmp::Ordering {
        ::core::cmp::Ordering::Equal
}

// A basic struct.
pub struct Point {
pub struct Point {
    x: u32,
    y: u32,
}
#[automatically_derived]
impl ::core::clone::Clone for Point {
    #[inline]
    fn clone(&self) -> Point {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
}
#[automatically_derived]
impl ::core::marker::Copy for Point { }
#[automatically_derived]
#[automatically_derived]
impl ::core::fmt::Debug for Point {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "Point", "x",
            &&self.x, "y", &&self.y)
}
#[automatically_derived]
impl ::core::default::Default for Point {
    #[inline]
    #[inline]
    fn default() -> Point {
        Point {
            x: ::core::default::Default::default(),
            y: ::core::default::Default::default(),
    }
}
#[automatically_derived]
impl ::core::hash::Hash for Point {
impl ::core::hash::Hash for Point {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&self.x, state);
        ::core::hash::Hash::hash(&self.y, state)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Point { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Point {
    #[inline]
    fn eq(&self, other: &Point) -> bool {
        self.x == other.x && self.y == other.y
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for Point { }
#[automatically_derived]
impl ::core::cmp::Eq for Point {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Point {
    #[inline]
    #[inline]
    fn partial_cmp(&self, other: &Point)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.x, &other.x) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                ::core::cmp::PartialOrd::partial_cmp(&self.y, &other.y),
            cmp => cmp,
    }
}
#[automatically_derived]
impl ::core::cmp::Ord for Point {
impl ::core::cmp::Ord for Point {
    #[inline]
    fn cmp(&self, other: &Point) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.x, &other.x) {
            ::core::cmp::Ordering::Equal =>
                ::core::cmp::Ord::cmp(&self.y, &other.y),
            cmp => cmp,
    }
}

// A large struct.
---
    b6: u32,
    b7: u32,
    b8: u32,
}
#[automatically_derived]
impl ::core::clone::Clone for Big {
    fn clone(&self) -> Big {
        Big {
        Big {
            b1: ::core::clone::Clone::clone(&self.b1),
            b2: ::core::clone::Clone::clone(&self.b2),
            b3: ::core::clone::Clone::clone(&self.b3),
            b4: ::core::clone::Clone::clone(&self.b4),
            b5: ::core::clone::Clone::clone(&self.b5),
            b6: ::core::clone::Clone::clone(&self.b6),
            b7: ::core::clone::Clone::clone(&self.b7),
            b8: ::core::clone::Clone::clone(&self.b8),
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::fmt::Debug for Big {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        let names: &'static _ =
            &["b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8"];
        let values: &[&dyn ::core::fmt::Debug] =
            &[&&self.b1, &&self.b2, &&self.b3, &&self.b4, &&self.b5,
                        &&self.b6, &&self.b7, &&self.b8];
        ::core::fmt::Formatter::debug_struct_fields_finish(f, "Big", names,
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::default::Default for Big {
    #[inline]
    fn default() -> Big {
        Big {
            b1: ::core::default::Default::default(),
            b2: ::core::default::Default::default(),
            b3: ::core::default::Default::default(),
            b4: ::core::default::Default::default(),
            b5: ::core::default::Default::default(),
            b6: ::core::default::Default::default(),
            b7: ::core::default::Default::default(),
            b8: ::core::default::Default::default(),
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for Big {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&self.b1, state);
        ::core::hash::Hash::hash(&self.b2, state);
        ::core::hash::Hash::hash(&self.b3, state);
        ::core::hash::Hash::hash(&self.b4, state);
        ::core::hash::Hash::hash(&self.b5, state);
        ::core::hash::Hash::hash(&self.b6, state);
        ::core::hash::Hash::hash(&self.b7, state);
        ::core::hash::Hash::hash(&self.b8, state)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Big { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Big {
    #[inline]
    fn eq(&self, other: &Big) -> bool {
        self.b1 == other.b1 && self.b2 == other.b2 && self.b3 == other.b3 &&
                            self.b4 == other.b4 && self.b5 == other.b5 &&
                    self.b6 == other.b6 && self.b7 == other.b7 &&
            self.b8 == other.b8
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for Big { }
#[automatically_derived]
impl ::core::cmp::Eq for Big {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Big {
    #[inline]
    fn partial_cmp(&self, other: &Big)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.b1, &other.b1) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match ::core::cmp::PartialOrd::partial_cmp(&self.b2,
                        &other.b2) {
                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                        =>
                        match ::core::cmp::PartialOrd::partial_cmp(&self.b3,
                                &other.b3) {
                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                =>
                                match ::core::cmp::PartialOrd::partial_cmp(&self.b4,
                                        &other.b4) {
                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                        =>
                                        match ::core::cmp::PartialOrd::partial_cmp(&self.b5,
                                                &other.b5) {
                                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                =>
                                                match ::core::cmp::PartialOrd::partial_cmp(&self.b6,
                                                        &other.b6) {
                                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                        =>
                                                        match ::core::cmp::PartialOrd::partial_cmp(&self.b7,
                                                                &other.b7) {
                                                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                                =>
                                                                ::core::cmp::PartialOrd::partial_cmp(&self.b8, &other.b8),
                                                            cmp => cmp,
                                                    cmp => cmp,
                                                },
                                            cmp => cmp,
                                        },
---
            cmp => cmp,
        }
    }
}
#[automatically_derived]
impl ::core::cmp::Ord for Big {
    #[inline]
    fn cmp(&self, other: &Big) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.b1, &other.b1) {
            ::core::cmp::Ordering::Equal =>
                match ::core::cmp::Ord::cmp(&self.b2, &other.b2) {
                    ::core::cmp::Ordering::Equal =>
                        match ::core::cmp::Ord::cmp(&self.b3, &other.b3) {
                            ::core::cmp::Ordering::Equal =>
                                match ::core::cmp::Ord::cmp(&self.b4, &other.b4) {
                                    ::core::cmp::Ordering::Equal =>
                                        match ::core::cmp::Ord::cmp(&self.b5, &other.b5) {
                                            ::core::cmp::Ordering::Equal =>
                                                match ::core::cmp::Ord::cmp(&self.b6, &other.b6) {
                                                    ::core::cmp::Ordering::Equal =>
                                                        match ::core::cmp::Ord::cmp(&self.b7, &other.b7) {
                                                            ::core::cmp::Ordering::Equal =>
                                                                ::core::cmp::Ord::cmp(&self.b8, &other.b8),
                                                            cmp => cmp,
                                                    cmp => cmp,
                                                },
                                            cmp => cmp,
                                        },
---
        }
    }
}

// A struct with an unsized field. Some derives are not usable in this case.
pub struct Unsized([u32]);
#[automatically_derived]
impl ::core::fmt::Debug for Unsized {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Unsized",
            &&self.0)
}
#[automatically_derived]
impl ::core::hash::Hash for Unsized {
impl ::core::hash::Hash for Unsized {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&self.0, state)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Unsized { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Unsized {
    #[inline]
    fn eq(&self, other: &Unsized) -> bool { self.0 == other.0 }
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for Unsized { }
#[automatically_derived]
impl ::core::cmp::Eq for Unsized {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<[u32]>;
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Unsized {
    #[inline]
    fn partial_cmp(&self, other: &Unsized)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for Unsized {
    #[inline]
    fn cmp(&self, other: &Unsized) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
}

// A packed tuple struct that impls `Copy`.
// A packed tuple struct that impls `Copy`.
#[repr(packed)]
pub struct PackedCopy(u32);
#[automatically_derived]
impl ::core::clone::Clone for PackedCopy {
    fn clone(&self) -> PackedCopy {
    fn clone(&self) -> PackedCopy {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::Copy for PackedCopy { }
#[automatically_derived]
impl ::core::fmt::Debug for PackedCopy {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedCopy",
            &&{ self.0 })
}
#[automatically_derived]
#[automatically_derived]
impl ::core::default::Default for PackedCopy {
    #[inline]
    fn default() -> PackedCopy {
        PackedCopy(::core::default::Default::default())
}
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for PackedCopy {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&{ self.0 }, state)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for PackedCopy { }
#[automatically_derived]
impl ::core::cmp::PartialEq for PackedCopy {
    #[inline]
    fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } }
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for PackedCopy { }
#[automatically_derived]
impl ::core::cmp::Eq for PackedCopy {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for PackedCopy {
    #[inline]
    fn partial_cmp(&self, other: &PackedCopy)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for PackedCopy {
    #[inline]
    fn cmp(&self, other: &PackedCopy) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 })
}


// A packed tuple struct that does not impl `Copy`. Note that the alignment of
// the field must be 1 for this code to be valid. Otherwise it triggers an
// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not
// derive Copy (error E0133)" at MIR building time. This is a weird case and
// it's possible that this struct is not supposed to work, but for now it does.
#[repr(packed)]
pub struct PackedNonCopy(u8);
#[automatically_derived]
impl ::core::clone::Clone for PackedNonCopy {
    #[inline]
    fn clone(&self) -> PackedNonCopy {
        let Self(ref __self_0_0) = *self;
        PackedNonCopy(::core::clone::Clone::clone(__self_0_0))
}
#[automatically_derived]
#[automatically_derived]
impl ::core::fmt::Debug for PackedNonCopy {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        let Self(ref __self_0_0) = *self;
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedNonCopy",
            &__self_0_0)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::default::Default for PackedNonCopy {
    #[inline]
    fn default() -> PackedNonCopy {
        PackedNonCopy(::core::default::Default::default())
}
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for PackedNonCopy {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        let Self(ref __self_0_0) = *self;
        ::core::hash::Hash::hash(__self_0_0, state)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for PackedNonCopy { }
#[automatically_derived]
impl ::core::cmp::PartialEq for PackedNonCopy {
    #[inline]
    fn eq(&self, other: &PackedNonCopy) -> bool {
        let Self(ref __self_0_0) = *self;
        let Self(ref __self_1_0) = *other;
        *__self_0_0 == *__self_1_0
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for PackedNonCopy { }
#[automatically_derived]
impl ::core::cmp::Eq for PackedNonCopy {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u8>;
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for PackedNonCopy {
    #[inline]
    fn partial_cmp(&self, other: &PackedNonCopy)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let Self(ref __self_0_0) = *self;
        let Self(ref __self_1_0) = *other;
        ::core::cmp::PartialOrd::partial_cmp(__self_0_0, __self_1_0)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for PackedNonCopy {
    #[inline]
    fn cmp(&self, other: &PackedNonCopy) -> ::core::cmp::Ordering {
        let Self(ref __self_0_0) = *self;
        let Self(ref __self_1_0) = *other;
        ::core::cmp::Ord::cmp(__self_0_0, __self_1_0)
}

// An empty enum.
pub enum Enum0 {}
pub enum Enum0 {}
#[automatically_derived]
impl ::core::clone::Clone for Enum0 {
    #[inline]
    fn clone(&self) -> Enum0 { *self }
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::Copy for Enum0 { }
#[automatically_derived]
impl ::core::fmt::Debug for Enum0 {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        unsafe { ::core::intrinsics::unreachable() }
}
#[automatically_derived]
impl ::core::hash::Hash for Enum0 {
impl ::core::hash::Hash for Enum0 {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        unsafe { ::core::intrinsics::unreachable() }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Enum0 { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Enum0 {
    #[inline]
    fn eq(&self, other: &Enum0) -> bool {
        unsafe { ::core::intrinsics::unreachable() }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for Enum0 { }
#[automatically_derived]
impl ::core::cmp::Eq for Enum0 {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Enum0 {
    #[inline]
    #[inline]
    fn partial_cmp(&self, other: &Enum0)
        -> ::core::option::Option<::core::cmp::Ordering> {
        unsafe { ::core::intrinsics::unreachable() }
}
#[automatically_derived]
impl ::core::cmp::Ord for Enum0 {
    #[inline]
    #[inline]
    fn cmp(&self, other: &Enum0) -> ::core::cmp::Ordering {
        unsafe { ::core::intrinsics::unreachable() }
}

// A single-variant enum.
pub enum Enum1 {
pub enum Enum1 {
    Single {
        x: u32,
    },
}
#[automatically_derived]
impl ::core::clone::Clone for Enum1 {
    #[inline]
    fn clone(&self) -> Enum1 {
        match self {
            Enum1::Single { x: __self_0 } =>
                Enum1::Single { x: ::core::clone::Clone::clone(__self_0) },
    }
}
#[automatically_derived]
impl ::core::fmt::Debug for Enum1 {
impl ::core::fmt::Debug for Enum1 {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Enum1::Single { x: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "Single", "x", &__self_0),
    }
}
#[automatically_derived]
impl ::core::hash::Hash for Enum1 {
impl ::core::hash::Hash for Enum1 {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        match self {
            Enum1::Single { x: __self_0 } =>
                ::core::hash::Hash::hash(__self_0, state),
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Enum1 { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Enum1 {
    #[inline]
    fn eq(&self, other: &Enum1) -> bool {
        match (self, other) {
            (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) =>
                *__self_0 == *__arg1_0,
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for Enum1 { }
#[automatically_derived]
impl ::core::cmp::Eq for Enum1 {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Enum1 {
    #[inline]
    #[inline]
    fn partial_cmp(&self, other: &Enum1)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match (self, other) {
            (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
    }
}
#[automatically_derived]
impl ::core::cmp::Ord for Enum1 {
impl ::core::cmp::Ord for Enum1 {
    #[inline]
    fn cmp(&self, other: &Enum1) -> ::core::cmp::Ordering {
        match (self, other) {
            (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) =>
                ::core::cmp::Ord::cmp(__self_0, __arg1_0),
    }
}


// A C-like, fieldless enum with a single variant.
pub enum Fieldless1 {
    #[default]
    A,
}
#[automatically_derived]
#[automatically_derived]
impl ::core::clone::Clone for Fieldless1 {
    #[inline]
    fn clone(&self) -> Fieldless1 { Fieldless1::A }
#[automatically_derived]
#[automatically_derived]
impl ::core::fmt::Debug for Fieldless1 {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "A")
}
#[automatically_derived]
impl ::core::default::Default for Fieldless1 {
    #[inline]
    #[inline]
    fn default() -> Fieldless1 { Self::A }
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for Fieldless1 {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Fieldless1 { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Fieldless1 {
    #[inline]
    fn eq(&self, other: &Fieldless1) -> bool { true }
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for Fieldless1 { }
#[automatically_derived]
impl ::core::cmp::Eq for Fieldless1 {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Fieldless1 {
    #[inline]
    fn partial_cmp(&self, other: &Fieldless1)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::option::Option::Some(::core::cmp::Ordering::Equal)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for Fieldless1 {
    #[inline]
    fn cmp(&self, other: &Fieldless1) -> ::core::cmp::Ordering {
        ::core::cmp::Ordering::Equal
}


// A C-like, fieldless enum.
pub enum Fieldless {
    #[default]
    A,
    B,
    C,
    C,
}
#[automatically_derived]
impl ::core::clone::Clone for Fieldless {
    #[inline]
    fn clone(&self) -> Fieldless { *self }
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::Copy for Fieldless { }
#[automatically_derived]
impl ::core::fmt::Debug for Fieldless {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Fieldless::A => ::core::fmt::Formatter::write_str(f, "A"),
            Fieldless::B => ::core::fmt::Formatter::write_str(f, "B"),
            Fieldless::C => ::core::fmt::Formatter::write_str(f, "C"),
    }
}
#[automatically_derived]
impl ::core::default::Default for Fieldless {
impl ::core::default::Default for Fieldless {
    #[inline]
    fn default() -> Fieldless { Self::A }
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for Fieldless {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_tag, state)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Fieldless { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Fieldless {
    #[inline]
    fn eq(&self, other: &Fieldless) -> bool {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        __self_tag == __arg1_tag
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for Fieldless { }
#[automatically_derived]
impl ::core::cmp::Eq for Fieldless {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Fieldless {
    #[inline]
    fn partial_cmp(&self, other: &Fieldless)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for Fieldless {
    #[inline]
    fn cmp(&self, other: &Fieldless) -> ::core::cmp::Ordering {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag)
}


// An enum with multiple fieldless and fielded variants.
pub enum Mixed {
    #[default]
    P,
    Q,
    R(u32),
---
}
#[automatically_derived]
impl ::core::clone::Clone for Mixed {
    #[inline]
    fn clone(&self) -> Mixed {
        let _: ::core::clone::AssertParamIsClone<u32>;
        let _: ::core::clone::AssertParamIsClone<Option<u32>>;
        let _: ::core::clone::AssertParamIsClone<Option<i32>>;
        *self
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::Copy for Mixed { }
#[automatically_derived]
impl ::core::fmt::Debug for Mixed {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Mixed::P => ::core::fmt::Formatter::write_str(f, "P"),
            Mixed::Q => ::core::fmt::Formatter::write_str(f, "Q"),
            Mixed::R(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "R",
                    &__self_0),
            Mixed::S { d1: __self_0, d2: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f, "S",
                    "d1", &__self_0, "d2", &__self_1),
    }
}
#[automatically_derived]
impl ::core::default::Default for Mixed {
impl ::core::default::Default for Mixed {
    #[inline]
    fn default() -> Mixed { Self::P }
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for Mixed {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_tag, state);
        match self {
            Mixed::R(__self_0) => ::core::hash::Hash::hash(__self_0, state),
            Mixed::S { d1: __self_0, d2: __self_1 } => {
                ::core::hash::Hash::hash(__self_0, state);
                ::core::hash::Hash::hash(__self_1, state)
            _ => {}
        }
    }
}
}
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Mixed { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Mixed {
    #[inline]
    fn eq(&self, other: &Mixed) -> bool {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        __self_tag == __arg1_tag &&
            match (self, other) {
                (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
                    *__self_0 == *__arg1_0,
                (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
                    d1: __arg1_0, d2: __arg1_1 }) =>
                    *__self_0 == *__arg1_0 && *__self_1 == *__arg1_1,
            }
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for Mixed { }
#[automatically_derived]
impl ::core::cmp::Eq for Mixed {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
        let _: ::core::cmp::AssertParamIsEq<Option<u32>>;
        let _: ::core::cmp::AssertParamIsEq<Option<i32>>;
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Mixed {
    #[inline]
    fn partial_cmp(&self, other: &Mixed)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match (self, other) {
                    (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
                    (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
                        d1: __arg1_0, d2: __arg1_1 }) =>
                        match ::core::cmp::PartialOrd::partial_cmp(__self_0,
                                __arg1_0) {
                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                => ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1),
                            cmp => cmp,
                    _ =>
                    _ =>
                        ::core::option::Option::Some(::core::cmp::Ordering::Equal),
            cmp => cmp,
        }
    }
}
}
#[automatically_derived]
impl ::core::cmp::Ord for Mixed {
    #[inline]
    fn cmp(&self, other: &Mixed) -> ::core::cmp::Ordering {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) {
            ::core::cmp::Ordering::Equal =>
                match (self, other) {
                    (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
                        d1: __arg1_0, d2: __arg1_1 }) =>
                        match ::core::cmp::Ord::cmp(__self_0, __arg1_0) {
                            ::core::cmp::Ordering::Equal =>
                                ::core::cmp::Ord::cmp(__self_1, __arg1_1),
                            cmp => cmp,
                        },
                    _ => ::core::cmp::Ordering::Equal,
            cmp => cmp,
        }
    }
}
}

// An enum with no fieldless variants. Note that `Default` cannot be derived
// for this enum.
pub enum Fielded { X(u32), Y(bool), Z(Option<i32>), }
#[automatically_derived]
impl ::core::clone::Clone for Fielded {
    fn clone(&self) -> Fielded {
        match self {
        match self {
            Fielded::X(__self_0) =>
                Fielded::X(::core::clone::Clone::clone(__self_0)),
            Fielded::Y(__self_0) =>
                Fielded::Y(::core::clone::Clone::clone(__self_0)),
            Fielded::Z(__self_0) =>
                Fielded::Z(::core::clone::Clone::clone(__self_0)),
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::fmt::Debug for Fielded {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Fielded::X(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "X",
                    &__self_0),
            Fielded::Y(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Y",
                    &__self_0),
            Fielded::Z(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Z",
                    &__self_0),
    }
}
#[automatically_derived]
impl ::core::hash::Hash for Fielded {
impl ::core::hash::Hash for Fielded {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_tag, state);
        match self {
            Fielded::X(__self_0) => ::core::hash::Hash::hash(__self_0, state),
            Fielded::Y(__self_0) => ::core::hash::Hash::hash(__self_0, state),
            Fielded::Z(__self_0) => ::core::hash::Hash::hash(__self_0, state),
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Fielded { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Fielded {
    #[inline]
    fn eq(&self, other: &Fielded) -> bool {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        __self_tag == __arg1_tag &&
            match (self, other) {
                (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
                    *__self_0 == *__arg1_0,
                (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
                    *__self_0 == *__arg1_0,
                (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
                    *__self_0 == *__arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for Fielded { }
#[automatically_derived]
impl ::core::cmp::Eq for Fielded {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
        let _: ::core::cmp::AssertParamIsEq<bool>;
        let _: ::core::cmp::AssertParamIsEq<Option<i32>>;
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Fielded {
    #[inline]
    fn partial_cmp(&self, other: &Fielded)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match (self, other) {
                    (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
                    (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
                    (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
                    _ => unsafe { ::core::intrinsics::unreachable() }
            cmp => cmp,
        }
    }
}
}
#[automatically_derived]
impl ::core::cmp::Ord for Fielded {
    #[inline]
    fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) {
            ::core::cmp::Ordering::Equal =>
                match (self, other) {
                    (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    _ => unsafe { ::core::intrinsics::unreachable() }
            cmp => cmp,
        }
    }
}
}

// A union. Most builtin traits are not derivable for unions.
pub union Union {
    pub b: bool,
    pub u: u32,
    pub i: i32,
#[automatically_derived]
impl ::core::clone::Clone for Union {
    #[inline]
    fn clone(&self) -> Union {
    fn clone(&self) -> Union {
        let _: ::core::clone::AssertParamIsCopy<Self>;
        *self
}
#[automatically_derived]
impl ::core::marker::Copy for Union { }


pub enum Void {}
#[automatically_derived]
impl ::core::clone::Clone for Void {
    #[inline]
    fn clone(&self) -> Void { *self }
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::Copy for Void { }
#[automatically_derived]
impl ::core::fmt::Debug for Void {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        unsafe { ::core::intrinsics::unreachable() }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for Void {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        unsafe { ::core::intrinsics::unreachable() }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Void { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Void {
    #[inline]
    fn eq(&self, other: &Void) -> bool {
        unsafe { ::core::intrinsics::unreachable() }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for Void { }
#[automatically_derived]
impl ::core::cmp::Eq for Void {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Void {
    #[inline]
    fn partial_cmp(&self, other: &Void)
        -> ::core::option::Option<::core::cmp::Ordering> {
        unsafe { ::core::intrinsics::unreachable() }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for Void {
    #[inline]
    fn cmp(&self, other: &Void) -> ::core::cmp::Ordering {
        unsafe { ::core::intrinsics::unreachable() }
}

pub struct WithUninhabited {
    x: u32,
    x: u32,
    v: Void,
    y: u32,
}
#[automatically_derived]
impl ::core::clone::Clone for WithUninhabited {
    #[inline]
    fn clone(&self) -> WithUninhabited {
        let _: ::core::clone::AssertParamIsClone<u32>;
        let _: ::core::clone::AssertParamIsClone<Void>;
        *self
}
#[automatically_derived]
impl ::core::marker::Copy for WithUninhabited { }
#[automatically_derived]
#[automatically_derived]
impl ::core::fmt::Debug for WithUninhabited {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f,
            "WithUninhabited", "x", &&self.x, "v", &&self.v, "y", &&self.y)
}
#[automatically_derived]
impl ::core::hash::Hash for WithUninhabited {
impl ::core::hash::Hash for WithUninhabited {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&self.x, state);
        ::core::hash::Hash::hash(&self.v, state);
        ::core::hash::Hash::hash(&self.y, state)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for WithUninhabited { }
#[automatically_derived]
impl ::core::cmp::PartialEq for WithUninhabited {
    #[inline]
    fn eq(&self, other: &WithUninhabited) -> bool {
        self.x == other.x && self.v == other.v && self.y == other.y
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for WithUninhabited { }
#[automatically_derived]
impl ::core::cmp::Eq for WithUninhabited {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
        let _: ::core::cmp::AssertParamIsEq<Void>;
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for WithUninhabited {
    #[inline]
    #[inline]
    fn partial_cmp(&self, other: &WithUninhabited)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.x, &other.x) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match ::core::cmp::PartialOrd::partial_cmp(&self.v, &other.v)
                    {
                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                        => ::core::cmp::PartialOrd::partial_cmp(&self.y, &other.y),
                    cmp => cmp,
            cmp => cmp,
        }
    }
}
}
#[automatically_derived]
impl ::core::cmp::Ord for WithUninhabited {
    #[inline]
    fn cmp(&self, other: &WithUninhabited) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.x, &other.x) {
            ::core::cmp::Ordering::Equal =>
                match ::core::cmp::Ord::cmp(&self.v, &other.v) {
                    ::core::cmp::Ordering::Equal =>
                        ::core::cmp::Ord::cmp(&self.y, &other.y),
                    cmp => cmp,
            cmp => cmp,
        }
    }
}
}

pub enum EnumWithUninhabited { A(u32), B(Void), C(u16), }
#[automatically_derived]
impl ::core::clone::Clone for EnumWithUninhabited {
    #[inline]
    fn clone(&self) -> EnumWithUninhabited {
        let _: ::core::clone::AssertParamIsClone<u32>;
        let _: ::core::clone::AssertParamIsClone<Void>;
        let _: ::core::clone::AssertParamIsClone<u16>;
        *self
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::Copy for EnumWithUninhabited { }
#[automatically_derived]
impl ::core::fmt::Debug for EnumWithUninhabited {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            EnumWithUninhabited::A(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "A",
                    &__self_0),
            EnumWithUninhabited::B(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "B",
                    &__self_0),
            EnumWithUninhabited::C(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "C",
                    &__self_0),
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for EnumWithUninhabited {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_tag, state);
        match self {
            EnumWithUninhabited::A(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            EnumWithUninhabited::B(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            EnumWithUninhabited::C(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for EnumWithUninhabited { }
#[automatically_derived]
impl ::core::cmp::PartialEq for EnumWithUninhabited {
    #[inline]
    fn eq(&self, other: &EnumWithUninhabited) -> bool {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        __self_tag == __arg1_tag &&
            match (self, other) {
                (EnumWithUninhabited::A(__self_0),
                    EnumWithUninhabited::A(__arg1_0)) => *__self_0 == *__arg1_0,
                (EnumWithUninhabited::B(__self_0),
                    EnumWithUninhabited::B(__arg1_0)) => *__self_0 == *__arg1_0,
                (EnumWithUninhabited::C(__self_0),
                    EnumWithUninhabited::C(__arg1_0)) => *__self_0 == *__arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::StructuralEq for EnumWithUninhabited { }
#[automatically_derived]
impl ::core::cmp::Eq for EnumWithUninhabited {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
        let _: ::core::cmp::AssertParamIsEq<Void>;
        let _: ::core::cmp::AssertParamIsEq<u16>;
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for EnumWithUninhabited {
    #[inline]
    fn partial_cmp(&self, other: &EnumWithUninhabited)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match (self, other) {
                    (EnumWithUninhabited::A(__self_0),
                        EnumWithUninhabited::A(__arg1_0)) =>
                        ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),

@cjgillot
Copy link
Contributor

As lifetimes are not meaningful in this check, you can call tcx.erase_regions on the types before calling the query.

@camsteffen
Copy link
Contributor Author

As lifetimes are not meaningful in this check, you can call tcx.erase_regions on the types before calling the query.

Then I bump into type variables should not be hashed. Is freshen (last commit) good here?

@compiler-errors
Copy link
Member

I'm not too familiar with this PR so take my advice with a grain of salt, but if you're performing a query on a type that has inference variables, and then returning a response that relates to those inference variables, you really should be canonicalizing: https://doc.rust-lang.org/stable/nightly-rustc/rustc_infer/infer/canonical/canonicalizer/struct.Canonicalizer.html#method.canonicalize

@cjgillot
Copy link
Contributor

I think that ICE saved us from an hard-to-debug issue.
The current impl of inhabited_predicate_type does not handle type variables. So having the query system preventing us from doing that is a good thing.

There are 2 cases:

  • either we are sufficiently late in the type-checking and we can resolve the variables --> call tcx.erase_regions(self.resolve_vars_if_possible(ty));
  • either we are not, the above call will still contain inference variables, and the check will have to be skipped.

IIUC, the goal of the call to inhabited_predicate_type is to diagnose unreachable expressions. Can this check be delayed after type inference? Delaying this will allow to use self.fully_resolve which always returns a fully resolved type, suitable for the query.

@camsteffen
Copy link
Contributor Author

IIUC, the goal of the call to inhabited_predicate_type is to diagnose unreachable expressions. Can this check be delayed after type inference?

If it's just for the unreachable_code lint then that would be easy enough. But this affects typeck a little bit more than that. See here and the change to src/test/ui/break-diverging-value.rs.

@cjgillot
Copy link
Contributor

After thinking a bit more about what happens, I agree that using freshen is the right thing to do. It will infer variables where possible, erase lifetimes, and replace remaining infer vars by fresh vars that are ok to be hashed.
The analysis is a bit more conservative than it could as it will consider fresh infer types as inhabited, which is probably not an issue.
The failure looks unrelated to the typeck changes, probably just needs re-blessing a ui/deriving test.

Splitting the unreachable code lint out may be a good idea, but that's out of the scope of this PR.

@camsteffen
Copy link
Contributor Author

The analysis is a bit more conservative than it could as it will consider fresh infer types as inhabited, which is probably not an issue.

Is this really okay? I'm worried that such cases are not well defined. Like if we make resolve_vars_if_possible "smarter" in the future, we will inadvertently change some behavior with uninhabited types.

Splitting the unreachable code lint out may be a good idea, but that's out of the scope of this PR.

Agreed.

@cjgillot
Copy link
Contributor

resolve_vars_if_possible probably won't get smarter, but it's results depend on the unification state of the type checker. Notably, on the order in which expressions are checked for type inference. I'll have to read the surrounding code more precisely to see how that order interferes with the uninhabited check.

@bors
Copy link
Contributor

bors commented Nov 3, 2022

☔ The latest upstream changes (presumably #103904) made this pull request unmergeable. Please resolve the merge conflicts.

@oli-obk oli-obk added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 10, 2023
@camsteffen
Copy link
Contributor Author

Unfortunately I haven't had much time for rust lately. @cjgillot PM'ed me and offered to take over here. I'm just going to close this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-testsuite Area: The testsuite used to check the correctness of rustc disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. perf-regression Performance regression. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.