Auto merge of #98758 - nnethercote:more-derive-output-improvements, r=Mark-Simulacrum
More derive output improvements This PR includes: - Some test improvements. - Some cosmetic changes to derive output that make the code look more like what a human would write. - Some more fundamental improvements to `cmp` and `partial_cmp` generation. r? `@Mark-Simulacrum`
This commit is contained in:
commit
fbdb07f4e7
15 changed files with 655 additions and 568 deletions
|
@ -2036,6 +2036,14 @@ impl TyKind {
|
||||||
pub fn is_unit(&self) -> bool {
|
pub fn is_unit(&self) -> bool {
|
||||||
matches!(self, TyKind::Tup(tys) if tys.is_empty())
|
matches!(self, TyKind::Tup(tys) if tys.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_simple_path(&self) -> Option<Symbol> {
|
||||||
|
if let TyKind::Path(None, Path { segments, .. }) = &self && segments.len() == 1 {
|
||||||
|
Some(segments[0].ident.name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Syntax used to declare a trait object.
|
/// Syntax used to declare a trait object.
|
||||||
|
|
|
@ -2,8 +2,8 @@ use crate::deriving::generic::ty::*;
|
||||||
use crate::deriving::generic::*;
|
use crate::deriving::generic::*;
|
||||||
use crate::deriving::path_std;
|
use crate::deriving::path_std;
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, VariantData};
|
||||||
use rustc_ast::{self as ast, Expr, Generics, ItemKind, MetaItem, VariantData};
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||||
use rustc_span::symbol::{kw, sym, Ident};
|
use rustc_span::symbol::{kw, sym, Ident};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -98,22 +98,31 @@ fn cs_clone_simple(
|
||||||
trait_span: Span,
|
trait_span: Span,
|
||||||
substr: &Substructure<'_>,
|
substr: &Substructure<'_>,
|
||||||
is_union: bool,
|
is_union: bool,
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
|
let mut seen_type_names = FxHashSet::default();
|
||||||
let mut process_variant = |variant: &VariantData| {
|
let mut process_variant = |variant: &VariantData| {
|
||||||
for field in variant.fields() {
|
for field in variant.fields() {
|
||||||
// let _: AssertParamIsClone<FieldTy>;
|
// This basic redundancy checking only prevents duplication of
|
||||||
super::assert_ty_bounds(
|
// assertions like `AssertParamIsClone<Foo>` where the type is a
|
||||||
cx,
|
// simple name. That's enough to get a lot of cases, though.
|
||||||
&mut stmts,
|
if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) {
|
||||||
field.ty.clone(),
|
// Already produced an assertion for this type.
|
||||||
field.span,
|
} else {
|
||||||
&[sym::clone, sym::AssertParamIsClone],
|
// let _: AssertParamIsClone<FieldTy>;
|
||||||
);
|
super::assert_ty_bounds(
|
||||||
|
cx,
|
||||||
|
&mut stmts,
|
||||||
|
field.ty.clone(),
|
||||||
|
field.span,
|
||||||
|
&[sym::clone, sym::AssertParamIsClone],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_union {
|
if is_union {
|
||||||
|
// Just a single assertion for unions, that the union impls `Copy`.
|
||||||
// let _: AssertParamIsCopy<Self>;
|
// let _: AssertParamIsCopy<Self>;
|
||||||
let self_ty = cx.ty_path(cx.path_ident(trait_span, Ident::with_dummy_span(kw::SelfUpper)));
|
let self_ty = cx.ty_path(cx.path_ident(trait_span, Ident::with_dummy_span(kw::SelfUpper)));
|
||||||
super::assert_ty_bounds(
|
super::assert_ty_bounds(
|
||||||
|
@ -139,8 +148,7 @@ fn cs_clone_simple(
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span))));
|
BlockOrExpr::new_mixed(stmts, cx.expr_deref(trait_span, cx.expr_self(trait_span)))
|
||||||
cx.expr_block(cx.block(trait_span, stmts))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cs_clone(
|
fn cs_clone(
|
||||||
|
@ -148,7 +156,7 @@ fn cs_clone(
|
||||||
cx: &mut ExtCtxt<'_>,
|
cx: &mut ExtCtxt<'_>,
|
||||||
trait_span: Span,
|
trait_span: Span,
|
||||||
substr: &Substructure<'_>,
|
substr: &Substructure<'_>,
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
let ctor_path;
|
let ctor_path;
|
||||||
let all_fields;
|
let all_fields;
|
||||||
let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]);
|
let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]);
|
||||||
|
@ -177,7 +185,7 @@ fn cs_clone(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match *vdata {
|
let expr = match *vdata {
|
||||||
VariantData::Struct(..) => {
|
VariantData::Struct(..) => {
|
||||||
let fields = all_fields
|
let fields = all_fields
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -201,5 +209,6 @@ fn cs_clone(
|
||||||
cx.expr_call(trait_span, path, subcalls)
|
cx.expr_call(trait_span, path, subcalls)
|
||||||
}
|
}
|
||||||
VariantData::Unit(..) => cx.expr_path(ctor_path),
|
VariantData::Unit(..) => cx.expr_path(ctor_path),
|
||||||
}
|
};
|
||||||
|
BlockOrExpr::new_expr(expr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ use crate::deriving::generic::ty::*;
|
||||||
use crate::deriving::generic::*;
|
use crate::deriving::generic::*;
|
||||||
use crate::deriving::path_std;
|
use crate::deriving::path_std;
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::{self as ast, MetaItem};
|
||||||
use rustc_ast::{self as ast, Expr, MetaItem};
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||||
use rustc_span::symbol::{sym, Ident};
|
use rustc_span::symbol::{sym, Ident};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -52,18 +52,26 @@ fn cs_total_eq_assert(
|
||||||
cx: &mut ExtCtxt<'_>,
|
cx: &mut ExtCtxt<'_>,
|
||||||
trait_span: Span,
|
trait_span: Span,
|
||||||
substr: &Substructure<'_>,
|
substr: &Substructure<'_>,
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
|
let mut seen_type_names = FxHashSet::default();
|
||||||
let mut process_variant = |variant: &ast::VariantData| {
|
let mut process_variant = |variant: &ast::VariantData| {
|
||||||
for field in variant.fields() {
|
for field in variant.fields() {
|
||||||
// let _: AssertParamIsEq<FieldTy>;
|
// This basic redundancy checking only prevents duplication of
|
||||||
super::assert_ty_bounds(
|
// assertions like `AssertParamIsEq<Foo>` where the type is a
|
||||||
cx,
|
// simple name. That's enough to get a lot of cases, though.
|
||||||
&mut stmts,
|
if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) {
|
||||||
field.ty.clone(),
|
// Already produced an assertion for this type.
|
||||||
field.span,
|
} else {
|
||||||
&[sym::cmp, sym::AssertParamIsEq],
|
// let _: AssertParamIsEq<FieldTy>;
|
||||||
);
|
super::assert_ty_bounds(
|
||||||
|
cx,
|
||||||
|
&mut stmts,
|
||||||
|
field.ty.clone(),
|
||||||
|
field.span,
|
||||||
|
&[sym::cmp, sym::AssertParamIsEq],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,5 +86,5 @@ fn cs_total_eq_assert(
|
||||||
}
|
}
|
||||||
_ => cx.span_bug(trait_span, "unexpected substructure in `derive(Eq)`"),
|
_ => cx.span_bug(trait_span, "unexpected substructure in `derive(Eq)`"),
|
||||||
}
|
}
|
||||||
cx.expr_block(cx.block(trait_span, stmts))
|
BlockOrExpr::new_stmts(stmts)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::deriving::generic::*;
|
||||||
use crate::deriving::path_std;
|
use crate::deriving::path_std;
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::{self as ast, Expr, MetaItem};
|
use rustc_ast::{self as ast, MetaItem};
|
||||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||||
use rustc_span::symbol::{sym, Ident};
|
use rustc_span::symbol::{sym, Ident};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -51,7 +51,7 @@ pub fn ordering_collapsed(
|
||||||
cx.expr_call_global(span, fn_cmp_path, vec![lft, rgt])
|
cx.expr_call_global(span, fn_cmp_path, vec![lft, rgt])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
|
pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
|
||||||
let test_id = Ident::new(sym::cmp, span);
|
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 equals_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<
|
||||||
// cmp => cmp
|
// cmp => cmp
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
cs_fold(
|
let expr = cs_fold(
|
||||||
// foldr nests the if-elses correctly, leaving the first field
|
// foldr nests the if-elses correctly, leaving the first field
|
||||||
// as the outermost one, and the last as the innermost.
|
// as the outermost one, and the last as the innermost.
|
||||||
false,
|
false,
|
||||||
|
@ -79,15 +79,12 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<
|
||||||
// ::std::cmp::Ordering::Equal => old,
|
// ::std::cmp::Ordering::Equal => old,
|
||||||
// cmp => cmp
|
// cmp => cmp
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let new = {
|
let new = {
|
||||||
let [other_f] = other_fs else {
|
let [other_f] = other_fs else {
|
||||||
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
|
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
|
||||||
};
|
};
|
||||||
|
|
||||||
let args =
|
let args =
|
||||||
vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())];
|
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)
|
cx.expr_call_global(span, cmp_path.clone(), args)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,7 +93,21 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<
|
||||||
|
|
||||||
cx.expr_match(span, new, vec![eq_arm, neq_arm])
|
cx.expr_match(span, new, vec![eq_arm, neq_arm])
|
||||||
},
|
},
|
||||||
cx.expr_path(equals_path.clone()),
|
|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| {
|
Box::new(|cx, span, tag_tuple| {
|
||||||
if tag_tuple.len() != 2 {
|
if tag_tuple.len() != 2 {
|
||||||
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`")
|
cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`")
|
||||||
|
@ -107,5 +118,6 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<
|
||||||
cx,
|
cx,
|
||||||
span,
|
span,
|
||||||
substr,
|
substr,
|
||||||
)
|
);
|
||||||
|
BlockOrExpr::new_expr(expr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,6 @@ pub fn expand_deriving_partial_eq(
|
||||||
item: &Annotatable,
|
item: &Annotatable,
|
||||||
push: &mut dyn FnMut(Annotatable),
|
push: &mut dyn FnMut(Annotatable),
|
||||||
) {
|
) {
|
||||||
// structures are equal if all fields are equal, and non equal, if
|
|
||||||
// any fields are not equal or if the enum variants are different
|
|
||||||
fn cs_op(
|
fn cs_op(
|
||||||
cx: &mut ExtCtxt<'_>,
|
cx: &mut ExtCtxt<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -24,7 +22,7 @@ pub fn expand_deriving_partial_eq(
|
||||||
op: BinOpKind,
|
op: BinOpKind,
|
||||||
combiner: BinOpKind,
|
combiner: BinOpKind,
|
||||||
base: bool,
|
base: bool,
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
let op = |cx: &mut ExtCtxt<'_>, span: Span, self_f: P<Expr>, other_fs: &[P<Expr>]| {
|
let op = |cx: &mut ExtCtxt<'_>, span: Span, self_f: P<Expr>, other_fs: &[P<Expr>]| {
|
||||||
let [other_f] = other_fs else {
|
let [other_f] = other_fs else {
|
||||||
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`");
|
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`");
|
||||||
|
@ -33,7 +31,7 @@ pub fn expand_deriving_partial_eq(
|
||||||
cx.expr_binary(span, op, self_f, other_f.clone())
|
cx.expr_binary(span, op, self_f, other_f.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
cs_fold1(
|
let expr = cs_fold(
|
||||||
true, // use foldl
|
true, // use foldl
|
||||||
|cx, span, subexpr, self_f, other_fs| {
|
|cx, span, subexpr, self_f, other_fs| {
|
||||||
let eq = op(cx, span, self_f, other_fs);
|
let eq = op(cx, span, self_f, other_fs);
|
||||||
|
@ -52,13 +50,14 @@ pub fn expand_deriving_partial_eq(
|
||||||
cx,
|
cx,
|
||||||
span,
|
span,
|
||||||
substr,
|
substr,
|
||||||
)
|
);
|
||||||
|
BlockOrExpr::new_expr(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
|
fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
|
||||||
cs_op(cx, span, substr, BinOpKind::Eq, BinOpKind::And, true)
|
cs_op(cx, span, substr, BinOpKind::Eq, BinOpKind::And, true)
|
||||||
}
|
}
|
||||||
fn cs_ne(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
|
fn cs_ne(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
|
||||||
cs_op(cx, span, substr, BinOpKind::Ne, BinOpKind::Or, false)
|
cs_op(cx, span, substr, BinOpKind::Ne, BinOpKind::Or, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,11 +48,10 @@ pub fn expand_deriving_partial_ord(
|
||||||
trait_def.expand(cx, mitem, item, push)
|
trait_def.expand(cx, mitem, item, push)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
|
pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
|
||||||
let test_id = Ident::new(sym::cmp, span);
|
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 = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
|
||||||
let ordering_expr = cx.expr_path(ordering.clone());
|
let ordering_expr = cx.expr_path(ordering.clone());
|
||||||
let equals_expr = cx.expr_some(span, ordering_expr);
|
|
||||||
|
|
||||||
let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
|
let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
|
||||||
|
|
||||||
|
@ -69,7 +68,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
|
||||||
// cmp => cmp
|
// cmp => cmp
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
cs_fold(
|
let expr = cs_fold(
|
||||||
// foldr nests the if-elses correctly, leaving the first field
|
// foldr nests the if-elses correctly, leaving the first field
|
||||||
// as the outermost one, and the last as the innermost.
|
// as the outermost one, and the last as the innermost.
|
||||||
false,
|
false,
|
||||||
|
@ -95,7 +94,21 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
|
||||||
|
|
||||||
cx.expr_match(span, new, vec![eq_arm, neq_arm])
|
cx.expr_match(span, new, vec![eq_arm, neq_arm])
|
||||||
},
|
},
|
||||||
equals_expr,
|
|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| {
|
Box::new(|cx, span, tag_tuple| {
|
||||||
if tag_tuple.len() != 2 {
|
if tag_tuple.len() != 2 {
|
||||||
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
|
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
|
||||||
|
@ -110,5 +123,6 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
|
||||||
cx,
|
cx,
|
||||||
span,
|
span,
|
||||||
substr,
|
substr,
|
||||||
)
|
);
|
||||||
|
BlockOrExpr::new_expr(expr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
|
||||||
use crate::deriving::generic::*;
|
use crate::deriving::generic::*;
|
||||||
use crate::deriving::path_std;
|
use crate::deriving::path_std;
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::{self as ast, MetaItem};
|
||||||
use rustc_ast::{self as ast, Expr, MetaItem};
|
|
||||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -42,7 +41,7 @@ pub fn expand_deriving_debug(
|
||||||
trait_def.expand(cx, mitem, item, push)
|
trait_def.expand(cx, mitem, item, push)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
|
fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
|
||||||
let (ident, vdata, fields) = match substr.fields {
|
let (ident, vdata, fields) = match substr.fields {
|
||||||
Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
|
Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
|
||||||
EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
|
EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
|
||||||
|
@ -74,7 +73,8 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
|
||||||
if fields.is_empty() {
|
if fields.is_empty() {
|
||||||
// Special case for no fields.
|
// Special case for no fields.
|
||||||
let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
|
let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
|
||||||
cx.expr_call_global(span, fn_path_write_str, vec![fmt, name])
|
let expr = cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]);
|
||||||
|
BlockOrExpr::new_expr(expr)
|
||||||
} else if fields.len() <= CUTOFF {
|
} else if fields.len() <= CUTOFF {
|
||||||
// Few enough fields that we can use a specific-length method.
|
// Few enough fields that we can use a specific-length method.
|
||||||
let debug = if is_struct {
|
let debug = if is_struct {
|
||||||
|
@ -100,7 +100,8 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
|
||||||
let field = cx.expr_addr_of(field.span, field);
|
let field = cx.expr_addr_of(field.span, field);
|
||||||
args.push(field);
|
args.push(field);
|
||||||
}
|
}
|
||||||
cx.expr_call_global(span, fn_path_debug, args)
|
let expr = cx.expr_call_global(span, fn_path_debug, args);
|
||||||
|
BlockOrExpr::new_expr(expr)
|
||||||
} else {
|
} else {
|
||||||
// Enough fields that we must use the any-length method.
|
// Enough fields that we must use the any-length method.
|
||||||
let mut name_exprs = Vec::with_capacity(fields.len());
|
let mut name_exprs = Vec::with_capacity(fields.len());
|
||||||
|
@ -176,8 +177,6 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
|
||||||
stmts.push(names_let.unwrap());
|
stmts.push(names_let.unwrap());
|
||||||
}
|
}
|
||||||
stmts.push(values_let);
|
stmts.push(values_let);
|
||||||
stmts.push(cx.stmt_expr(expr));
|
BlockOrExpr::new_mixed(stmts, expr)
|
||||||
|
|
||||||
cx.expr_block(cx.block(span, stmts))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ fn decodable_substructure(
|
||||||
trait_span: Span,
|
trait_span: Span,
|
||||||
substr: &Substructure<'_>,
|
substr: &Substructure<'_>,
|
||||||
krate: Symbol,
|
krate: Symbol,
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
let decoder = substr.nonself_args[0].clone();
|
let decoder = substr.nonself_args[0].clone();
|
||||||
let recurse = vec![
|
let recurse = vec![
|
||||||
Ident::new(krate, trait_span),
|
Ident::new(krate, trait_span),
|
||||||
|
@ -74,7 +74,7 @@ fn decodable_substructure(
|
||||||
let blkarg = Ident::new(sym::_d, trait_span);
|
let blkarg = Ident::new(sym::_d, trait_span);
|
||||||
let blkdecoder = cx.expr_ident(trait_span, blkarg);
|
let blkdecoder = cx.expr_ident(trait_span, blkarg);
|
||||||
|
|
||||||
match *substr.fields {
|
let expr = match *substr.fields {
|
||||||
StaticStruct(_, ref summary) => {
|
StaticStruct(_, ref summary) => {
|
||||||
let nfields = match *summary {
|
let nfields = match *summary {
|
||||||
Unnamed(ref fields, _) => fields.len(),
|
Unnamed(ref fields, _) => fields.len(),
|
||||||
|
@ -173,7 +173,8 @@ fn decodable_substructure(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
|
_ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
|
||||||
}
|
};
|
||||||
|
BlockOrExpr::new_expr(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a decoder for a single enum variant/struct:
|
/// Creates a decoder for a single enum variant/struct:
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::deriving::generic::ty::*;
|
use crate::deriving::generic::ty::*;
|
||||||
use crate::deriving::generic::*;
|
use crate::deriving::generic::*;
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::walk_list;
|
use rustc_ast::walk_list;
|
||||||
use rustc_ast::EnumDef;
|
use rustc_ast::EnumDef;
|
||||||
use rustc_ast::VariantData;
|
use rustc_ast::VariantData;
|
||||||
use rustc_ast::{Expr, MetaItem};
|
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
|
@ -16,7 +15,7 @@ use smallvec::SmallVec;
|
||||||
pub fn expand_deriving_default(
|
pub fn expand_deriving_default(
|
||||||
cx: &mut ExtCtxt<'_>,
|
cx: &mut ExtCtxt<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
mitem: &MetaItem,
|
mitem: &ast::MetaItem,
|
||||||
item: &Annotatable,
|
item: &Annotatable,
|
||||||
push: &mut dyn FnMut(Annotatable),
|
push: &mut dyn FnMut(Annotatable),
|
||||||
) {
|
) {
|
||||||
|
@ -59,12 +58,12 @@ fn default_struct_substructure(
|
||||||
trait_span: Span,
|
trait_span: Span,
|
||||||
substr: &Substructure<'_>,
|
substr: &Substructure<'_>,
|
||||||
summary: &StaticFields,
|
summary: &StaticFields,
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
// Note that `kw::Default` is "default" and `sym::Default` is "Default"!
|
// Note that `kw::Default` is "default" and `sym::Default` is "Default"!
|
||||||
let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]);
|
let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]);
|
||||||
let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new());
|
let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new());
|
||||||
|
|
||||||
match summary {
|
let expr = match summary {
|
||||||
Unnamed(ref fields, is_tuple) => {
|
Unnamed(ref fields, is_tuple) => {
|
||||||
if !is_tuple {
|
if !is_tuple {
|
||||||
cx.expr_ident(trait_span, substr.type_ident)
|
cx.expr_ident(trait_span, substr.type_ident)
|
||||||
|
@ -80,31 +79,27 @@ fn default_struct_substructure(
|
||||||
.collect();
|
.collect();
|
||||||
cx.expr_struct_ident(trait_span, substr.type_ident, default_fields)
|
cx.expr_struct_ident(trait_span, substr.type_ident, default_fields)
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
BlockOrExpr::new_expr(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_enum_substructure(
|
fn default_enum_substructure(
|
||||||
cx: &mut ExtCtxt<'_>,
|
cx: &mut ExtCtxt<'_>,
|
||||||
trait_span: Span,
|
trait_span: Span,
|
||||||
enum_def: &EnumDef,
|
enum_def: &EnumDef,
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
let Ok(default_variant) = extract_default_variant(cx, enum_def, trait_span) else {
|
let expr = if let Ok(default_variant) = extract_default_variant(cx, enum_def, trait_span)
|
||||||
return DummyResult::raw_expr(trait_span, true);
|
&& let Ok(_) = validate_default_attribute(cx, default_variant)
|
||||||
|
{
|
||||||
|
// We now know there is exactly one unit variant with exactly one `#[default]` attribute.
|
||||||
|
cx.expr_path(cx.path(
|
||||||
|
default_variant.span,
|
||||||
|
vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident],
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
DummyResult::raw_expr(trait_span, true)
|
||||||
};
|
};
|
||||||
|
BlockOrExpr::new_expr(expr)
|
||||||
// At this point, we know that there is exactly one variant with a `#[default]` attribute. The
|
|
||||||
// attribute hasn't yet been validated.
|
|
||||||
|
|
||||||
if let Err(()) = validate_default_attribute(cx, default_variant) {
|
|
||||||
return DummyResult::raw_expr(trait_span, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We now know there is exactly one unit variant with exactly one `#[default]` attribute.
|
|
||||||
|
|
||||||
cx.expr_path(cx.path(
|
|
||||||
default_variant.span,
|
|
||||||
vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident],
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_default_variant<'a>(
|
fn extract_default_variant<'a>(
|
||||||
|
|
|
@ -89,8 +89,7 @@ use crate::deriving::generic::ty::*;
|
||||||
use crate::deriving::generic::*;
|
use crate::deriving::generic::*;
|
||||||
use crate::deriving::pathvec_std;
|
use crate::deriving::pathvec_std;
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::{ExprKind, MetaItem, Mutability};
|
||||||
use rustc_ast::{Expr, ExprKind, MetaItem, Mutability};
|
|
||||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -147,7 +146,7 @@ fn encodable_substructure(
|
||||||
trait_span: Span,
|
trait_span: Span,
|
||||||
substr: &Substructure<'_>,
|
substr: &Substructure<'_>,
|
||||||
krate: Symbol,
|
krate: Symbol,
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
let encoder = substr.nonself_args[0].clone();
|
let encoder = substr.nonself_args[0].clone();
|
||||||
// throw an underscore in front to suppress unused variable warnings
|
// throw an underscore in front to suppress unused variable warnings
|
||||||
let blkarg = Ident::new(sym::_e, trait_span);
|
let blkarg = Ident::new(sym::_e, trait_span);
|
||||||
|
@ -208,7 +207,7 @@ fn encodable_substructure(
|
||||||
let fn_emit_struct_path =
|
let fn_emit_struct_path =
|
||||||
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]);
|
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]);
|
||||||
|
|
||||||
cx.expr_call_global(
|
let expr = cx.expr_call_global(
|
||||||
trait_span,
|
trait_span,
|
||||||
fn_emit_struct_path,
|
fn_emit_struct_path,
|
||||||
vec![
|
vec![
|
||||||
|
@ -217,7 +216,8 @@ fn encodable_substructure(
|
||||||
cx.expr_usize(trait_span, fields.len()),
|
cx.expr_usize(trait_span, fields.len()),
|
||||||
blk,
|
blk,
|
||||||
],
|
],
|
||||||
)
|
);
|
||||||
|
BlockOrExpr::new_expr(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
EnumMatching(idx, _, variant, ref fields) => {
|
EnumMatching(idx, _, variant, ref fields) => {
|
||||||
|
@ -279,12 +279,12 @@ fn encodable_substructure(
|
||||||
let blk = cx.lambda1(trait_span, call, blkarg);
|
let blk = cx.lambda1(trait_span, call, blkarg);
|
||||||
let fn_emit_enum_path: Vec<_> =
|
let fn_emit_enum_path: Vec<_> =
|
||||||
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]);
|
cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]);
|
||||||
let ret = cx.expr_call_global(
|
let expr = cx.expr_call_global(
|
||||||
trait_span,
|
trait_span,
|
||||||
fn_emit_enum_path,
|
fn_emit_enum_path,
|
||||||
vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk],
|
vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk],
|
||||||
);
|
);
|
||||||
cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)]))
|
BlockOrExpr::new_mixed(vec![me], expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"),
|
_ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"),
|
||||||
|
|
|
@ -296,7 +296,7 @@ pub enum SubstructureFields<'a> {
|
||||||
/// Combine the values of all the fields together. The last argument is
|
/// Combine the values of all the fields together. The last argument is
|
||||||
/// all the fields of all the structures.
|
/// all the fields of all the structures.
|
||||||
pub type CombineSubstructureFunc<'a> =
|
pub type CombineSubstructureFunc<'a> =
|
||||||
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> P<Expr> + 'a>;
|
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>;
|
||||||
|
|
||||||
/// Deal with non-matching enum variants. The slice is the identifiers holding
|
/// Deal with non-matching enum variants. The slice is the identifiers holding
|
||||||
/// the variant index value for each of the `Self` arguments.
|
/// the variant index value for each of the `Self` arguments.
|
||||||
|
@ -314,6 +314,48 @@ struct TypeParameter {
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The code snippets built up for derived code are sometimes used as blocks
|
||||||
|
// (e.g. in a function body) and sometimes used as expressions (e.g. in a match
|
||||||
|
// arm). This structure avoids committing to either form until necessary,
|
||||||
|
// avoiding the insertion of any unnecessary blocks.
|
||||||
|
//
|
||||||
|
// The statements come before the expression.
|
||||||
|
pub struct BlockOrExpr(Vec<ast::Stmt>, Option<P<Expr>>);
|
||||||
|
|
||||||
|
impl BlockOrExpr {
|
||||||
|
pub fn new_stmts(stmts: Vec<ast::Stmt>) -> BlockOrExpr {
|
||||||
|
BlockOrExpr(stmts, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_expr(expr: P<Expr>) -> BlockOrExpr {
|
||||||
|
BlockOrExpr(vec![], Some(expr))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_mixed(stmts: Vec<ast::Stmt>, expr: P<Expr>) -> BlockOrExpr {
|
||||||
|
BlockOrExpr(stmts, Some(expr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts it into a block.
|
||||||
|
fn into_block(mut self, cx: &ExtCtxt<'_>, span: Span) -> P<ast::Block> {
|
||||||
|
if let Some(expr) = self.1 {
|
||||||
|
self.0.push(cx.stmt_expr(expr));
|
||||||
|
}
|
||||||
|
cx.block(span, self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts it into an expression.
|
||||||
|
fn into_expr(self, cx: &ExtCtxt<'_>, span: Span) -> P<Expr> {
|
||||||
|
if self.0.is_empty() {
|
||||||
|
match self.1 {
|
||||||
|
None => cx.expr_block(cx.block(span, vec![])),
|
||||||
|
Some(expr) => expr,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cx.expr_block(self.into_block(cx, span))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This method helps to extract all the type parameters referenced from a
|
/// This method helps to extract all the type parameters referenced from a
|
||||||
/// type. For a type parameter `<T>`, it looks for either a `TyPath` that
|
/// type. For a type parameter `<T>`, it looks for either a `TyPath` that
|
||||||
/// is not global and starts with `T`, or a `TyQPath`.
|
/// is not global and starts with `T`, or a `TyQPath`.
|
||||||
|
@ -827,7 +869,7 @@ impl<'a> MethodDef<'a> {
|
||||||
type_ident: Ident,
|
type_ident: Ident,
|
||||||
nonself_args: &[P<Expr>],
|
nonself_args: &[P<Expr>],
|
||||||
fields: &SubstructureFields<'_>,
|
fields: &SubstructureFields<'_>,
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
let span = trait_.span;
|
let span = trait_.span;
|
||||||
let substructure = Substructure { type_ident, nonself_args, fields };
|
let substructure = Substructure { type_ident, nonself_args, fields };
|
||||||
let mut f = self.combine_substructure.borrow_mut();
|
let mut f = self.combine_substructure.borrow_mut();
|
||||||
|
@ -902,7 +944,7 @@ impl<'a> MethodDef<'a> {
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
explicit_self: Option<ast::ExplicitSelf>,
|
explicit_self: Option<ast::ExplicitSelf>,
|
||||||
arg_types: Vec<(Ident, P<ast::Ty>)>,
|
arg_types: Vec<(Ident, P<ast::Ty>)>,
|
||||||
body: P<Expr>,
|
body: BlockOrExpr,
|
||||||
) -> P<ast::AssocItem> {
|
) -> P<ast::AssocItem> {
|
||||||
let span = trait_.span;
|
let span = trait_.span;
|
||||||
// Create the generics that aren't for `Self`.
|
// Create the generics that aren't for `Self`.
|
||||||
|
@ -921,7 +963,7 @@ impl<'a> MethodDef<'a> {
|
||||||
|
|
||||||
let method_ident = Ident::new(self.name, span);
|
let method_ident = Ident::new(self.name, span);
|
||||||
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
|
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
|
||||||
let body_block = cx.block_expr(body);
|
let body_block = body.into_block(cx, span);
|
||||||
|
|
||||||
let trait_lo_sp = span.shrink_to_lo();
|
let trait_lo_sp = span.shrink_to_lo();
|
||||||
|
|
||||||
|
@ -986,7 +1028,7 @@ impl<'a> MethodDef<'a> {
|
||||||
nonself_args: &[P<Expr>],
|
nonself_args: &[P<Expr>],
|
||||||
use_temporaries: bool,
|
use_temporaries: bool,
|
||||||
is_packed: bool,
|
is_packed: bool,
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
let mut raw_fields = Vec::new(); // Vec<[fields of self], [fields of next Self arg], [etc]>
|
let mut raw_fields = Vec::new(); // Vec<[fields of self], [fields of next Self arg], [etc]>
|
||||||
let span = trait_.span;
|
let span = trait_.span;
|
||||||
let mut patterns = Vec::new();
|
let mut patterns = Vec::new();
|
||||||
|
@ -1047,16 +1089,14 @@ impl<'a> MethodDef<'a> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if !is_packed {
|
if !is_packed {
|
||||||
body.span = span;
|
|
||||||
body
|
body
|
||||||
} else {
|
} else {
|
||||||
// Do the let-destructuring.
|
// Do the let-destructuring.
|
||||||
let mut stmts: Vec<_> = iter::zip(self_args, patterns)
|
let mut stmts: Vec<_> = iter::zip(self_args, patterns)
|
||||||
.map(|(arg_expr, pat)| cx.stmt_let_pat(span, pat, arg_expr.clone()))
|
.map(|(arg_expr, pat)| cx.stmt_let_pat(span, pat, arg_expr.clone()))
|
||||||
.collect();
|
.collect();
|
||||||
stmts.push(cx.stmt_expr(body));
|
stmts.extend(std::mem::take(&mut body.0));
|
||||||
|
BlockOrExpr(stmts, body.1)
|
||||||
cx.expr_block(cx.block(span, stmts))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1067,7 +1107,7 @@ impl<'a> MethodDef<'a> {
|
||||||
struct_def: &VariantData,
|
struct_def: &VariantData,
|
||||||
type_ident: Ident,
|
type_ident: Ident,
|
||||||
nonself_args: &[P<Expr>],
|
nonself_args: &[P<Expr>],
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
let summary = trait_.summarise_struct(cx, struct_def);
|
let summary = trait_.summarise_struct(cx, struct_def);
|
||||||
|
|
||||||
self.call_substructure_method(
|
self.call_substructure_method(
|
||||||
|
@ -1130,7 +1170,7 @@ impl<'a> MethodDef<'a> {
|
||||||
type_ident: Ident,
|
type_ident: Ident,
|
||||||
mut self_args: Vec<P<Expr>>,
|
mut self_args: Vec<P<Expr>>,
|
||||||
nonself_args: &[P<Expr>],
|
nonself_args: &[P<Expr>],
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
let span = trait_.span;
|
let span = trait_.span;
|
||||||
let variants = &enum_def.variants;
|
let variants = &enum_def.variants;
|
||||||
|
|
||||||
|
@ -1199,7 +1239,11 @@ impl<'a> MethodDef<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here is the pat = `(&VariantK, &VariantK, ...)`
|
// Here is the pat = `(&VariantK, &VariantK, ...)`
|
||||||
let single_pat = cx.pat_tuple(span, subpats);
|
let single_pat = if subpats.len() == 1 {
|
||||||
|
subpats.pop().unwrap()
|
||||||
|
} else {
|
||||||
|
cx.pat_tuple(span, subpats)
|
||||||
|
};
|
||||||
|
|
||||||
// For the BodyK, we need to delegate to our caller,
|
// For the BodyK, we need to delegate to our caller,
|
||||||
// passing it an EnumMatching to indicate which case
|
// passing it an EnumMatching to indicate which case
|
||||||
|
@ -1253,13 +1297,9 @@ impl<'a> MethodDef<'a> {
|
||||||
// Self arg, assuming all are instances of VariantK.
|
// Self arg, assuming all are instances of VariantK.
|
||||||
// Build up code associated with such a case.
|
// Build up code associated with such a case.
|
||||||
let substructure = EnumMatching(index, variants.len(), variant, field_tuples);
|
let substructure = EnumMatching(index, variants.len(), variant, field_tuples);
|
||||||
let arm_expr = self.call_substructure_method(
|
let arm_expr = self
|
||||||
cx,
|
.call_substructure_method(cx, trait_, type_ident, nonself_args, &substructure)
|
||||||
trait_,
|
.into_expr(cx, span);
|
||||||
type_ident,
|
|
||||||
nonself_args,
|
|
||||||
&substructure,
|
|
||||||
);
|
|
||||||
|
|
||||||
cx.arm(span, single_pat, arm_expr)
|
cx.arm(span, single_pat, arm_expr)
|
||||||
})
|
})
|
||||||
|
@ -1271,13 +1311,16 @@ impl<'a> MethodDef<'a> {
|
||||||
// The index and actual variant aren't meaningful in this case,
|
// The index and actual variant aren't meaningful in this case,
|
||||||
// so just use whatever
|
// so just use whatever
|
||||||
let substructure = EnumMatching(0, variants.len(), v, Vec::new());
|
let substructure = EnumMatching(0, variants.len(), v, Vec::new());
|
||||||
Some(self.call_substructure_method(
|
Some(
|
||||||
cx,
|
self.call_substructure_method(
|
||||||
trait_,
|
cx,
|
||||||
type_ident,
|
trait_,
|
||||||
nonself_args,
|
type_ident,
|
||||||
&substructure,
|
nonself_args,
|
||||||
))
|
&substructure,
|
||||||
|
)
|
||||||
|
.into_expr(cx, span),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_ if variants.len() > 1 && self_args.len() > 1 => {
|
_ if variants.len() > 1 && self_args.len() > 1 => {
|
||||||
// Since we know that all the arguments will match if we reach
|
// Since we know that all the arguments will match if we reach
|
||||||
|
@ -1341,13 +1384,15 @@ impl<'a> MethodDef<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let arm_expr = self.call_substructure_method(
|
let arm_expr = self
|
||||||
cx,
|
.call_substructure_method(
|
||||||
trait_,
|
cx,
|
||||||
type_ident,
|
trait_,
|
||||||
nonself_args,
|
type_ident,
|
||||||
&catch_all_substructure,
|
nonself_args,
|
||||||
);
|
&catch_all_substructure,
|
||||||
|
)
|
||||||
|
.into_expr(cx, span);
|
||||||
|
|
||||||
// Final wrinkle: the self_args are expressions that deref
|
// Final wrinkle: the self_args are expressions that deref
|
||||||
// down to desired places, but we cannot actually deref
|
// down to desired places, but we cannot actually deref
|
||||||
|
@ -1371,8 +1416,7 @@ impl<'a> MethodDef<'a> {
|
||||||
// }
|
// }
|
||||||
let all_match = cx.expr_match(span, match_arg, match_arms);
|
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));
|
let arm_expr = cx.expr_if(span, discriminant_test, all_match, Some(arm_expr));
|
||||||
index_let_stmts.push(cx.stmt_expr(arm_expr));
|
BlockOrExpr(index_let_stmts, Some(arm_expr))
|
||||||
cx.expr_block(cx.block(span, index_let_stmts))
|
|
||||||
} else if variants.is_empty() {
|
} else if variants.is_empty() {
|
||||||
// As an additional wrinkle, For a zero-variant enum A,
|
// As an additional wrinkle, For a zero-variant enum A,
|
||||||
// currently the compiler
|
// currently the compiler
|
||||||
|
@ -1423,7 +1467,7 @@ impl<'a> MethodDef<'a> {
|
||||||
// derive Debug on such a type could here generate code
|
// derive Debug on such a type could here generate code
|
||||||
// that needs the feature gate enabled.)
|
// that needs the feature gate enabled.)
|
||||||
|
|
||||||
deriving::call_unreachable(cx, span)
|
BlockOrExpr(vec![], Some(deriving::call_unreachable(cx, span)))
|
||||||
} else {
|
} else {
|
||||||
// Final wrinkle: the self_args are expressions that deref
|
// Final wrinkle: the self_args are expressions that deref
|
||||||
// down to desired places, but we cannot actually deref
|
// down to desired places, but we cannot actually deref
|
||||||
|
@ -1431,8 +1475,12 @@ impl<'a> MethodDef<'a> {
|
||||||
// expression; here add a layer of borrowing, turning
|
// expression; here add a layer of borrowing, turning
|
||||||
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
|
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
|
||||||
self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
|
self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
|
||||||
let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
|
let match_arg = if self_args.len() == 1 {
|
||||||
cx.expr_match(span, match_arg, match_arms)
|
self_args.pop().unwrap()
|
||||||
|
} else {
|
||||||
|
cx.expr(span, ast::ExprKind::Tup(self_args))
|
||||||
|
};
|
||||||
|
BlockOrExpr(vec![], Some(cx.expr_match(span, match_arg, match_arms)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1443,7 +1491,7 @@ impl<'a> MethodDef<'a> {
|
||||||
enum_def: &EnumDef,
|
enum_def: &EnumDef,
|
||||||
type_ident: Ident,
|
type_ident: Ident,
|
||||||
nonself_args: &[P<Expr>],
|
nonself_args: &[P<Expr>],
|
||||||
) -> P<Expr> {
|
) -> BlockOrExpr {
|
||||||
let summary = enum_def
|
let summary = enum_def
|
||||||
.variants
|
.variants
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1606,71 +1654,6 @@ impl<'a> TraitDef<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helpful premade recipes
|
|
||||||
|
|
||||||
fn cs_fold_fields<'a, F>(
|
|
||||||
use_foldl: bool,
|
|
||||||
mut f: F,
|
|
||||||
base: P<Expr>,
|
|
||||||
cx: &mut ExtCtxt<'_>,
|
|
||||||
all_fields: &[FieldInfo<'a>],
|
|
||||||
) -> P<Expr>
|
|
||||||
where
|
|
||||||
F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
|
|
||||||
{
|
|
||||||
if use_foldl {
|
|
||||||
all_fields
|
|
||||||
.iter()
|
|
||||||
.fold(base, |old, field| f(cx, field.span, old, field.self_.clone(), &field.other))
|
|
||||||
} else {
|
|
||||||
all_fields
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.fold(base, |old, field| f(cx, field.span, old, field.self_.clone(), &field.other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cs_fold_enumnonmatch(
|
|
||||||
mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
|
|
||||||
cx: &mut ExtCtxt<'_>,
|
|
||||||
trait_span: Span,
|
|
||||||
substructure: &Substructure<'_>,
|
|
||||||
) -> P<Expr> {
|
|
||||||
match *substructure.fields {
|
|
||||||
EnumNonMatchingCollapsed(tuple) => enum_nonmatch_f(cx, trait_span, tuple),
|
|
||||||
_ => cx.span_bug(trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cs_fold_static(cx: &mut ExtCtxt<'_>, trait_span: Span) -> P<Expr> {
|
|
||||||
cx.span_bug(trait_span, "static function in `derive`")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fold the fields. `use_foldl` controls whether this is done
|
|
||||||
/// left-to-right (`true`) or right-to-left (`false`).
|
|
||||||
pub fn cs_fold<F>(
|
|
||||||
use_foldl: bool,
|
|
||||||
f: F,
|
|
||||||
base: P<Expr>,
|
|
||||||
enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
|
|
||||||
cx: &mut ExtCtxt<'_>,
|
|
||||||
trait_span: Span,
|
|
||||||
substructure: &Substructure<'_>,
|
|
||||||
) -> P<Expr>
|
|
||||||
where
|
|
||||||
F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
|
|
||||||
{
|
|
||||||
match *substructure.fields {
|
|
||||||
EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => {
|
|
||||||
cs_fold_fields(use_foldl, f, base, cx, all_fields)
|
|
||||||
}
|
|
||||||
EnumNonMatchingCollapsed(..) => {
|
|
||||||
cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
|
|
||||||
}
|
|
||||||
StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx, trait_span),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Function to fold over fields, with three cases, to generate more efficient and concise code.
|
/// Function to fold over fields, with three cases, to generate more efficient and concise code.
|
||||||
/// When the `substructure` has grouped fields, there are two cases:
|
/// When the `substructure` has grouped fields, there are two cases:
|
||||||
/// Zero fields: call the base case function with `None` (like the usual base case of `cs_fold`).
|
/// Zero fields: call the base case function with `None` (like the usual base case of `cs_fold`).
|
||||||
|
@ -1679,11 +1662,11 @@ where
|
||||||
/// fields.
|
/// fields.
|
||||||
/// When the `substructure` is an `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f`
|
/// When the `substructure` is an `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f`
|
||||||
/// is returned. Statics may not be folded over.
|
/// is returned. Statics may not be folded over.
|
||||||
pub fn cs_fold1<F, B>(
|
pub fn cs_fold<F, B>(
|
||||||
use_foldl: bool,
|
use_foldl: bool,
|
||||||
f: F,
|
mut f: F,
|
||||||
mut b: B,
|
mut b: B,
|
||||||
enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
|
mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
|
||||||
cx: &mut ExtCtxt<'_>,
|
cx: &mut ExtCtxt<'_>,
|
||||||
trait_span: Span,
|
trait_span: Span,
|
||||||
substructure: &Substructure<'_>,
|
substructure: &Substructure<'_>,
|
||||||
|
@ -1708,12 +1691,18 @@ where
|
||||||
(true, _) => (b(cx, None), &all_fields[..]),
|
(true, _) => (b(cx, None), &all_fields[..]),
|
||||||
};
|
};
|
||||||
|
|
||||||
cs_fold_fields(use_foldl, f, base, cx, rest)
|
if use_foldl {
|
||||||
|
rest.iter().fold(base, |old, field| {
|
||||||
|
f(cx, field.span, old, field.self_.clone(), &field.other)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
rest.iter().rev().fold(base, |old, field| {
|
||||||
|
f(cx, field.span, old, field.self_.clone(), &field.other)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EnumNonMatchingCollapsed(..) => {
|
EnumNonMatchingCollapsed(tuple) => enum_nonmatch_f(cx, trait_span, tuple),
|
||||||
cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
|
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
|
||||||
}
|
|
||||||
StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx, trait_span),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
|
||||||
use crate::deriving::generic::*;
|
use crate::deriving::generic::*;
|
||||||
use crate::deriving::{self, path_std, pathvec_std};
|
use crate::deriving::{self, path_std, pathvec_std};
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::{MetaItem, Mutability};
|
||||||
use rustc_ast::{Expr, MetaItem, Mutability};
|
|
||||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -45,7 +44,11 @@ pub fn expand_deriving_hash(
|
||||||
hash_trait_def.expand(cx, mitem, item, push);
|
hash_trait_def.expand(cx, mitem, item, push);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> P<Expr> {
|
fn hash_substructure(
|
||||||
|
cx: &mut ExtCtxt<'_>,
|
||||||
|
trait_span: Span,
|
||||||
|
substr: &Substructure<'_>,
|
||||||
|
) -> BlockOrExpr {
|
||||||
let [state_expr] = substr.nonself_args else {
|
let [state_expr] = substr.nonself_args else {
|
||||||
cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`");
|
cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`");
|
||||||
};
|
};
|
||||||
|
@ -81,6 +84,5 @@ fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructu
|
||||||
stmts.extend(
|
stmts.extend(
|
||||||
fields.iter().map(|FieldInfo { ref self_, span, .. }| call_hash(*span, self_.clone())),
|
fields.iter().map(|FieldInfo { ref self_, span, .. }| call_hash(*span, self_.clone())),
|
||||||
);
|
);
|
||||||
|
BlockOrExpr::new_stmts(stmts)
|
||||||
cx.expr_block(cx.block(trait_span, stmts))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
// CHECK: @STATIC = {{.*}}, align 4
|
// CHECK: @STATIC = {{.*}}, align 4
|
||||||
|
|
||||||
// This checks the constants from inline_enum_const
|
// This checks the constants from inline_enum_const
|
||||||
// CHECK: @alloc14 = {{.*}}, align 2
|
// CHECK: @alloc12 = {{.*}}, align 2
|
||||||
|
|
||||||
// This checks the constants from {low,high}_align_const, they share the same
|
// This checks the constants from {low,high}_align_const, they share the same
|
||||||
// constant, but the alignment differs, so the higher one should be used
|
// constant, but the alignment differs, so the higher one should be used
|
||||||
|
|
|
@ -39,6 +39,16 @@ struct Big {
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
struct Packed(u32);
|
struct Packed(u32);
|
||||||
|
|
||||||
|
// An empty enum.
|
||||||
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
enum Enum0 {}
|
||||||
|
|
||||||
|
// A single-variant enum.
|
||||||
|
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
enum Enum1 {
|
||||||
|
Single { x: u32 }
|
||||||
|
}
|
||||||
|
|
||||||
// A C-like, fieldless enum.
|
// A C-like, fieldless enum.
|
||||||
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
enum Fieldless {
|
enum Fieldless {
|
||||||
|
@ -66,3 +76,11 @@ enum Fielded {
|
||||||
Y(bool),
|
Y(bool),
|
||||||
Z(Option<i32>),
|
Z(Option<i32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A union. Most builtin traits are not derivable for unions.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub union Union {
|
||||||
|
pub b: bool,
|
||||||
|
pub u: u32,
|
||||||
|
pub i: i32,
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue