simplify inject_impl_of_structural_trait
This commit is contained in:
parent
790309b102
commit
0522bde4bc
4 changed files with 42 additions and 114 deletions
|
@ -18,6 +18,20 @@ pub fn expand_deriving_eq(
|
||||||
is_const: bool,
|
is_const: bool,
|
||||||
) {
|
) {
|
||||||
let span = cx.with_def_site_ctxt(span);
|
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 {
|
let trait_def = TraitDef {
|
||||||
span,
|
span,
|
||||||
path: path_std!(cmp::Eq),
|
path: path_std!(cmp::Eq),
|
||||||
|
@ -44,9 +58,6 @@ pub fn expand_deriving_eq(
|
||||||
associated_types: Vec::new(),
|
associated_types: Vec::new(),
|
||||||
is_const,
|
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)
|
trait_def.expand_ext(cx, mitem, item, push, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,13 +72,20 @@ pub fn expand_deriving_partial_eq(
|
||||||
BlockOrExpr::new_expr(expr)
|
BlockOrExpr::new_expr(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
super::inject_impl_of_structural_trait(
|
let structural_trait_def = TraitDef {
|
||||||
cx,
|
|
||||||
span,
|
span,
|
||||||
item,
|
path: path_std!(marker::StructuralPartialEq),
|
||||||
path_std!(marker::StructuralPartialEq),
|
skip_path_as_bound: true, // crucial!
|
||||||
push,
|
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
|
// No need to generate `ne`, the default suffices, and not generating it is
|
||||||
// faster.
|
// faster.
|
||||||
|
|
|
@ -711,7 +711,9 @@ impl<'a> TraitDef<'a> {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Require the current trait.
|
// 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.
|
// Add a `Copy` bound if required.
|
||||||
if is_packed && self.needs_copy_as_bound_if_packed {
|
if is_packed && self.needs_copy_as_bound_if_packed {
|
||||||
|
@ -722,15 +724,17 @@ impl<'a> TraitDef<'a> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let predicate = ast::WhereBoundPredicate {
|
if !bounds.is_empty() {
|
||||||
span: self.span,
|
let predicate = ast::WhereBoundPredicate {
|
||||||
bound_generic_params: field_ty_param.bound_generic_params,
|
span: self.span,
|
||||||
bounded_ty: field_ty_param.ty,
|
bound_generic_params: field_ty_param.bound_generic_params,
|
||||||
bounds,
|
bounded_ty: field_ty_param.ty,
|
||||||
};
|
bounds,
|
||||||
|
};
|
||||||
|
|
||||||
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
||||||
where_clause.predicates.push(predicate);
|
where_clause.predicates.push(predicate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::ptr::P;
|
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_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
|
||||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use thin_vec::{thin_vec, ThinVec};
|
use thin_vec::{thin_vec, ThinVec};
|
||||||
|
|
||||||
|
@ -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(
|
fn assert_ty_bounds(
|
||||||
cx: &mut ExtCtxt<'_>,
|
cx: &mut ExtCtxt<'_>,
|
||||||
stmts: &mut ThinVec<ast::Stmt>,
|
stmts: &mut ThinVec<ast::Stmt>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue