Rollup merge of #98741 - nnethercote:deriving-cleanups, r=Mark-Simulacrum

Many small deriving cleanups

These commits remove lots of little unnecessary things, and clarifies other things.

r? `@Mark-Simulacrum`
This commit is contained in:
Dylan DPC 2022-07-01 20:19:20 +05:30 committed by GitHub
commit c0cf363ca1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 125 additions and 304 deletions

View File

@ -19,7 +19,6 @@ pub fn expand_deriving_copy(
path: path_std!(marker::Copy),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: true,
methods: Vec::new(),
associated_types: Vec::new(),

View File

@ -15,23 +15,22 @@ pub fn expand_deriving_clone(
item: &Annotatable,
push: &mut dyn FnMut(Annotatable),
) {
// check if we can use a short form
// The simple form is `fn clone(&self) -> Self { *self }`, possibly with
// some additional `AssertParamIsClone` assertions.
//
// the short form is `fn clone(&self) -> Self { *self }`
//
// we can use the short form if:
// - the item is Copy (unfortunately, all we can check is whether it's also deriving Copy)
// - there are no generic parameters (after specialization this limitation can be removed)
// if we used the short form with generics, we'd have to bound the generics with
// Clone + Copy, and then there'd be no Clone impl at all if the user fills in something
// that is Clone but not Copy. and until specialization we can't write both impls.
// - the item is a union with Copy fields
// Unions with generic parameters still can derive Clone because they require Copy
// for deriving, Clone alone is not enough.
// Wherever Clone is implemented for fields is irrelevant so we don't assert it.
// We can use the simple form if either of the following are true.
// - The type derives Copy and there are no generic parameters. (If we
// used the simple form with generics, we'd have to bound the generics
// with Clone + Copy, and then there'd be no Clone impl at all if the
// user fills in something that is Clone but not Copy. After
// specialization we can remove this no-generics limitation.)
// - The item is a union. (Unions with generic parameters still can derive
// Clone because they require Copy for deriving, Clone alone is not
// enough. Whether Clone is implemented for fields is irrelevant so we
// don't assert it.)
let bounds;
let substructure;
let is_shallow;
let is_simple;
match *item {
Annotatable::Item(ref annitem) => match annitem.kind {
ItemKind::Struct(_, Generics { ref params, .. })
@ -44,30 +43,25 @@ pub fn expand_deriving_clone(
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
{
bounds = vec![];
is_shallow = true;
is_simple = true;
substructure = combine_substructure(Box::new(|c, s, sub| {
cs_clone_shallow("Clone", c, s, sub, false)
cs_clone_simple("Clone", c, s, sub, false)
}));
} else {
bounds = vec![];
is_shallow = false;
is_simple = false;
substructure =
combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub)));
}
}
ItemKind::Union(..) => {
bounds = vec![Literal(path_std!(marker::Copy))];
is_shallow = true;
bounds = vec![Path(path_std!(marker::Copy))];
is_simple = true;
substructure = combine_substructure(Box::new(|c, s, sub| {
cs_clone_shallow("Clone", c, s, sub, true)
cs_clone_simple("Clone", c, s, sub, true)
}));
}
_ => {
bounds = vec![];
is_shallow = false;
substructure =
combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub)));
}
_ => cx.span_bug(span, "`#[derive(Clone)]` on wrong item kind"),
},
_ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
@ -81,26 +75,24 @@ pub fn expand_deriving_clone(
path: path_std!(clone::Clone),
additional_bounds: bounds,
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: true,
methods: vec![MethodDef {
name: sym::clone,
generics: Bounds::empty(),
explicit_self: borrowed_explicit_self(),
explicit_self: true,
args: Vec::new(),
ret_ty: Self_,
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: false,
combine_substructure: substructure,
}],
associated_types: Vec::new(),
};
trait_def.expand_ext(cx, mitem, item, push, is_shallow)
trait_def.expand_ext(cx, mitem, item, push, is_simple)
}
fn cs_clone_shallow(
fn cs_clone_simple(
name: &str,
cx: &mut ExtCtxt<'_>,
trait_span: Span,
@ -143,7 +135,7 @@ fn cs_clone_shallow(
}
_ => cx.span_bug(
trait_span,
&format!("unexpected substructure in shallow `derive({})`", name),
&format!("unexpected substructure in simple `derive({})`", name),
),
}
}

View File

@ -27,16 +27,14 @@ pub fn expand_deriving_eq(
path: path_std!(cmp::Eq),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: true,
methods: vec![MethodDef {
name: sym::assert_receiver_is_total_eq,
generics: Bounds::empty(),
explicit_self: borrowed_explicit_self(),
explicit_self: true,
args: vec![],
ret_ty: nil_ty(),
ret_ty: Unit,
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
cs_total_eq_assert(a, b, c)

View File

@ -23,16 +23,14 @@ pub fn expand_deriving_ord(
path: path_std!(cmp::Ord),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::cmp,
generics: Bounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec![(borrowed_self(), sym::other)],
ret_ty: Literal(path_std!(cmp::Ordering)),
explicit_self: true,
args: vec![(self_ref(), sym::other)],
ret_ty: Path(path_std!(cmp::Ordering)),
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))),
}],
@ -99,8 +97,8 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<
cx.expr_match(span, new, vec![eq_arm, neq_arm])
},
cx.expr_path(equals_path.clone()),
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
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)

View File

@ -48,7 +48,7 @@ pub fn expand_deriving_partial_eq(
None => cx.expr_bool(span, base),
}
},
Box::new(|cx, span, _, _| cx.expr_bool(span, !base)),
Box::new(|cx, span, _| cx.expr_bool(span, !base)),
cx,
span,
substr,
@ -69,11 +69,10 @@ pub fn expand_deriving_partial_eq(
MethodDef {
name: $name,
generics: Bounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec![(borrowed_self(), sym::other)],
ret_ty: Literal(path_local!(bool)),
explicit_self: true,
args: vec![(self_ref(), sym::other)],
ret_ty: Path(path_local!(bool)),
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(Box::new(|a, b, c| $f(a, b, c))),
}
@ -102,7 +101,6 @@ pub fn expand_deriving_partial_eq(
path: path_std!(cmp::PartialEq),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods,
associated_types: Vec::new(),

View File

@ -15,13 +15,9 @@ pub fn expand_deriving_partial_ord(
item: &Annotatable,
push: &mut dyn FnMut(Annotatable),
) {
let ordering_ty = Literal(path_std!(cmp::Ordering));
let ret_ty = Literal(Path::new_(
pathvec_std!(option::Option),
None,
vec![Box::new(ordering_ty)],
PathKind::Std,
));
let ordering_ty = Path(path_std!(cmp::Ordering));
let ret_ty =
Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));
let inline = cx.meta_word(span, sym::inline);
let attrs = vec![cx.attribute(inline)];
@ -29,11 +25,10 @@ pub fn expand_deriving_partial_ord(
let partial_cmp_def = MethodDef {
name: sym::partial_cmp,
generics: Bounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec![(borrowed_self(), sym::other)],
explicit_self: true,
args: vec![(self_ref(), sym::other)],
ret_ty,
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
cs_partial_cmp(cx, span, substr)
@ -46,7 +41,6 @@ pub fn expand_deriving_partial_ord(
path: path_std!(cmp::PartialOrd),
additional_bounds: vec![],
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![partial_cmp_def],
associated_types: Vec::new(),
@ -102,8 +96,8 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
cx.expr_match(span, new, vec![eq_arm, neq_arm])
},
equals_expr,
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
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]));

View File

@ -16,8 +16,7 @@ pub fn expand_deriving_debug(
push: &mut dyn FnMut(Annotatable),
) {
// &mut ::std::fmt::Formatter
let fmtr =
Ptr(Box::new(Literal(path_std!(fmt::Formatter))), Borrowed(None, ast::Mutability::Mut));
let fmtr = Ref(Box::new(Path(path_std!(fmt::Formatter))), ast::Mutability::Mut);
let trait_def = TraitDef {
span,
@ -25,16 +24,14 @@ pub fn expand_deriving_debug(
path: path_std!(fmt::Debug),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::fmt,
generics: Bounds::empty(),
explicit_self: borrowed_explicit_self(),
explicit_self: true,
args: vec![(fmtr, sym::f)],
ret_ty: Literal(path_std!(fmt::Result)),
ret_ty: Path(path_std!(fmt::Result)),
attributes: Vec::new(),
is_unsafe: false,
unify_fieldless_variants: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
show_substructure(a, b, c)
@ -64,8 +61,6 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
let (is_struct, args_per_field) = match vdata {
ast::VariantData::Unit(..) => {
// Special fast path for unit variants.
//let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
//return cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]);
assert!(fields.is_empty());
(false, 0)
}

View File

@ -23,40 +23,29 @@ pub fn expand_deriving_rustc_decodable(
let trait_def = TraitDef {
span,
attributes: Vec::new(),
path: Path::new_(vec![krate, sym::Decodable], None, vec![], PathKind::Global),
path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::decode,
generics: Bounds {
bounds: vec![(
typaram,
vec![Path::new_(vec![krate, sym::Decoder], None, vec![], PathKind::Global)],
vec![Path::new_(vec![krate, sym::Decoder], vec![], PathKind::Global)],
)],
},
explicit_self: None,
args: vec![(
Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
sym::d,
)],
ret_ty: Literal(Path::new_(
explicit_self: false,
args: vec![(Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), sym::d)],
ret_ty: Path(Path::new_(
pathvec_std!(result::Result),
None,
vec![
Box::new(Self_),
Box::new(Literal(Path::new_(
vec![typaram, sym::Error],
None,
vec![],
PathKind::Local,
))),
Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
],
PathKind::Std,
)),
attributes: Vec::new(),
is_unsafe: false,
unify_fieldless_variants: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
decodable_substructure(a, b, c, krate)

View File

@ -30,16 +30,14 @@ pub fn expand_deriving_default(
path: Path::new(vec![kw::Default, sym::Default]),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![MethodDef {
name: kw::Default,
generics: Bounds::empty(),
explicit_self: None,
explicit_self: false,
args: Vec::new(),
ret_ty: Self_,
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: false,
combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| {
match substr.fields {

View File

@ -108,40 +108,29 @@ pub fn expand_deriving_rustc_encodable(
let trait_def = TraitDef {
span,
attributes: Vec::new(),
path: Path::new_(vec![krate, sym::Encodable], None, vec![], PathKind::Global),
path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::encode,
generics: Bounds {
bounds: vec![(
typaram,
vec![Path::new_(vec![krate, sym::Encoder], None, vec![], PathKind::Global)],
vec![Path::new_(vec![krate, sym::Encoder], vec![], PathKind::Global)],
)],
},
explicit_self: borrowed_explicit_self(),
args: vec![(
Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
sym::s,
)],
ret_ty: Literal(Path::new_(
explicit_self: true,
args: vec![(Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), sym::s)],
ret_ty: Path(Path::new_(
pathvec_std!(result::Result),
None,
vec![
Box::new(Tuple(Vec::new())),
Box::new(Literal(Path::new_(
vec![typaram, sym::Error],
None,
vec![],
PathKind::Local,
))),
Box::new(Unit),
Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
],
PathKind::Std,
)),
attributes: Vec::new(),
is_unsafe: false,
unify_fieldless_variants: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
encodable_substructure(a, b, c, krate)

View File

@ -146,8 +146,6 @@
//!
//! ```{.text}
//! EnumNonMatchingCollapsed(
//! vec![<ident of self>, <ident of __arg_1>],
//! &[<ast::Variant for C0>, <ast::Variant for C1>],
//! &[<ident for self index value>, <ident of __arg_1 index value>])
//! ```
//!
@ -190,7 +188,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use ty::{Bounds, Path, Ptr, PtrTy, Self_, Ty};
use ty::{Bounds, Path, Ref, Self_, Ty};
use crate::deriving;
@ -212,9 +210,6 @@ pub struct TraitDef<'a> {
/// Any extra lifetimes and/or bounds, e.g., `D: serialize::Decoder`
pub generics: Bounds,
/// Is it an `unsafe` trait?
pub is_unsafe: bool,
/// Can this trait be derived for unions?
pub supports_unions: bool,
@ -229,10 +224,8 @@ pub struct MethodDef<'a> {
/// List of generics, e.g., `R: rand::Rng`
pub generics: Bounds,
/// Whether there is a self argument (outer Option) i.e., whether
/// this is a static function, and whether it is a pointer (inner
/// Option)
pub explicit_self: Option<Option<PtrTy>>,
/// Is there is a `&self` argument? If not, it is a static function.
pub explicit_self: bool,
/// Arguments other than the self argument
pub args: Vec<(Ty, Symbol)>,
@ -242,9 +235,6 @@ pub struct MethodDef<'a> {
pub attributes: Vec<ast::Attribute>,
// Is it an `unsafe fn`?
pub is_unsafe: bool,
/// Can we combine fieldless variants for enums into a single match arm?
pub unify_fieldless_variants: bool,
@ -255,14 +245,7 @@ pub struct MethodDef<'a> {
pub struct Substructure<'a> {
/// ident of self
pub type_ident: Ident,
/// ident of the method
pub method_ident: Ident,
/// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)`][ptr] arguments
///
/// [`Self_`]: ty::Ty::Self_
/// [ptr]: ty::Ty::Ptr
pub self_args: &'a [P<Expr>],
/// verbatim access to any other arguments
/// verbatim access to any non-self arguments
pub nonself_args: &'a [P<Expr>],
pub fields: &'a SubstructureFields<'a>,
}
@ -299,13 +282,10 @@ pub enum SubstructureFields<'a> {
/// variant.
EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo<'a>>),
/// Non-matching variants of the enum, but with all state hidden from
/// the consequent code. The first component holds `Ident`s for all of
/// the `Self` arguments; the second component is a slice of all of the
/// variants for the enum itself, and the third component is a list of
/// `Ident`s bound to the variant index values for each of the actual
/// input `Self` arguments.
EnumNonMatchingCollapsed(Vec<Ident>, &'a [ast::Variant], &'a [Ident]),
/// 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]),
/// A static method where `Self` is a struct.
StaticStruct(&'a ast::VariantData, StaticFields),
@ -318,13 +298,10 @@ pub enum SubstructureFields<'a> {
pub type CombineSubstructureFunc<'a> =
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> P<Expr> + 'a>;
/// Deal with non-matching enum variants. The tuple is a list of
/// identifiers (one for each `Self` argument, which could be any of the
/// variants since they have been collapsed together) and the identifiers
/// holding the variant index value for each of the `Self` arguments. The
/// last argument is all the non-`Self` args of the method being derived.
/// Deal with non-matching enum variants. The slice is the identifiers holding
/// the variant index value for each of the `Self` arguments.
pub type EnumNonMatchCollapsedFunc<'a> =
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &[Ident]) -> P<Expr> + 'a>;
pub fn combine_substructure(
f: CombineSubstructureFunc<'_>,
@ -727,14 +704,12 @@ impl<'a> TraitDef<'a> {
let mut a = vec![attr, unused_qual];
a.extend(self.attributes.iter().cloned());
let unsafety = if self.is_unsafe { ast::Unsafe::Yes(self.span) } else { ast::Unsafe::No };
cx.item(
self.span,
Ident::empty(),
a,
ast::ItemKind::Impl(Box::new(ast::Impl {
unsafety,
unsafety: ast::Unsafe::No,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: ast::Const::No,
@ -771,7 +746,6 @@ impl<'a> TraitDef<'a> {
self,
struct_def,
type_ident,
&self_args,
&nonself_args,
)
} else {
@ -820,7 +794,6 @@ impl<'a> TraitDef<'a> {
self,
enum_def,
type_ident,
&self_args,
&nonself_args,
)
} else {
@ -848,18 +821,11 @@ impl<'a> MethodDef<'a> {
cx: &mut ExtCtxt<'_>,
trait_: &TraitDef<'_>,
type_ident: Ident,
self_args: &[P<Expr>],
nonself_args: &[P<Expr>],
fields: &SubstructureFields<'_>,
) -> P<Expr> {
let span = trait_.span;
let substructure = Substructure {
type_ident,
method_ident: Ident::new(self.name, span),
self_args,
nonself_args,
fields,
};
let substructure = Substructure { type_ident, nonself_args, fields };
let mut f = self.combine_substructure.borrow_mut();
let f: &mut CombineSubstructureFunc<'_> = &mut *f;
f(cx, span, &substructure)
@ -876,7 +842,7 @@ impl<'a> MethodDef<'a> {
}
fn is_static(&self) -> bool {
self.explicit_self.is_none()
!self.explicit_self
}
fn split_self_nonself_args(
@ -889,17 +855,15 @@ impl<'a> MethodDef<'a> {
let mut self_args = Vec::new();
let mut nonself_args = Vec::new();
let mut arg_tys = Vec::new();
let mut nonstatic = false;
let span = trait_.span;
let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| {
let (self_expr, explicit_self) = ty::get_explicit_self(cx, span, self_ptr);
let ast_explicit_self = if self.explicit_self {
let (self_expr, explicit_self) = ty::get_explicit_self(cx, span);
self_args.push(self_expr);
nonstatic = true;
explicit_self
});
Some(explicit_self)
} else {
None
};
for (ty, name) in self.args.iter() {
let ast_ty = ty.to_ty(cx, span, type_ident, generics);
@ -911,10 +875,10 @@ impl<'a> MethodDef<'a> {
match *ty {
// for static methods, just treat any Self
// arguments as a normal arg
Self_ if nonstatic => {
Self_ if !self.is_static() => {
self_args.push(arg_expr);
}
Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
Ref(ref ty, _) if matches!(**ty, Self_) && !self.is_static() => {
self_args.push(cx.expr_deref(span, arg_expr))
}
_ => {
@ -955,15 +919,9 @@ impl<'a> MethodDef<'a> {
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
let body_block = cx.block_expr(body);
let unsafety = if self.is_unsafe { ast::Unsafe::Yes(span) } else { ast::Unsafe::No };
let trait_lo_sp = span.shrink_to_lo();
let sig = ast::FnSig {
header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() },
decl: fn_decl,
span,
};
let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
let defaultness = ast::Defaultness::Final;
// Create the method.
@ -1083,7 +1041,6 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
self_args,
nonself_args,
&Struct(struct_def, fields),
);
@ -1104,7 +1061,6 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'_>,
struct_def: &VariantData,
type_ident: Ident,
self_args: &[P<Expr>],
nonself_args: &[P<Expr>],
) -> P<Expr> {
let summary = trait_.summarise_struct(cx, struct_def);
@ -1113,7 +1069,6 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
self_args,
nonself_args,
&StaticStruct(struct_def, summary),
)
@ -1184,11 +1139,6 @@ impl<'a> MethodDef<'a> {
)
.collect::<Vec<String>>();
let self_arg_idents = self_arg_names
.iter()
.map(|name| Ident::from_str_and_span(name, span))
.collect::<Vec<Ident>>();
// The `vi_idents` will be bound, solely in the catch-all, to
// a series of let statements mapping each self_arg to an int
// value corresponding to its discriminant.
@ -1203,8 +1153,7 @@ impl<'a> MethodDef<'a> {
// 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(self_arg_idents, &variants, &vi_idents);
let catch_all_substructure = EnumNonMatchingCollapsed(&vi_idents);
let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
@ -1303,7 +1252,6 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
&self_args[..],
nonself_args,
&substructure,
);
@ -1322,7 +1270,6 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
&self_args[..],
nonself_args,
&substructure,
))
@ -1393,7 +1340,6 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
&self_args[..],
nonself_args,
&catch_all_substructure,
);
@ -1491,7 +1437,6 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'_>,
enum_def: &EnumDef,
type_ident: Ident,
self_args: &[P<Expr>],
nonself_args: &[P<Expr>],
) -> P<Expr> {
let summary = enum_def
@ -1507,7 +1452,6 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
self_args,
nonself_args,
&StaticEnum(enum_def, summary),
)
@ -1628,7 +1572,7 @@ impl<'a> TraitDef<'a> {
// helpful premade recipes
pub fn cs_fold_fields<'a, F>(
fn cs_fold_fields<'a, F>(
use_foldl: bool,
mut f: F,
base: P<Expr>,
@ -1650,21 +1594,19 @@ where
}
}
pub fn cs_fold_enumnonmatch(
fn cs_fold_enumnonmatch(
mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
cx: &mut ExtCtxt<'_>,
trait_span: Span,
substructure: &Substructure<'_>,
) -> P<Expr> {
match *substructure.fields {
EnumNonMatchingCollapsed(ref all_args, _, tuple) => {
enum_nonmatch_f(cx, trait_span, (&all_args[..], tuple), substructure.nonself_args)
}
EnumNonMatchingCollapsed(tuple) => enum_nonmatch_f(cx, trait_span, tuple),
_ => cx.span_bug(trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed"),
}
}
pub fn cs_fold_static(cx: &mut ExtCtxt<'_>, trait_span: Span) -> P<Expr> {
fn cs_fold_static(cx: &mut ExtCtxt<'_>, trait_span: Span) -> P<Expr> {
cx.span_bug(trait_span, "static function in `derive`")
}
@ -1717,22 +1659,21 @@ where
{
match *substructure.fields {
EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => {
let (base, all_fields) = match (all_fields.is_empty(), use_foldl) {
let (base, rest) = match (all_fields.is_empty(), use_foldl) {
(false, true) => {
let field = &all_fields[0];
let args = (field.span, field.self_.clone(), &field.other[..]);
(b(cx, Some(args)), &all_fields[1..])
let (first, rest) = all_fields.split_first().unwrap();
let args = (first.span, first.self_.clone(), &first.other[..]);
(b(cx, Some(args)), rest)
}
(false, false) => {
let idx = all_fields.len() - 1;
let field = &all_fields[idx];
let args = (field.span, field.self_.clone(), &field.other[..]);
(b(cx, Some(args)), &all_fields[..idx])
let (last, rest) = all_fields.split_last().unwrap();
let args = (last.span, last.self_.clone(), &last.other[..]);
(b(cx, Some(args)), rest)
}
(true, _) => (b(cx, None), &all_fields[..]),
};
cs_fold_fields(use_foldl, f, base, cx, all_fields)
cs_fold_fields(use_foldl, f, base, cx, rest)
}
EnumNonMatchingCollapsed(..) => {
cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)

View File

@ -1,7 +1,6 @@
//! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use
//! when specifying impls to be derived.
pub use PtrTy::*;
pub use Ty::*;
use rustc_ast::ptr::P;
@ -11,22 +10,11 @@ use rustc_span::source_map::{respan, DUMMY_SP};
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span;
/// The types of pointers
#[derive(Clone)]
pub enum PtrTy {
/// &'lifetime mut
Borrowed(Option<Ident>, ast::Mutability),
/// *mut
#[allow(dead_code)]
Raw(ast::Mutability),
}
/// A path, e.g., `::std::option::Option::<i32>` (global). Has support
/// for type parameters and a lifetime.
/// for type parameters.
#[derive(Clone)]
pub struct Path {
path: Vec<Symbol>,
lifetime: Option<Ident>,
params: Vec<Box<Ty>>,
kind: PathKind,
}
@ -40,18 +28,13 @@ pub enum PathKind {
impl Path {
pub fn new(path: Vec<Symbol>) -> Path {
Path::new_(path, None, Vec::new(), PathKind::Std)
Path::new_(path, Vec::new(), PathKind::Std)
}
pub fn new_local(path: Symbol) -> Path {
Path::new_(vec![path], None, Vec::new(), PathKind::Local)
Path::new_(vec![path], Vec::new(), PathKind::Local)
}
pub fn new_(
path: Vec<Symbol>,
lifetime: Option<Ident>,
params: Vec<Box<Ty>>,
kind: PathKind,
) -> Path {
Path { path, lifetime, params, kind }
pub fn new_(path: Vec<Symbol>, params: Vec<Box<Ty>>, kind: PathKind) -> Path {
Path { path, params, kind }
}
pub fn to_ty(
@ -71,10 +54,8 @@ impl Path {
self_generics: &Generics,
) -> ast::Path {
let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect();
let lt = mk_lifetimes(cx, span, &self.lifetime);
let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics));
let params =
lt.into_iter().map(GenericArg::Lifetime).chain(tys.map(GenericArg::Type)).collect();
let params = tys.map(GenericArg::Type).collect();
match self.kind {
PathKind::Global => cx.path_all(span, true, idents, params),
@ -92,40 +73,17 @@ impl Path {
#[derive(Clone)]
pub enum Ty {
Self_,
/// &/Box/ Ty
Ptr(Box<Ty>, PtrTy),
/// A reference.
Ref(Box<Ty>, ast::Mutability),
/// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type
/// parameter, and things like `i32`
Literal(Path),
/// includes unit
Tuple(Vec<Ty>),
Path(Path),
/// For () return types.
Unit,
}
pub fn borrowed_ptrty() -> PtrTy {
Borrowed(None, ast::Mutability::Not)
}
pub fn borrowed(ty: Box<Ty>) -> Ty {
Ptr(ty, borrowed_ptrty())
}
pub fn borrowed_explicit_self() -> Option<Option<PtrTy>> {
Some(Some(borrowed_ptrty()))
}
pub fn borrowed_self() -> Ty {
borrowed(Box::new(Self_))
}
pub fn nil_ty() -> Ty {
Tuple(Vec::new())
}
fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Option<ast::Lifetime> {
lt.map(|ident| cx.lifetime(span, ident))
}
fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Vec<ast::Lifetime> {
mk_lifetime(cx, span, lt).into_iter().collect()
pub fn self_ref() -> Ty {
Ref(Box::new(Self_), ast::Mutability::Not)
}
impl Ty {
@ -136,23 +94,15 @@ impl Ty {
self_ty: Ident,
self_generics: &Generics,
) -> P<ast::Ty> {
match *self {
Ptr(ref ty, ref ptr) => {
match self {
Ref(ty, mutbl) => {
let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
match *ptr {
Borrowed(ref lt, mutbl) => {
let lt = mk_lifetime(cx, span, lt);
cx.ty_rptr(span, raw_ty, lt, mutbl)
cx.ty_rptr(span, raw_ty, None, *mutbl)
}
Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl),
}
}
Literal(ref p) => p.to_ty(cx, span, self_ty, self_generics),
Path(p) => p.to_ty(cx, span, self_ty, self_generics),
Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
Tuple(ref fields) => {
let ty = ast::TyKind::Tup(
fields.iter().map(|f| f.to_ty(cx, span, self_ty, self_generics)).collect(),
);
Unit => {
let ty = ast::TyKind::Tup(vec![]);
cx.ty(span, ty)
}
}
@ -185,9 +135,9 @@ impl Ty {
cx.path_all(span, false, vec![self_ty], params)
}
Literal(ref p) => p.to_path(cx, span, self_ty, generics),
Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"),
Tuple(..) => cx.span_bug(span, "tuple in a path in generic `derive`"),
Path(ref p) => p.to_path(cx, span, self_ty, generics),
Ref(..) => cx.span_bug(span, "ref in a path in generic `derive`"),
Unit => cx.span_bug(span, "unit in a path in generic `derive`"),
}
}
}
@ -245,28 +195,10 @@ impl Bounds {
}
}
pub fn get_explicit_self(
cx: &ExtCtxt<'_>,
span: Span,
self_ptr: &Option<PtrTy>,
) -> (P<Expr>, ast::ExplicitSelf) {
pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) {
// this constructs a fresh `self` path
let self_path = cx.expr_self(span);
match *self_ptr {
None => (self_path, respan(span, SelfKind::Value(ast::Mutability::Not))),
Some(ref ptr) => {
let self_ty = respan(
span,
match *ptr {
Borrowed(ref lt, mutbl) => {
let lt = lt.map(|s| cx.lifetime(span, s));
SelfKind::Region(lt, mutbl)
}
Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition"),
},
);
let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not));
let self_expr = cx.expr_deref(span, self_path);
(self_expr, self_ty)
}
}
}

View File

@ -15,7 +15,7 @@ pub fn expand_deriving_hash(
item: &Annotatable,
push: &mut dyn FnMut(Annotatable),
) {
let path = Path::new_(pathvec_std!(hash::Hash), None, vec![], PathKind::Std);
let path = Path::new_(pathvec_std!(hash::Hash), vec![], PathKind::Std);
let typaram = sym::__H;
@ -26,16 +26,14 @@ pub fn expand_deriving_hash(
path,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::hash,
generics: Bounds { bounds: vec![(typaram, vec![path_std!(hash::Hasher)])] },
explicit_self: borrowed_explicit_self(),
args: vec![(Ptr(Box::new(Literal(arg)), Borrowed(None, Mutability::Mut)), sym::state)],
ret_ty: nil_ty(),
explicit_self: true,
args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)],
ret_ty: Unit,
attributes: vec![],
is_unsafe: false,
unify_fieldless_variants: true,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
hash_substructure(a, b, c)