-
-
Notifications
You must be signed in to change notification settings - Fork 14.9k
Implement fast path for derive(PartialOrd) when deriving Ord
#155598
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
base: main
Are you sure you want to change the base?
Changes from 3 commits
c15a04c
2481e2c
76ac16f
2fd68fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind, Safety}; | ||
| use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind, Safety, ast}; | ||
| use rustc_expand::base::{Annotatable, ExtCtxt}; | ||
| use rustc_span::{Ident, Span, sym}; | ||
| use thin_vec::thin_vec; | ||
| use thin_vec::{ThinVec, thin_vec}; | ||
|
|
||
| use crate::deriving::generic::ty::*; | ||
| use crate::deriving::generic::*; | ||
|
|
@@ -41,6 +41,35 @@ pub(crate) fn expand_deriving_partial_ord( | |
| } else { | ||
| true | ||
| }; | ||
|
|
||
| let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); | ||
| let has_derive_ord = cx.resolver.has_derive_ord(container_id); | ||
| let is_simple_candidate = |params: &ThinVec<ast::GenericParam>| -> bool { | ||
| has_derive_ord | ||
| && !params.iter().any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) | ||
| }; | ||
|
|
||
| let default_substructure = combine_substructure(Box::new(|cx, span, substr| { | ||
| cs_partial_cmp(cx, span, substr, discr_then_data) | ||
| })); | ||
| let simple_substructure = combine_substructure(Box::new(|cx, span, _| { | ||
| cs_partial_cmp_simple(cx, span, cx.expr_ident(span, Ident::new(sym::other, span))) | ||
| })); | ||
| let (is_simple, substructure) = match item { | ||
| Annotatable::Item(annitem) => match &annitem.kind { | ||
| // For unit structs, the default generated code is better. | ||
| ItemKind::Struct(.., ast::VariantData::Unit(..)) => (false, default_substructure), | ||
| ItemKind::Struct(_, ast::Generics { params, .. }, _) | ||
| | ItemKind::Enum(_, ast::Generics { params, .. }, _) | ||
| if is_simple_candidate(params) => | ||
| { | ||
| (true, simple_substructure) | ||
| } | ||
| _ => (false, default_substructure), | ||
| }, | ||
| _ => (false, default_substructure), | ||
| }; | ||
|
|
||
| let partial_cmp_def = MethodDef { | ||
| name: sym::partial_cmp, | ||
| generics: Bounds::empty(), | ||
|
|
@@ -49,9 +78,7 @@ pub(crate) fn expand_deriving_partial_ord( | |
| ret_ty, | ||
| 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, discr_then_data) | ||
| })), | ||
| combine_substructure: substructure, | ||
| }; | ||
|
|
||
| let trait_def = TraitDef { | ||
|
|
@@ -68,7 +95,18 @@ pub(crate) fn expand_deriving_partial_ord( | |
| safety: Safety::Default, | ||
| document: true, | ||
| }; | ||
| trait_def.expand(cx, mitem, item, push) | ||
| trait_def.expand_ext(cx, mitem, item, push, is_simple) | ||
| } | ||
|
|
||
| // Special case for the type deriving both `PartialOrd` and `Ord`. Builds: | ||
| // ``` | ||
| // Some(::core::cmp::Ord::cmp(self, other)) | ||
| // ``` | ||
| fn cs_partial_cmp_simple(cx: &ExtCtxt<'_>, span: Span, other_expr: Box<ast::Expr>) -> BlockOrExpr { | ||
| let ord_cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]); | ||
| let cmp_expr = | ||
| cx.expr_call_global(span, ord_cmp_path, thin_vec![cx.expr_self(span), other_expr]); | ||
| BlockOrExpr::new_expr(cx.expr_some(span, cmp_expr)) | ||
| } | ||
|
|
||
| fn cs_partial_cmp( | ||
|
|
@@ -98,7 +136,8 @@ fn cs_partial_cmp( | |
| |cx, fold| match fold { | ||
| CsFold::Single(field) => { | ||
| let [other_expr] = &field.other_selflike_exprs[..] else { | ||
| cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`"); | ||
| cx.dcx() | ||
| .span_bug(field.span, "not exactly 2 arguments in `derive(PartialOrd)`"); | ||
| }; | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is probably a copy-paste curse, so I changed that, not 100% sure though. |
||
| let args = thin_vec![field.self_expr.clone(), other_expr.clone()]; | ||
| cx.expr_call_global(field.span, partial_cmp_path.clone(), args) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1227,7 +1227,10 @@ impl ExternPreludeEntry<'_> { | |
| struct DeriveData { | ||
| resolutions: Vec<DeriveResolution>, | ||
| helper_attrs: Vec<(usize, IdentKey, Span)>, | ||
| // if this list keeps getting extended, we could use `bitflags`, | ||
| // something like what [`rustc_type_ir::flags::TypeFlags`] is doing. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We had multiple flags here in the past, and they indeed used flags, and one map in the resolver instead of two
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for providing the context. I was thinking about doing one more round of scanning derives to collect all flags such that it might solve #124794. I don't know if that had been discussed before, and if it did I'd really want to know the reason of why not doing that.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If I correctly understand what you are talking about, it's a much worse hack and it cannot work correctly. |
||
| has_derive_copy: bool, | ||
| has_derive_ord: bool, | ||
| } | ||
|
|
||
| struct MacroData { | ||
|
|
@@ -1381,6 +1384,7 @@ pub struct Resolver<'ra, 'tcx> { | |
| /// Derive macros cannot modify the item themselves and have to store the markers in the global | ||
| /// context, so they attach the markers to derive container IDs using this resolver table. | ||
| containers_deriving_copy: FxHashSet<LocalExpnId> = default::fx_hash_set(), | ||
| containers_deriving_ord: FxHashSet<LocalExpnId> = default::fx_hash_set(), | ||
| /// Parent scopes in which the macros were invoked. | ||
| /// FIXME: `derives` are missing in these parent scopes and need to be taken from elsewhere. | ||
| invocation_parent_scopes: FxHashMap<LocalExpnId, ParentScope<'ra>> = default::fx_hash_map(), | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.