refine returned match errors

This commit is contained in:
2026-07-22 02:04:48 +02:00
parent 2c2a310e6d
commit 8e153fa84e
9 changed files with 586 additions and 16 deletions
+67
View File
@@ -552,6 +552,73 @@ can_sum_widen :: proc(from, to: Type, store: ^Store) -> bool {
return true
}
// Reports whether every selected variant from `from` is represented identically in
// `to`. The checker uses this only after control flow has proven that the source value
// is one of `selected`; it is not a general implicit narrowing rule.
selected_sum_fits :: proc(from, to: Type, selected: []u32, store: ^Store) -> bool {
if len(selected) == 0 {
return false
}
from_variants: [dynamic]Sum_Variant
from_variants.allocator = store.allocator
defer delete(from_variants)
to_variants: [dynamic]Sum_Variant
to_variants.allocator = store.allocator
defer delete(to_variants)
if !append_sum_variants(store, from, &from_variants) ||
!append_sum_variants(store, to, &to_variants) {
return false
}
for name in selected {
source_variant: Sum_Variant
source_found := false
for variant in from_variants {
if variant.name == name {
source_variant = variant
source_found = true
break
}
}
if !source_found {
return false
}
matched := false
for variant in to_variants {
if variant.id == source_variant.id && variant.payload == source_variant.payload {
matched = true
break
}
}
if !matched {
return false
}
}
return true
}
// Sum_Project is emitted only with a checker proof. This weaker structural predicate is
// retained by the backend as a defensive check that the two sums share a valid variant.
can_sum_project :: proc(from, to: Type, store: ^Store) -> bool {
from_variants: [dynamic]Sum_Variant
from_variants.allocator = store.allocator
defer delete(from_variants)
to_variants: [dynamic]Sum_Variant
to_variants.allocator = store.allocator
defer delete(to_variants)
if !append_sum_variants(store, from, &from_variants) ||
!append_sum_variants(store, to, &to_variants) {
return false
}
for source_variant in from_variants {
for target_variant in to_variants {
if target_variant.id == source_variant.id && target_variant.payload == source_variant.payload {
return true
}
}
}
return false
}
define_struct :: proc(store: ^Store, id: Type, fields: []Field, c_layout, opaque: bool) -> bool {
return define_record(store, id, fields, c_layout, opaque)
}