Skip to content

Commit d04a71d

Browse files
committed
Support outer-variant patterns in nested match
1 parent aaa4071 commit d04a71d

File tree

3 files changed

+154
-0
lines changed

3 files changed

+154
-0
lines changed

nestum/src/lib.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,20 @@ fn rewrite_pat_path(
567567
let Some((module_path, explicit_crate, outer_enum, outer_variant, inner_variant)) =
568568
split_nested_path(&pat_path.path)?
569569
else {
570+
if let Some(new_path) = rewrite_outer_variant_path(
571+
&pat_path.path,
572+
current_file,
573+
module_root,
574+
current_module,
575+
enums_by_ident,
576+
cache,
577+
)? {
578+
return Ok(Pat::Path(PatPath {
579+
attrs: pat_path.attrs,
580+
qself: pat_path.qself,
581+
path: new_path,
582+
}));
583+
}
570584
return Ok(Pat::Path(pat_path));
571585
};
572586

@@ -685,6 +699,22 @@ fn rewrite_pat_tuple_struct(
685699
let Some((module_path, explicit_crate, outer_enum, outer_variant, inner_variant)) =
686700
split_nested_path(&pat_tuple.path)?
687701
else {
702+
if let Some(new_path) = rewrite_outer_variant_path(
703+
&pat_tuple.path,
704+
current_file,
705+
module_root,
706+
current_module,
707+
enums_by_ident,
708+
cache,
709+
)? {
710+
return Ok(Pat::TupleStruct(PatTupleStruct {
711+
attrs: pat_tuple.attrs,
712+
qself: pat_tuple.qself,
713+
path: new_path,
714+
paren_token: pat_tuple.paren_token,
715+
elems: pat_tuple.elems,
716+
}));
717+
}
688718
return Ok(Pat::TupleStruct(pat_tuple));
689719
};
690720

@@ -806,6 +836,23 @@ fn rewrite_pat_struct(
806836
let Some((module_path, explicit_crate, outer_enum, outer_variant, inner_variant)) =
807837
split_nested_path(&pat_struct.path)?
808838
else {
839+
if let Some(new_path) = rewrite_outer_variant_path(
840+
&pat_struct.path,
841+
current_file,
842+
module_root,
843+
current_module,
844+
enums_by_ident,
845+
cache,
846+
)? {
847+
return Ok(Pat::Struct(PatStruct {
848+
attrs: pat_struct.attrs,
849+
qself: pat_struct.qself,
850+
path: new_path,
851+
brace_token: pat_struct.brace_token,
852+
fields: pat_struct.fields,
853+
rest: pat_struct.rest,
854+
}));
855+
}
809856
return Ok(Pat::Struct(pat_struct));
810857
};
811858

@@ -943,6 +990,88 @@ fn split_nested_path(
943990
)))
944991
}
945992

993+
fn split_outer_variant_path(
994+
path: &syn::Path,
995+
) -> Option<(Vec<syn::Ident>, bool, syn::Ident, syn::Ident)> {
996+
let segments: Vec<_> = path.segments.iter().map(|s| s.ident.clone()).collect();
997+
if segments.len() < 2 {
998+
return None;
999+
}
1000+
1001+
let outer_idx = segments.len() - 2;
1002+
let variant_idx = segments.len() - 1;
1003+
let module_path = segments[..outer_idx].to_vec();
1004+
let explicit_crate = module_path
1005+
.first()
1006+
.map(|ident| ident == "crate")
1007+
.unwrap_or(false);
1008+
Some((
1009+
module_path,
1010+
explicit_crate,
1011+
segments[outer_idx].clone(),
1012+
segments[variant_idx].clone(),
1013+
))
1014+
}
1015+
1016+
fn rewrite_outer_variant_path(
1017+
path: &syn::Path,
1018+
current_file: &str,
1019+
module_root: &std::path::Path,
1020+
current_module: &str,
1021+
enums_by_ident: &HashMap<String, ItemEnum>,
1022+
cache: &mut HashMap<String, HashMap<String, ItemEnum>>,
1023+
) -> Result<Option<syn::Path>, syn::Error> {
1024+
let Some((module_path, explicit_crate, outer_enum, outer_variant)) =
1025+
split_outer_variant_path(path)
1026+
else {
1027+
return Ok(None);
1028+
};
1029+
1030+
let Some(outer_info) = resolve_enum_from_path(
1031+
&module_path,
1032+
explicit_crate,
1033+
&outer_enum,
1034+
current_file,
1035+
module_root,
1036+
current_module,
1037+
enums_by_ident,
1038+
cache,
1039+
)?
1040+
else {
1041+
return Ok(None);
1042+
};
1043+
1044+
let (outer_enum_item, outer_marked) = outer_info;
1045+
if !outer_marked {
1046+
return Ok(None);
1047+
}
1048+
1049+
if !outer_enum_item
1050+
.variants
1051+
.iter()
1052+
.any(|v| v.ident == outer_variant)
1053+
{
1054+
return Err(syn::Error::new(
1055+
path.span(),
1056+
format!(
1057+
"variant {} not found on enum {}",
1058+
outer_variant, outer_enum
1059+
),
1060+
));
1061+
}
1062+
1063+
let outer_module_idents = effective_module_idents(&module_path, explicit_crate, current_module);
1064+
let outer_variant_path = build_path_from_idents(
1065+
outer_module_idents,
1066+
&[
1067+
outer_enum.clone(),
1068+
outer_enum.clone(),
1069+
outer_variant.clone(),
1070+
],
1071+
);
1072+
Ok(Some(outer_variant_path))
1073+
}
1074+
9461075
fn resolve_enum_from_path(
9471076
module_path: &[syn::Ident],
9481077
explicit_crate: bool,

nestum/tests/trybuild.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ fn ui() {
99
t.pass("tests/ui/pass_match_struct.rs");
1010
t.pass("tests/ui/pass_match_or.rs");
1111
t.pass("tests/ui/pass_match_module.rs");
12+
t.pass("tests/ui/pass_match_mixed.rs");
1213
t.compile_fail("tests/ui/fail_enum_args.rs");
1314
t.compile_fail("tests/ui/fail_variant_attr.rs");
1415
t.compile_fail("tests/ui/fail_external_not_tuple.rs");
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use nestum::{nestum, nested};
2+
3+
#[nestum]
4+
pub enum Inner {
5+
VariantA,
6+
VariantB(u8),
7+
}
8+
9+
#[nestum]
10+
pub enum Outer {
11+
Variant1,
12+
Variant2(Inner),
13+
}
14+
15+
fn main() {
16+
let event = Outer::Variant2::VariantA;
17+
nested! {
18+
match event {
19+
Outer::Variant1 => {}
20+
Outer::Variant2::VariantA => {}
21+
Outer::Variant2::VariantB(n) => { let _ = n; }
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)