union #shared_nil

This adds a feature to `union` which requires all the variants to have a `nil` value and on assign to the union, checks whether that value is `nil` or not. If the value is `nil`, the union will be `nil` (thus sharing the `nil` value)
This commit is contained in:
gingerBill
2022-03-24 11:55:03 +00:00
parent 3e66eec735
commit 3f935bea25
10 changed files with 104 additions and 32 deletions
+28 -3
View File
@@ -1176,10 +1176,35 @@ void lb_emit_store_union_variant_tag(lbProcedure *p, lbValue parent, Type *varia
}
void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant, Type *variant_type) {
lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type));
Type *pt = base_type(type_deref(parent.type));
GB_ASSERT(pt->kind == Type_Union);
if (pt->Union.kind == UnionType_shared_nil) {
lbBlock *if_nil = lb_create_block(p, "shared_nil.if_nil");
lbBlock *if_not_nil = lb_create_block(p, "shared_nil.if_not_nil");
lbBlock *done = lb_create_block(p, "shared_nil.done");
lb_emit_store(p, underlying, variant);
lb_emit_store_union_variant_tag(p, parent, variant_type);
lbValue cond_is_nil = lb_emit_comp_against_nil(p, Token_CmpEq, variant);
lb_emit_if(p, cond_is_nil, if_nil, if_not_nil);
lb_start_block(p, if_nil);
lb_emit_store(p, parent, lb_const_nil(p->module, type_deref(parent.type)));
lb_emit_jump(p, done);
lb_start_block(p, if_not_nil);
lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type));
lb_emit_store(p, underlying, variant);
lb_emit_store_union_variant_tag(p, parent, variant_type);
lb_emit_jump(p, done);
lb_start_block(p, done);
} else {
lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type));
lb_emit_store(p, underlying, variant);
lb_emit_store_union_variant_tag(p, parent, variant_type);
}
}