mirror of
https://github.com/odin-lang/Odin.git
synced 2026-10-09 06:12:05 -04:00
Clean up comments and add more wait signal guards for union variants
This commit is contained in:
1 parent
3b366c9e29
commit
3b9ef40fae
6 files changed
+35
-72
No files matched your search
+18
-38
@@ -389,9 +389,8 @@ gb_internal void check_scope_decls(CheckerContext *c, Slice<Ast *> const &nodes,
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(bill): Reuse an already-generated polymorphic procedure specialization `other`.
|
||||
// Records it as the result and, if its body has not been checked yet, schedules it.
|
||||
// The caller must have released `gen_procs->mutex` before calling this (it queues work).
|
||||
// Reuse an existing generated specialization `other`, scheduling its body if unchecked.
|
||||
// Caller must have released gen_procs->mutex first.
|
||||
gb_internal bool reuse_gen_polymorphic_procedure(Checker *checker, Entity *other, Ast *poly_def_node, PolyProcData *poly_proc_data) {
|
||||
if (poly_proc_data) {
|
||||
poly_proc_data->gen_entity = other;
|
||||
@@ -585,13 +584,8 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
|
||||
}
|
||||
|
||||
|
||||
// NOTE(bill): The two lookups above ran under a shared lock which was then released, so a
|
||||
// concurrent instantiation of this same specialization could have been published in the gap.
|
||||
// Acquire the exclusive lock now and hold it across the re-check below and the array_add at the
|
||||
// end, so that finding-then-publishing is atomic. Without this, two threads racing on the same
|
||||
// specialization could both miss and each build and enqueue a distinct entity for it. The lock
|
||||
// is only released here on an early return (a late-arriving duplicate); the normal path releases
|
||||
// it after publishing. (@local-mutex)
|
||||
// Re-check under the exclusive lock (the lookups above ran under a released shared lock) and
|
||||
// hold it across construction + array_add so find-then-publish is atomic. (@local-mutex)
|
||||
rw_mutex_lock(&gen_procs->mutex); // @local-mutex
|
||||
for (Entity *other : gen_procs->procs) {
|
||||
if (are_types_identical(base_type(other->type), final_proc_type)) {
|
||||
@@ -670,8 +664,6 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(bill): The exclusive lock has been held since just before construction (see above),
|
||||
// so this publish is atomic with the re-check that preceded it.
|
||||
array_add(&gen_procs->procs, entity);
|
||||
rw_mutex_unlock(&gen_procs->mutex); // @local-mutex
|
||||
|
||||
@@ -923,6 +915,7 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
||||
}
|
||||
|
||||
if (is_type_union(dst) && allow_unions) {
|
||||
wait_signal_until_available(&dst->Union.variants_wait_signal);
|
||||
for (Type *vt : dst->Union.variants) {
|
||||
if (are_types_identical(vt, s)) {
|
||||
return 1;
|
||||
@@ -1587,13 +1580,9 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T
|
||||
return is_polymorphic_type_assignable(c, poly->Array.elem, source->EnumeratedArray.elem, true, false);
|
||||
}
|
||||
|
||||
// NOTE(bill): Capture the polymorphic element node ($T) before rewriting `poly`
|
||||
// in place. Array.elem and EnumeratedArray.elem share the same union offset, so
|
||||
// assigning EnumeratedArray.elem below would otherwise clobber the pointer to the
|
||||
// shared $T generic node, and the element-binding recursion at the end would
|
||||
// compare concrete-vs-concrete and never bind $T (leaving it unresolved in the
|
||||
// procedure body). Keeping the node lets that recursion mutate it in place, just
|
||||
// like the fixed-array branch above.
|
||||
// Capture $T before rewriting `poly`: Array.elem and EnumeratedArray.elem share a
|
||||
// union offset, so the assignment below would clobber it and the elem recursion
|
||||
// would never bind $T.
|
||||
Type *poly_elem = poly->Array.elem;
|
||||
|
||||
poly->kind = Type_EnumeratedArray;
|
||||
@@ -1636,10 +1625,7 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T
|
||||
}
|
||||
return is_polymorphic_type_assignable(c, poly->EnumeratedArray.index, source->EnumeratedArray.index, true, modify_type);
|
||||
}
|
||||
// NOTE(bill): Both are evaluated (not short-circuited) so their modify_type side effects
|
||||
// are applied, but both the index and the element must match for the pattern to hold.
|
||||
// A previous `index || elem` here over-accepted (e.g. `[Dir]$T` vs `[Other]f32`), binding
|
||||
// `$T` and leaving the index mismatch to be reported later as a confusing assignment error.
|
||||
// Evaluate both (for modify_type side effects) but require both to match.
|
||||
bool index = is_polymorphic_type_assignable(c, poly->EnumeratedArray.index, source->EnumeratedArray.index, true, modify_type);
|
||||
bool elem = is_polymorphic_type_assignable(c, poly->EnumeratedArray.elem, source->EnumeratedArray.elem, true, modify_type);
|
||||
return index && elem;
|
||||
@@ -1813,11 +1799,7 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T
|
||||
return false;
|
||||
case Type_Map:
|
||||
if (source->kind == Type_Map) {
|
||||
// NOTE(bill): Both are evaluated (not short-circuited) so their modify_type side effects
|
||||
// are applied, but both the key and the value must match for the pattern to hold. A
|
||||
// previous `key || value` here over-accepted (e.g. `map[int]$V` vs `map[string]f32`),
|
||||
// binding `$V` and leaving the key mismatch to be reported later as a confusing
|
||||
// assignment error, and would finalize a map that was only partially matched.
|
||||
// Evaluate both (for modify_type side effects) but require both to match.
|
||||
bool key = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true, modify_type);
|
||||
bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true, modify_type);
|
||||
if (key && value) {
|
||||
@@ -5470,6 +5452,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
case Type_Union:
|
||||
if (!is_operand_nil(*operand) && !is_operand_uninit(*operand)) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
wait_signal_until_available(&t->Union.variants_wait_signal);
|
||||
|
||||
isize count = t->Union.variants.count;
|
||||
ValidIndexAndScore *valids = temporary_alloc_array<ValidIndexAndScore>(count);
|
||||
@@ -8771,11 +8754,9 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
|
||||
{
|
||||
GenTypesData *found_gen_types = ensure_polymorphic_record_entity_has_gen_types(c, original_type);
|
||||
mutex_lock(&found_gen_types->mutex);
|
||||
// NOTE(bill): For a struct instantiation, check_struct_type releases this mutex early (right
|
||||
// after publishing the instantiation into gen_types, before checking its fields) to avoid a
|
||||
// cross-record ABBA deadlock between mutually-recursive generic records; it signals that by
|
||||
// leaving `gen_types_locked` cleared below. The union path and the cache-hit path keep the
|
||||
// mutex until the end of this scope.
|
||||
// check_struct_type/check_union_type release this mutex early (after publishing, before
|
||||
// checking members) to avoid a cross-record ABBA, clearing gen_types_locked. The cache-hit
|
||||
// path keeps it until scope end.
|
||||
bool gen_types_locked = true;
|
||||
defer (if (gen_types_locked) mutex_unlock(&found_gen_types->mutex));
|
||||
|
||||
@@ -8823,11 +8804,6 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
|
||||
GB_PANIC("Unsupported parametric polymorphic record type");
|
||||
}
|
||||
|
||||
// NOTE(bill): The instantiation's canonical name is now set inside
|
||||
// check_struct_type/check_union_type (before it is published into gen_types), so that a
|
||||
// concurrent thread which finds the in-progress struct instantiation never observes a
|
||||
// torn name.
|
||||
|
||||
operand->mode = Addressing_Type;
|
||||
operand->type = named_type;
|
||||
}
|
||||
@@ -9711,6 +9687,7 @@ gb_internal bool attempt_implicit_selector_expr(CheckerContext *c, Operand *o, A
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
Type *union_type = base_type(th);
|
||||
wait_signal_until_available(&union_type->Union.variants_wait_signal);
|
||||
auto operands = array_make<Operand>(temporary_allocator(), 0, union_type->Union.variants.count);
|
||||
|
||||
for (Type *vt : union_type->Union.variants) {
|
||||
@@ -12016,6 +11993,9 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no
|
||||
|
||||
Type *src = type_deref(o->type);
|
||||
Type *bsrc = base_type(src);
|
||||
if (bsrc->kind == Type_Union) {
|
||||
wait_signal_until_available(&bsrc->Union.variants_wait_signal);
|
||||
}
|
||||
|
||||
|
||||
if (ta->type != nullptr && ta->type->kind == Ast_UnaryExpr && ta->type->UnaryExpr.op.kind == Token_Question) {
|
||||
|
||||
Reference in new issue
Block a user