From 3bddde20abe9239ce2f3fae91419ac4a68aeb2fb Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 26 Jun 2024 21:48:10 +0200 Subject: [PATCH] Fixes to distinct inline conversions. --- releasenotes.md | 1 + src/compiler/compiler_internal.h | 1 - src/compiler/enums.h | 2 +- src/compiler/types.c | 102 +++++++++++------------- test/unit/regression/distinct_inline.c3 | 17 ++++ 5 files changed, 66 insertions(+), 57 deletions(-) create mode 100644 test/unit/regression/distinct_inline.c3 diff --git a/releasenotes.md b/releasenotes.md index ca93c2a0b..352980e1e 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -20,6 +20,7 @@ - Fix bug with @jump miscompile. - Bit negate does implicit integer promotion. - Bitstructs, unions and flexible arrays now correctly emitted in headers. +- Fix distinct inline conversions. ### Stdlib changes - Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 94b4a15be..090883b61 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2440,7 +2440,6 @@ void type_mangle_introspect_name_to_buffer(Type *type); AlignSize type_abi_alignment(Type *type); bool type_func_match(Type *fn_type, Type *rtype, unsigned arg_count, ...); AlignSize type_alloca_alignment(Type *type); -Type *type_find_common_ancestor(Type *left, Type *right); Type *type_find_largest_union_element(Type *type); Type *type_find_max_type(Type *type, Type *other); Type *type_find_max_type_may_fail(Type *type, Type *other); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index b25c8dd35..47b358c8f 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -681,6 +681,7 @@ typedef enum TYPE_F128, TYPE_FLOAT_LAST = TYPE_F128, TYPE_NUM_LAST = TYPE_FLOAT_LAST, + TYPE_DISTINCT, TYPE_ANY, TYPE_INTERFACE, TYPE_ANYFAULT, @@ -694,7 +695,6 @@ typedef enum TYPE_BITSTRUCT, TYPE_FAULTTYPE, TYPE_TYPEDEF, - TYPE_DISTINCT, TYPE_SLICE, TYPE_ARRAY, TYPE_FIRST_ARRAYLIKE = TYPE_ARRAY, diff --git a/src/compiler/types.c b/src/compiler/types.c index 756d4297d..569fe4728 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1878,25 +1878,50 @@ Type *type_decay_array_pointer(Type *type) return type; } } +#define MAX_SEARCH_DEPTH 512 +static inline Type *type_find_max_distinct_type(Type *left, Type *right) +{ + assert(left == left->canonical && right == right->canonical); + assert(left != right); + assert(left->type_kind == TYPE_DISTINCT && right->type_kind == TYPE_DISTINCT); + static Type *left_types[MAX_SEARCH_DEPTH]; + int depth = 0; + while (depth < MAX_SEARCH_DEPTH) + { + left_types[depth++] = left; + if (left->type_kind != TYPE_DISTINCT || !left->decl->is_substruct) break; + left = left->decl->distinct->type; + if (left == right) return right; + } + if (depth == MAX_SEARCH_DEPTH) + { + error_exit("Common ancestor search depth %d exceeded.", MAX_SEARCH_DEPTH); + } + assert(left != right); + while (true) + { + for (int i = 0; i < depth; i++) + { + if (right == left_types[i]) return right; + } + if (right->type_kind != TYPE_DISTINCT || !right->decl->is_substruct) return NULL; + right = right->decl->distinct->type; + if (left == right) return right; + } +} + Type *type_find_max_type(Type *type, Type *other) { type = type->canonical; other = other->canonical; - assert(!type_is_optional(type) && !type_is_optional(other)); +RETRY_DISTINCT: if (type == other) return type; if (type == type_wildcard) return other; if (other == type_wildcard) return type; - // Lower inlined distinct types. - while (type->type_kind == TYPE_DISTINCT && type->decl->is_substruct) type = type->decl->distinct->type; - while (other->type_kind == TYPE_DISTINCT && other->decl->is_substruct) other = other->decl->distinct->type; - - // We may now have a match. - if (type == other) return type; - // Sort types if (type->type_kind > other->type_kind) { @@ -1926,7 +1951,7 @@ Type *type_find_max_type(Type *type, Type *other) if (other->type_kind == TYPE_VECTOR) return other; return type_find_max_num_type(type, other); case ALL_FLOATS: - if (other->type_kind == TYPE_DISTINCT && type_is_float(other->decl->distinct->type)) return other; + if (other->type_kind == TYPE_DISTINCT && type_is_float(type_flatten(other))) return other; if (other->type_kind == TYPE_VECTOR) return other; return type_find_max_num_type(type, other); case TYPE_ANY: @@ -2000,9 +2025,6 @@ Type *type_find_max_type(Type *type, Type *other) return NULL; case TYPE_TYPEDEF: UNREACHABLE - case TYPE_DISTINCT: - // distinct + any other type => no - return NULL; case TYPE_ARRAY: // array + [slice, other array, vector] => no return NULL; @@ -2012,53 +2034,23 @@ Type *type_find_max_type(Type *type, Type *other) case TYPE_VECTOR: // No implicit conversion between vectors return NULL; + case TYPE_DISTINCT: + if (other->type_kind == TYPE_DISTINCT) + { + return type_find_max_distinct_type(type, other); + } + // Try matching with its inline type + if (type->decl->is_substruct) + { + type = type->decl->distinct->type; + goto RETRY_DISTINCT; + } + // distinct + any other type => no + return NULL; } UNREACHABLE } -#define MAX_SEARCH_DEPTH 512 - -Type *type_find_common_ancestor(Type *left, Type *right) -{ - if (left == right) return left; - left = left->canonical; - right = right->canonical; - if (left == right) return left; - if (left->type_kind != right->type_kind) return NULL; - if (left->type_kind == TYPE_POINTER) - { - Type *common = type_find_common_ancestor(left->pointer, right->pointer); - return common ? type_get_ptr(common) : NULL; - } - if (left->type_kind != TYPE_STRUCT) return NULL; - - static Type *left_types[MAX_SEARCH_DEPTH]; - int depth = 0; - while (depth < MAX_SEARCH_DEPTH) - { - if (!left->decl->strukt.members) break; - Decl *first_element = left->decl->strukt.members[0]; - if (first_element->decl_kind != DECL_VAR) break; - if (first_element->type->canonical == right) return right; - left = first_element->type->canonical; - left_types[depth++] = left; - } - if (depth == MAX_SEARCH_DEPTH) - { - error_exit("Struct type depth %d exceeded.", MAX_SEARCH_DEPTH); - } - while (true) - { - if (!right->decl->strukt.members) return NULL; - Decl *first_element = right->decl->strukt.members[0]; - if (first_element->decl_kind != DECL_VAR) return NULL; - right = first_element->type->canonical; - for (int i = 0; i < depth; i++) - { - if (right == left_types[i]) return right; - } - } -} unsigned type_get_introspection_kind(TypeKind kind) { diff --git a/test/unit/regression/distinct_inline.c3 b/test/unit/regression/distinct_inline.c3 new file mode 100644 index 000000000..ddfd3904b --- /dev/null +++ b/test/unit/regression/distinct_inline.c3 @@ -0,0 +1,17 @@ +module distinct_inline @test; + +distinct Foo = inline int; +distinct Bar = inline Foo; +distinct Baz = inline Foo; +distinct Abc = inline Baz; +distinct Def = inline Abc; +distinct Other = inline int; +distinct Other2 = inline Other; +fn void test() +{ + assert($typeof((Foo)1 + 1).typeid == Foo.typeid); + assert($typeof((Foo)1 + (Bar)1).typeid == Foo.typeid); + assert($typeof((Baz)1 + (Bar)1).typeid == Foo.typeid); + assert($typeof((Def)1 + (Bar)1).typeid == Foo.typeid); + assert($typeof((Other2)1 + (Def)1).typeid == int.typeid); +} \ No newline at end of file