1
Fork 0

Auto merge of #99046 - nnethercote:final-derive-output-improvements, r=Mark-Simulacrum

Final derive output improvements

With all these changes, the derive output in `deriving-all-codegen.stdout` is pretty close to optimal, i.e. very similar to what you'd write by hand.

r? `@ghost`
This commit is contained in:
bors 2022-07-15 14:30:14 +00:00
commit 0fe5390a88
11 changed files with 720 additions and 578 deletions

View file

@ -148,7 +148,7 @@ fn cs_clone_simple(
), ),
} }
} }
BlockOrExpr::new_mixed(stmts, cx.expr_deref(trait_span, cx.expr_self(trait_span))) BlockOrExpr::new_mixed(stmts, Some(cx.expr_deref(trait_span, cx.expr_self(trait_span))))
} }
fn cs_clone( fn cs_clone(
@ -161,7 +161,7 @@ fn cs_clone(
let all_fields; let all_fields;
let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]); let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]);
let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo| { let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo| {
let args = vec![cx.expr_addr_of(field.span, field.self_expr.clone())]; let args = vec![field.self_expr.clone()];
cx.expr_call_global(field.span, fn_path.clone(), args) cx.expr_call_global(field.span, fn_path.clone(), args)
}; };
@ -177,9 +177,7 @@ fn cs_clone(
all_fields = af; all_fields = af;
vdata = &variant.data; vdata = &variant.data;
} }
EnumNonMatchingCollapsed(..) => { EnumTag(..) => cx.span_bug(trait_span, &format!("enum tags in `derive({})`", name,)),
cx.span_bug(trait_span, &format!("non-matching enum variants in `derive({})`", name,))
}
StaticEnum(..) | StaticStruct(..) => { StaticEnum(..) | StaticStruct(..) => {
cx.span_bug(trait_span, &format!("associated function in `derive({})`", name)) cx.span_bug(trait_span, &format!("associated function in `derive({})`", name))
} }

View file

@ -63,10 +63,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> Bl
let [other_expr] = &field.other_selflike_exprs[..] else { let [other_expr] = &field.other_selflike_exprs[..] else {
cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`"); cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
}; };
let args = vec![ let args = vec![field.self_expr.clone(), other_expr.clone()];
cx.expr_addr_of(field.span, field.self_expr.clone()),
cx.expr_addr_of(field.span, other_expr.clone()),
];
cx.expr_call_global(field.span, cmp_path.clone(), args) cx.expr_call_global(field.span, cmp_path.clone(), args)
} }
CsFold::Combine(span, expr1, expr2) => { CsFold::Combine(span, expr1, expr2) => {
@ -76,16 +73,6 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> Bl
cx.expr_match(span, expr2, vec![eq_arm, neq_arm]) cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
} }
CsFold::Fieldless => cx.expr_path(equal_path.clone()), CsFold::Fieldless => cx.expr_path(equal_path.clone()),
CsFold::EnumNonMatching(span, tag_tuple) => {
if tag_tuple.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`")
} else {
let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0]));
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[1]));
let fn_cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);
cx.expr_call_global(span, fn_cmp_path, vec![lft, rgt])
}
}
}, },
); );
BlockOrExpr::new_expr(expr) BlockOrExpr::new_expr(expr)

View file

@ -2,7 +2,8 @@ use crate::deriving::generic::ty::*;
use crate::deriving::generic::*; use crate::deriving::generic::*;
use crate::deriving::{path_local, path_std}; use crate::deriving::{path_local, path_std};
use rustc_ast::{BinOpKind, MetaItem}; use rustc_ast::ptr::P;
use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability};
use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::Span; use rustc_span::Span;
@ -32,11 +33,24 @@ pub fn expand_deriving_partial_eq(
let [other_expr] = &field.other_selflike_exprs[..] else { let [other_expr] = &field.other_selflike_exprs[..] else {
cx.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`"); cx.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
}; };
cx.expr_binary(field.span, op, field.self_expr.clone(), other_expr.clone())
// We received `&T` arguments. Convert them to `T` by
// stripping `&` or adding `*`. This isn't necessary for
// type checking, but it results in much better error
// messages if something goes wrong.
let convert = |expr: &P<Expr>| {
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) =
&expr.kind
{
inner.clone()
} else {
cx.expr_deref(field.span, expr.clone())
}
};
cx.expr_binary(field.span, op, convert(&field.self_expr), convert(other_expr))
} }
CsFold::Combine(span, expr1, expr2) => cx.expr_binary(span, combiner, expr1, expr2), CsFold::Combine(span, expr1, expr2) => cx.expr_binary(span, combiner, expr1, expr2),
CsFold::Fieldless => cx.expr_bool(span, base), CsFold::Fieldless => cx.expr_bool(span, base),
CsFold::EnumNonMatching(span, _tag_tuple) => cx.expr_bool(span, !base),
}, },
); );
BlockOrExpr::new_expr(expr) BlockOrExpr::new_expr(expr)

View file

@ -71,10 +71,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
let [other_expr] = &field.other_selflike_exprs[..] else { let [other_expr] = &field.other_selflike_exprs[..] else {
cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`"); cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
}; };
let args = vec![ let args = vec![field.self_expr.clone(), other_expr.clone()];
cx.expr_addr_of(field.span, field.self_expr.clone()),
cx.expr_addr_of(field.span, other_expr.clone()),
];
cx.expr_call_global(field.span, partial_cmp_path.clone(), args) cx.expr_call_global(field.span, partial_cmp_path.clone(), args)
} }
CsFold::Combine(span, expr1, expr2) => { CsFold::Combine(span, expr1, expr2) => {
@ -85,17 +82,6 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
cx.expr_match(span, expr2, vec![eq_arm, neq_arm]) cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
} }
CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())), CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())),
CsFold::EnumNonMatching(span, tag_tuple) => {
if tag_tuple.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
} else {
let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0]));
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[1]));
let fn_partial_cmp_path =
cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
cx.expr_call_global(span, fn_partial_cmp_path, vec![lft, rgt])
}
}
}, },
); );
BlockOrExpr::new_expr(expr) BlockOrExpr::new_expr(expr)

View file

@ -45,7 +45,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
let (ident, vdata, fields) = match substr.fields { let (ident, vdata, fields) = match substr.fields {
Struct(vdata, fields) => (substr.type_ident, *vdata, fields), Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields), EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { EnumTag(..) | StaticStruct(..) | StaticEnum(..) => {
cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
} }
}; };
@ -95,9 +95,8 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
); );
args.push(name); args.push(name);
} }
// Use double indirection to make sure this works for unsized types // Use an extra indirection to make sure this works for unsized types.
let field = cx.expr_addr_of(field.span, field.self_expr.clone()); let field = cx.expr_addr_of(field.span, field.self_expr.clone());
let field = cx.expr_addr_of(field.span, field);
args.push(field); args.push(field);
} }
let expr = cx.expr_call_global(span, fn_path_debug, args); let expr = cx.expr_call_global(span, fn_path_debug, args);
@ -115,9 +114,9 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
)); ));
} }
// Use double indirection to make sure this works for unsized types // Use an extra indirection to make sure this works for unsized types.
let value_ref = cx.expr_addr_of(field.span, field.self_expr.clone()); let field = cx.expr_addr_of(field.span, field.self_expr.clone());
value_exprs.push(cx.expr_addr_of(field.span, value_ref)); value_exprs.push(field);
} }
// `let names: &'static _ = &["field1", "field2"];` // `let names: &'static _ = &["field1", "field2"];`
@ -177,6 +176,6 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
stmts.push(names_let.unwrap()); stmts.push(names_let.unwrap());
} }
stmts.push(values_let); stmts.push(values_let);
BlockOrExpr::new_mixed(stmts, expr) BlockOrExpr::new_mixed(stmts, Some(expr))
} }
} }

View file

@ -287,7 +287,7 @@ fn encodable_substructure(
fn_emit_enum_path, fn_emit_enum_path,
vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk], vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk],
); );
BlockOrExpr::new_mixed(vec![me], expr) BlockOrExpr::new_mixed(vec![me], Some(expr))
} }
_ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"), _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"),

View file

@ -21,21 +21,14 @@
//! `struct T(i32, char)`). //! `struct T(i32, char)`).
//! - `EnumMatching`, when `Self` is an enum and all the arguments are the //! - `EnumMatching`, when `Self` is an enum and all the arguments are the
//! same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`) //! same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`)
//! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments //! - `EnumTag` when `Self` is an enum, for comparing the enum tags.
//! are not the same variant (e.g., `None`, `Some(1)` and `None`).
//! - `StaticEnum` and `StaticStruct` for static methods, where the type //! - `StaticEnum` and `StaticStruct` for static methods, where the type
//! being derived upon is either an enum or struct respectively. (Any //! being derived upon is either an enum or struct respectively. (Any
//! argument with type Self is just grouped among the non-self //! argument with type Self is just grouped among the non-self
//! arguments.) //! arguments.)
//! //!
//! In the first two cases, the values from the corresponding fields in //! In the first two cases, the values from the corresponding fields in
//! all the arguments are grouped together. For `EnumNonMatchingCollapsed` //! all the arguments are grouped together.
//! this isn't possible (different variants have different fields), so the
//! fields are inaccessible. (Previous versions of the deriving infrastructure
//! had a way to expand into code that could access them, at the cost of
//! generating exponential amounts of code; see issue #15375). There are no
//! fields with values in the static cases, so these are treated entirely
//! differently.
//! //!
//! The non-static cases have `Option<ident>` in several places associated //! The non-static cases have `Option<ident>` in several places associated
//! with field `expr`s. This represents the name of the field it is //! with field `expr`s. This represents the name of the field it is
@ -142,21 +135,15 @@
//! }]) //! }])
//! ``` //! ```
//! //!
//! For `C0(a)` and `C1 {x}` , //! For the tags,
//! //!
//! ```{.text} //! ```{.text}
//! EnumNonMatchingCollapsed( //! EnumTag(
//! &[<ident for self index value>, <ident of __arg_1 index value>]) //! &[<ident of self tag>, <ident of other tag>], <expr to combine with>)
//! ``` //! ```
//! //! Note that this setup doesn't allow for the brute-force "match every variant
//! It is the same for when the arguments are flipped to `C1 {x}` and //! against every other variant" approach, which is bad because it produces a
//! `C0(a)`; the only difference is what the values of the identifiers //! quadratic amount of code (see #15375).
//! <ident for self index value> and <ident of __arg_1 index value> will
//! be in the generated code.
//!
//! `EnumNonMatchingCollapsed` deliberately provides far less information
//! than is generally available for a given pair of variants; see #15375
//! for discussion.
//! //!
//! ## Static //! ## Static
//! //!
@ -180,10 +167,9 @@ use std::iter;
use std::vec; use std::vec;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::{self as ast, BinOpKind, EnumDef, Expr, Generics, PatKind}; use rustc_ast::{self as ast, EnumDef, Expr, Generics, PatKind};
use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_ast::{GenericArg, GenericParamKind, VariantData};
use rustc_attr as attr; use rustc_attr as attr;
use rustc_data_structures::map_in_place::MapInPlace;
use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span; use rustc_span::Span;
@ -236,6 +222,8 @@ pub struct MethodDef<'a> {
pub attributes: Vec<ast::Attribute>, pub attributes: Vec<ast::Attribute>,
/// Can we combine fieldless variants for enums into a single match arm? /// Can we combine fieldless variants for enums into a single match arm?
/// If true, indicates that the trait operation uses the enum tag in some
/// way.
pub unify_fieldless_variants: bool, pub unify_fieldless_variants: bool,
pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>, pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
@ -275,19 +263,22 @@ pub enum StaticFields {
/// A summary of the possible sets of fields. /// A summary of the possible sets of fields.
pub enum SubstructureFields<'a> { pub enum SubstructureFields<'a> {
/// A non-static method with `Self` is a struct.
Struct(&'a ast::VariantData, Vec<FieldInfo>), Struct(&'a ast::VariantData, Vec<FieldInfo>),
/// Matching variants of the enum: variant index, variant count, ast::Variant, /// Matching variants of the enum: variant index, variant count, ast::Variant,
/// fields: the field name is only non-`None` in the case of a struct /// fields: the field name is only non-`None` in the case of a struct
/// variant. /// variant.
EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo>), EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo>),
/// Non-matching variants of the enum, but with all state hidden from the /// The tag of an enum. The first field is a `FieldInfo` for the tags, as
/// consequent code. The field is a list of `Ident`s bound to the variant /// if they were fields. The second field is the expression to combine the
/// index values for each of the actual input `Self` arguments. /// tag expression with; it will be `None` if no match is necessary.
EnumNonMatchingCollapsed(&'a [Ident]), EnumTag(FieldInfo, Option<P<Expr>>),
/// A static method where `Self` is a struct. /// A static method where `Self` is a struct.
StaticStruct(&'a ast::VariantData, StaticFields), StaticStruct(&'a ast::VariantData, StaticFields),
/// A static method where `Self` is an enum. /// A static method where `Self` is an enum.
StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>), StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
} }
@ -325,8 +316,8 @@ impl BlockOrExpr {
BlockOrExpr(vec![], Some(expr)) BlockOrExpr(vec![], Some(expr))
} }
pub fn new_mixed(stmts: Vec<ast::Stmt>, expr: P<Expr>) -> BlockOrExpr { pub fn new_mixed(stmts: Vec<ast::Stmt>, expr: Option<P<Expr>>) -> BlockOrExpr {
BlockOrExpr(stmts, Some(expr)) BlockOrExpr(stmts, expr)
} }
// Converts it into a block. // Converts it into a block.
@ -344,7 +335,14 @@ impl BlockOrExpr {
None => cx.expr_block(cx.block(span, vec![])), None => cx.expr_block(cx.block(span, vec![])),
Some(expr) => expr, Some(expr) => expr,
} }
} else if self.0.len() == 1
&& let ast::StmtKind::Expr(expr) = &self.0[0].kind
&& self.1.is_none()
{
// There's only a single statement expression. Pull it out.
expr.clone()
} else { } else {
// Multiple statements and/or expressions.
cx.expr_block(self.into_block(cx, span)) cx.expr_block(self.into_block(cx, span))
} }
} }
@ -455,7 +453,6 @@ impl<'a> TraitDef<'a> {
}; };
let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id); let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id);
let use_temporaries = is_packed && always_copy;
let newitem = match item.kind { let newitem = match item.kind {
ast::ItemKind::Struct(ref struct_def, ref generics) => self.expand_struct_def( ast::ItemKind::Struct(ref struct_def, ref generics) => self.expand_struct_def(
@ -464,11 +461,11 @@ impl<'a> TraitDef<'a> {
item.ident, item.ident,
generics, generics,
from_scratch, from_scratch,
use_temporaries,
is_packed, is_packed,
always_copy,
), ),
ast::ItemKind::Enum(ref enum_def, ref generics) => { ast::ItemKind::Enum(ref enum_def, ref generics) => {
// We ignore `use_temporaries` here, because // We ignore `is_packed`/`always_copy` here, because
// `repr(packed)` enums cause an error later on. // `repr(packed)` enums cause an error later on.
// //
// This can only cause further compilation errors // This can only cause further compilation errors
@ -484,8 +481,8 @@ impl<'a> TraitDef<'a> {
item.ident, item.ident,
generics, generics,
from_scratch, from_scratch,
use_temporaries,
is_packed, is_packed,
always_copy,
) )
} else { } else {
cx.span_err(mitem.span, "this trait cannot be derived for unions"); cx.span_err(mitem.span, "this trait cannot be derived for unions");
@ -766,8 +763,8 @@ impl<'a> TraitDef<'a> {
type_ident: Ident, type_ident: Ident,
generics: &Generics, generics: &Generics,
from_scratch: bool, from_scratch: bool,
use_temporaries: bool,
is_packed: bool, is_packed: bool,
always_copy: bool,
) -> P<ast::Item> { ) -> P<ast::Item> {
let field_tys: Vec<P<ast::Ty>> = let field_tys: Vec<P<ast::Ty>> =
struct_def.fields().iter().map(|field| field.ty.clone()).collect(); struct_def.fields().iter().map(|field| field.ty.clone()).collect();
@ -795,8 +792,8 @@ impl<'a> TraitDef<'a> {
type_ident, type_ident,
&selflike_args, &selflike_args,
&nonselflike_args, &nonselflike_args,
use_temporaries,
is_packed, is_packed,
always_copy,
) )
}; };
@ -937,9 +934,7 @@ impl<'a> MethodDef<'a> {
match ty { match ty {
// Selflike (`&Self`) arguments only occur in non-static methods. // Selflike (`&Self`) arguments only occur in non-static methods.
Ref(box Self_, _) if !self.is_static() => { Ref(box Self_, _) if !self.is_static() => selflike_args.push(arg_expr),
selflike_args.push(cx.expr_deref(span, arg_expr))
}
Self_ => cx.span_bug(span, "`Self` in non-return position"), Self_ => cx.span_bug(span, "`Self` in non-return position"),
_ => nonselflike_args.push(arg_expr), _ => nonselflike_args.push(arg_expr),
} }
@ -1008,7 +1003,7 @@ impl<'a> MethodDef<'a> {
/// ``` /// ```
/// #[derive(PartialEq)] /// #[derive(PartialEq)]
/// # struct Dummy; /// # struct Dummy;
/// struct A { x: i32, y: i32 } /// struct A { x: u8, y: u8 }
/// ///
/// // equivalent to: /// // equivalent to:
/// impl PartialEq for A { /// impl PartialEq for A {
@ -1018,11 +1013,27 @@ impl<'a> MethodDef<'a> {
/// } /// }
/// ``` /// ```
/// But if the struct is `repr(packed)`, we can't use something like /// But if the struct is `repr(packed)`, we can't use something like
/// `&self.x` on a packed type (as required for e.g. `Debug` and `Hash`) /// `&self.x` because that might cause an unaligned ref. So for any trait
/// because that might cause an unaligned ref. So we use let-destructuring /// method that takes a reference, if the struct impls `Copy` then we use a
/// instead. /// local block to force a copy:
/// ``` /// ```
/// # struct A { x: i32, y: i32 } /// # struct A { x: u8, y: u8 }
/// impl PartialEq for A {
/// fn eq(&self, other: &A) -> bool {
/// // Desugars to `{ self.x }.eq(&{ other.y }) && ...`
/// { self.x } == { other.y } && { self.y } == { other.y }
/// }
/// }
/// impl Hash for A {
/// fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
/// ::core::hash::Hash::hash(&{ self.x }, state);
/// ::core::hash::Hash::hash(&{ self.y }, state)
/// }
/// }
/// ```
/// If the struct doesn't impl `Copy`, we use let-destructuring with `ref`:
/// ```
/// # struct A { x: u8, y: u8 }
/// impl PartialEq for A { /// impl PartialEq for A {
/// fn eq(&self, other: &A) -> bool { /// fn eq(&self, other: &A) -> bool {
/// let Self { x: ref __self_0_0, y: ref __self_0_1 } = *self; /// let Self { x: ref __self_0_0, y: ref __self_0_1 } = *self;
@ -1031,6 +1042,8 @@ impl<'a> MethodDef<'a> {
/// } /// }
/// } /// }
/// ``` /// ```
/// This latter case only works if the fields match the alignment required
/// by the `packed(N)` attribute. (We'll get errors later on if not.)
fn expand_struct_method_body<'b>( fn expand_struct_method_body<'b>(
&self, &self,
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
@ -1039,8 +1052,8 @@ impl<'a> MethodDef<'a> {
type_ident: Ident, type_ident: Ident,
selflike_args: &[P<Expr>], selflike_args: &[P<Expr>],
nonselflike_args: &[P<Expr>], nonselflike_args: &[P<Expr>],
use_temporaries: bool,
is_packed: bool, is_packed: bool,
always_copy: bool,
) -> BlockOrExpr { ) -> BlockOrExpr {
let span = trait_.span; let span = trait_.span;
assert!(selflike_args.len() == 1 || selflike_args.len() == 2); assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
@ -1057,29 +1070,31 @@ impl<'a> MethodDef<'a> {
if !is_packed { if !is_packed {
let selflike_fields = let selflike_fields =
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def); trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, false);
mk_body(cx, selflike_fields)
} else if always_copy {
let selflike_fields =
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, true);
mk_body(cx, selflike_fields) mk_body(cx, selflike_fields)
} else { } else {
// Neither packed nor copy. Need to use ref patterns.
let prefixes: Vec<_> = let prefixes: Vec<_> =
(0..selflike_args.len()).map(|i| format!("__self_{}", i)).collect(); (0..selflike_args.len()).map(|i| format!("__self_{}", i)).collect();
let addr_of = always_copy;
let selflike_fields = let selflike_fields =
trait_.create_struct_pattern_fields(cx, struct_def, &prefixes, use_temporaries); trait_.create_struct_pattern_fields(cx, struct_def, &prefixes, addr_of);
let mut body = mk_body(cx, selflike_fields); let mut body = mk_body(cx, selflike_fields);
let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]); let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]);
let patterns = trait_.create_struct_patterns( let use_ref_pat = is_packed && !always_copy;
cx, let patterns =
struct_path, trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, use_ref_pat);
struct_def,
&prefixes,
ast::Mutability::Not,
use_temporaries,
);
// Do the let-destructuring. // Do the let-destructuring.
let mut stmts: Vec<_> = iter::zip(selflike_args, patterns) let mut stmts: Vec<_> = iter::zip(selflike_args, patterns)
.map(|(selflike_arg_expr, pat)| { .map(|(selflike_arg_expr, pat)| {
cx.stmt_let_pat(span, pat, selflike_arg_expr.clone()) let selflike_arg_expr = cx.expr_deref(span, selflike_arg_expr.clone());
cx.stmt_let_pat(span, pat, selflike_arg_expr)
}) })
.collect(); .collect();
stmts.extend(std::mem::take(&mut body.0)); stmts.extend(std::mem::take(&mut body.0));
@ -1119,82 +1134,128 @@ impl<'a> MethodDef<'a> {
/// impl ::core::cmp::PartialEq for A { /// impl ::core::cmp::PartialEq for A {
/// #[inline] /// #[inline]
/// fn eq(&self, other: &A) -> bool { /// fn eq(&self, other: &A) -> bool {
/// { /// let __self_tag = ::core::intrinsics::discriminant_value(self);
/// let __self_vi = ::core::intrinsics::discriminant_value(&*self); /// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
/// let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); /// __self_tag == __arg1_tag &&
/// if true && __self_vi == __arg_1_vi { /// match (self, other) {
/// match (&*self, &*other) { /// (A::A2(__self_0), A::A2(__arg1_0)) =>
/// (&A::A2(ref __self_0), &A::A2(ref __arg_1_0)) => /// *__self_0 == *__arg1_0,
/// (*__self_0) == (*__arg_1_0),
/// _ => true, /// _ => true,
/// } /// }
/// } else {
/// false // catch-all handler
/// }
/// }
/// } /// }
/// } /// }
/// ``` /// ```
/// Creates a match for a tuple of all `selflike_args`, where either all /// Creates a tag check combined with a match for a tuple of all
/// variants match, or it falls into a catch-all for when one variant /// `selflike_args`, with an arm for each variant with fields, possibly an
/// does not match. /// arm for each fieldless variant (if `!unify_fieldless_variants` is not
/// /// true), and possibly a default arm.
/// There are N + 1 cases because is a case for each of the N
/// variants where all of the variants match, and one catch-all for
/// when one does not match.
///
/// As an optimization we generate code which checks whether all variants
/// match first which makes llvm see that C-like enums can be compiled into
/// a simple equality check (for PartialEq).
///
/// The catch-all handler is provided access the variant index values
/// for each of the selflike_args, carried in precomputed variables.
fn expand_enum_method_body<'b>( fn expand_enum_method_body<'b>(
&self, &self,
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
trait_: &TraitDef<'b>, trait_: &TraitDef<'b>,
enum_def: &'b EnumDef, enum_def: &'b EnumDef,
type_ident: Ident, type_ident: Ident,
mut selflike_args: Vec<P<Expr>>, selflike_args: Vec<P<Expr>>,
nonselflike_args: &[P<Expr>], nonselflike_args: &[P<Expr>],
) -> BlockOrExpr { ) -> BlockOrExpr {
let span = trait_.span; let span = trait_.span;
let variants = &enum_def.variants; let variants = &enum_def.variants;
// Traits that unify fieldless variants always use the tag(s).
let uses_tags = self.unify_fieldless_variants;
// There is no sensible code to be generated for *any* deriving on a
// zero-variant enum. So we just generate a failing expression.
if variants.is_empty() {
return BlockOrExpr(vec![], Some(deriving::call_unreachable(cx, span)));
}
let prefixes = iter::once("__self".to_string()) let prefixes = iter::once("__self".to_string())
.chain( .chain(
selflike_args selflike_args
.iter() .iter()
.enumerate() .enumerate()
.skip(1) .skip(1)
.map(|(arg_count, _selflike_arg)| format!("__arg_{}", arg_count)), .map(|(arg_count, _selflike_arg)| format!("__arg{}", arg_count)),
) )
.collect::<Vec<String>>(); .collect::<Vec<String>>();
// The `vi_idents` will be bound, solely in the catch-all, to // Build a series of let statements mapping each selflike_arg
// a series of let statements mapping each selflike_arg to an int // to its discriminant value.
// value corresponding to its discriminant. //
let vi_idents = prefixes // e.g. for `PartialEq::eq` builds two statements:
// ```
// let __self_tag = ::core::intrinsics::discriminant_value(self);
// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
// ```
let get_tag_pieces = |cx: &ExtCtxt<'_>| {
let tag_idents: Vec<_> = prefixes
.iter() .iter()
.map(|name| { .map(|name| Ident::from_str_and_span(&format!("{}_tag", name), span))
let vi_suffix = format!("{}_vi", name); .collect();
Ident::from_str_and_span(&vi_suffix, span)
let mut tag_exprs: Vec<_> = tag_idents
.iter()
.map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident)))
.collect();
let self_expr = tag_exprs.remove(0);
let other_selflike_exprs = tag_exprs;
let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };
let tag_let_stmts: Vec<_> = iter::zip(&tag_idents, &selflike_args)
.map(|(&ident, selflike_arg)| {
let variant_value = deriving::call_intrinsic(
cx,
span,
sym::discriminant_value,
vec![selflike_arg.clone()],
);
cx.stmt_let(span, false, ident, variant_value)
}) })
.collect::<Vec<Ident>>(); .collect();
// Builds, via callback to call_substructure_method, the (tag_field, tag_let_stmts)
// delegated expression that handles the catch-all case, };
// using `__variants_tuple` to drive logic if necessary.
let catch_all_substructure = EnumNonMatchingCollapsed(&vi_idents);
let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty()); // There are some special cases involving fieldless enums where no
// match is necessary.
let all_fieldless = variants.iter().all(|v| v.data.fields().is_empty());
if all_fieldless {
if uses_tags && variants.len() > 1 {
// If the type is fieldless and the trait uses the tag and
// there are multiple variants, we need just an operation on
// the tag(s).
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
let mut tag_check = self.call_substructure_method(
cx,
trait_,
type_ident,
nonselflike_args,
&EnumTag(tag_field, None),
);
tag_let_stmts.append(&mut tag_check.0);
return BlockOrExpr(tag_let_stmts, tag_check.1);
}
if variants.len() == 1 {
// If there is a single variant, we don't need an operation on
// the tag(s). Just use the most degenerate result.
return self.call_substructure_method(
cx,
trait_,
type_ident,
nonselflike_args,
&EnumMatching(0, 1, &variants[0], Vec::new()),
);
};
}
// These arms are of the form: // These arms are of the form:
// (Variant1, Variant1, ...) => Body1 // (Variant1, Variant1, ...) => Body1
// (Variant2, Variant2, ...) => Body2 // (Variant2, Variant2, ...) => Body2
// ... // ...
// where each tuple has length = selflike_args.len() // where each tuple has length = selflike_args.len()
let mut match_arms: Vec<ast::Arm> = variants let mut match_arms: Vec<ast::Arm> = variants
.iter() .iter()
.enumerate() .enumerate()
@ -1203,30 +1264,22 @@ impl<'a> MethodDef<'a> {
// A single arm has form (&VariantK, &VariantK, ...) => BodyK // A single arm has form (&VariantK, &VariantK, ...) => BodyK
// (see "Final wrinkle" note below for why.) // (see "Final wrinkle" note below for why.)
let use_temporaries = false; // enums can't be repr(packed) let addr_of = false; // because enums can't be repr(packed)
let fields = trait_.create_struct_pattern_fields( let fields =
cx, trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes, addr_of);
&variant.data,
&prefixes,
use_temporaries,
);
let sp = variant.span.with_ctxt(trait_.span.ctxt()); let sp = variant.span.with_ctxt(trait_.span.ctxt());
let variant_path = cx.path(sp, vec![type_ident, variant.ident]); let variant_path = cx.path(sp, vec![type_ident, variant.ident]);
let mut subpats: Vec<_> = trait_ let use_ref_pat = false; // because enums can't be repr(packed)
.create_struct_patterns( let mut subpats: Vec<_> = trait_.create_struct_patterns(
cx, cx,
variant_path, variant_path,
&variant.data, &variant.data,
&prefixes, &prefixes,
ast::Mutability::Not, use_ref_pat,
use_temporaries, );
)
.into_iter()
.map(|p| cx.pat(span, PatKind::Ref(p, ast::Mutability::Not)))
.collect();
// Here is the pat = `(&VariantK, &VariantK, ...)` // `(VariantK, VariantK, ...)` or just `VariantK`.
let single_pat = if subpats.len() == 1 { let single_pat = if subpats.len() == 1 {
subpats.pop().unwrap() subpats.pop().unwrap()
} else { } else {
@ -1256,27 +1309,28 @@ impl<'a> MethodDef<'a> {
}) })
.collect(); .collect();
// Add a default arm to the match, if necessary.
let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
let default = match first_fieldless { let default = match first_fieldless {
Some(v) if self.unify_fieldless_variants => { Some(v) if self.unify_fieldless_variants => {
// We need a default case that handles the fieldless variants. // We need a default case that handles all the fieldless
// The index and actual variant aren't meaningful in this case, // variants. The index and actual variant aren't meaningful in
// so just use whatever // this case, so just use dummy values.
let substructure = EnumMatching(0, variants.len(), v, Vec::new());
Some( Some(
self.call_substructure_method( self.call_substructure_method(
cx, cx,
trait_, trait_,
type_ident, type_ident,
nonselflike_args, nonselflike_args,
&substructure, &EnumMatching(0, variants.len(), v, Vec::new()),
) )
.into_expr(cx, span), .into_expr(cx, span),
) )
} }
_ if variants.len() > 1 && selflike_args.len() > 1 => { _ if variants.len() > 1 && selflike_args.len() > 1 => {
// Since we know that all the arguments will match if we reach // Because we know that all the arguments will match if we reach
// the match expression we add the unreachable intrinsics as the // the match expression we add the unreachable intrinsics as the
// result of the catch all which should help llvm in optimizing it // result of the default which should help llvm in optimizing it.
Some(deriving::call_unreachable(cx, span)) Some(deriving::call_unreachable(cx, span))
} }
_ => None, _ => None,
@ -1285,111 +1339,41 @@ impl<'a> MethodDef<'a> {
match_arms.push(cx.arm(span, cx.pat_wild(span), arm)); match_arms.push(cx.arm(span, cx.pat_wild(span), arm));
} }
// We will usually need the catch-all after matching the // Create a match expression with one arm per discriminant plus
// tuples `(VariantK, VariantK, ...)` for each VariantK of the // possibly a default arm, e.g.:
// enum. But: // match (self, other) {
//
// * when there is only one Self arg, the arms above suffice
// (and the deriving we call back into may not be prepared to
// handle EnumNonMatchCollapsed), and,
//
// * when the enum has only one variant, the single arm that
// is already present always suffices.
//
// * In either of the two cases above, if we *did* add a
// catch-all `_` match, it would trigger the
// unreachable-pattern error.
//
if variants.len() > 1 && selflike_args.len() > 1 {
// Build a series of let statements mapping each selflike_arg
// to its discriminant value.
//
// i.e., for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
// with three Self args, builds three statements:
// ```
// let __self_vi = std::intrinsics::discriminant_value(&self);
// let __arg_1_vi = std::intrinsics::discriminant_value(&arg1);
// let __arg_2_vi = std::intrinsics::discriminant_value(&arg2);
// ```
let mut index_let_stmts: Vec<ast::Stmt> = Vec::with_capacity(vi_idents.len() + 1);
// We also build an expression which checks whether all discriminants are equal:
// `__self_vi == __arg_1_vi && __self_vi == __arg_2_vi && ...`
let mut discriminant_test = cx.expr_bool(span, true);
for (i, (&ident, selflike_arg)) in iter::zip(&vi_idents, &selflike_args).enumerate() {
let selflike_addr = cx.expr_addr_of(span, selflike_arg.clone());
let variant_value = deriving::call_intrinsic(
cx,
span,
sym::discriminant_value,
vec![selflike_addr],
);
let let_stmt = cx.stmt_let(span, false, ident, variant_value);
index_let_stmts.push(let_stmt);
if i > 0 {
let id0 = cx.expr_ident(span, vi_idents[0]);
let id = cx.expr_ident(span, ident);
let test = cx.expr_binary(span, BinOpKind::Eq, id0, id);
discriminant_test = if i == 1 {
test
} else {
cx.expr_binary(span, BinOpKind::And, discriminant_test, test)
};
}
}
let arm_expr = self
.call_substructure_method(
cx,
trait_,
type_ident,
nonselflike_args,
&catch_all_substructure,
)
.into_expr(cx, span);
// Final wrinkle: the selflike_args are expressions that deref
// down to desired places, but we cannot actually deref
// them when they are fed as r-values into a tuple
// expression; here add a layer of borrowing, turning
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
selflike_args.map_in_place(|selflike_arg| cx.expr_addr_of(span, selflike_arg));
let match_arg = cx.expr(span, ast::ExprKind::Tup(selflike_args));
// Lastly we create an expression which branches on all discriminants being equal
// if discriminant_test {
// match (...) {
// (Variant1, Variant1, ...) => Body1 // (Variant1, Variant1, ...) => Body1
// (Variant2, Variant2, ...) => Body2, // (Variant2, Variant2, ...) => Body2,
// ... // ...
// _ => ::core::intrinsics::unreachable() // _ => ::core::intrinsics::unreachable()
// } // }
// } let get_match_expr = |mut selflike_args: Vec<P<Expr>>| {
// else {
// <delegated expression referring to __self_vi, et al.>
// }
let all_match = cx.expr_match(span, match_arg, match_arms);
let arm_expr = cx.expr_if(span, discriminant_test, all_match, Some(arm_expr));
BlockOrExpr(index_let_stmts, Some(arm_expr))
} else if variants.is_empty() {
// There is no sensible code to be generated for *any* deriving on
// a zero-variant enum. So we just generate a failing expression
// for the zero variant case.
BlockOrExpr(vec![], Some(deriving::call_unreachable(cx, span)))
} else {
// Final wrinkle: the selflike_args are expressions that deref
// down to desired places, but we cannot actually deref
// them when they are fed as r-values into a tuple
// expression; here add a layer of borrowing, turning
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
selflike_args.map_in_place(|selflike_arg| cx.expr_addr_of(span, selflike_arg));
let match_arg = if selflike_args.len() == 1 { let match_arg = if selflike_args.len() == 1 {
selflike_args.pop().unwrap() selflike_args.pop().unwrap()
} else { } else {
cx.expr(span, ast::ExprKind::Tup(selflike_args)) cx.expr(span, ast::ExprKind::Tup(selflike_args))
}; };
BlockOrExpr(vec![], Some(cx.expr_match(span, match_arg, match_arms))) cx.expr_match(span, match_arg, match_arms)
};
// If the trait uses the tag and there are multiple variants, we need
// to add a tag check operation before the match. Otherwise, the match
// is enough.
if uses_tags && variants.len() > 1 {
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
// Combine a tag check with the match.
let mut tag_check_plus_match = self.call_substructure_method(
cx,
trait_,
type_ident,
nonselflike_args,
&EnumTag(tag_field, Some(get_match_expr(selflike_args))),
);
tag_let_stmts.append(&mut tag_check_plus_match.0);
BlockOrExpr(tag_let_stmts, tag_check_plus_match.1)
} else {
BlockOrExpr(vec![], Some(get_match_expr(selflike_args)))
} }
} }
@ -1453,8 +1437,7 @@ impl<'a> TraitDef<'a> {
struct_path: ast::Path, struct_path: ast::Path,
struct_def: &'a VariantData, struct_def: &'a VariantData,
prefixes: &[String], prefixes: &[String],
mutbl: ast::Mutability, use_ref_pat: bool,
use_temporaries: bool,
) -> Vec<P<ast::Pat>> { ) -> Vec<P<ast::Pat>> {
prefixes prefixes
.iter() .iter()
@ -1462,10 +1445,10 @@ impl<'a> TraitDef<'a> {
let pieces_iter = let pieces_iter =
struct_def.fields().iter().enumerate().map(|(i, struct_field)| { struct_def.fields().iter().enumerate().map(|(i, struct_field)| {
let sp = struct_field.span.with_ctxt(self.span.ctxt()); let sp = struct_field.span.with_ctxt(self.span.ctxt());
let binding_mode = if use_temporaries { let binding_mode = if use_ref_pat {
ast::BindingMode::ByValue(ast::Mutability::Not) ast::BindingMode::ByRef(ast::Mutability::Not)
} else { } else {
ast::BindingMode::ByRef(mutbl) ast::BindingMode::ByValue(ast::Mutability::Not)
}; };
let ident = self.mk_pattern_ident(prefix, i); let ident = self.mk_pattern_ident(prefix, i);
let path = ident.with_span_pos(sp); let path = ident.with_span_pos(sp);
@ -1544,7 +1527,7 @@ impl<'a> TraitDef<'a> {
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
struct_def: &'a VariantData, struct_def: &'a VariantData,
prefixes: &[String], prefixes: &[String],
use_temporaries: bool, addr_of: bool,
) -> Vec<FieldInfo> { ) -> Vec<FieldInfo> {
self.create_fields(struct_def, |i, _struct_field, sp| { self.create_fields(struct_def, |i, _struct_field, sp| {
prefixes prefixes
@ -1552,7 +1535,7 @@ impl<'a> TraitDef<'a> {
.map(|prefix| { .map(|prefix| {
let ident = self.mk_pattern_ident(prefix, i); let ident = self.mk_pattern_ident(prefix, i);
let expr = cx.expr_path(cx.path_ident(sp, ident)); let expr = cx.expr_path(cx.path_ident(sp, ident));
if use_temporaries { expr } else { cx.expr_deref(sp, expr) } if addr_of { cx.expr_addr_of(sp, expr) } else { expr }
}) })
.collect() .collect()
}) })
@ -1563,20 +1546,17 @@ impl<'a> TraitDef<'a> {
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,
selflike_args: &[P<Expr>], selflike_args: &[P<Expr>],
struct_def: &'a VariantData, struct_def: &'a VariantData,
copy: bool,
) -> Vec<FieldInfo> { ) -> Vec<FieldInfo> {
self.create_fields(struct_def, |i, struct_field, sp| { self.create_fields(struct_def, |i, struct_field, sp| {
selflike_args selflike_args
.iter() .iter()
.map(|mut selflike_arg| { .map(|selflike_arg| {
// We don't the need the deref, if there is one. // Note: we must use `struct_field.span` rather than `sp` in the
if let ast::ExprKind::Unary(ast::UnOp::Deref, inner) = &selflike_arg.kind {
selflike_arg = inner;
}
// Note: we must use `struct_field.span` rather than `span` in the
// `unwrap_or_else` case otherwise the hygiene is wrong and we get // `unwrap_or_else` case otherwise the hygiene is wrong and we get
// "field `0` of struct `Point` is private" errors on tuple // "field `0` of struct `Point` is private" errors on tuple
// structs. // structs.
cx.expr( let mut field_expr = cx.expr(
sp, sp,
ast::ExprKind::Field( ast::ExprKind::Field(
selflike_arg.clone(), selflike_arg.clone(),
@ -1584,7 +1564,13 @@ impl<'a> TraitDef<'a> {
Ident::from_str_and_span(&i.to_string(), struct_field.span) Ident::from_str_and_span(&i.to_string(), struct_field.span)
}), }),
), ),
) );
if copy {
field_expr = cx.expr_block(
cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]),
);
}
cx.expr_addr_of(sp, field_expr)
}) })
.collect() .collect()
}) })
@ -1605,11 +1591,6 @@ pub enum CsFold<'a> {
// The fallback case for a struct or enum variant with no fields. // The fallback case for a struct or enum variant with no fields.
Fieldless, Fieldless,
/// The fallback case for non-matching enum variants. The slice is the
/// identifiers holding the variant index value for each of the `Self`
/// arguments.
EnumNonMatching(Span, &'a [Ident]),
} }
/// Folds over fields, combining the expressions for each field in a sequence. /// Folds over fields, combining the expressions for each field in a sequence.
@ -1624,8 +1605,8 @@ pub fn cs_fold<F>(
where where
F: FnMut(&mut ExtCtxt<'_>, CsFold<'_>) -> P<Expr>, F: FnMut(&mut ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
{ {
match *substructure.fields { match substructure.fields {
EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => { EnumMatching(.., all_fields) | Struct(_, all_fields) => {
if all_fields.is_empty() { if all_fields.is_empty() {
return f(cx, CsFold::Fieldless); return f(cx, CsFold::Fieldless);
} }
@ -1649,7 +1630,18 @@ where
rest.iter().rfold(base_expr, op) rest.iter().rfold(base_expr, op)
} }
} }
EnumNonMatchingCollapsed(tuple) => f(cx, CsFold::EnumNonMatching(trait_span, tuple)), EnumTag(tag_field, match_expr) => {
let tag_check_expr = f(cx, CsFold::Single(tag_field));
if let Some(match_expr) = match_expr {
if use_foldl {
f(cx, CsFold::Combine(trait_span, tag_check_expr, match_expr.clone()))
} else {
f(cx, CsFold::Combine(trait_span, match_expr.clone(), tag_check_expr))
}
} else {
tag_check_expr
}
}
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"), StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
} }
} }

View file

@ -196,9 +196,8 @@ impl Bounds {
} }
pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) { pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) {
// this constructs a fresh `self` path // This constructs a fresh `self` path.
let self_path = cx.expr_self(span); let self_path = cx.expr_self(span);
let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not)); let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not));
let self_expr = cx.expr_deref(span, self_path); (self_path, self_ty)
(self_expr, self_ty)
} }

View file

@ -1,6 +1,6 @@
use crate::deriving::generic::ty::*; use crate::deriving::generic::ty::*;
use crate::deriving::generic::*; use crate::deriving::generic::*;
use crate::deriving::{self, path_std, pathvec_std}; use crate::deriving::{path_std, pathvec_std};
use rustc_ast::{MetaItem, Mutability}; use rustc_ast::{MetaItem, Mutability};
use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_expand::base::{Annotatable, ExtCtxt};
@ -52,39 +52,29 @@ fn hash_substructure(
let [state_expr] = substr.nonselflike_args else { let [state_expr] = substr.nonselflike_args else {
cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`"); cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`");
}; };
let call_hash = |span, thing_expr| { let call_hash = |span, expr| {
let hash_path = { let hash_path = {
let strs = cx.std_path(&[sym::hash, sym::Hash, sym::hash]); let strs = cx.std_path(&[sym::hash, sym::Hash, sym::hash]);
cx.expr_path(cx.path_global(span, strs)) cx.expr_path(cx.path_global(span, strs))
}; };
let ref_thing = cx.expr_addr_of(span, thing_expr); let expr = cx.expr_call(span, hash_path, vec![expr, state_expr.clone()]);
let expr = cx.expr_call(span, hash_path, vec![ref_thing, state_expr.clone()]);
cx.stmt_expr(expr) cx.stmt_expr(expr)
}; };
let mut stmts = Vec::new();
let fields = match substr.fields { let (stmts, match_expr) = match substr.fields {
Struct(_, fs) | EnumMatching(_, 1, .., fs) => fs, Struct(_, fields) | EnumMatching(.., fields) => {
EnumMatching(.., fs) => { let stmts =
let variant_value = deriving::call_intrinsic( fields.iter().map(|field| call_hash(field.span, field.self_expr.clone())).collect();
cx, (stmts, None)
trait_span, }
sym::discriminant_value, EnumTag(tag_field, match_expr) => {
vec![cx.expr_self(trait_span)], assert!(tag_field.other_selflike_exprs.is_empty());
); let stmts = vec![call_hash(tag_field.span, tag_field.self_expr.clone())];
(stmts, match_expr.clone())
stmts.push(call_hash(trait_span, variant_value));
fs
} }
_ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`"), _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`"),
}; };
stmts.extend( BlockOrExpr::new_mixed(stmts, match_expr)
fields
.iter()
.map(|FieldInfo { ref self_expr, span, .. }| call_hash(*span, self_expr.clone())),
);
BlockOrExpr::new_stmts(stmts)
} }

View file

@ -31,13 +31,26 @@ struct Point {
// A large struct. // A large struct.
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct Big { struct Big {
b1: u32, b2: u32, b3: u32, b4: u32, b5: u32, b6: u32, b7: u32, b8:u32, b1: u32, b2: u32, b3: u32, b4: u32, b5: u32, b6: u32, b7: u32, b8: u32,
} }
// A packed tuple struct. // A struct with an unsized field. Some derives are not usable in this case.
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct Unsized([u32]);
// A packed tuple struct that impls `Copy`.
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(packed)] #[repr(packed)]
struct Packed(u32); struct PackedCopy(u32);
// 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.
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(packed)]
struct PackedNonCopy(u8);
// An empty enum. // An empty enum.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
@ -49,6 +62,13 @@ enum Enum1 {
Single { x: u32 } Single { x: u32 }
} }
// A C-like, fieldless enum with a single variant.
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum Fieldless1 {
#[default]
A,
}
// A C-like, fieldless enum. // A C-like, fieldless enum.
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum Fieldless { enum Fieldless {

View file

@ -367,65 +367,112 @@ impl ::core::cmp::Ord for Big {
} }
} }
// A packed tuple struct. // A struct with an unsized field. Some derives are not usable in this case.
#[repr(packed)] struct Unsized([u32]);
struct Packed(u32);
#[automatically_derived] #[automatically_derived]
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::clone::Clone for Packed { 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]
#[allow(unused_qualifications)]
impl ::core::hash::Hash for Unsized {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&self.0, state)
}
}
impl ::core::marker::StructuralPartialEq for Unsized {}
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Unsized {
#[inline] #[inline]
fn clone(&self) -> Packed { fn eq(&self, other: &Unsized) -> bool { self.0 == other.0 }
#[inline]
fn ne(&self, other: &Unsized) -> bool { self.0 != other.0 }
}
impl ::core::marker::StructuralEq for Unsized {}
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::cmp::Eq for Unsized {
#[inline]
#[doc(hidden)]
#[no_coverage]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<[u32]>;
}
}
#[automatically_derived]
#[allow(unused_qualifications)]
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]
#[allow(unused_qualifications)]
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`.
#[repr(packed)]
struct PackedCopy(u32);
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::clone::Clone for PackedCopy {
#[inline]
fn clone(&self) -> PackedCopy {
let _: ::core::clone::AssertParamIsClone<u32>; let _: ::core::clone::AssertParamIsClone<u32>;
*self *self
} }
} }
#[automatically_derived] #[automatically_derived]
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::marker::Copy for Packed { } impl ::core::marker::Copy for PackedCopy { }
#[automatically_derived] #[automatically_derived]
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::fmt::Debug for Packed { impl ::core::fmt::Debug for PackedCopy {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let Self(__self_0_0) = *self; ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedCopy",
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Packed", &&{ self.0 })
&&__self_0_0)
} }
} }
#[automatically_derived] #[automatically_derived]
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::default::Default for Packed { impl ::core::default::Default for PackedCopy {
#[inline] #[inline]
fn default() -> Packed { Packed(::core::default::Default::default()) } fn default() -> PackedCopy {
PackedCopy(::core::default::Default::default())
}
} }
#[automatically_derived] #[automatically_derived]
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::hash::Hash for Packed { impl ::core::hash::Hash for PackedCopy {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
let Self(__self_0_0) = *self; ::core::hash::Hash::hash(&{ self.0 }, state)
::core::hash::Hash::hash(&__self_0_0, state)
} }
} }
impl ::core::marker::StructuralPartialEq for Packed {} impl ::core::marker::StructuralPartialEq for PackedCopy {}
#[automatically_derived] #[automatically_derived]
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Packed { impl ::core::cmp::PartialEq for PackedCopy {
#[inline] #[inline]
fn eq(&self, other: &Packed) -> bool { fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } }
let Self(__self_0_0) = *self;
let Self(__self_1_0) = *other;
__self_0_0 == __self_1_0
}
#[inline] #[inline]
fn ne(&self, other: &Packed) -> bool { fn ne(&self, other: &PackedCopy) -> bool { { self.0 } != { other.0 } }
let Self(__self_0_0) = *self;
let Self(__self_1_0) = *other;
__self_0_0 != __self_1_0
}
} }
impl ::core::marker::StructuralEq for Packed {} impl ::core::marker::StructuralEq for PackedCopy {}
#[automatically_derived] #[automatically_derived]
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::cmp::Eq for Packed { impl ::core::cmp::Eq for PackedCopy {
#[inline] #[inline]
#[doc(hidden)] #[doc(hidden)]
#[no_coverage] #[no_coverage]
@ -435,23 +482,110 @@ impl ::core::cmp::Eq for Packed {
} }
#[automatically_derived] #[automatically_derived]
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for Packed { impl ::core::cmp::PartialOrd for PackedCopy {
#[inline] #[inline]
fn partial_cmp(&self, other: &Packed) fn partial_cmp(&self, other: &PackedCopy)
-> ::core::option::Option<::core::cmp::Ordering> { -> ::core::option::Option<::core::cmp::Ordering> {
let Self(__self_0_0) = *self; ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
let Self(__self_1_0) = *other;
::core::cmp::PartialOrd::partial_cmp(&__self_0_0, &__self_1_0)
} }
} }
#[automatically_derived] #[automatically_derived]
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::cmp::Ord for Packed { impl ::core::cmp::Ord for PackedCopy {
#[inline] #[inline]
fn cmp(&self, other: &Packed) -> ::core::cmp::Ordering { fn cmp(&self, other: &PackedCopy) -> ::core::cmp::Ordering {
let Self(__self_0_0) = *self; ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 })
let Self(__self_1_0) = *other; }
::core::cmp::Ord::cmp(&__self_0_0, &__self_1_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)]
struct PackedNonCopy(u8);
#[automatically_derived]
#[allow(unused_qualifications)]
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]
#[allow(unused_qualifications)]
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]
#[allow(unused_qualifications)]
impl ::core::default::Default for PackedNonCopy {
#[inline]
fn default() -> PackedNonCopy {
PackedNonCopy(::core::default::Default::default())
}
}
#[automatically_derived]
#[allow(unused_qualifications)]
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)
}
}
impl ::core::marker::StructuralPartialEq for PackedNonCopy {}
#[automatically_derived]
#[allow(unused_qualifications)]
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
}
#[inline]
fn ne(&self, other: &PackedNonCopy) -> bool {
let Self(ref __self_0_0) = *self;
let Self(ref __self_1_0) = *other;
*__self_0_0 != *__self_1_0
}
}
impl ::core::marker::StructuralEq for PackedNonCopy {}
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::cmp::Eq for PackedNonCopy {
#[inline]
#[doc(hidden)]
#[no_coverage]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<u8>;
}
}
#[automatically_derived]
#[allow(unused_qualifications)]
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]
#[allow(unused_qualifications)]
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)
} }
} }
@ -527,9 +661,9 @@ enum Enum1 {
impl ::core::clone::Clone for Enum1 { impl ::core::clone::Clone for Enum1 {
#[inline] #[inline]
fn clone(&self) -> Enum1 { fn clone(&self) -> Enum1 {
match &*self { match self {
&Enum1::Single { x: ref __self_0 } => Enum1::Single { x: __self_0 } =>
Enum1::Single { x: ::core::clone::Clone::clone(&*__self_0) }, Enum1::Single { x: ::core::clone::Clone::clone(__self_0) },
} }
} }
} }
@ -537,10 +671,10 @@ impl ::core::clone::Clone for Enum1 {
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::fmt::Debug for Enum1 { impl ::core::fmt::Debug for Enum1 {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match &*self { match self {
&Enum1::Single { x: ref __self_0 } => Enum1::Single { x: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f, ::core::fmt::Formatter::debug_struct_field1_finish(f,
"Single", "x", &&*__self_0), "Single", "x", &__self_0),
} }
} }
} }
@ -548,10 +682,9 @@ impl ::core::fmt::Debug for Enum1 {
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::hash::Hash for Enum1 { impl ::core::hash::Hash for Enum1 {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
match &*self { match self {
&Enum1::Single { x: ref __self_0 } => { Enum1::Single { x: __self_0 } =>
::core::hash::Hash::hash(&*__self_0, state) ::core::hash::Hash::hash(__self_0, state),
}
} }
} }
} }
@ -561,16 +694,16 @@ impl ::core::marker::StructuralPartialEq for Enum1 {}
impl ::core::cmp::PartialEq for Enum1 { impl ::core::cmp::PartialEq for Enum1 {
#[inline] #[inline]
fn eq(&self, other: &Enum1) -> bool { fn eq(&self, other: &Enum1) -> bool {
match (&*self, &*other) { match (self, other) {
(&Enum1::Single { x: ref __self_0 }, &Enum1::Single { (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) =>
x: ref __arg_1_0 }) => *__self_0 == *__arg_1_0, *__self_0 == *__arg1_0,
} }
} }
#[inline] #[inline]
fn ne(&self, other: &Enum1) -> bool { fn ne(&self, other: &Enum1) -> bool {
match (&*self, &*other) { match (self, other) {
(&Enum1::Single { x: ref __self_0 }, &Enum1::Single { (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) =>
x: ref __arg_1_0 }) => *__self_0 != *__arg_1_0, *__self_0 != *__arg1_0,
} }
} }
} }
@ -591,10 +724,9 @@ impl ::core::cmp::PartialOrd for Enum1 {
#[inline] #[inline]
fn partial_cmp(&self, other: &Enum1) fn partial_cmp(&self, other: &Enum1)
-> ::core::option::Option<::core::cmp::Ordering> { -> ::core::option::Option<::core::cmp::Ordering> {
match (&*self, &*other) { match (self, other) {
(&Enum1::Single { x: ref __self_0 }, &Enum1::Single { (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) =>
x: ref __arg_1_0 }) => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
::core::cmp::PartialOrd::partial_cmp(&*__self_0, &*__arg_1_0),
} }
} }
} }
@ -603,14 +735,77 @@ impl ::core::cmp::PartialOrd for Enum1 {
impl ::core::cmp::Ord for Enum1 { impl ::core::cmp::Ord for Enum1 {
#[inline] #[inline]
fn cmp(&self, other: &Enum1) -> ::core::cmp::Ordering { fn cmp(&self, other: &Enum1) -> ::core::cmp::Ordering {
match (&*self, &*other) { match (self, other) {
(&Enum1::Single { x: ref __self_0 }, &Enum1::Single { (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) =>
x: ref __arg_1_0 }) => ::core::cmp::Ord::cmp(__self_0, __arg1_0),
::core::cmp::Ord::cmp(&*__self_0, &*__arg_1_0),
} }
} }
} }
// A C-like, fieldless enum with a single variant.
enum Fieldless1 {
#[default]
A,
}
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::clone::Clone for Fieldless1 {
#[inline]
fn clone(&self) -> Fieldless1 { Fieldless1::A }
}
#[automatically_derived]
#[allow(unused_qualifications)]
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]
#[allow(unused_qualifications)]
impl ::core::default::Default for Fieldless1 {
#[inline]
fn default() -> Fieldless1 { Self::A }
}
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::hash::Hash for Fieldless1 {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
}
impl ::core::marker::StructuralPartialEq for Fieldless1 {}
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Fieldless1 {
#[inline]
fn eq(&self, other: &Fieldless1) -> bool { true }
}
impl ::core::marker::StructuralEq for Fieldless1 {}
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::cmp::Eq for Fieldless1 {
#[inline]
#[doc(hidden)]
#[no_coverage]
fn assert_receiver_is_total_eq(&self) -> () {}
}
#[automatically_derived]
#[allow(unused_qualifications)]
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]
#[allow(unused_qualifications)]
impl ::core::cmp::Ord for Fieldless1 {
#[inline]
fn cmp(&self, other: &Fieldless1) -> ::core::cmp::Ordering {
::core::cmp::Ordering::Equal
}
}
// A C-like, fieldless enum. // A C-like, fieldless enum.
enum Fieldless { enum Fieldless {
@ -632,10 +827,10 @@ impl ::core::marker::Copy for Fieldless { }
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::fmt::Debug for Fieldless { impl ::core::fmt::Debug for Fieldless {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match &*self { match self {
&Fieldless::A => ::core::fmt::Formatter::write_str(f, "A"), Fieldless::A => ::core::fmt::Formatter::write_str(f, "A"),
&Fieldless::B => ::core::fmt::Formatter::write_str(f, "B"), Fieldless::B => ::core::fmt::Formatter::write_str(f, "B"),
&Fieldless::C => ::core::fmt::Formatter::write_str(f, "C"), Fieldless::C => ::core::fmt::Formatter::write_str(f, "C"),
} }
} }
} }
@ -649,12 +844,8 @@ impl ::core::default::Default for Fieldless {
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::hash::Hash for Fieldless { impl ::core::hash::Hash for Fieldless {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
match &*self { let __self_tag = ::core::intrinsics::discriminant_value(self);
_ => { ::core::hash::Hash::hash(&__self_tag, state)
::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
state)
}
}
} }
} }
impl ::core::marker::StructuralPartialEq for Fieldless {} impl ::core::marker::StructuralPartialEq for Fieldless {}
@ -663,11 +854,9 @@ impl ::core::marker::StructuralPartialEq for Fieldless {}
impl ::core::cmp::PartialEq for Fieldless { impl ::core::cmp::PartialEq for Fieldless {
#[inline] #[inline]
fn eq(&self, other: &Fieldless) -> bool { fn eq(&self, other: &Fieldless) -> bool {
let __self_vi = ::core::intrinsics::discriminant_value(&*self); let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); let __arg1_tag = ::core::intrinsics::discriminant_value(other);
if __self_vi == __arg_1_vi { __self_tag == __arg1_tag
match (&*self, &*other) { _ => true, }
} else { false }
} }
} }
impl ::core::marker::StructuralEq for Fieldless {} impl ::core::marker::StructuralEq for Fieldless {}
@ -685,16 +874,9 @@ impl ::core::cmp::PartialOrd for Fieldless {
#[inline] #[inline]
fn partial_cmp(&self, other: &Fieldless) fn partial_cmp(&self, other: &Fieldless)
-> ::core::option::Option<::core::cmp::Ordering> { -> ::core::option::Option<::core::cmp::Ordering> {
let __self_vi = ::core::intrinsics::discriminant_value(&*self); let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); let __arg1_tag = ::core::intrinsics::discriminant_value(other);
if __self_vi == __arg_1_vi { ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag)
match (&*self, &*other) {
_ =>
::core::option::Option::Some(::core::cmp::Ordering::Equal),
}
} else {
::core::cmp::PartialOrd::partial_cmp(&__self_vi, &__arg_1_vi)
}
} }
} }
#[automatically_derived] #[automatically_derived]
@ -702,11 +884,9 @@ impl ::core::cmp::PartialOrd for Fieldless {
impl ::core::cmp::Ord for Fieldless { impl ::core::cmp::Ord for Fieldless {
#[inline] #[inline]
fn cmp(&self, other: &Fieldless) -> ::core::cmp::Ordering { fn cmp(&self, other: &Fieldless) -> ::core::cmp::Ordering {
let __self_vi = ::core::intrinsics::discriminant_value(&*self); let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); let __arg1_tag = ::core::intrinsics::discriminant_value(other);
if __self_vi == __arg_1_vi { ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag)
match (&*self, &*other) { _ => ::core::cmp::Ordering::Equal, }
} else { ::core::cmp::Ord::cmp(&__self_vi, &__arg_1_vi) }
} }
} }
@ -738,15 +918,15 @@ impl ::core::marker::Copy for Mixed { }
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::fmt::Debug for Mixed { impl ::core::fmt::Debug for Mixed {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match &*self { match self {
&Mixed::P => ::core::fmt::Formatter::write_str(f, "P"), Mixed::P => ::core::fmt::Formatter::write_str(f, "P"),
&Mixed::Q => ::core::fmt::Formatter::write_str(f, "Q"), Mixed::Q => ::core::fmt::Formatter::write_str(f, "Q"),
&Mixed::R(ref __self_0) => Mixed::R(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "R", ::core::fmt::Formatter::debug_tuple_field1_finish(f, "R",
&&*__self_0), &__self_0),
&Mixed::S { d1: ref __self_0, d2: ref __self_1 } => Mixed::S { d1: __self_0, d2: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f, "S", ::core::fmt::Formatter::debug_struct_field2_finish(f, "S",
"d1", &&*__self_0, "d2", &&*__self_1), "d1", &__self_0, "d2", &__self_1),
} }
} }
} }
@ -760,22 +940,15 @@ impl ::core::default::Default for Mixed {
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::hash::Hash for Mixed { impl ::core::hash::Hash for Mixed {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
match &*self { let __self_tag = ::core::intrinsics::discriminant_value(self);
&Mixed::R(ref __self_0) => { ::core::hash::Hash::hash(&__self_tag, state);
::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self), match self {
state); Mixed::R(__self_0) => ::core::hash::Hash::hash(__self_0, state),
::core::hash::Hash::hash(&*__self_0, state) Mixed::S { d1: __self_0, d2: __self_1 } => {
} ::core::hash::Hash::hash(__self_0, state);
&Mixed::S { d1: ref __self_0, d2: ref __self_1 } => { ::core::hash::Hash::hash(__self_1, state)
::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
state);
::core::hash::Hash::hash(&*__self_0, state);
::core::hash::Hash::hash(&*__self_1, state)
}
_ => {
::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
state)
} }
_ => {}
} }
} }
} }
@ -785,33 +958,31 @@ impl ::core::marker::StructuralPartialEq for Mixed {}
impl ::core::cmp::PartialEq for Mixed { impl ::core::cmp::PartialEq for Mixed {
#[inline] #[inline]
fn eq(&self, other: &Mixed) -> bool { fn eq(&self, other: &Mixed) -> bool {
let __self_vi = ::core::intrinsics::discriminant_value(&*self); let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); let __arg1_tag = ::core::intrinsics::discriminant_value(other);
if __self_vi == __arg_1_vi { __self_tag == __arg1_tag &&
match (&*self, &*other) { match (self, other) {
(&Mixed::R(ref __self_0), &Mixed::R(ref __arg_1_0)) => (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
*__self_0 == *__arg_1_0, *__self_0 == *__arg1_0,
(&Mixed::S { d1: ref __self_0, d2: ref __self_1 }, (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
&Mixed::S { d1: ref __arg_1_0, d2: ref __arg_1_1 }) => d1: __arg1_0, d2: __arg1_1 }) =>
*__self_0 == *__arg_1_0 && *__self_1 == *__arg_1_1, *__self_0 == *__arg1_0 && *__self_1 == *__arg1_1,
_ => true, _ => true,
} }
} else { false }
} }
#[inline] #[inline]
fn ne(&self, other: &Mixed) -> bool { fn ne(&self, other: &Mixed) -> bool {
let __self_vi = ::core::intrinsics::discriminant_value(&*self); let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); let __arg1_tag = ::core::intrinsics::discriminant_value(other);
if __self_vi == __arg_1_vi { __self_tag != __arg1_tag ||
match (&*self, &*other) { match (self, other) {
(&Mixed::R(ref __self_0), &Mixed::R(ref __arg_1_0)) => (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
*__self_0 != *__arg_1_0, *__self_0 != *__arg1_0,
(&Mixed::S { d1: ref __self_0, d2: ref __self_1 }, (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
&Mixed::S { d1: ref __arg_1_0, d2: ref __arg_1_1 }) => d1: __arg1_0, d2: __arg1_1 }) =>
*__self_0 != *__arg_1_0 || *__self_1 != *__arg_1_1, *__self_0 != *__arg1_0 || *__self_1 != *__arg1_1,
_ => false, _ => false,
} }
} else { true }
} }
} }
impl ::core::marker::StructuralEq for Mixed {} impl ::core::marker::StructuralEq for Mixed {}
@ -831,28 +1002,25 @@ impl ::core::cmp::PartialOrd for Mixed {
#[inline] #[inline]
fn partial_cmp(&self, other: &Mixed) fn partial_cmp(&self, other: &Mixed)
-> ::core::option::Option<::core::cmp::Ordering> { -> ::core::option::Option<::core::cmp::Ordering> {
let __self_vi = ::core::intrinsics::discriminant_value(&*self); let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); let __arg1_tag = ::core::intrinsics::discriminant_value(other);
if __self_vi == __arg_1_vi { match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) {
match (&*self, &*other) { ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
(&Mixed::R(ref __self_0), &Mixed::R(ref __arg_1_0)) => match (self, other) {
::core::cmp::PartialOrd::partial_cmp(&*__self_0, (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
&*__arg_1_0), ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
(&Mixed::S { d1: ref __self_0, d2: ref __self_1 }, (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
&Mixed::S { d1: ref __arg_1_0, d2: ref __arg_1_1 }) => d1: __arg1_0, d2: __arg1_1 }) =>
match ::core::cmp::PartialOrd::partial_cmp(&*__self_0, match ::core::cmp::PartialOrd::partial_cmp(__self_0,
&*__arg_1_0) { __arg1_0) {
::core::option::Option::Some(::core::cmp::Ordering::Equal) ::core::option::Option::Some(::core::cmp::Ordering::Equal)
=> => ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1),
::core::cmp::PartialOrd::partial_cmp(&*__self_1,
&*__arg_1_1),
cmp => cmp, cmp => cmp,
}, },
_ => _ =>
::core::option::Option::Some(::core::cmp::Ordering::Equal), ::core::option::Option::Some(::core::cmp::Ordering::Equal),
} },
} else { cmp => cmp,
::core::cmp::PartialOrd::partial_cmp(&__self_vi, &__arg_1_vi)
} }
} }
} }
@ -861,22 +1029,24 @@ impl ::core::cmp::PartialOrd for Mixed {
impl ::core::cmp::Ord for Mixed { impl ::core::cmp::Ord for Mixed {
#[inline] #[inline]
fn cmp(&self, other: &Mixed) -> ::core::cmp::Ordering { fn cmp(&self, other: &Mixed) -> ::core::cmp::Ordering {
let __self_vi = ::core::intrinsics::discriminant_value(&*self); let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); let __arg1_tag = ::core::intrinsics::discriminant_value(other);
if __self_vi == __arg_1_vi { match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) {
match (&*self, &*other) {
(&Mixed::R(ref __self_0), &Mixed::R(ref __arg_1_0)) =>
::core::cmp::Ord::cmp(&*__self_0, &*__arg_1_0),
(&Mixed::S { d1: ref __self_0, d2: ref __self_1 },
&Mixed::S { d1: ref __arg_1_0, d2: ref __arg_1_1 }) =>
match ::core::cmp::Ord::cmp(&*__self_0, &*__arg_1_0) {
::core::cmp::Ordering::Equal => ::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(&*__self_1, &*__arg_1_1), 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, cmp => cmp,
}, },
_ => ::core::cmp::Ordering::Equal, _ => ::core::cmp::Ordering::Equal,
},
cmp => cmp,
} }
} else { ::core::cmp::Ord::cmp(&__self_vi, &__arg_1_vi) }
} }
} }
@ -888,13 +1058,13 @@ enum Fielded { X(u32), Y(bool), Z(Option<i32>), }
impl ::core::clone::Clone for Fielded { impl ::core::clone::Clone for Fielded {
#[inline] #[inline]
fn clone(&self) -> Fielded { fn clone(&self) -> Fielded {
match &*self { match self {
&Fielded::X(ref __self_0) => Fielded::X(__self_0) =>
Fielded::X(::core::clone::Clone::clone(&*__self_0)), Fielded::X(::core::clone::Clone::clone(__self_0)),
&Fielded::Y(ref __self_0) => Fielded::Y(__self_0) =>
Fielded::Y(::core::clone::Clone::clone(&*__self_0)), Fielded::Y(::core::clone::Clone::clone(__self_0)),
&Fielded::Z(ref __self_0) => Fielded::Z(__self_0) =>
Fielded::Z(::core::clone::Clone::clone(&*__self_0)), Fielded::Z(::core::clone::Clone::clone(__self_0)),
} }
} }
} }
@ -902,16 +1072,16 @@ impl ::core::clone::Clone for Fielded {
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::fmt::Debug for Fielded { impl ::core::fmt::Debug for Fielded {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match &*self { match self {
&Fielded::X(ref __self_0) => Fielded::X(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "X", ::core::fmt::Formatter::debug_tuple_field1_finish(f, "X",
&&*__self_0), &__self_0),
&Fielded::Y(ref __self_0) => Fielded::Y(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Y", ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Y",
&&*__self_0), &__self_0),
&Fielded::Z(ref __self_0) => Fielded::Z(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Z", ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Z",
&&*__self_0), &__self_0),
} }
} }
} }
@ -919,22 +1089,12 @@ impl ::core::fmt::Debug for Fielded {
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl ::core::hash::Hash for Fielded { impl ::core::hash::Hash for Fielded {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
match &*self { let __self_tag = ::core::intrinsics::discriminant_value(self);
&Fielded::X(ref __self_0) => { ::core::hash::Hash::hash(&__self_tag, state);
::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self), match self {
state); Fielded::X(__self_0) => ::core::hash::Hash::hash(__self_0, state),
::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),
&Fielded::Y(ref __self_0) => {
::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
state);
::core::hash::Hash::hash(&*__self_0, state)
}
&Fielded::Z(ref __self_0) => {
::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
state);
::core::hash::Hash::hash(&*__self_0, state)
}
} }
} }
} }
@ -944,35 +1104,33 @@ impl ::core::marker::StructuralPartialEq for Fielded {}
impl ::core::cmp::PartialEq for Fielded { impl ::core::cmp::PartialEq for Fielded {
#[inline] #[inline]
fn eq(&self, other: &Fielded) -> bool { fn eq(&self, other: &Fielded) -> bool {
let __self_vi = ::core::intrinsics::discriminant_value(&*self); let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); let __arg1_tag = ::core::intrinsics::discriminant_value(other);
if __self_vi == __arg_1_vi { __self_tag == __arg1_tag &&
match (&*self, &*other) { match (self, other) {
(&Fielded::X(ref __self_0), &Fielded::X(ref __arg_1_0)) => (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
*__self_0 == *__arg_1_0, *__self_0 == *__arg1_0,
(&Fielded::Y(ref __self_0), &Fielded::Y(ref __arg_1_0)) => (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
*__self_0 == *__arg_1_0, *__self_0 == *__arg1_0,
(&Fielded::Z(ref __self_0), &Fielded::Z(ref __arg_1_0)) => (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
*__self_0 == *__arg_1_0, *__self_0 == *__arg1_0,
_ => unsafe { ::core::intrinsics::unreachable() } _ => unsafe { ::core::intrinsics::unreachable() }
} }
} else { false }
} }
#[inline] #[inline]
fn ne(&self, other: &Fielded) -> bool { fn ne(&self, other: &Fielded) -> bool {
let __self_vi = ::core::intrinsics::discriminant_value(&*self); let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); let __arg1_tag = ::core::intrinsics::discriminant_value(other);
if __self_vi == __arg_1_vi { __self_tag != __arg1_tag ||
match (&*self, &*other) { match (self, other) {
(&Fielded::X(ref __self_0), &Fielded::X(ref __arg_1_0)) => (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
*__self_0 != *__arg_1_0, *__self_0 != *__arg1_0,
(&Fielded::Y(ref __self_0), &Fielded::Y(ref __arg_1_0)) => (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
*__self_0 != *__arg_1_0, *__self_0 != *__arg1_0,
(&Fielded::Z(ref __self_0), &Fielded::Z(ref __arg_1_0)) => (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
*__self_0 != *__arg_1_0, *__self_0 != *__arg1_0,
_ => unsafe { ::core::intrinsics::unreachable() } _ => unsafe { ::core::intrinsics::unreachable() }
} }
} else { true }
} }
} }
impl ::core::marker::StructuralEq for Fielded {} impl ::core::marker::StructuralEq for Fielded {}
@ -994,23 +1152,20 @@ impl ::core::cmp::PartialOrd for Fielded {
#[inline] #[inline]
fn partial_cmp(&self, other: &Fielded) fn partial_cmp(&self, other: &Fielded)
-> ::core::option::Option<::core::cmp::Ordering> { -> ::core::option::Option<::core::cmp::Ordering> {
let __self_vi = ::core::intrinsics::discriminant_value(&*self); let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); let __arg1_tag = ::core::intrinsics::discriminant_value(other);
if __self_vi == __arg_1_vi { match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) {
match (&*self, &*other) { ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
(&Fielded::X(ref __self_0), &Fielded::X(ref __arg_1_0)) => match (self, other) {
::core::cmp::PartialOrd::partial_cmp(&*__self_0, (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
&*__arg_1_0), ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
(&Fielded::Y(ref __self_0), &Fielded::Y(ref __arg_1_0)) => (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
::core::cmp::PartialOrd::partial_cmp(&*__self_0, ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
&*__arg_1_0), (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
(&Fielded::Z(ref __self_0), &Fielded::Z(ref __arg_1_0)) => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
::core::cmp::PartialOrd::partial_cmp(&*__self_0,
&*__arg_1_0),
_ => unsafe { ::core::intrinsics::unreachable() } _ => unsafe { ::core::intrinsics::unreachable() }
} },
} else { cmp => cmp,
::core::cmp::PartialOrd::partial_cmp(&__self_vi, &__arg_1_vi)
} }
} }
} }
@ -1019,19 +1174,21 @@ impl ::core::cmp::PartialOrd for Fielded {
impl ::core::cmp::Ord for Fielded { impl ::core::cmp::Ord for Fielded {
#[inline] #[inline]
fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering { fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering {
let __self_vi = ::core::intrinsics::discriminant_value(&*self); let __self_tag = ::core::intrinsics::discriminant_value(self);
let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other); let __arg1_tag = ::core::intrinsics::discriminant_value(other);
if __self_vi == __arg_1_vi { match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) {
match (&*self, &*other) { ::core::cmp::Ordering::Equal =>
(&Fielded::X(ref __self_0), &Fielded::X(ref __arg_1_0)) => match (self, other) {
::core::cmp::Ord::cmp(&*__self_0, &*__arg_1_0), (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
(&Fielded::Y(ref __self_0), &Fielded::Y(ref __arg_1_0)) => ::core::cmp::Ord::cmp(__self_0, __arg1_0),
::core::cmp::Ord::cmp(&*__self_0, &*__arg_1_0), (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
(&Fielded::Z(ref __self_0), &Fielded::Z(ref __arg_1_0)) => ::core::cmp::Ord::cmp(__self_0, __arg1_0),
::core::cmp::Ord::cmp(&*__self_0, &*__arg_1_0), (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
::core::cmp::Ord::cmp(__self_0, __arg1_0),
_ => unsafe { ::core::intrinsics::unreachable() } _ => unsafe { ::core::intrinsics::unreachable() }
},
cmp => cmp,
} }
} else { ::core::cmp::Ord::cmp(&__self_vi, &__arg_1_vi) }
} }
} }