Skip to content

Commit c9cc7ea

Browse files
committed
Emit const item block instead and use MutVisitor pattern
1 parent aeb9f0f commit c9cc7ea

8 files changed

Lines changed: 206 additions & 160 deletions

File tree

compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs

Lines changed: 131 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,82 @@
1+
use rustc_ast::mut_visit::{self, MutVisitor};
12
use rustc_ast::{self as ast, MetaItem, Safety};
23
use rustc_data_structures::fx::FxHashSet;
34
use rustc_expand::base::{Annotatable, ExtCtxt};
4-
use rustc_span::{Ident, Span, sym};
5+
use rustc_span::{Ident, Span, kw, sym};
56
use thin_vec::{ThinVec, thin_vec};
67

78
use crate::deriving::generic::*;
89
use crate::deriving::path_std;
910

11+
struct ReplaceSelfTyVisitor(Box<ast::Ty>);
12+
impl MutVisitor for ReplaceSelfTyVisitor {
13+
fn visit_ty(&mut self, ty: &mut ast::Ty) {
14+
if let ast::TyKind::Path(None, path) = &mut ty.kind
15+
&& let [segment] = &path.segments[..]
16+
&& *segment == kw::SelfUpper
17+
{
18+
*ty = *self.0.clone();
19+
} else {
20+
mut_visit::walk_ty(self, ty);
21+
}
22+
}
23+
}
24+
25+
struct RespanGenericsVisitor(Span);
26+
impl MutVisitor for RespanGenericsVisitor {
27+
fn visit_generics(&mut self, generics: &mut ast::Generics) {
28+
generics.where_clause.span = self.0.with_ctxt(generics.where_clause.span.ctxt());
29+
generics.span = self.0.with_ctxt(generics.span.ctxt());
30+
mut_visit::walk_generics(self, generics);
31+
}
32+
fn visit_where_predicate(&mut self, predicate: &mut ast::WherePredicate) {
33+
predicate.span = self.0.with_ctxt(predicate.span.ctxt());
34+
mut_visit::walk_where_predicate(self, predicate);
35+
}
36+
fn visit_where_predicate_kind(&mut self, kind: &mut ast::WherePredicateKind) {
37+
match kind {
38+
ast::WherePredicateKind::BoundPredicate(bound_predicate) => {
39+
bound_predicate.bounded_ty.span =
40+
self.0.with_ctxt(bound_predicate.bounded_ty.span.ctxt());
41+
}
42+
ast::WherePredicateKind::EqPredicate(eq_predicate) => {
43+
eq_predicate.lhs_ty.span = self.0.with_ctxt(eq_predicate.lhs_ty.span.ctxt());
44+
eq_predicate.rhs_ty.span = self.0.with_ctxt(eq_predicate.rhs_ty.span.ctxt());
45+
}
46+
ast::WherePredicateKind::RegionPredicate(_) => {}
47+
}
48+
mut_visit::walk_where_predicate_kind(self, kind);
49+
}
50+
fn visit_param_bound(
51+
&mut self,
52+
bound: &mut rustc_ast::GenericBound,
53+
_ctxt: rustc_ast::visit::BoundKind,
54+
) {
55+
match bound {
56+
ast::GenericBound::Trait(poly_trait_ref) => {
57+
poly_trait_ref.span = self.0.with_ctxt(poly_trait_ref.span.ctxt());
58+
}
59+
ast::GenericBound::Outlives(_) => {}
60+
ast::GenericBound::Use(_, _) => {}
61+
}
62+
ast::mut_visit::walk_param_bound(self, bound);
63+
}
64+
}
65+
66+
struct StripConstTraitBoundsVisitor;
67+
impl MutVisitor for StripConstTraitBoundsVisitor {
68+
fn visit_param_bound(
69+
&mut self,
70+
bound: &mut rustc_ast::GenericBound,
71+
_ctxt: rustc_ast::visit::BoundKind,
72+
) {
73+
if let ast::GenericBound::Trait(poly_trait_ref) = bound {
74+
poly_trait_ref.modifiers.constness = ast::BoundConstness::Never;
75+
}
76+
mut_visit::walk_param_bound(self, bound);
77+
}
78+
}
79+
1080
pub(crate) fn expand_deriving_eq(
1181
cx: &ExtCtxt<'_>,
1282
span: Span,
@@ -17,8 +87,8 @@ pub(crate) fn expand_deriving_eq(
1787
) {
1888
let span = cx.with_def_site_ctxt(span);
1989

20-
let mut impl_generics = ast::Generics::default();
21-
let mut impl_self_ty = None;
90+
let mut fn_generics = ast::Generics { span, ..Default::default() };
91+
let mut self_ty = None;
2292

2393
let trait_def = TraitDef {
2494
span,
@@ -45,150 +115,90 @@ pub(crate) fn expand_deriving_eq(
45115
let ast::ItemKind::Impl(imp) = &mut item.kind else {
46116
unreachable!("should have emitted an Impl in trait_def.expand_ext");
47117
};
48-
impl_generics = imp.generics.clone();
49-
impl_self_ty = Some(imp.self_ty.clone());
50-
respan_generics_for_derive(&mut imp.generics, span);
118+
use ast::mut_visit::MutVisitor;
119+
RespanGenericsVisitor(span).visit_generics(&mut imp.generics);
120+
fn_generics = imp.generics.clone();
121+
self_ty = Some(imp.self_ty.clone());
51122
push(a)
52123
},
53124
true,
54125
);
55126

56-
let assert_stmts = eq_assert_stmts_from_item(cx, span, item);
127+
let self_ty =
128+
self_ty.unwrap_or_else(|| cx.dcx().span_bug(span, "missing self type in `derive(Eq)`"));
129+
let assert_stmts = eq_assert_stmts_from_item(cx, span, item, ReplaceSelfTyVisitor(self_ty));
57130

58131
// Skip generating `assert_fields_are_eq` impl if there are no assertions to make
59132
if assert_stmts.is_empty() {
60133
return;
61134
}
62135

63-
let impl_self_ty = impl_self_ty
64-
.unwrap_or_else(|| cx.dcx().span_bug(span, "missing self type in `derive(Eq)`"));
65-
push(Annotatable::Item(assert_fields_are_eq_impl(
66-
cx,
67-
span,
68-
strip_const_trait_bounds_from_generics(impl_generics),
69-
impl_self_ty,
70-
assert_stmts,
71-
)));
72-
}
73-
74-
fn respan_generics_for_derive(generics: &mut ast::Generics, span: Span) {
75-
for predicate in &mut generics.where_clause.predicates {
76-
predicate.span = span.with_ctxt(predicate.span.ctxt());
77-
78-
match &mut predicate.kind {
79-
ast::WherePredicateKind::BoundPredicate(bound_predicate) => {
80-
bound_predicate.bounded_ty.span =
81-
span.with_ctxt(bound_predicate.bounded_ty.span.ctxt());
82-
83-
for bound in &mut bound_predicate.bounds {
84-
match bound {
85-
ast::GenericBound::Trait(poly_trait_ref) => {
86-
poly_trait_ref.span = span.with_ctxt(poly_trait_ref.span.ctxt());
87-
}
88-
_ => {}
89-
}
90-
}
91-
}
92-
ast::WherePredicateKind::RegionPredicate(region_predicate) => {
93-
for bound in &mut region_predicate.bounds {
94-
match bound {
95-
ast::GenericBound::Trait(poly_trait_ref) => {
96-
poly_trait_ref.span = span.with_ctxt(poly_trait_ref.span.ctxt());
97-
}
98-
_ => {}
99-
}
100-
}
101-
}
102-
ast::WherePredicateKind::EqPredicate(eq_predicate) => {
103-
eq_predicate.lhs_ty.span = span.with_ctxt(eq_predicate.lhs_ty.span.ctxt());
104-
eq_predicate.rhs_ty.span = span.with_ctxt(eq_predicate.rhs_ty.span.ctxt());
105-
}
106-
}
107-
}
108-
generics.where_clause.span = span.with_ctxt(generics.where_clause.span.ctxt());
109-
generics.span = span.with_ctxt(generics.span.ctxt());
136+
StripConstTraitBoundsVisitor.visit_generics(&mut fn_generics);
137+
push(Annotatable::Item(expand_const_item_block(cx, span, fn_generics, assert_stmts)));
110138
}
111139

112-
fn assert_fields_are_eq_impl(
140+
fn expand_const_item_block(
113141
cx: &ExtCtxt<'_>,
114142
span: Span,
115-
impl_generics: ast::Generics,
116-
impl_self_ty: Box<ast::Ty>,
143+
fn_generics: ast::Generics,
117144
assert_stmts: ThinVec<ast::Stmt>,
118145
) -> Box<ast::Item> {
119146
cx.item(
120147
span,
121148
ast::AttrVec::new(),
122-
ast::ItemKind::Impl(ast::Impl {
123-
generics: impl_generics,
124-
of_trait: None,
125-
constness: ast::Const::No,
126-
self_ty: impl_self_ty,
127-
items: thin_vec![Box::new(ast::AssocItem {
128-
id: ast::DUMMY_NODE_ID,
129-
attrs: thin_vec![
130-
cx.attr_nested_word(sym::doc, sym::hidden, span),
131-
cx.attr_nested_word(sym::coverage, sym::off, span),
132-
],
149+
ast::ItemKind::ConstBlock(ast::ConstBlockItem {
150+
span,
151+
id: ast::DUMMY_NODE_ID,
152+
block: cx.block(
133153
span,
134-
vis: ast::Visibility {
135-
span: span.shrink_to_lo(),
136-
kind: ast::VisibilityKind::Inherited,
137-
tokens: None,
138-
},
139-
kind: ast::AssocItemKind::Fn(Box::new(ast::Fn {
140-
defaultness: ast::Defaultness::Implicit,
141-
ident: Ident::new(sym::assert_fields_are_eq, span),
142-
generics: ast::Generics { span, ..Default::default() },
143-
sig: ast::FnSig {
144-
header: ast::FnHeader {
145-
constness: ast::Const::Yes(span),
146-
coroutine_kind: None,
147-
safety: ast::Safety::Default,
148-
ext: ast::Extern::None,
149-
},
150-
decl: cx.fn_decl(ThinVec::new(), ast::FnRetTy::Default(span)),
154+
thin_vec![ast::Stmt {
155+
span,
156+
id: ast::DUMMY_NODE_ID,
157+
kind: ast::StmtKind::Item(Box::new(ast::Item {
151158
span,
152-
},
153-
contract: None,
154-
define_opaque: None,
155-
body: Some(cx.block(span, assert_stmts)),
156-
eii_impls: ThinVec::new(),
157-
})),
158-
tokens: None,
159-
})],
159+
id: ast::DUMMY_NODE_ID,
160+
attrs: thin_vec![
161+
cx.attr_nested_word(sym::doc, sym::hidden, span),
162+
cx.attr_nested_word(sym::coverage, sym::off, span),
163+
cx.attr_word(sym::inline, span),
164+
],
165+
vis: ast::Visibility {
166+
kind: ast::VisibilityKind::Inherited,
167+
span,
168+
tokens: None,
169+
},
170+
tokens: None,
171+
kind: ast::ItemKind::Fn(Box::new(ast::Fn {
172+
defaultness: ast::Defaultness::Implicit,
173+
ident: Ident::new(sym::assert_fields_are_eq, span),
174+
generics: fn_generics,
175+
sig: ast::FnSig {
176+
header: ast::FnHeader {
177+
constness: ast::Const::Yes(span),
178+
coroutine_kind: None,
179+
safety: ast::Safety::Default,
180+
ext: ast::Extern::None,
181+
},
182+
decl: cx.fn_decl(ThinVec::new(), ast::FnRetTy::Default(span)),
183+
span,
184+
},
185+
contract: None,
186+
define_opaque: None,
187+
body: Some(cx.block(span, assert_stmts)),
188+
eii_impls: ThinVec::new(),
189+
}))
190+
}))
191+
},],
192+
),
160193
}),
161194
)
162195
}
163196

164-
fn strip_const_trait_bounds_from_generics(mut generics: ast::Generics) -> ast::Generics {
165-
for param in &mut generics.params {
166-
if let ast::GenericParamKind::Type { .. } = &param.kind {
167-
strip_constness_from_bounds(&mut param.bounds);
168-
}
169-
}
170-
171-
for predicate in &mut generics.where_clause.predicates {
172-
if let ast::WherePredicateKind::BoundPredicate(bound_predicate) = &mut predicate.kind {
173-
strip_constness_from_bounds(&mut bound_predicate.bounds);
174-
}
175-
}
176-
177-
generics
178-
}
179-
180-
fn strip_constness_from_bounds(bounds: &mut [ast::GenericBound]) {
181-
for bound in bounds {
182-
if let ast::GenericBound::Trait(poly_trait_ref) = bound {
183-
poly_trait_ref.modifiers.constness = ast::BoundConstness::Never;
184-
}
185-
}
186-
}
187-
188197
fn eq_assert_stmts_from_item(
189198
cx: &ExtCtxt<'_>,
190199
span: Span,
191200
item: &Annotatable,
201+
mut replace_self_ty: ReplaceSelfTyVisitor,
192202
) -> ThinVec<ast::Stmt> {
193203
let mut stmts = ThinVec::new();
194204
let mut seen_type_names = FxHashSet::default();
@@ -202,11 +212,14 @@ fn eq_assert_stmts_from_item(
202212
{
203213
// Already produced an assertion for this type.
204214
} else {
215+
use ast::mut_visit::MutVisitor;
216+
let mut field_ty = field.ty.clone();
217+
replace_self_ty.visit_ty(&mut field_ty);
205218
// let _: AssertParamIsEq<FieldTy>;
206219
super::assert_ty_bounds(
207220
cx,
208221
&mut stmts,
209-
field.ty.clone(),
222+
field_ty,
210223
field.span,
211224
&[sym::cmp, sym::AssertParamIsEq],
212225
);

tests/ui/deriving/deriving-all-codegen.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ struct Reorder {
7979
b10: &'static *const bool,
8080
}
8181

82+
// A struct with a recursive type.
83+
#[derive(PartialEq, Eq, PartialOrd, Ord)]
84+
struct Recursive(Option<Box<Self>>);
85+
8286
// A struct that doesn't impl `Copy`, which means it gets the non-trivial
8387
// `clone` implemention that clones the fields individually.
8488
#[derive(Clone)]

0 commit comments

Comments
 (0)