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(
@ -161,7 +161,7 @@ fn cs_clone(
let all_fields;
let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]);
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)
};
@ -177,9 +177,7 @@ fn cs_clone(
all_fields = af;
vdata = &variant.data;
}
EnumNonMatchingCollapsed(..) => {
cx.span_bug(trait_span, &format!("non-matching enum variants in `derive({})`", name,))
}
EnumTag(..) => cx.span_bug(trait_span, &format!("enum tags in `derive({})`", name,)),
StaticEnum(..) | StaticStruct(..) => {
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 {
cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
};
let args = vec![
cx.expr_addr_of(field.span, field.self_expr.clone()),
cx.expr_addr_of(field.span, other_expr.clone()),
];
let args = vec![field.self_expr.clone(), other_expr.clone()];
cx.expr_call_global(field.span, cmp_path.clone(), args)
}
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])
}
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)

View File

@ -2,7 +2,8 @@ use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
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_span::symbol::sym;
use rustc_span::Span;
@ -32,11 +33,24 @@ pub fn expand_deriving_partial_eq(
let [other_expr] = &field.other_selflike_exprs[..] else {
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::Fieldless => cx.expr_bool(span, base),
CsFold::EnumNonMatching(span, _tag_tuple) => cx.expr_bool(span, !base),
},
);
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 {
cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
};
let args = vec![
cx.expr_addr_of(field.span, field.self_expr.clone()),
cx.expr_addr_of(field.span, other_expr.clone()),
];
let args = vec![field.self_expr.clone(), other_expr.clone()];
cx.expr_call_global(field.span, partial_cmp_path.clone(), args)
}
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])
}
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)

View File

@ -45,7 +45,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
let (ident, vdata, fields) = match substr.fields {
Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
EnumTag(..) | StaticStruct(..) | StaticEnum(..) => {
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);
}
// 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);
args.push(field);
}
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
let value_ref = cx.expr_addr_of(field.span, field.self_expr.clone());
value_exprs.push(cx.expr_addr_of(field.span, value_ref));
// Use an extra indirection to make sure this works for unsized types.
let field = cx.expr_addr_of(field.span, field.self_expr.clone());
value_exprs.push(field);
}
// `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(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,
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)"),

View File

@ -21,21 +21,14 @@
//! `struct T(i32, char)`).
//! - `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)`)
//! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments
//! are not the same variant (e.g., `None`, `Some(1)` and `None`).
//! - `EnumTag` when `Self` is an enum, for comparing the enum tags.
//! - `StaticEnum` and `StaticStruct` for static methods, where the type
//! being derived upon is either an enum or struct respectively. (Any
//! argument with type Self is just grouped among the non-self
//! arguments.)
//!
//! In the first two cases, the values from the corresponding fields in
//! all the arguments are grouped together. For `EnumNonMatchingCollapsed`
//! 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.
//! all the arguments are grouped together.
//!
//! The non-static cases have `Option<ident>` in several places associated
//! 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}
//! EnumNonMatchingCollapsed(
//! &[<ident for self index value>, <ident of __arg_1 index value>])
//! EnumTag(
//! &[<ident of self tag>, <ident of other tag>], <expr to combine with>)
//! ```
//!
//! It is the same for when the arguments are flipped to `C1 {x}` and
//! `C0(a)`; the only difference is what the values of the identifiers
//! <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.
//! Note that this setup doesn't allow for the brute-force "match every variant
//! against every other variant" approach, which is bad because it produces a
//! quadratic amount of code (see #15375).
//!
//! ## Static
//!
@ -180,10 +167,9 @@ use std::iter;
use std::vec;
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_attr as attr;
use rustc_data_structures::map_in_place::MapInPlace;
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
@ -236,6 +222,8 @@ pub struct MethodDef<'a> {
pub attributes: Vec<ast::Attribute>,
/// 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 combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
@ -275,19 +263,22 @@ pub enum StaticFields {
/// A summary of the possible sets of fields.
pub enum SubstructureFields<'a> {
/// A non-static method with `Self` is a struct.
Struct(&'a ast::VariantData, Vec<FieldInfo>),
/// 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
/// variant.
EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo>),
/// Non-matching variants of the enum, but with all state hidden from the
/// consequent code. The field is a list of `Ident`s bound to the variant
/// index values for each of the actual input `Self` arguments.
EnumNonMatchingCollapsed(&'a [Ident]),
/// The tag of an enum. The first field is a `FieldInfo` for the tags, as
/// if they were fields. The second field is the expression to combine the
/// tag expression with; it will be `None` if no match is necessary.
EnumTag(FieldInfo, Option<P<Expr>>),
/// A static method where `Self` is a struct.
StaticStruct(&'a ast::VariantData, StaticFields),
/// A static method where `Self` is an enum.
StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
}
@ -325,8 +316,8 @@ impl BlockOrExpr {
BlockOrExpr(vec![], Some(expr))
}
pub fn new_mixed(stmts: Vec<ast::Stmt>, expr: P<Expr>) -> BlockOrExpr {
BlockOrExpr(stmts, Some(expr))
pub fn new_mixed(stmts: Vec<ast::Stmt>, expr: Option<P<Expr>>) -> BlockOrExpr {
BlockOrExpr(stmts, expr)
}
// Converts it into a block.
@ -344,7 +335,14 @@ impl BlockOrExpr {
None => cx.expr_block(cx.block(span, vec![])),
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 {
// Multiple statements and/or expressions.
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 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 {
ast::ItemKind::Struct(ref struct_def, ref generics) => self.expand_struct_def(
@ -464,11 +461,11 @@ impl<'a> TraitDef<'a> {
item.ident,
generics,
from_scratch,
use_temporaries,
is_packed,
always_copy,
),
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.
//
// This can only cause further compilation errors
@ -484,8 +481,8 @@ impl<'a> TraitDef<'a> {
item.ident,
generics,
from_scratch,
use_temporaries,
is_packed,
always_copy,
)
} else {
cx.span_err(mitem.span, "this trait cannot be derived for unions");
@ -766,8 +763,8 @@ impl<'a> TraitDef<'a> {
type_ident: Ident,
generics: &Generics,
from_scratch: bool,
use_temporaries: bool,
is_packed: bool,
always_copy: bool,
) -> P<ast::Item> {
let field_tys: Vec<P<ast::Ty>> =
struct_def.fields().iter().map(|field| field.ty.clone()).collect();
@ -795,8 +792,8 @@ impl<'a> TraitDef<'a> {
type_ident,
&selflike_args,
&nonselflike_args,
use_temporaries,
is_packed,
always_copy,
)
};
@ -937,9 +934,7 @@ impl<'a> MethodDef<'a> {
match ty {
// Selflike (`&Self`) arguments only occur in non-static methods.
Ref(box Self_, _) if !self.is_static() => {
selflike_args.push(cx.expr_deref(span, arg_expr))
}
Ref(box Self_, _) if !self.is_static() => selflike_args.push(arg_expr),
Self_ => cx.span_bug(span, "`Self` in non-return position"),
_ => nonselflike_args.push(arg_expr),
}
@ -1008,7 +1003,7 @@ impl<'a> MethodDef<'a> {
/// ```
/// #[derive(PartialEq)]
/// # struct Dummy;
/// struct A { x: i32, y: i32 }
/// struct A { x: u8, y: u8 }
///
/// // equivalent to:
/// 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
/// `&self.x` on a packed type (as required for e.g. `Debug` and `Hash`)
/// because that might cause an unaligned ref. So we use let-destructuring
/// instead.
/// `&self.x` because that might cause an unaligned ref. So for any trait
/// method that takes a reference, if the struct impls `Copy` then we use a
/// 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 {
/// fn eq(&self, other: &A) -> bool {
/// 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>(
&self,
cx: &mut ExtCtxt<'_>,
@ -1039,8 +1052,8 @@ impl<'a> MethodDef<'a> {
type_ident: Ident,
selflike_args: &[P<Expr>],
nonselflike_args: &[P<Expr>],
use_temporaries: bool,
is_packed: bool,
always_copy: bool,
) -> BlockOrExpr {
let span = trait_.span;
assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
@ -1057,29 +1070,31 @@ impl<'a> MethodDef<'a> {
if !is_packed {
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)
} else {
// Neither packed nor copy. Need to use ref patterns.
let prefixes: Vec<_> =
(0..selflike_args.len()).map(|i| format!("__self_{}", i)).collect();
let addr_of = always_copy;
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 struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]);
let patterns = trait_.create_struct_patterns(
cx,
struct_path,
struct_def,
&prefixes,
ast::Mutability::Not,
use_temporaries,
);
let use_ref_pat = is_packed && !always_copy;
let patterns =
trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, use_ref_pat);
// Do the let-destructuring.
let mut stmts: Vec<_> = iter::zip(selflike_args, patterns)
.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();
stmts.extend(std::mem::take(&mut body.0));
@ -1119,82 +1134,128 @@ impl<'a> MethodDef<'a> {
/// impl ::core::cmp::PartialEq for A {
/// #[inline]
/// fn eq(&self, other: &A) -> bool {
/// {
/// let __self_vi = ::core::intrinsics::discriminant_value(&*self);
/// let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
/// if true && __self_vi == __arg_1_vi {
/// match (&*self, &*other) {
/// (&A::A2(ref __self_0), &A::A2(ref __arg_1_0)) =>
/// (*__self_0) == (*__arg_1_0),
/// _ => true,
/// }
/// } else {
/// false // catch-all handler
/// let __self_tag = ::core::intrinsics::discriminant_value(self);
/// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
/// __self_tag == __arg1_tag &&
/// match (self, other) {
/// (A::A2(__self_0), A::A2(__arg1_0)) =>
/// *__self_0 == *__arg1_0,
/// _ => true,
/// }
/// }
/// }
/// }
/// ```
/// Creates a match for a tuple of all `selflike_args`, where either all
/// variants match, or it falls into a catch-all for when one variant
/// does not match.
///
/// 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.
/// Creates a tag check combined with a match for a tuple of all
/// `selflike_args`, with an arm for each variant with fields, possibly an
/// arm for each fieldless variant (if `!unify_fieldless_variants` is not
/// true), and possibly a default arm.
fn expand_enum_method_body<'b>(
&self,
cx: &mut ExtCtxt<'_>,
trait_: &TraitDef<'b>,
enum_def: &'b EnumDef,
type_ident: Ident,
mut selflike_args: Vec<P<Expr>>,
selflike_args: Vec<P<Expr>>,
nonselflike_args: &[P<Expr>],
) -> BlockOrExpr {
let span = trait_.span;
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())
.chain(
selflike_args
.iter()
.enumerate()
.skip(1)
.map(|(arg_count, _selflike_arg)| format!("__arg_{}", arg_count)),
.map(|(arg_count, _selflike_arg)| format!("__arg{}", arg_count)),
)
.collect::<Vec<String>>();
// The `vi_idents` will be bound, solely in the catch-all, to
// a series of let statements mapping each selflike_arg to an int
// value corresponding to its discriminant.
let vi_idents = prefixes
.iter()
.map(|name| {
let vi_suffix = format!("{}_vi", name);
Ident::from_str_and_span(&vi_suffix, span)
})
.collect::<Vec<Ident>>();
// Build a series of let statements mapping each selflike_arg
// to its discriminant value.
//
// 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()
.map(|name| Ident::from_str_and_span(&format!("{}_tag", name), span))
.collect();
// Builds, via callback to call_substructure_method, the
// delegated expression that handles the catch-all case,
// using `__variants_tuple` to drive logic if necessary.
let catch_all_substructure = EnumNonMatchingCollapsed(&vi_idents);
let mut tag_exprs: Vec<_> = tag_idents
.iter()
.map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident)))
.collect();
let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
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();
(tag_field, tag_let_stmts)
};
// 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:
// (Variant1, Variant1, ...) => Body1
// (Variant2, Variant2, ...) => Body2
// ...
// where each tuple has length = selflike_args.len()
let mut match_arms: Vec<ast::Arm> = variants
.iter()
.enumerate()
@ -1203,30 +1264,22 @@ impl<'a> MethodDef<'a> {
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
// (see "Final wrinkle" note below for why.)
let use_temporaries = false; // enums can't be repr(packed)
let fields = trait_.create_struct_pattern_fields(
cx,
&variant.data,
&prefixes,
use_temporaries,
);
let addr_of = false; // because enums can't be repr(packed)
let fields =
trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes, addr_of);
let sp = variant.span.with_ctxt(trait_.span.ctxt());
let variant_path = cx.path(sp, vec![type_ident, variant.ident]);
let mut subpats: Vec<_> = trait_
.create_struct_patterns(
cx,
variant_path,
&variant.data,
&prefixes,
ast::Mutability::Not,
use_temporaries,
)
.into_iter()
.map(|p| cx.pat(span, PatKind::Ref(p, ast::Mutability::Not)))
.collect();
let use_ref_pat = false; // because enums can't be repr(packed)
let mut subpats: Vec<_> = trait_.create_struct_patterns(
cx,
variant_path,
&variant.data,
&prefixes,
use_ref_pat,
);
// Here is the pat = `(&VariantK, &VariantK, ...)`
// `(VariantK, VariantK, ...)` or just `VariantK`.
let single_pat = if subpats.len() == 1 {
subpats.pop().unwrap()
} else {
@ -1256,27 +1309,28 @@ impl<'a> MethodDef<'a> {
})
.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 {
Some(v) if self.unify_fieldless_variants => {
// We need a default case that handles the fieldless variants.
// The index and actual variant aren't meaningful in this case,
// so just use whatever
let substructure = EnumMatching(0, variants.len(), v, Vec::new());
// We need a default case that handles all the fieldless
// variants. The index and actual variant aren't meaningful in
// this case, so just use dummy values.
Some(
self.call_substructure_method(
cx,
trait_,
type_ident,
nonselflike_args,
&substructure,
&EnumMatching(0, variants.len(), v, Vec::new()),
)
.into_expr(cx, span),
)
}
_ 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
// 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))
}
_ => None,
@ -1285,111 +1339,41 @@ impl<'a> MethodDef<'a> {
match_arms.push(cx.arm(span, cx.pat_wild(span), arm));
}
// We will usually need the catch-all after matching the
// tuples `(VariantK, VariantK, ...)` for each VariantK of the
// enum. But:
//
// * 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
// (Variant2, Variant2, ...) => Body2,
// ...
// _ => ::core::intrinsics::unreachable()
// }
// }
// 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));
// Create a match expression with one arm per discriminant plus
// possibly a default arm, e.g.:
// match (self, other) {
// (Variant1, Variant1, ...) => Body1
// (Variant2, Variant2, ...) => Body2,
// ...
// _ => ::core::intrinsics::unreachable()
// }
let get_match_expr = |mut selflike_args: Vec<P<Expr>>| {
let match_arg = if selflike_args.len() == 1 {
selflike_args.pop().unwrap()
} else {
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_def: &'a VariantData,
prefixes: &[String],
mutbl: ast::Mutability,
use_temporaries: bool,
use_ref_pat: bool,
) -> Vec<P<ast::Pat>> {
prefixes
.iter()
@ -1462,10 +1445,10 @@ impl<'a> TraitDef<'a> {
let pieces_iter =
struct_def.fields().iter().enumerate().map(|(i, struct_field)| {
let sp = struct_field.span.with_ctxt(self.span.ctxt());
let binding_mode = if use_temporaries {
ast::BindingMode::ByValue(ast::Mutability::Not)
let binding_mode = if use_ref_pat {
ast::BindingMode::ByRef(ast::Mutability::Not)
} else {
ast::BindingMode::ByRef(mutbl)
ast::BindingMode::ByValue(ast::Mutability::Not)
};
let ident = self.mk_pattern_ident(prefix, i);
let path = ident.with_span_pos(sp);
@ -1544,7 +1527,7 @@ impl<'a> TraitDef<'a> {
cx: &mut ExtCtxt<'_>,
struct_def: &'a VariantData,
prefixes: &[String],
use_temporaries: bool,
addr_of: bool,
) -> Vec<FieldInfo> {
self.create_fields(struct_def, |i, _struct_field, sp| {
prefixes
@ -1552,7 +1535,7 @@ impl<'a> TraitDef<'a> {
.map(|prefix| {
let ident = self.mk_pattern_ident(prefix, i);
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()
})
@ -1563,20 +1546,17 @@ impl<'a> TraitDef<'a> {
cx: &mut ExtCtxt<'_>,
selflike_args: &[P<Expr>],
struct_def: &'a VariantData,
copy: bool,
) -> Vec<FieldInfo> {
self.create_fields(struct_def, |i, struct_field, sp| {
selflike_args
.iter()
.map(|mut selflike_arg| {
// We don't the need the deref, if there is one.
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
.map(|selflike_arg| {
// Note: we must use `struct_field.span` rather than `sp` in the
// `unwrap_or_else` case otherwise the hygiene is wrong and we get
// "field `0` of struct `Point` is private" errors on tuple
// structs.
cx.expr(
let mut field_expr = cx.expr(
sp,
ast::ExprKind::Field(
selflike_arg.clone(),
@ -1584,7 +1564,13 @@ impl<'a> TraitDef<'a> {
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()
})
@ -1605,11 +1591,6 @@ pub enum CsFold<'a> {
// The fallback case for a struct or enum variant with no fields.
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.
@ -1624,8 +1605,8 @@ pub fn cs_fold<F>(
where
F: FnMut(&mut ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
{
match *substructure.fields {
EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => {
match substructure.fields {
EnumMatching(.., all_fields) | Struct(_, all_fields) => {
if all_fields.is_empty() {
return f(cx, CsFold::Fieldless);
}
@ -1649,7 +1630,18 @@ where
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`"),
}
}

View File

@ -196,9 +196,8 @@ impl Bounds {
}
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_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not));
let self_expr = cx.expr_deref(span, self_path);
(self_expr, self_ty)
(self_path, self_ty)
}

View File

@ -1,6 +1,6 @@
use crate::deriving::generic::ty::*;
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_expand::base::{Annotatable, ExtCtxt};
@ -52,39 +52,29 @@ fn hash_substructure(
let [state_expr] = substr.nonselflike_args else {
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 strs = cx.std_path(&[sym::hash, sym::Hash, sym::hash]);
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![ref_thing, state_expr.clone()]);
let expr = cx.expr_call(span, hash_path, vec![expr, state_expr.clone()]);
cx.stmt_expr(expr)
};
let mut stmts = Vec::new();
let fields = match substr.fields {
Struct(_, fs) | EnumMatching(_, 1, .., fs) => fs,
EnumMatching(.., fs) => {
let variant_value = deriving::call_intrinsic(
cx,
trait_span,
sym::discriminant_value,
vec![cx.expr_self(trait_span)],
);
stmts.push(call_hash(trait_span, variant_value));
fs
let (stmts, match_expr) = match substr.fields {
Struct(_, fields) | EnumMatching(.., fields) => {
let stmts =
fields.iter().map(|field| call_hash(field.span, field.self_expr.clone())).collect();
(stmts, None)
}
EnumTag(tag_field, match_expr) => {
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())
}
_ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`"),
};
stmts.extend(
fields
.iter()
.map(|FieldInfo { ref self_expr, span, .. }| call_hash(*span, self_expr.clone())),
);
BlockOrExpr::new_stmts(stmts)
BlockOrExpr::new_mixed(stmts, match_expr)
}

View File

@ -31,13 +31,26 @@ struct Point {
// A large struct.
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
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)]
#[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.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
@ -49,6 +62,13 @@ enum Enum1 {
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.
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum Fieldless {

View File

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