refine returned match errors
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user