diff --git a/releasenotes.md b/releasenotes.md index ce7d82c8d..418c9ab9f 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -21,6 +21,7 @@ - Support untyped second argument for operator overloading. - The form-feed character '\f' is no longer valid white space. - Show code that caused unreachable code #2207 +- Allow generics over distinct types #2216. ### Fixes - `-2147483648`, MIN literals work correctly. diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index e8e988f8c..dab5074d6 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -4724,6 +4724,23 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module, return new_module; } +static inline void mangle_type_param(Type *type, bool mangled) +{ + type = type->canonical; + if (mangled) + { + type_mangle_introspect_name_to_buffer(type); + } + else + { + scratch_buffer_append(type->name); + if (type_is_user_defined(type) && type->decl->unit->module->generic_suffix) + { + scratch_buffer_append(type->decl->unit->module->generic_suffix); + } + } +} + static bool sema_generate_parameterized_name_to_scratch(SemaContext *context, Module *module, Expr **params, bool mangled, bool *was_recursive_ref) { @@ -4762,11 +4779,12 @@ static bool sema_generate_parameterized_name_to_scratch(SemaContext *context, Mo { if (!sema_analyse_ct_expr(context, param)) return false; Type *type = param->type->canonical; + if (type->type_kind == TYPE_DISTINCT) type = type_flatten(type); + bool is_enum_or_fault = type_kind_is_enum_or_fault(type->type_kind); if (!type_is_integer_or_bool_kind(type) && !is_enum_or_fault) { - SEMA_ERROR(param, "Only integer, bool, fault and enum values may be generic arguments."); - return poisoned_decl; + RETURN_SEMA_ERROR(param, "Only integer, bool, fault and enum values may be generic arguments."); } ASSERT(expr_is_const(param)); } @@ -4790,23 +4808,17 @@ static bool sema_generate_parameterized_name_to_scratch(SemaContext *context, Mo } if (param->expr_kind == EXPR_TYPEINFO) { - Type *type = param->type_expr->type->canonical; - if (mangled) - { - type_mangle_introspect_name_to_buffer(type); - } - else - { - scratch_buffer_append(type->name); - if (type_is_user_defined(type) && type->decl->unit->module->generic_suffix) - { - scratch_buffer_append(type->decl->unit->module->generic_suffix); - } - } + mangle_type_param(param->type_expr->type, mangled); } else { Type *type = param->type->canonical; + if (type->type_kind == TYPE_DISTINCT) + { + mangle_type_param(type, mangled); + scratch_buffer_append(mangled ? "$" : ", "); + type = type_flatten(type); + } if (type == type_bool) { if (mangled) diff --git a/test/test_suite/generic/generic_distinct.c3t b/test/test_suite/generic/generic_distinct.c3t new file mode 100644 index 000000000..8e0747013 --- /dev/null +++ b/test/test_suite/generic/generic_distinct.c3t @@ -0,0 +1,23 @@ +// #target: macos-x64 +module test; +import test1; +typedef Foo = int; + +fn void main() +{ + Foo $f = 1; + test1::foo{$f}(); +} +module test1 {FOO}; + +fn void foo() {} + +/* #expect: test.ll + +define void @test.main() #0 { +entry: + call void @"test1$test.Foo$1$.foo"() + ret void +} + +declare extern_weak void @"test1$test.Foo$1$.foo"() #0