mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
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:
commit
0fe5390a88
@ -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))
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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)"),
|
||||
|
@ -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`"),
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user