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

simplify inject_impl_of_structural_trait #115891

Merged
merged 1 commit into from
Sep 18, 2023
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
17 changes: 14 additions & 3 deletions compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ pub fn expand_deriving_eq(
is_const: bool,
) {
let span = cx.with_def_site_ctxt(span);

let structural_trait_def = TraitDef {
span,
path: path_std!(marker::StructuralEq),
skip_path_as_bound: true, // crucial!
needs_copy_as_bound_if_packed: false,
additional_bounds: Vec::new(),
supports_unions: true,
methods: Vec::new(),
associated_types: Vec::new(),
is_const: false,
};
structural_trait_def.expand(cx, mitem, item, push);

let trait_def = TraitDef {
span,
path: path_std!(cmp::Eq),
Expand All @@ -44,9 +58,6 @@ pub fn expand_deriving_eq(
associated_types: Vec::new(),
is_const,
};

super::inject_impl_of_structural_trait(cx, span, item, path_std!(marker::StructuralEq), push);

trait_def.expand_ext(cx, mitem, item, push, true)
}

Expand Down
19 changes: 13 additions & 6 deletions compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,20 @@ pub fn expand_deriving_partial_eq(
BlockOrExpr::new_expr(expr)
}

super::inject_impl_of_structural_trait(
cx,
let structural_trait_def = TraitDef {
span,
item,
path_std!(marker::StructuralPartialEq),
push,
);
path: path_std!(marker::StructuralPartialEq),
skip_path_as_bound: true, // crucial!
needs_copy_as_bound_if_packed: false,
additional_bounds: Vec::new(),
// We really don't support unions, but that's already checked by the impl generated below;
// a second check here would lead to redundant error messages.
supports_unions: true,
methods: Vec::new(),
associated_types: Vec::new(),
is_const: false,
};
structural_trait_def.expand(cx, mitem, item, push);

// No need to generate `ne`, the default suffices, and not generating it is
// faster.
Expand Down
22 changes: 13 additions & 9 deletions compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,9 @@ impl<'a> TraitDef<'a> {
.collect();

// Require the current trait.
bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
if !self.skip_path_as_bound {
bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
}

// Add a `Copy` bound if required.
if is_packed && self.needs_copy_as_bound_if_packed {
Expand All @@ -722,15 +724,17 @@ impl<'a> TraitDef<'a> {
));
}

let predicate = ast::WhereBoundPredicate {
span: self.span,
bound_generic_params: field_ty_param.bound_generic_params,
bounded_ty: field_ty_param.ty,
bounds,
};
if !bounds.is_empty() {
let predicate = ast::WhereBoundPredicate {
span: self.span,
bound_generic_params: field_ty_param.bound_generic_params,
bounded_ty: field_ty_param.ty,
bounds,
};

let predicate = ast::WherePredicate::BoundPredicate(predicate);
where_clause.predicates.push(predicate);
let predicate = ast::WherePredicate::BoundPredicate(predicate);
where_clause.predicates.push(predicate);
}
}
}
}
Expand Down
98 changes: 2 additions & 96 deletions compiler/rustc_builtin_macros/src/deriving/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::{GenericArg, Impl, ItemKind, MetaItem};
use rustc_ast::{GenericArg, MetaItem};
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use thin_vec::{thin_vec, ThinVec};

Expand Down Expand Up @@ -116,100 +116,6 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
}))
}

// Injects `impl<...> Structural for ItemType<...> { }`. In particular,
// does *not* add `where T: Structural` for parameters `T` in `...`.
// (That's the main reason we cannot use TraitDef here.)
fn inject_impl_of_structural_trait(
cx: &mut ExtCtxt<'_>,
span: Span,
item: &Annotatable,
structural_path: generic::ty::Path,
push: &mut dyn FnMut(Annotatable),
) {
let Annotatable::Item(item) = item else {
unreachable!();
};

let generics = match &item.kind {
ItemKind::Struct(_, generics) | ItemKind::Enum(_, generics) => generics,
// Do not inject `impl Structural for Union`. (`PartialEq` does not
// support unions, so we will see error downstream.)
ItemKind::Union(..) => return,
_ => unreachable!(),
};

// Create generics param list for where clauses and impl headers
let mut generics = generics.clone();

let ctxt = span.ctxt();

// Create the type of `self`.
//
// in addition, remove defaults from generic params (impls cannot have them).
let self_params: Vec<_> = generics
.params
.iter_mut()
.map(|param| match &mut param.kind {
ast::GenericParamKind::Lifetime => ast::GenericArg::Lifetime(
cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident),
),
ast::GenericParamKind::Type { default } => {
*default = None;
ast::GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
}
ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
*default = None;
ast::GenericArg::Const(
cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident),
)
}
})
.collect();

let type_ident = item.ident;

let trait_ref = cx.trait_ref(structural_path.to_path(cx, span, type_ident, &generics));
let self_type = cx.ty_path(cx.path_all(span, false, vec![type_ident], self_params));

// It would be nice to also encode constraint `where Self: Eq` (by adding it
// onto `generics` cloned above). Unfortunately, that strategy runs afoul of
// rust-lang/rust#48214. So we perform that additional check in the compiler
// itself, instead of encoding it here.

// Keep the lint and stability attributes of the original item, to control
// how the generated implementation is linted.
let mut attrs = ast::AttrVec::new();
attrs.extend(
item.attrs
.iter()
.filter(|a| {
[sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable]
.contains(&a.name_or_empty())
})
.cloned(),
);
// Mark as `automatically_derived` to avoid some silly lints.
attrs.push(cx.attr_word(sym::automatically_derived, span));

let newitem = cx.item(
span,
Ident::empty(),
attrs,
ItemKind::Impl(Box::new(Impl {
unsafety: ast::Unsafe::No,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: ast::Const::No,
generics,
of_trait: Some(trait_ref),
self_ty: self_type,
items: ThinVec::new(),
})),
);

push(Annotatable::Item(newitem));
}

fn assert_ty_bounds(
cx: &mut ExtCtxt<'_>,
stmts: &mut ThinVec<ast::Stmt>,
Expand Down
Loading