Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

builtin-derive: tag → discriminant #123919

Merged
merged 1 commit into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_builtin_macros/src/deriving/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ fn cs_clone(
all_fields = af;
vdata = &variant.data;
}
EnumTag(..) | AllFieldlessEnum(..) => {
cx.dcx().span_bug(trait_span, format!("enum tags in `derive({name})`",))
EnumDiscr(..) | AllFieldlessEnum(..) => {
cx.dcx().span_bug(trait_span, format!("enum discriminants in `derive({name})`",))
}
StaticEnum(..) | StaticStruct(..) => {
cx.dcx().span_bug(trait_span, format!("associated function in `derive({name})`"))
Expand Down
20 changes: 10 additions & 10 deletions compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ pub fn expand_deriving_partial_ord(
Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));

// Order in which to perform matching
let tag_then_data = if let Annotatable::Item(item) = item
let discr_then_data = if let Annotatable::Item(item) = item
&& let ItemKind::Enum(def, _) = &item.kind
{
let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect();
match dataful.iter().filter(|&&b| b).count() {
// No data, placing the tag check first makes codegen simpler
// No data, placing the discriminant check first makes codegen simpler
0 => true,
1..=2 => false,
_ => (0..dataful.len() - 1).any(|i| {
Expand All @@ -50,7 +50,7 @@ pub fn expand_deriving_partial_ord(
attributes: thin_vec![cx.attr_word(sym::inline, span)],
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
cs_partial_cmp(cx, span, substr, tag_then_data)
cs_partial_cmp(cx, span, substr, discr_then_data)
})),
};

Expand All @@ -72,7 +72,7 @@ fn cs_partial_cmp(
cx: &ExtCtxt<'_>,
span: Span,
substr: &Substructure<'_>,
tag_then_data: bool,
discr_then_data: bool,
) -> BlockOrExpr {
let test_id = Ident::new(sym::cmp, span);
let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
Expand Down Expand Up @@ -108,12 +108,12 @@ fn cs_partial_cmp(
// cmp => cmp
// }
// ```
// where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match`
// against the enum variants. This means that we begin by comparing the enum tags,
// where `expr2` is `partial_cmp(self_discr, other_discr)`, and `expr1` is a `match`
// against the enum variants. This means that we begin by comparing the enum discriminants,
// before either inspecting their contents (if they match), or returning
// the `cmp::Ordering` of comparing the enum tags.
// the `cmp::Ordering` of comparing the enum discriminants.
// ```
// match partial_cmp(self_tag, other_tag) {
// match partial_cmp(self_discr, other_discr) {
// Some(Ordering::Equal) => match (self, other) {
// (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
// (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0),
Expand All @@ -126,12 +126,12 @@ fn cs_partial_cmp(
// ```
// match (self, other) {
// (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
// _ => partial_cmp(self_tag, other_tag)
// _ => partial_cmp(self_discr, other_discr)
// }
// ```
// Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354

if !tag_then_data
if !discr_then_data
&& let ExprKind::Match(_, arms, _) = &mut expr1.kind
&& let Some(last) = arms.last_mut()
&& let PatKind::Wild = last.pat.kind
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) ->
Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
EnumMatching(_, v, fields) => (v.ident, &v.data, fields),
AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
EnumTag(..) | StaticStruct(..) | StaticEnum(..) => {
EnumDiscr(..) | StaticStruct(..) | StaticEnum(..) => {
cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
}
};
Expand Down
88 changes: 44 additions & 44 deletions compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
//! `struct T(i32, char)`).
//! - `EnumMatching`, when `Self` is an enum and all the arguments are the
//! same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`)
//! - `EnumTag` when `Self` is an enum, for comparing the enum tags.
//! - `EnumDiscr` when `Self` is an enum, for comparing the enum discriminants.
//! - `StaticEnum` and `StaticStruct` for static methods, where the type
//! being derived upon is either an enum or struct respectively. (Any
//! argument with type Self is just grouped among the non-self
Expand Down Expand Up @@ -143,11 +143,11 @@
//! )
//! ```
//!
//! For the tags,
//! For the discriminants,
//!
//! ```text
//! EnumTag(
//! &[<ident of self tag>, <ident of other tag>],
//! EnumDiscr(
//! &[<ident of self discriminant>, <ident of other discriminant>],
//! <expr to combine with>,
//! )
//! ```
Expand Down Expand Up @@ -315,10 +315,10 @@ pub enum SubstructureFields<'a> {
/// variant.
EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo>),

/// The tag of an enum. The first field is a `FieldInfo` for the tags, as
/// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as
/// if they were fields. The second field is the expression to combine the
/// tag expression with; it will be `None` if no match is necessary.
EnumTag(FieldInfo, Option<P<Expr>>),
/// discriminant expression with; it will be `None` if no match is necessary.
EnumDiscr(FieldInfo, Option<P<Expr>>),

/// A static method where `Self` is a struct.
StaticStruct(&'a ast::VariantData, StaticFields),
Expand Down Expand Up @@ -1137,9 +1137,9 @@ impl<'a> MethodDef<'a> {
/// impl ::core::cmp::PartialEq for A {
/// #[inline]
/// fn eq(&self, other: &A) -> bool {
/// let __self_tag = ::core::intrinsics::discriminant_value(self);
/// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
/// __self_tag == __arg1_tag
/// let __self_discr = ::core::intrinsics::discriminant_value(self);
/// let __arg1_discr = ::core::intrinsics::discriminant_value(other);
/// __self_discr == __arg1_discr
/// && match (self, other) {
/// (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0,
/// _ => true,
Expand All @@ -1148,7 +1148,7 @@ impl<'a> MethodDef<'a> {
/// }
/// ```
///
/// Creates a tag check combined with a match for a tuple of all
/// Creates a discriminant check combined with a match for a tuple of all
/// `selflike_args`, with an arm for each variant with fields, possibly an
/// arm for each fieldless variant (if `unify_fieldless_variants` is not
/// `Unify`), and possibly a default arm.
Expand All @@ -1169,7 +1169,7 @@ impl<'a> MethodDef<'a> {
let span = trait_.span;
let variants = &enum_def.variants;

// Traits that unify fieldless variants always use the tag(s).
// Traits that unify fieldless variants always use the discriminant(s).
let unify_fieldless_variants =
self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify;

Expand Down Expand Up @@ -1199,25 +1199,25 @@ impl<'a> MethodDef<'a> {
//
// e.g. for `PartialEq::eq` builds two statements:
// ```
// let __self_tag = ::core::intrinsics::discriminant_value(self);
// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
// let __self_discr = ::core::intrinsics::discriminant_value(self);
// let __arg1_discr = ::core::intrinsics::discriminant_value(other);
// ```
let get_tag_pieces = |cx: &ExtCtxt<'_>| {
let tag_idents: Vec<_> = prefixes
let get_discr_pieces = |cx: &ExtCtxt<'_>| {
let discr_idents: Vec<_> = prefixes
.iter()
.map(|name| Ident::from_str_and_span(&format!("{name}_tag"), span))
.map(|name| Ident::from_str_and_span(&format!("{name}_discr"), span))
.collect();

let mut tag_exprs: Vec<_> = tag_idents
let mut discr_exprs: Vec<_> = discr_idents
.iter()
.map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident)))
.collect();

let self_expr = tag_exprs.remove(0);
let other_selflike_exprs = tag_exprs;
let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };
let self_expr = discr_exprs.remove(0);
let other_selflike_exprs = discr_exprs;
let discr_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };

let tag_let_stmts: ThinVec<_> = iter::zip(&tag_idents, &selflike_args)
let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args)
.map(|(&ident, selflike_arg)| {
let variant_value = deriving::call_intrinsic(
cx,
Expand All @@ -1229,7 +1229,7 @@ impl<'a> MethodDef<'a> {
})
.collect();

(tag_field, tag_let_stmts)
(discr_field, discr_let_stmts)
};

// There are some special cases involving fieldless enums where no
Expand All @@ -1239,19 +1239,19 @@ impl<'a> MethodDef<'a> {
if variants.len() > 1 {
match self.fieldless_variants_strategy {
FieldlessVariantsStrategy::Unify => {
// If the type is fieldless and the trait uses the tag and
// If the type is fieldless and the trait uses the discriminant and
// there are multiple variants, we need just an operation on
// the tag(s).
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
let mut tag_check = self.call_substructure_method(
// the discriminant(s).
let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx);
let mut discr_check = self.call_substructure_method(
cx,
trait_,
type_ident,
nonselflike_args,
&EnumTag(tag_field, None),
&EnumDiscr(discr_field, None),
);
tag_let_stmts.append(&mut tag_check.0);
return BlockOrExpr(tag_let_stmts, tag_check.1);
discr_let_stmts.append(&mut discr_check.0);
return BlockOrExpr(discr_let_stmts, discr_check.1);
}
FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => {
return self.call_substructure_method(
Expand All @@ -1266,7 +1266,7 @@ impl<'a> MethodDef<'a> {
}
} else if variants.len() == 1 {
// If there is a single variant, we don't need an operation on
// the tag(s). Just use the most degenerate result.
// the discriminant(s). Just use the most degenerate result.
return self.call_substructure_method(
cx,
trait_,
Expand Down Expand Up @@ -1380,22 +1380,22 @@ impl<'a> MethodDef<'a> {
cx.expr_match(span, match_arg, match_arms)
};

// If the trait uses the tag and there are multiple variants, we need
// to add a tag check operation before the match. Otherwise, the match
// If the trait uses the discriminant and there are multiple variants, we need
// to add a discriminant check operation before the match. Otherwise, the match
// is enough.
if unify_fieldless_variants && variants.len() > 1 {
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx);

// Combine a tag check with the match.
let mut tag_check_plus_match = self.call_substructure_method(
// Combine a discriminant check with the match.
let mut discr_check_plus_match = self.call_substructure_method(
cx,
trait_,
type_ident,
nonselflike_args,
&EnumTag(tag_field, Some(get_match_expr(selflike_args))),
&EnumDiscr(discr_field, Some(get_match_expr(selflike_args))),
);
tag_let_stmts.append(&mut tag_check_plus_match.0);
BlockOrExpr(tag_let_stmts, tag_check_plus_match.1)
discr_let_stmts.append(&mut discr_check_plus_match.0);
BlockOrExpr(discr_let_stmts, discr_check_plus_match.1)
} else {
BlockOrExpr(ThinVec::new(), Some(get_match_expr(selflike_args)))
}
Expand Down Expand Up @@ -1701,16 +1701,16 @@ where
rest.iter().rfold(base_expr, op)
}
}
EnumTag(tag_field, match_expr) => {
let tag_check_expr = f(cx, CsFold::Single(tag_field));
EnumDiscr(discr_field, match_expr) => {
let discr_check_expr = f(cx, CsFold::Single(discr_field));
if let Some(match_expr) = match_expr {
if use_foldl {
f(cx, CsFold::Combine(trait_span, tag_check_expr, match_expr.clone()))
f(cx, CsFold::Combine(trait_span, discr_check_expr, match_expr.clone()))
} else {
f(cx, CsFold::Combine(trait_span, match_expr.clone(), tag_check_expr))
f(cx, CsFold::Combine(trait_span, match_expr.clone(), discr_check_expr))
}
} else {
tag_check_expr
discr_check_expr
}
}
StaticEnum(..) | StaticStruct(..) => {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_builtin_macros/src/deriving/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ fn hash_substructure(cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'
fields.iter().map(|field| call_hash(field.span, field.self_expr.clone())).collect();
(stmts, None)
}
EnumTag(tag_field, match_expr) => {
assert!(tag_field.other_selflike_exprs.is_empty());
let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())];
EnumDiscr(discr_field, match_expr) => {
assert!(discr_field.other_selflike_exprs.is_empty());
let stmts = thin_vec![call_hash(discr_field.span, discr_field.self_expr.clone())];
(stmts, match_expr.clone())
}
_ => cx.dcx().span_bug(trait_span, "impossible substructure in `derive(Hash)`"),
Expand Down
Loading
Loading