1 //! This module contains functions to generate default trait impl function bodies where possible.
4 ast::{self, edit::AstNodeEdit, make, AstNode, BinaryOp, CmpOp, HasName, LogicOp},
8 /// Generate custom trait bodies where possible.
10 /// Returns `Option` so that we can use `?` rather than `if let Some`. Returning
11 /// `None` means that generating a custom trait body failed, and the body will remain
12 /// as `todo!` instead.
13 pub(crate) fn gen_trait_fn_body(
15 trait_path: &ast::Path,
18 match trait_path.segment()?.name_ref()?.text().as_str() {
19 "Clone" => gen_clone_impl(adt, func),
20 "Debug" => gen_debug_impl(adt, func),
21 "Default" => gen_default_impl(adt, func),
22 "Hash" => gen_hash_impl(adt, func),
23 "PartialEq" => gen_partial_eq(adt, func),
24 "PartialOrd" => gen_partial_ord(adt, func),
29 /// Generate a `Clone` impl based on the fields and members of the target type.
30 fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
31 fn gen_clone_call(target: ast::Expr) -> ast::Expr {
32 let method = make::name_ref("clone");
33 make::expr_method_call(target, method, make::arg_list(None))
35 let expr = match adt {
36 // `Clone` cannot be derived for unions, so no default impl can be provided.
37 ast::Adt::Union(_) => return None,
38 ast::Adt::Enum(enum_) => {
39 let list = enum_.variant_list()?;
40 let mut arms = vec![];
41 for variant in list.variants() {
42 let name = variant.name()?;
43 let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?;
45 match variant.field_list() {
46 // => match self { Self::Name { x } => Self::Name { x: x.clone() } }
47 Some(ast::FieldList::RecordFieldList(list)) => {
48 let mut pats = vec![];
49 let mut fields = vec![];
50 for field in list.fields() {
51 let field_name = field.name()?;
52 let pat = make::ident_pat(false, false, field_name.clone());
53 pats.push(pat.into());
55 let path = make::ext::ident_path(&field_name.to_string());
56 let method_call = gen_clone_call(make::expr_path(path));
57 let name_ref = make::name_ref(&field_name.to_string());
58 let field = make::record_expr_field(name_ref, Some(method_call));
61 let pat = make::record_pat(variant_name.clone(), pats.into_iter());
62 let fields = make::record_expr_field_list(fields);
63 let record_expr = make::record_expr(variant_name, fields).into();
64 arms.push(make::match_arm(Some(pat.into()), None, record_expr));
67 // => match self { Self::Name(arg1) => Self::Name(arg1.clone()) }
68 Some(ast::FieldList::TupleFieldList(list)) => {
69 let mut pats = vec![];
70 let mut fields = vec![];
71 for (i, _) in list.fields().enumerate() {
72 let field_name = format!("arg{}", i);
73 let pat = make::ident_pat(false, false, make::name(&field_name));
74 pats.push(pat.into());
76 let f_path = make::expr_path(make::ext::ident_path(&field_name));
77 fields.push(gen_clone_call(f_path));
79 let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
80 let struct_name = make::expr_path(variant_name);
81 let tuple_expr = make::expr_call(struct_name, make::arg_list(fields));
82 arms.push(make::match_arm(Some(pat.into()), None, tuple_expr));
85 // => match self { Self::Name => Self::Name }
87 let pattern = make::path_pat(variant_name.clone());
88 let variant_expr = make::expr_path(variant_name);
89 arms.push(make::match_arm(Some(pattern.into()), None, variant_expr));
94 let match_target = make::expr_path(make::ext::ident_path("self"));
95 let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
96 make::expr_match(match_target, list)
98 ast::Adt::Struct(strukt) => {
99 match strukt.field_list() {
100 // => Self { name: self.name.clone() }
101 Some(ast::FieldList::RecordFieldList(field_list)) => {
102 let mut fields = vec![];
103 for field in field_list.fields() {
104 let base = make::expr_path(make::ext::ident_path("self"));
105 let target = make::expr_field(base, &field.name()?.to_string());
106 let method_call = gen_clone_call(target);
107 let name_ref = make::name_ref(&field.name()?.to_string());
108 let field = make::record_expr_field(name_ref, Some(method_call));
111 let struct_name = make::ext::ident_path("Self");
112 let fields = make::record_expr_field_list(fields);
113 make::record_expr(struct_name, fields).into()
115 // => Self(self.0.clone(), self.1.clone())
116 Some(ast::FieldList::TupleFieldList(field_list)) => {
117 let mut fields = vec![];
118 for (i, _) in field_list.fields().enumerate() {
119 let f_path = make::expr_path(make::ext::ident_path("self"));
120 let target = make::expr_field(f_path, &format!("{}", i)).into();
121 fields.push(gen_clone_call(target));
123 let struct_name = make::expr_path(make::ext::ident_path("Self"));
124 make::expr_call(struct_name, make::arg_list(fields))
128 let struct_name = make::ext::ident_path("Self");
129 let fields = make::record_expr_field_list(None);
130 make::record_expr(struct_name, fields).into()
135 let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
136 ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
140 /// Generate a `Debug` impl based on the fields and members of the target type.
141 fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
142 let annotated_name = adt.name()?;
144 // `Debug` cannot be derived for unions, so no default impl can be provided.
145 ast::Adt::Union(_) => None,
147 // => match self { Self::Variant => write!(f, "Variant") }
148 ast::Adt::Enum(enum_) => {
149 let list = enum_.variant_list()?;
150 let mut arms = vec![];
151 for variant in list.variants() {
152 let name = variant.name()?;
153 let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?;
154 let target = make::expr_path(make::ext::ident_path("f").into());
156 match variant.field_list() {
157 Some(ast::FieldList::RecordFieldList(list)) => {
158 // => f.debug_struct(name)
159 let target = make::expr_path(make::ext::ident_path("f"));
160 let method = make::name_ref("debug_struct");
161 let struct_name = format!("\"{}\"", name);
162 let args = make::arg_list(Some(make::expr_literal(&struct_name).into()));
163 let mut expr = make::expr_method_call(target, method, args);
165 let mut pats = vec![];
166 for field in list.fields() {
167 let field_name = field.name()?;
169 // create a field pattern for use in `MyStruct { fields.. }`
170 let pat = make::ident_pat(false, false, field_name.clone());
171 pats.push(pat.into());
173 // => <expr>.field("field_name", field)
174 let method_name = make::name_ref("field");
175 let name = make::expr_literal(&(format!("\"{}\"", field_name))).into();
176 let path = &format!("{}", field_name);
177 let path = make::expr_path(make::ext::ident_path(path));
178 let args = make::arg_list(vec![name, path]);
179 expr = make::expr_method_call(expr, method_name, args);
182 // => <expr>.finish()
183 let method = make::name_ref("finish");
184 let expr = make::expr_method_call(expr, method, make::arg_list(None));
186 // => MyStruct { fields.. } => f.debug_struct("MyStruct")...finish(),
187 let pat = make::record_pat(variant_name.clone(), pats.into_iter());
188 arms.push(make::match_arm(Some(pat.into()), None, expr));
190 Some(ast::FieldList::TupleFieldList(list)) => {
191 // => f.debug_tuple(name)
192 let target = make::expr_path(make::ext::ident_path("f"));
193 let method = make::name_ref("debug_tuple");
194 let struct_name = format!("\"{}\"", name);
195 let args = make::arg_list(Some(make::expr_literal(&struct_name).into()));
196 let mut expr = make::expr_method_call(target, method, args);
198 let mut pats = vec![];
199 for (i, _) in list.fields().enumerate() {
200 let name = format!("arg{}", i);
202 // create a field pattern for use in `MyStruct(fields..)`
203 let field_name = make::name(&name);
204 let pat = make::ident_pat(false, false, field_name.clone());
205 pats.push(pat.into());
207 // => <expr>.field(field)
208 let method_name = make::name_ref("field");
209 let field_path = &format!("{}", name);
210 let field_path = make::expr_path(make::ext::ident_path(field_path));
211 let args = make::arg_list(vec![field_path]);
212 expr = make::expr_method_call(expr, method_name, args);
215 // => <expr>.finish()
216 let method = make::name_ref("finish");
217 let expr = make::expr_method_call(expr, method, make::arg_list(None));
219 // => MyStruct (fields..) => f.debug_tuple("MyStruct")...finish(),
220 let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
221 arms.push(make::match_arm(Some(pat.into()), None, expr));
224 let fmt_string = make::expr_literal(&(format!("\"{}\"", name))).into();
225 let args = make::arg_list([target, fmt_string]);
226 let macro_name = make::expr_path(make::ext::ident_path("write"));
227 let macro_call = make::expr_macro_call(macro_name, args);
229 let variant_name = make::path_pat(variant_name);
230 arms.push(make::match_arm(
231 Some(variant_name.into()),
239 let match_target = make::expr_path(make::ext::ident_path("self"));
240 let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
241 let match_expr = make::expr_match(match_target, list);
243 let body = make::block_expr(None, Some(match_expr));
244 let body = body.indent(ast::edit::IndentLevel(1));
245 ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
249 ast::Adt::Struct(strukt) => {
250 let name = format!("\"{}\"", annotated_name);
251 let args = make::arg_list(Some(make::expr_literal(&name).into()));
252 let target = make::expr_path(make::ext::ident_path("f"));
254 let expr = match strukt.field_list() {
255 // => f.debug_struct("Name").finish()
256 None => make::expr_method_call(target, make::name_ref("debug_struct"), args),
258 // => f.debug_struct("Name").field("foo", &self.foo).finish()
259 Some(ast::FieldList::RecordFieldList(field_list)) => {
260 let method = make::name_ref("debug_struct");
261 let mut expr = make::expr_method_call(target, method, args);
262 for field in field_list.fields() {
263 let name = field.name()?;
264 let f_name = make::expr_literal(&(format!("\"{}\"", name))).into();
265 let f_path = make::expr_path(make::ext::ident_path("self"));
266 let f_path = make::expr_ref(f_path, false);
267 let f_path = make::expr_field(f_path, &format!("{}", name)).into();
268 let args = make::arg_list([f_name, f_path]);
269 expr = make::expr_method_call(expr, make::name_ref("field"), args);
274 // => f.debug_tuple("Name").field(self.0).finish()
275 Some(ast::FieldList::TupleFieldList(field_list)) => {
276 let method = make::name_ref("debug_tuple");
277 let mut expr = make::expr_method_call(target, method, args);
278 for (i, _) in field_list.fields().enumerate() {
279 let f_path = make::expr_path(make::ext::ident_path("self"));
280 let f_path = make::expr_ref(f_path, false);
281 let f_path = make::expr_field(f_path, &format!("{}", i)).into();
282 let method = make::name_ref("field");
283 expr = make::expr_method_call(expr, method, make::arg_list(Some(f_path)));
289 let method = make::name_ref("finish");
290 let expr = make::expr_method_call(expr, method, make::arg_list(None));
291 let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
292 ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
298 /// Generate a `Debug` impl based on the fields and members of the target type.
299 fn gen_default_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
300 fn gen_default_call() -> Option<ast::Expr> {
301 let fn_name = make::ext::path_from_idents(["Default", "default"])?;
302 Some(make::expr_call(make::expr_path(fn_name), make::arg_list(None)))
305 // `Debug` cannot be derived for unions, so no default impl can be provided.
306 ast::Adt::Union(_) => None,
307 // Deriving `Debug` for enums is not stable yet.
308 ast::Adt::Enum(_) => None,
309 ast::Adt::Struct(strukt) => {
310 let expr = match strukt.field_list() {
311 Some(ast::FieldList::RecordFieldList(field_list)) => {
312 let mut fields = vec![];
313 for field in field_list.fields() {
314 let method_call = gen_default_call()?;
315 let name_ref = make::name_ref(&field.name()?.to_string());
316 let field = make::record_expr_field(name_ref, Some(method_call));
319 let struct_name = make::ext::ident_path("Self");
320 let fields = make::record_expr_field_list(fields);
321 make::record_expr(struct_name, fields).into()
323 Some(ast::FieldList::TupleFieldList(field_list)) => {
324 let struct_name = make::expr_path(make::ext::ident_path("Self"));
325 let fields = field_list
327 .map(|_| gen_default_call())
328 .collect::<Option<Vec<ast::Expr>>>()?;
329 make::expr_call(struct_name, make::arg_list(fields))
332 let struct_name = make::ext::ident_path("Self");
333 let fields = make::record_expr_field_list(None);
334 make::record_expr(struct_name, fields).into()
337 let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
338 ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
344 /// Generate a `Hash` impl based on the fields and members of the target type.
345 fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
346 fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
347 let method = make::name_ref("hash");
348 let arg = make::expr_path(make::ext::ident_path("state"));
349 let expr = make::expr_method_call(target, method, make::arg_list(Some(arg)));
350 make::expr_stmt(expr).into()
353 let body = match adt {
354 // `Hash` cannot be derived for unions, so no default impl can be provided.
355 ast::Adt::Union(_) => return None,
357 // => std::mem::discriminant(self).hash(state);
358 ast::Adt::Enum(_) => {
359 let fn_name = make_discriminant()?;
361 let arg = make::expr_path(make::ext::ident_path("self"));
362 let fn_call = make::expr_call(fn_name, make::arg_list(Some(arg)));
363 let stmt = gen_hash_call(fn_call);
365 make::block_expr(Some(stmt), None).indent(ast::edit::IndentLevel(1))
367 ast::Adt::Struct(strukt) => match strukt.field_list() {
368 // => self.<field>.hash(state);
369 Some(ast::FieldList::RecordFieldList(field_list)) => {
370 let mut stmts = vec![];
371 for field in field_list.fields() {
372 let base = make::expr_path(make::ext::ident_path("self"));
373 let target = make::expr_field(base, &field.name()?.to_string());
374 stmts.push(gen_hash_call(target));
376 make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
379 // => self.<field_index>.hash(state);
380 Some(ast::FieldList::TupleFieldList(field_list)) => {
381 let mut stmts = vec![];
382 for (i, _) in field_list.fields().enumerate() {
383 let base = make::expr_path(make::ext::ident_path("self"));
384 let target = make::expr_field(base, &format!("{}", i));
385 stmts.push(gen_hash_call(target));
387 make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
390 // No fields in the body means there's nothing to hash.
395 ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
399 /// Generate a `PartialEq` impl based on the fields and members of the target type.
400 fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
401 fn gen_eq_chain(expr: Option<ast::Expr>, cmp: ast::Expr) -> Option<ast::Expr> {
403 Some(expr) => Some(make::expr_bin_op(expr, BinaryOp::LogicOp(LogicOp::And), cmp)),
408 fn gen_record_pat_field(field_name: &str, pat_name: &str) -> ast::RecordPatField {
409 let pat = make::ext::simple_ident_pat(make::name(&pat_name));
410 let name_ref = make::name_ref(field_name);
411 make::record_pat_field(name_ref, pat.into())
414 fn gen_record_pat(record_name: ast::Path, fields: Vec<ast::RecordPatField>) -> ast::RecordPat {
415 let list = make::record_pat_field_list(fields);
416 make::record_pat_with_fields(record_name, list)
419 fn gen_variant_path(variant: &ast::Variant) -> Option<ast::Path> {
420 make::ext::path_from_idents(["Self", &variant.name()?.to_string()])
423 fn gen_tuple_field(field_name: &String) -> ast::Pat {
424 ast::Pat::IdentPat(make::ident_pat(false, false, make::name(field_name)))
427 // FIXME: return `None` if the trait carries a generic type; we can only
428 // generate this code `Self` for the time being.
430 let body = match adt {
431 // `Hash` cannot be derived for unions, so no default impl can be provided.
432 ast::Adt::Union(_) => return None,
434 ast::Adt::Enum(enum_) => {
435 // => std::mem::discriminant(self) == std::mem::discriminant(other)
436 let lhs_name = make::expr_path(make::ext::ident_path("self"));
437 let lhs = make::expr_call(make_discriminant()?, make::arg_list(Some(lhs_name.clone())));
438 let rhs_name = make::expr_path(make::ext::ident_path("other"));
439 let rhs = make::expr_call(make_discriminant()?, make::arg_list(Some(rhs_name.clone())));
441 make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
444 let mut arms = vec![];
445 for variant in enum_.variant_list()?.variants() {
447 match variant.field_list() {
448 // => (Self::Bar { bin: l_bin }, Self::Bar { bin: r_bin }) => l_bin == r_bin,
449 Some(ast::FieldList::RecordFieldList(list)) => {
451 let mut l_fields = vec![];
452 let mut r_fields = vec![];
454 for field in list.fields() {
455 let field_name = field.name()?.to_string();
457 let l_name = &format!("l_{}", field_name);
458 l_fields.push(gen_record_pat_field(&field_name, &l_name));
460 let r_name = &format!("r_{}", field_name);
461 r_fields.push(gen_record_pat_field(&field_name, &r_name));
463 let lhs = make::expr_path(make::ext::ident_path(l_name));
464 let rhs = make::expr_path(make::ext::ident_path(r_name));
465 let cmp = make::expr_bin_op(
467 BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
470 expr = gen_eq_chain(expr, cmp);
473 let left = gen_record_pat(gen_variant_path(&variant)?, l_fields);
474 let right = gen_record_pat(gen_variant_path(&variant)?, r_fields);
475 let tuple = make::tuple_pat(vec![left.into(), right.into()]);
477 if let Some(expr) = expr {
478 arms.push(make::match_arm(Some(tuple.into()), None, expr));
482 Some(ast::FieldList::TupleFieldList(list)) => {
484 let mut l_fields = vec![];
485 let mut r_fields = vec![];
487 for (i, _) in list.fields().enumerate() {
488 let field_name = format!("{}", i);
490 let l_name = format!("l{}", field_name);
491 l_fields.push(gen_tuple_field(&l_name));
493 let r_name = format!("r{}", field_name);
494 r_fields.push(gen_tuple_field(&r_name));
496 let lhs = make::expr_path(make::ext::ident_path(&l_name));
497 let rhs = make::expr_path(make::ext::ident_path(&r_name));
498 let cmp = make::expr_bin_op(
500 BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
503 expr = gen_eq_chain(expr, cmp);
506 let left = make::tuple_struct_pat(gen_variant_path(&variant)?, l_fields);
507 let right = make::tuple_struct_pat(gen_variant_path(&variant)?, r_fields);
508 let tuple = make::tuple_pat(vec![left.into(), right.into()]);
510 if let Some(expr) = expr {
511 arms.push(make::match_arm(Some(tuple.into()), None, expr));
518 let expr = match arms.len() {
521 if n_cases > arms.len() {
522 let lhs = make::wildcard_pat().into();
523 arms.push(make::match_arm(Some(lhs), None, eq_check));
526 let match_target = make::expr_tuple(vec![lhs_name, rhs_name]);
527 let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
528 make::expr_match(match_target, list)
532 make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
534 ast::Adt::Struct(strukt) => match strukt.field_list() {
535 Some(ast::FieldList::RecordFieldList(field_list)) => {
537 for field in field_list.fields() {
538 let lhs = make::expr_path(make::ext::ident_path("self"));
539 let lhs = make::expr_field(lhs, &field.name()?.to_string());
540 let rhs = make::expr_path(make::ext::ident_path("other"));
541 let rhs = make::expr_field(rhs, &field.name()?.to_string());
543 make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
544 expr = gen_eq_chain(expr, cmp);
546 make::block_expr(None, expr).indent(ast::edit::IndentLevel(1))
549 Some(ast::FieldList::TupleFieldList(field_list)) => {
551 for (i, _) in field_list.fields().enumerate() {
552 let idx = format!("{}", i);
553 let lhs = make::expr_path(make::ext::ident_path("self"));
554 let lhs = make::expr_field(lhs, &idx);
555 let rhs = make::expr_path(make::ext::ident_path("other"));
556 let rhs = make::expr_field(rhs, &idx);
558 make::expr_bin_op(lhs, BinaryOp::CmpOp(CmpOp::Eq { negated: false }), rhs);
559 expr = gen_eq_chain(expr, cmp);
561 make::block_expr(None, expr).indent(ast::edit::IndentLevel(1))
564 // No fields in the body means there's nothing to hash.
566 let expr = make::expr_literal("true").into();
567 make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
572 ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
576 fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
577 fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
578 let method = make::name_ref("partial_cmp");
579 make::expr_method_call(lhs, method, make::arg_list(Some(rhs)))
581 fn gen_partial_cmp_call2(mut lhs: Vec<ast::Expr>, mut rhs: Vec<ast::Expr>) -> ast::Expr {
582 let (lhs, rhs) = match (lhs.len(), rhs.len()) {
583 (1, 1) => (lhs.pop().unwrap(), rhs.pop().unwrap()),
584 _ => (make::expr_tuple(lhs.into_iter()), make::expr_tuple(rhs.into_iter())),
586 let method = make::name_ref("partial_cmp");
587 make::expr_method_call(lhs, method, make::arg_list(Some(rhs)))
590 fn gen_record_pat_field(field_name: &str, pat_name: &str) -> ast::RecordPatField {
591 let pat = make::ext::simple_ident_pat(make::name(&pat_name));
592 let name_ref = make::name_ref(field_name);
593 make::record_pat_field(name_ref, pat.into())
596 fn gen_record_pat(record_name: ast::Path, fields: Vec<ast::RecordPatField>) -> ast::RecordPat {
597 let list = make::record_pat_field_list(fields);
598 make::record_pat_with_fields(record_name, list)
601 fn gen_variant_path(variant: &ast::Variant) -> Option<ast::Path> {
602 make::ext::path_from_idents(["Self", &variant.name()?.to_string()])
605 fn gen_tuple_field(field_name: &String) -> ast::Pat {
606 ast::Pat::IdentPat(make::ident_pat(false, false, make::name(field_name)))
609 // FIXME: return `None` if the trait carries a generic type; we can only
610 // generate this code `Self` for the time being.
612 let body = match adt {
613 // `Hash` cannot be derived for unions, so no default impl can be provided.
614 ast::Adt::Union(_) => return None,
616 ast::Adt::Enum(enum_) => {
617 // => std::mem::discriminant(self) == std::mem::discriminant(other)
618 let lhs_name = make::expr_path(make::ext::ident_path("self"));
619 let lhs = make::expr_call(make_discriminant()?, make::arg_list(Some(lhs_name.clone())));
620 let rhs_name = make::expr_path(make::ext::ident_path("other"));
621 let rhs = make::expr_call(make_discriminant()?, make::arg_list(Some(rhs_name.clone())));
622 let ord_check = gen_partial_cmp_call(lhs, rhs);
624 let mut case_count = 0;
625 let mut arms = vec![];
626 for variant in enum_.variant_list()?.variants() {
628 match variant.field_list() {
629 // => (Self::Bar { bin: l_bin }, Self::Bar { bin: r_bin }) => l_bin == r_bin,
630 Some(ast::FieldList::RecordFieldList(list)) => {
631 let mut l_pat_fields = vec![];
632 let mut r_pat_fields = vec![];
633 let mut l_fields = vec![];
634 let mut r_fields = vec![];
636 for field in list.fields() {
637 let field_name = field.name()?.to_string();
639 let l_name = &format!("l_{}", field_name);
640 l_pat_fields.push(gen_record_pat_field(&field_name, &l_name));
642 let r_name = &format!("r_{}", field_name);
643 r_pat_fields.push(gen_record_pat_field(&field_name, &r_name));
645 let lhs = make::expr_path(make::ext::ident_path(l_name));
646 let rhs = make::expr_path(make::ext::ident_path(r_name));
651 let left_pat = gen_record_pat(gen_variant_path(&variant)?, l_pat_fields);
652 let right_pat = gen_record_pat(gen_variant_path(&variant)?, r_pat_fields);
653 let tuple_pat = make::tuple_pat(vec![left_pat.into(), right_pat.into()]);
655 let len = l_fields.len();
657 let mut expr = gen_partial_cmp_call2(l_fields, r_fields);
659 expr = make::block_expr(None, Some(expr))
660 .indent(ast::edit::IndentLevel(1))
663 arms.push(make::match_arm(Some(tuple_pat.into()), None, expr));
667 Some(ast::FieldList::TupleFieldList(list)) => {
668 let mut l_pat_fields = vec![];
669 let mut r_pat_fields = vec![];
670 let mut l_fields = vec![];
671 let mut r_fields = vec![];
673 for (i, _) in list.fields().enumerate() {
674 let field_name = format!("{}", i);
676 let l_name = format!("l{}", field_name);
677 l_pat_fields.push(gen_tuple_field(&l_name));
679 let r_name = format!("r{}", field_name);
680 r_pat_fields.push(gen_tuple_field(&r_name));
682 let lhs = make::expr_path(make::ext::ident_path(&l_name));
683 let rhs = make::expr_path(make::ext::ident_path(&r_name));
689 make::tuple_struct_pat(gen_variant_path(&variant)?, l_pat_fields);
691 make::tuple_struct_pat(gen_variant_path(&variant)?, r_pat_fields);
692 let tuple_pat = make::tuple_pat(vec![left_pat.into(), right_pat.into()]);
694 let len = l_fields.len();
696 let mut expr = gen_partial_cmp_call2(l_fields, r_fields);
698 expr = make::block_expr(None, Some(expr))
699 .indent(ast::edit::IndentLevel(1))
702 arms.push(make::match_arm(Some(tuple_pat.into()), None, expr));
709 let expr = match arms.len() {
712 if case_count > arms.len() {
713 let lhs = make::wildcard_pat().into();
714 arms.push(make::match_arm(Some(lhs), None, ord_check));
717 let match_target = make::expr_tuple(vec![lhs_name, rhs_name]);
718 let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
719 make::expr_match(match_target, list)
723 make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
725 ast::Adt::Struct(strukt) => match strukt.field_list() {
726 Some(ast::FieldList::RecordFieldList(field_list)) => {
727 let mut l_fields = vec![];
728 let mut r_fields = vec![];
729 for field in field_list.fields() {
730 let lhs = make::expr_path(make::ext::ident_path("self"));
731 let lhs = make::expr_field(lhs, &field.name()?.to_string());
732 let rhs = make::expr_path(make::ext::ident_path("other"));
733 let rhs = make::expr_field(rhs, &field.name()?.to_string());
738 let expr = gen_partial_cmp_call2(l_fields, r_fields);
739 make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
742 Some(ast::FieldList::TupleFieldList(field_list)) => {
743 let mut l_fields = vec![];
744 let mut r_fields = vec![];
745 for (i, _) in field_list.fields().enumerate() {
746 let idx = format!("{}", i);
747 let lhs = make::expr_path(make::ext::ident_path("self"));
748 let lhs = make::expr_field(lhs, &idx);
749 let rhs = make::expr_path(make::ext::ident_path("other"));
750 let rhs = make::expr_field(rhs, &idx);
754 let expr = gen_partial_cmp_call2(l_fields, r_fields);
755 make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
758 // No fields in the body means there's nothing to hash.
760 let expr = make::expr_literal("true").into();
761 make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
766 ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
770 fn make_discriminant() -> Option<ast::Expr> {
771 Some(make::expr_path(make::ext::path_from_idents(["core", "mem", "discriminant"])?))