Skip to content

Commit

Permalink
Rollup merge of #98915 - nnethercote:clarify-deriving-code, r=Mark-Si…
Browse files Browse the repository at this point in the history
…mulacrum

Clarify deriving code

A number of clarifications to the deriving code.

r? ``@Mark-Simulacrum``
  • Loading branch information
Dylan-DPC authored Jul 9, 2022
2 parents fd4f11d + 0578697 commit 5e6812b
Show file tree
Hide file tree
Showing 11 changed files with 454 additions and 567 deletions.
6 changes: 3 additions & 3 deletions compiler/rustc_builtin_macros/src/deriving/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ pub fn expand_deriving_clone(
name: sym::clone,
generics: Bounds::empty(),
explicit_self: true,
args: Vec::new(),
nonself_args: Vec::new(),
ret_ty: Self_,
attributes: attrs,
unify_fieldless_variants: false,
Expand Down Expand Up @@ -160,8 +160,8 @@ fn cs_clone(
let ctor_path;
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_.clone())];
let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo| {
let args = vec![cx.expr_addr_of(field.span, field.self_expr.clone())];
cx.expr_call_global(field.span, fn_path.clone(), args)
};

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub fn expand_deriving_eq(
name: sym::assert_receiver_is_total_eq,
generics: Bounds::empty(),
explicit_self: true,
args: vec![],
nonself_args: vec![],
ret_ty: Unit,
attributes: attrs,
unify_fieldless_variants: true,
Expand Down
103 changes: 36 additions & 67 deletions compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::path_std;

use rustc_ast::ptr::P;
use rustc_ast::{self as ast, MetaItem};
use rustc_ast::MetaItem;
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
Expand All @@ -28,7 +27,7 @@ pub fn expand_deriving_ord(
name: sym::cmp,
generics: Bounds::empty(),
explicit_self: true,
args: vec![(self_ref(), sym::other)],
nonself_args: vec![(self_ref(), sym::other)],
ret_ty: Path(path_std!(cmp::Ordering)),
attributes: attrs,
unify_fieldless_variants: true,
Expand All @@ -40,84 +39,54 @@ pub fn expand_deriving_ord(
trait_def.expand(cx, mitem, item, push)
}

pub fn ordering_collapsed(
cx: &mut ExtCtxt<'_>,
span: Span,
self_arg_tags: &[Ident],
) -> P<ast::Expr> {
let lft = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[0]));
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[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])
}

pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
let test_id = Ident::new(sym::cmp, span);
let equals_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));

let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);

// Builds:
//
// match ::std::cmp::Ord::cmp(&self_field1, &other_field1) {
// ::std::cmp::Ordering::Equal =>
// match ::std::cmp::Ord::cmp(&self_field2, &other_field2) {
// ::std::cmp::Ordering::Equal => {
// ...
// match ::core::cmp::Ord::cmp(&self.x, &other.x) {
// ::std::cmp::Ordering::Equal =>
// ::core::cmp::Ord::cmp(&self.y, &other.y),
// cmp => cmp,
// }
// cmp => cmp
// },
// cmp => cmp
// }
//
let expr = cs_fold(
// foldr nests the if-elses correctly, leaving the first field
// as the outermost one, and the last as the innermost.
false,
|cx, span, old, self_f, other_fs| {
// match new {
// ::std::cmp::Ordering::Equal => old,
// cmp => cmp
// }
let new = {
let [other_f] = other_fs else {
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
};
let args =
vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())];
cx.expr_call_global(span, cmp_path.clone(), args)
};

let eq_arm = cx.arm(span, cx.pat_path(span, equals_path.clone()), old);
let neq_arm = cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));

cx.expr_match(span, new, vec![eq_arm, neq_arm])
},
|cx, args| match args {
Some((span, self_f, other_fs)) => {
let new = {
let [other_f] = other_fs else {
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
};
let args =
vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())];
cx.expr_call_global(span, cmp_path.clone(), args)
};

new
}
None => cx.expr_path(equals_path.clone()),
},
Box::new(|cx, span, tag_tuple| {
if tag_tuple.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`")
} else {
ordering_collapsed(cx, span, tag_tuple)
}
}),
cx,
span,
substr,
|cx, fold| match fold {
CsFold::Single(field) => {
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()),
];
cx.expr_call_global(field.span, cmp_path.clone(), args)
}
CsFold::Combine(span, expr1, expr2) => {
let eq_arm = cx.arm(span, cx.pat_path(span, equal_path.clone()), expr1);
let neq_arm =
cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
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)
}
38 changes: 13 additions & 25 deletions compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::{path_local, path_std};

use rustc_ast::ptr::P;
use rustc_ast::{BinOpKind, Expr, MetaItem};
use rustc_ast::{BinOpKind, MetaItem};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::sym;
use rustc_span::Span;
Expand All @@ -23,33 +22,22 @@ pub fn expand_deriving_partial_eq(
combiner: BinOpKind,
base: bool,
) -> BlockOrExpr {
let op = |cx: &mut ExtCtxt<'_>, span: Span, self_f: P<Expr>, other_fs: &[P<Expr>]| {
let [other_f] = other_fs else {
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`");
};

cx.expr_binary(span, op, self_f, other_f.clone())
};

let expr = cs_fold(
true, // use foldl
|cx, span, subexpr, self_f, other_fs| {
let eq = op(cx, span, self_f, other_fs);
cx.expr_binary(span, combiner, subexpr, eq)
},
|cx, args| {
match args {
Some((span, self_f, other_fs)) => {
// Special-case the base case to generate cleaner code.
op(cx, span, self_f, other_fs)
}
None => cx.expr_bool(span, base),
}
},
Box::new(|cx, span, _| cx.expr_bool(span, !base)),
cx,
span,
substr,
|cx, fold| match fold {
CsFold::Single(field) => {
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())
}
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)
}
Expand All @@ -69,7 +57,7 @@ pub fn expand_deriving_partial_eq(
name: $name,
generics: Bounds::empty(),
explicit_self: true,
args: vec![(self_ref(), sym::other)],
nonself_args: vec![(self_ref(), sym::other)],
ret_ty: Path(path_local!(bool)),
attributes: attrs,
unify_fieldless_variants: true,
Expand Down
102 changes: 38 additions & 64 deletions compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::{path_std, pathvec_std};

use rustc_ast::ptr::P;
use rustc_ast::{Expr, MetaItem};
use rustc_ast::MetaItem;
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
Expand All @@ -26,7 +25,7 @@ pub fn expand_deriving_partial_ord(
name: sym::partial_cmp,
generics: Bounds::empty(),
explicit_self: true,
args: vec![(self_ref(), sym::other)],
nonself_args: vec![(self_ref(), sym::other)],
ret_ty,
attributes: attrs,
unify_fieldless_variants: true,
Expand All @@ -50,79 +49,54 @@ pub fn expand_deriving_partial_ord(

pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
let test_id = Ident::new(sym::cmp, span);
let ordering = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
let ordering_expr = cx.expr_path(ordering.clone());

let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);

// Builds:
//
// match ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1) {
// ::std::option::Option::Some(::std::cmp::Ordering::Equal) =>
// match ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2) {
// ::std::option::Option::Some(::std::cmp::Ordering::Equal) => {
// ...
// }
// cmp => cmp
// },
// cmp => cmp
// match ::core::cmp::PartialOrd::partial_cmp(&self.x, &other.x) {
// ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
// ::core::cmp::PartialOrd::partial_cmp(&self.y, &other.y),
// cmp => cmp,
// }
//
let expr = cs_fold(
// foldr nests the if-elses correctly, leaving the first field
// as the outermost one, and the last as the innermost.
false,
|cx, span, old, self_f, other_fs| {
// match new {
// Some(::std::cmp::Ordering::Equal) => old,
// cmp => cmp
// }

let new = {
let [other_f] = other_fs else {
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`");
};

let args =
vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())];

cx.expr_call_global(span, partial_cmp_path.clone(), args)
};

let eq_arm = cx.arm(span, cx.pat_some(span, cx.pat_path(span, ordering.clone())), old);
let neq_arm = cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));

cx.expr_match(span, new, vec![eq_arm, neq_arm])
},
|cx: &mut ExtCtxt<'_>, args: Option<(Span, P<Expr>, &[P<Expr>])>| match args {
Some((span, self_f, other_fs)) => {
let new = {
let [other_f] = other_fs else {
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
};
let args =
vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())];
cx.expr_call_global(span, partial_cmp_path.clone(), args)
};

new
}
None => cx.expr_some(span, ordering_expr.clone()),
},
Box::new(|cx, 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])
}
}),
cx,
span,
substr,
|cx, fold| match fold {
CsFold::Single(field) => {
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()),
];
cx.expr_call_global(field.span, partial_cmp_path.clone(), args)
}
CsFold::Combine(span, expr1, expr2) => {
let eq_arm =
cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1);
let neq_arm =
cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
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)
}
Loading

0 comments on commit 5e6812b

Please sign in to comment.