Skip to content

Commit 9c4a770

Browse files
Fix some things with builtin derives
1. Err on unions on derive where it's required. 2. Err on `#[derive(Default)]` on enums without `#[default]` variant. 3. Don't add where bounds `T: Default` when expanding `Default` on enums (structs need that, enums not). Also, because I was annoyed by that, in minicore, add a way to filter on multiple flags in the line-filter (`// :`). This is required for the `Debug` and `Hash` derives, because the derive should be in the prelude but the trait not.
1 parent f14bf95 commit 9c4a770

File tree

5 files changed

+190
-72
lines changed

5 files changed

+190
-72
lines changed

crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,3 +746,83 @@ struct Struct9<#[pointee] T, U>(T) where T: ?Sized;
746746
623..690: `derive(CoercePointee)` requires `T` to be marked `?Sized`"#]],
747747
);
748748
}
749+
750+
#[test]
751+
fn union_derive() {
752+
check_errors(
753+
r#"
754+
//- minicore: clone, copy, default, fmt, hash, ord, eq, derive
755+
756+
#[derive(Copy)]
757+
union Foo1 { _v: () }
758+
#[derive(Clone)]
759+
union Foo2 { _v: () }
760+
#[derive(Default)]
761+
union Foo3 { _v: () }
762+
#[derive(Debug)]
763+
union Foo4 { _v: () }
764+
#[derive(Hash)]
765+
union Foo5 { _v: () }
766+
#[derive(Ord)]
767+
union Foo6 { _v: () }
768+
#[derive(PartialOrd)]
769+
union Foo7 { _v: () }
770+
#[derive(Eq)]
771+
union Foo8 { _v: () }
772+
#[derive(PartialEq)]
773+
union Foo9 { _v: () }
774+
"#,
775+
expect![[r#"
776+
78..118: this trait cannot be derived for unions
777+
119..157: this trait cannot be derived for unions
778+
158..195: this trait cannot be derived for unions
779+
196..232: this trait cannot be derived for unions
780+
233..276: this trait cannot be derived for unions
781+
313..355: this trait cannot be derived for unions"#]],
782+
);
783+
}
784+
785+
#[test]
786+
fn default_enum_without_default_attr() {
787+
check_errors(
788+
r#"
789+
//- minicore: default, derive
790+
791+
#[derive(Default)]
792+
enum Foo {
793+
Bar,
794+
}
795+
"#,
796+
expect!["1..41: `#[derive(Default)]` on enum with no `#[default]`"],
797+
);
798+
}
799+
800+
#[test]
801+
fn generic_enum_default() {
802+
check(
803+
r#"
804+
//- minicore: default, derive
805+
806+
#[derive(Default)]
807+
enum Foo<T> {
808+
Bar(T),
809+
#[default]
810+
Baz,
811+
}
812+
"#,
813+
expect![[r#"
814+
815+
#[derive(Default)]
816+
enum Foo<T> {
817+
Bar(T),
818+
#[default]
819+
Baz,
820+
}
821+
822+
impl <T, > $crate::default::Default for Foo<T, > where {
823+
fn default() -> Self {
824+
Foo::Baz
825+
}
826+
}"#]],
827+
);
828+
}

crates/hir-expand/src/builtin/derive_macro.rs

Lines changed: 82 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ fn expand_simple_derive(
458458
invoc_span: Span,
459459
tt: &tt::TopSubtree,
460460
trait_path: tt::TopSubtree,
461+
allow_unions: bool,
461462
make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::TopSubtree,
462463
) -> ExpandResult<tt::TopSubtree> {
463464
let info = match parse_adt(db, tt, invoc_span) {
@@ -469,6 +470,12 @@ fn expand_simple_derive(
469470
);
470471
}
471472
};
473+
if !allow_unions && matches!(info.shape, AdtShape::Union) {
474+
return ExpandResult::new(
475+
tt::TopSubtree::empty(tt::DelimSpan::from_single(invoc_span)),
476+
ExpandError::other(invoc_span, "this trait cannot be derived for unions"),
477+
);
478+
}
472479
ExpandResult::ok(expand_simple_derive_with_parsed(
473480
invoc_span,
474481
info,
@@ -535,7 +542,14 @@ fn copy_expand(
535542
tt: &tt::TopSubtree,
536543
) -> ExpandResult<tt::TopSubtree> {
537544
let krate = dollar_crate(span);
538-
expand_simple_derive(db, span, tt, quote! {span => #krate::marker::Copy }, |_| quote! {span =>})
545+
expand_simple_derive(
546+
db,
547+
span,
548+
tt,
549+
quote! {span => #krate::marker::Copy },
550+
true,
551+
|_| quote! {span =>},
552+
)
539553
}
540554

541555
fn clone_expand(
@@ -544,7 +558,7 @@ fn clone_expand(
544558
tt: &tt::TopSubtree,
545559
) -> ExpandResult<tt::TopSubtree> {
546560
let krate = dollar_crate(span);
547-
expand_simple_derive(db, span, tt, quote! {span => #krate::clone::Clone }, |adt| {
561+
expand_simple_derive(db, span, tt, quote! {span => #krate::clone::Clone }, true, |adt| {
548562
if matches!(adt.shape, AdtShape::Union) {
549563
let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
550564
return quote! {span =>
@@ -599,41 +613,63 @@ fn default_expand(
599613
tt: &tt::TopSubtree,
600614
) -> ExpandResult<tt::TopSubtree> {
601615
let krate = &dollar_crate(span);
602-
expand_simple_derive(db, span, tt, quote! {span => #krate::default::Default }, |adt| {
603-
let body = match &adt.shape {
604-
AdtShape::Struct(fields) => {
605-
let name = &adt.name;
606-
fields.as_pattern_map(
607-
quote!(span =>#name),
616+
let adt = match parse_adt(db, tt, span) {
617+
Ok(info) => info,
618+
Err(e) => {
619+
return ExpandResult::new(
620+
tt::TopSubtree::empty(tt::DelimSpan { open: span, close: span }),
621+
e,
622+
);
623+
}
624+
};
625+
let (body, constrain_to_trait) = match &adt.shape {
626+
AdtShape::Struct(fields) => {
627+
let name = &adt.name;
628+
let body = fields.as_pattern_map(
629+
quote!(span =>#name),
630+
span,
631+
|_| quote!(span =>#krate::default::Default::default()),
632+
);
633+
(body, true)
634+
}
635+
AdtShape::Enum { default_variant, variants } => {
636+
if let Some(d) = default_variant {
637+
let (name, fields) = &variants[*d];
638+
let adt_name = &adt.name;
639+
let body = fields.as_pattern_map(
640+
quote!(span =>#adt_name :: #name),
608641
span,
609642
|_| quote!(span =>#krate::default::Default::default()),
610-
)
643+
);
644+
(body, false)
645+
} else {
646+
return ExpandResult::new(
647+
tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
648+
ExpandError::other(span, "`#[derive(Default)]` on enum with no `#[default]`"),
649+
);
611650
}
612-
AdtShape::Enum { default_variant, variants } => {
613-
if let Some(d) = default_variant {
614-
let (name, fields) = &variants[*d];
615-
let adt_name = &adt.name;
616-
fields.as_pattern_map(
617-
quote!(span =>#adt_name :: #name),
618-
span,
619-
|_| quote!(span =>#krate::default::Default::default()),
620-
)
621-
} else {
622-
// FIXME: Return expand error here
623-
quote!(span =>)
651+
}
652+
AdtShape::Union => {
653+
return ExpandResult::new(
654+
tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
655+
ExpandError::other(span, "this trait cannot be derived for unions"),
656+
);
657+
}
658+
};
659+
ExpandResult::ok(expand_simple_derive_with_parsed(
660+
span,
661+
adt,
662+
quote! {span => #krate::default::Default },
663+
|_adt| {
664+
quote! {span =>
665+
fn default() -> Self {
666+
#body
624667
}
625668
}
626-
AdtShape::Union => {
627-
// FIXME: Return expand error here
628-
quote!(span =>)
629-
}
630-
};
631-
quote! {span =>
632-
fn default() -> Self {
633-
#body
634-
}
635-
}
636-
})
669+
},
670+
constrain_to_trait,
671+
tt::TopSubtree::empty(tt::DelimSpan::from_single(span)),
672+
))
637673
}
638674

639675
fn debug_expand(
@@ -642,7 +678,7 @@ fn debug_expand(
642678
tt: &tt::TopSubtree,
643679
) -> ExpandResult<tt::TopSubtree> {
644680
let krate = &dollar_crate(span);
645-
expand_simple_derive(db, span, tt, quote! {span => #krate::fmt::Debug }, |adt| {
681+
expand_simple_derive(db, span, tt, quote! {span => #krate::fmt::Debug }, false, |adt| {
646682
let for_variant = |name: String, v: &VariantShape| match v {
647683
VariantShape::Struct(fields) => {
648684
let for_fields = fields.iter().map(|it| {
@@ -697,10 +733,7 @@ fn debug_expand(
697733
}
698734
})
699735
.collect(),
700-
AdtShape::Union => {
701-
// FIXME: Return expand error here
702-
vec![]
703-
}
736+
AdtShape::Union => unreachable!(),
704737
};
705738
quote! {span =>
706739
fn fmt(&self, f: &mut #krate::fmt::Formatter) -> #krate::fmt::Result {
@@ -718,11 +751,7 @@ fn hash_expand(
718751
tt: &tt::TopSubtree,
719752
) -> ExpandResult<tt::TopSubtree> {
720753
let krate = &dollar_crate(span);
721-
expand_simple_derive(db, span, tt, quote! {span => #krate::hash::Hash }, |adt| {
722-
if matches!(adt.shape, AdtShape::Union) {
723-
// FIXME: Return expand error here
724-
return quote! {span =>};
725-
}
754+
expand_simple_derive(db, span, tt, quote! {span => #krate::hash::Hash }, false, |adt| {
726755
if matches!(&adt.shape, AdtShape::Enum { variants, .. } if variants.is_empty()) {
727756
let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
728757
return quote! {span =>
@@ -769,7 +798,14 @@ fn eq_expand(
769798
tt: &tt::TopSubtree,
770799
) -> ExpandResult<tt::TopSubtree> {
771800
let krate = dollar_crate(span);
772-
expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>})
801+
expand_simple_derive(
802+
db,
803+
span,
804+
tt,
805+
quote! {span => #krate::cmp::Eq },
806+
true,
807+
|_| quote! {span =>},
808+
)
773809
}
774810

775811
fn partial_eq_expand(
@@ -778,11 +814,7 @@ fn partial_eq_expand(
778814
tt: &tt::TopSubtree,
779815
) -> ExpandResult<tt::TopSubtree> {
780816
let krate = dollar_crate(span);
781-
expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialEq }, |adt| {
782-
if matches!(adt.shape, AdtShape::Union) {
783-
// FIXME: Return expand error here
784-
return quote! {span =>};
785-
}
817+
expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialEq }, false, |adt| {
786818
let name = &adt.name;
787819

788820
let (self_patterns, other_patterns) = self_and_other_patterns(adt, name, span);
@@ -854,7 +886,7 @@ fn ord_expand(
854886
tt: &tt::TopSubtree,
855887
) -> ExpandResult<tt::TopSubtree> {
856888
let krate = &dollar_crate(span);
857-
expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Ord }, |adt| {
889+
expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Ord }, false, |adt| {
858890
fn compare(
859891
krate: &tt::Ident,
860892
left: tt::TopSubtree,
@@ -873,10 +905,6 @@ fn ord_expand(
873905
}
874906
}
875907
}
876-
if matches!(adt.shape, AdtShape::Union) {
877-
// FIXME: Return expand error here
878-
return quote!(span =>);
879-
}
880908
let (self_patterns, other_patterns) = self_and_other_patterns(adt, &adt.name, span);
881909
let arms = izip!(self_patterns, other_patterns, adt.shape.field_names(span)).map(
882910
|(pat1, pat2, fields)| {
@@ -916,7 +944,7 @@ fn partial_ord_expand(
916944
tt: &tt::TopSubtree,
917945
) -> ExpandResult<tt::TopSubtree> {
918946
let krate = &dollar_crate(span);
919-
expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialOrd }, |adt| {
947+
expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialOrd }, false, |adt| {
920948
fn compare(
921949
krate: &tt::Ident,
922950
left: tt::TopSubtree,
@@ -935,10 +963,6 @@ fn partial_ord_expand(
935963
}
936964
}
937965
}
938-
if matches!(adt.shape, AdtShape::Union) {
939-
// FIXME: Return expand error here
940-
return quote!(span =>);
941-
}
942966
let left = quote!(span =>#krate::intrinsics::discriminant_value(self));
943967
let right = quote!(span =>#krate::intrinsics::discriminant_value(other));
944968

crates/ide-completion/src/tests/attribute.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,7 @@ mod derive {
878878
expect![[r#"
879879
de Clone macro Clone
880880
de Clone, Copy
881+
de Debug macro Debug
881882
de Default macro Default
882883
de PartialEq macro PartialEq
883884
de PartialEq, Eq
@@ -900,6 +901,7 @@ mod derive {
900901
expect![[r#"
901902
de Clone macro Clone
902903
de Clone, Copy
904+
de Debug macro Debug
903905
de Default macro Default
904906
de Eq
905907
de Eq, PartialOrd, Ord
@@ -921,6 +923,7 @@ mod derive {
921923
expect![[r#"
922924
de Clone macro Clone
923925
de Clone, Copy
926+
de Debug macro Debug
924927
de Default macro Default
925928
de Eq
926929
de Eq, PartialOrd, Ord
@@ -942,6 +945,7 @@ mod derive {
942945
expect![[r#"
943946
de Clone macro Clone
944947
de Clone, Copy
948+
de Debug macro Debug
945949
de Default macro Default
946950
de PartialOrd
947951
de PartialOrd, Ord

crates/test-utils/src/fixture.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -435,14 +435,16 @@ impl MiniCore {
435435
continue;
436436
}
437437

438-
let mut active_line_region = false;
439-
let mut inactive_line_region = false;
438+
let mut active_line_region = 0;
439+
let mut inactive_line_region = 0;
440440
if let Some(idx) = trimmed.find("// :!") {
441-
inactive_line_region = true;
442-
inactive_regions.push(&trimmed[idx + "// :!".len()..]);
441+
let regions = trimmed[idx + "// :!".len()..].split(", ");
442+
inactive_line_region += regions.clone().count();
443+
inactive_regions.extend(regions);
443444
} else if let Some(idx) = trimmed.find("// :") {
444-
active_line_region = true;
445-
active_regions.push(&trimmed[idx + "// :".len()..]);
445+
let regions = trimmed[idx + "// :".len()..].split(", ");
446+
active_line_region += regions.clone().count();
447+
active_regions.extend(regions);
446448
}
447449

448450
let mut keep = true;
@@ -462,11 +464,11 @@ impl MiniCore {
462464
if keep {
463465
buf.push_str(line);
464466
}
465-
if active_line_region {
466-
active_regions.pop().unwrap();
467+
if active_line_region > 0 {
468+
active_regions.drain(active_regions.len() - active_line_region..);
467469
}
468-
if inactive_line_region {
469-
inactive_regions.pop().unwrap();
470+
if inactive_line_region > 0 {
471+
inactive_regions.drain(inactive_regions.len() - active_line_region..);
470472
}
471473
}
472474

0 commit comments

Comments
 (0)