Skip to content

Commit 9b63a6e

Browse files
committed
checker: expand nested generic sumtype variants
1 parent faeb987 commit 9b63a6e

2 files changed

Lines changed: 69 additions & 10 deletions

File tree

vlib/v/checker/match.v

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -691,32 +691,75 @@ fn (mut c Checker) match_sumtype_has_variant(parent ast.Type, variant ast.Type)
691691
if c.table.sym(parent).kind == .sum_type {
692692
return false
693693
}
694-
for candidate in c.concrete_sumtype_variants(parent) {
694+
for candidate in c.match_sumtype_matchable_variants(parent) {
695695
if c.match_sumtype_variant_is_handled(candidate, variant) {
696696
return true
697697
}
698698
}
699699
return false
700700
}
701701

702+
fn (mut c Checker) match_sumtype_matchable_variants(parent ast.Type) []ast.Type {
703+
if c.table.sym(parent).kind == .sum_type {
704+
return c.table.sumtype_matchable_variants(parent)
705+
}
706+
mut variants := []ast.Type{}
707+
mut seen := map[u32]bool{}
708+
c.collect_match_sumtype_matchable_variants(parent, mut seen, mut variants)
709+
return variants
710+
}
711+
712+
fn (mut c Checker) collect_match_sumtype_matchable_variants(parent ast.Type, mut seen map[u32]bool, mut variants []ast.Type) {
713+
for variant in c.concrete_sumtype_variants(parent) {
714+
key := u32(variant)
715+
if key in seen {
716+
continue
717+
}
718+
seen[key] = true
719+
variants << variant
720+
if c.concrete_sumtype_variants(variant).len > 0 {
721+
c.collect_match_sumtype_matchable_variants(variant, mut seen, mut variants)
722+
}
723+
}
724+
}
725+
702726
fn (mut c Checker) match_sumtype_missing_variants(parent ast.Type, handled []ast.Type) []ast.Type {
703727
if c.table.sym(parent).kind == .sum_type {
704728
return c.table.sumtype_missing_variants(parent, handled)
705729
}
706730
mut missing := []ast.Type{}
731+
mut seen := map[u32]bool{}
732+
c.collect_match_sumtype_missing_variants(parent, handled, mut seen, mut missing)
733+
return missing
734+
}
735+
736+
fn (mut c Checker) collect_match_sumtype_missing_variants(parent ast.Type, handled []ast.Type, mut seen map[u32]bool, mut missing []ast.Type) {
737+
if c.match_sumtype_variant_is_handled_by(parent, handled) {
738+
return
739+
}
707740
for variant in c.concrete_sumtype_variants(parent) {
708-
mut is_handled := false
709-
for handled_variant in handled {
710-
if c.match_sumtype_variant_is_handled(variant, handled_variant) {
711-
is_handled = true
712-
break
741+
if c.match_sumtype_variant_is_handled_by(variant, handled) {
742+
continue
743+
}
744+
if c.concrete_sumtype_variants(variant).len > 0 {
745+
c.collect_match_sumtype_missing_variants(variant, handled, mut seen, mut missing)
746+
} else {
747+
key := u32(variant)
748+
if key !in seen {
749+
seen[key] = true
750+
missing << variant
713751
}
714752
}
715-
if !is_handled {
716-
missing << variant
753+
}
754+
}
755+
756+
fn (mut c Checker) match_sumtype_variant_is_handled_by(variant ast.Type, handled []ast.Type) bool {
757+
for handled_variant in handled {
758+
if c.match_sumtype_variant_is_handled(variant, handled_variant) {
759+
return true
717760
}
718761
}
719-
return missing
762+
return false
720763
}
721764

722765
fn (mut c Checker) match_sumtype_variant_is_handled(variant ast.Type, handled ast.Type) bool {
@@ -737,7 +780,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym
737780
is_alias_to_matchable_type := cond_type_sym.kind == .alias
738781
&& cond_final_sym.kind in [.interface, .sum_type]
739782
cond_match_sym := if is_alias_to_matchable_type { cond_final_sym } else { cond_type_sym }
740-
sumtype_match_variants := c.concrete_sumtype_variants(cond_match_type)
783+
sumtype_match_variants := c.match_sumtype_matchable_variants(cond_match_type)
741784
is_cond_match_sumtype := sumtype_match_variants.len > 0
742785
mut enum_ref_checked := false
743786
mut is_comptime_value_match := false

vlib/v/tests/sumtypes/generic_sumtype_alias_match_regression_test.v

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,19 @@ fn generic_sumtype_alias_match_exhaustive[T](value GenericSumtypeAliasMatchValue
1313
fn test_generic_sumtype_alias_match_with_generic_variant_is_exhaustive() {
1414
assert generic_sumtype_alias_match_exhaustive(GenericSumtypeAliasMatchItem{}) == 3
1515
}
16+
17+
type GenericSumtypeAliasNestedInner = int | string
18+
type GenericSumtypeAliasNestedOuter[T] = GenericSumtypeAliasNestedInner | T
19+
20+
fn generic_sumtype_alias_match_nested_variants[T](value GenericSumtypeAliasNestedOuter[T]) int {
21+
return match value {
22+
int { 1 }
23+
string { 2 }
24+
T { 3 }
25+
}
26+
}
27+
28+
fn test_generic_sumtype_alias_match_expands_nested_sumtype_variants() {
29+
assert generic_sumtype_alias_match_nested_variants[bool](1) == 1
30+
assert generic_sumtype_alias_match_nested_variants[bool](true) == 3
31+
}

0 commit comments

Comments
 (0)