Skip to content

Commit 48c3be9

Browse files
Merge #10574
10574: fix: Fix PartialOrd codegen r=lnicola a=yoshuawuyts Closes #10571 (comment). Thanks! r? `@lnicola` Co-authored-by: Yoshua Wuyts <[email protected]>
2 parents 5ce9b04 + a9ec345 commit 48c3be9

File tree

2 files changed

+10
-253
lines changed

2 files changed

+10
-253
lines changed

crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs

Lines changed: 3 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ struct Foo {
693693
694694
impl PartialOrd for Foo {
695695
$0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
696-
self.bin.partial_cmp(other.bin)
696+
self.bin.partial_cmp(&other.bin)
697697
}
698698
}
699699
"#,
@@ -722,7 +722,7 @@ struct Foo {
722722
723723
impl PartialOrd for Foo {
724724
$0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
725-
(self.bin, self.bar, self.baz).partial_cmp((other.bin, other.bar, other.baz))
725+
(self.bin, self.bar, self.baz).partial_cmp(&(other.bin, other.bar, other.baz))
726726
}
727727
}
728728
"#,
@@ -743,120 +743,7 @@ struct Foo(usize, usize, usize);
743743
744744
impl PartialOrd for Foo {
745745
$0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
746-
(self.0, self.1, self.2).partial_cmp((other.0, other.1, other.2))
747-
}
748-
}
749-
"#,
750-
)
751-
}
752-
753-
#[test]
754-
fn add_custom_impl_partial_ord_enum() {
755-
check_assist(
756-
replace_derive_with_manual_impl,
757-
r#"
758-
//- minicore: ord
759-
#[derive(Partial$0Ord)]
760-
enum Foo {
761-
Bin,
762-
Bar,
763-
Baz,
764-
}
765-
"#,
766-
r#"
767-
enum Foo {
768-
Bin,
769-
Bar,
770-
Baz,
771-
}
772-
773-
impl PartialOrd for Foo {
774-
$0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
775-
core::mem::discriminant(self).partial_cmp(core::mem::discriminant(other))
776-
}
777-
}
778-
"#,
779-
)
780-
}
781-
782-
#[test]
783-
fn add_custom_impl_partial_ord_record_enum() {
784-
check_assist(
785-
replace_derive_with_manual_impl,
786-
r#"
787-
//- minicore: ord
788-
#[derive(Partial$0Ord)]
789-
enum Foo {
790-
Bar {
791-
bin: String,
792-
},
793-
Baz {
794-
qux: String,
795-
fez: String,
796-
},
797-
Qux {},
798-
Bin,
799-
}
800-
"#,
801-
r#"
802-
enum Foo {
803-
Bar {
804-
bin: String,
805-
},
806-
Baz {
807-
qux: String,
808-
fez: String,
809-
},
810-
Qux {},
811-
Bin,
812-
}
813-
814-
impl PartialOrd for Foo {
815-
$0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
816-
match (self, other) {
817-
(Self::Bar { bin: l_bin }, Self::Bar { bin: r_bin }) => l_bin.partial_cmp(r_bin),
818-
(Self::Baz { qux: l_qux, fez: l_fez }, Self::Baz { qux: r_qux, fez: r_fez }) => {
819-
(l_qux, l_fez).partial_cmp((r_qux, r_fez))
820-
}
821-
_ => core::mem::discriminant(self).partial_cmp(core::mem::discriminant(other)),
822-
}
823-
}
824-
}
825-
"#,
826-
)
827-
}
828-
829-
#[test]
830-
fn add_custom_impl_partial_ord_tuple_enum() {
831-
check_assist(
832-
replace_derive_with_manual_impl,
833-
r#"
834-
//- minicore: ord
835-
#[derive(Partial$0Ord)]
836-
enum Foo {
837-
Bar(String),
838-
Baz(String, String),
839-
Qux(),
840-
Bin,
841-
}
842-
"#,
843-
r#"
844-
enum Foo {
845-
Bar(String),
846-
Baz(String, String),
847-
Qux(),
848-
Bin,
849-
}
850-
851-
impl PartialOrd for Foo {
852-
$0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
853-
match (self, other) {
854-
(Self::Bar(l0), Self::Bar(r0)) => l0.partial_cmp(r0),
855-
(Self::Baz(l0, l1), Self::Baz(r0, r1)) => {
856-
(l0, l1).partial_cmp((r0, r1))
857-
}
858-
_ => core::mem::discriminant(self).partial_cmp(core::mem::discriminant(other)),
859-
}
746+
(self.0, self.1, self.2).partial_cmp(&(other.0, other.1, other.2))
860747
}
861748
}
862749
"#,

crates/ide_assists/src/utils/gen_trait_fn_body.rs

Lines changed: 7 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -574,154 +574,24 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
574574
}
575575

576576
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)))
580-
}
581-
fn gen_partial_cmp_call2(mut lhs: Vec<ast::Expr>, mut rhs: Vec<ast::Expr>) -> ast::Expr {
577+
fn gen_partial_cmp_call(mut lhs: Vec<ast::Expr>, mut rhs: Vec<ast::Expr>) -> ast::Expr {
582578
let (lhs, rhs) = match (lhs.len(), rhs.len()) {
583579
(1, 1) => (lhs.pop().unwrap(), rhs.pop().unwrap()),
584580
_ => (make::expr_tuple(lhs.into_iter()), make::expr_tuple(rhs.into_iter())),
585581
};
582+
let rhs = make::expr_ref(rhs, false);
586583
let method = make::name_ref("partial_cmp");
587584
make::expr_method_call(lhs, method, make::arg_list(Some(rhs)))
588585
}
589586

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())
594-
}
595-
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)
599-
}
600-
601-
fn gen_variant_path(variant: &ast::Variant) -> Option<ast::Path> {
602-
make::ext::path_from_idents(["Self", &variant.name()?.to_string()])
603-
}
604-
605-
fn gen_tuple_field(field_name: &String) -> ast::Pat {
606-
ast::Pat::IdentPat(make::ident_pat(false, false, make::name(field_name)))
607-
}
608-
609587
// FIXME: return `None` if the trait carries a generic type; we can only
610588
// generate this code `Self` for the time being.
611589

612590
let body = match adt {
613-
// `Hash` cannot be derived for unions, so no default impl can be provided.
591+
// `PartialOrd` cannot be derived for unions, so no default impl can be provided.
614592
ast::Adt::Union(_) => return None,
615-
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);
623-
624-
let mut case_count = 0;
625-
let mut arms = vec![];
626-
for variant in enum_.variant_list()?.variants() {
627-
case_count += 1;
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![];
635-
636-
for field in list.fields() {
637-
let field_name = field.name()?.to_string();
638-
639-
let l_name = &format!("l_{}", field_name);
640-
l_pat_fields.push(gen_record_pat_field(&field_name, &l_name));
641-
642-
let r_name = &format!("r_{}", field_name);
643-
r_pat_fields.push(gen_record_pat_field(&field_name, &r_name));
644-
645-
let lhs = make::expr_path(make::ext::ident_path(l_name));
646-
let rhs = make::expr_path(make::ext::ident_path(r_name));
647-
l_fields.push(lhs);
648-
r_fields.push(rhs);
649-
}
650-
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()]);
654-
655-
let len = l_fields.len();
656-
if len != 0 {
657-
let mut expr = gen_partial_cmp_call2(l_fields, r_fields);
658-
if len >= 2 {
659-
expr = make::block_expr(None, Some(expr))
660-
.indent(ast::edit::IndentLevel(1))
661-
.into();
662-
}
663-
arms.push(make::match_arm(Some(tuple_pat.into()), None, expr));
664-
}
665-
}
666-
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![];
672-
673-
for (i, _) in list.fields().enumerate() {
674-
let field_name = format!("{}", i);
675-
676-
let l_name = format!("l{}", field_name);
677-
l_pat_fields.push(gen_tuple_field(&l_name));
678-
679-
let r_name = format!("r{}", field_name);
680-
r_pat_fields.push(gen_tuple_field(&r_name));
681-
682-
let lhs = make::expr_path(make::ext::ident_path(&l_name));
683-
let rhs = make::expr_path(make::ext::ident_path(&r_name));
684-
l_fields.push(lhs);
685-
r_fields.push(rhs);
686-
}
687-
688-
let left_pat =
689-
make::tuple_struct_pat(gen_variant_path(&variant)?, l_pat_fields);
690-
let right_pat =
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()]);
693-
694-
let len = l_fields.len();
695-
if len != 0 {
696-
let mut expr = gen_partial_cmp_call2(l_fields, r_fields);
697-
if len >= 2 {
698-
expr = make::block_expr(None, Some(expr))
699-
.indent(ast::edit::IndentLevel(1))
700-
.into();
701-
}
702-
arms.push(make::match_arm(Some(tuple_pat.into()), None, expr));
703-
}
704-
}
705-
None => continue,
706-
}
707-
}
708-
709-
let expr = match arms.len() {
710-
0 => ord_check,
711-
_ => {
712-
if case_count > arms.len() {
713-
let lhs = make::wildcard_pat().into();
714-
arms.push(make::match_arm(Some(lhs), None, ord_check));
715-
}
716-
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)
720-
}
721-
};
722-
723-
make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
724-
}
593+
// `core::mem::Discriminant` does not implement `PartialOrd` in stable Rust today.
594+
ast::Adt::Enum(_) => return None,
725595
ast::Adt::Struct(strukt) => match strukt.field_list() {
726596
Some(ast::FieldList::RecordFieldList(field_list)) => {
727597
let mut l_fields = vec![];
@@ -735,7 +605,7 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
735605
r_fields.push(rhs);
736606
}
737607

738-
let expr = gen_partial_cmp_call2(l_fields, r_fields);
608+
let expr = gen_partial_cmp_call(l_fields, r_fields);
739609
make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
740610
}
741611

@@ -751,7 +621,7 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
751621
l_fields.push(lhs);
752622
r_fields.push(rhs);
753623
}
754-
let expr = gen_partial_cmp_call2(l_fields, r_fields);
624+
let expr = gen_partial_cmp_call(l_fields, r_fields);
755625
make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1))
756626
}
757627

0 commit comments

Comments
 (0)