diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 609173981..a91664bb0 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -412,7 +412,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E if (!src->Proc.is_polymorphic || src->Proc.is_poly_specialized) { // NOTE: polymorphic procedure check not idempotent without this if (src->Proc.is_poly_specialized && base_entity->Procedure.generated_from_polymorphic) { - if (are_types_identical(src, dst)) { + if (are_types_identical(src, dst)) { if (poly_proc_data) { poly_proc_data->gen_entity = base_entity; } diff --git a/src/check_type.cpp b/src/check_type.cpp index ed916ceb2..97f609dd8 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1791,6 +1791,7 @@ gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_ if (e->kind == Entity_Procedure) { param_value.kind = ParameterValue_Constant; param_value.value = exact_value_procedure(e->identifier); + param_value.proc_entity = e; add_entity_use(ctx, e->identifier, e); } else { if (e->flags & EntityFlag_Param) { diff --git a/src/entity.cpp b/src/entity.cpp index 31f90023b..d3170c823 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -111,6 +111,7 @@ enum ParameterValueKind { struct ParameterValue { ParameterValueKind kind; Ast *original_ast_expr; + Entity *proc_entity; union { ExactValue value; Ast *ast_value; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 9f1b5dd3f..1cff61ba9 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -4669,6 +4669,12 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TypeProc *procedure_type, Ast* call_expression) { switch (param_value.kind) { case ParameterValue_Constant: + if (param_value.proc_entity != nullptr && is_type_proc(parameter_type)) { + lbValue v = lb_find_procedure_value_from_entity(p->module, param_value.proc_entity); + if (v.value != nullptr) { + return lb_emit_conv(p, v, parameter_type); + } + } if (is_type_constant_type(parameter_type)) { auto res = lb_const_value(p->module, parameter_type, param_value.value); return res; diff --git a/tests/issues/run.bat b/tests/issues/run.bat index 269c91a0b..6d562ccbc 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -26,6 +26,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused ..\..\..\odin build ..\test_issue_5097.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_5097-2.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_5265.odin %COMMON% || exit /b +..\..\..\odin build ..\test_issue_5573.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "2" || exit /b ..\..\..\odin test ..\test_issue_5699.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_6068.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_6101.odin %COMMON% || exit /b diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 9bcc53dfe..49b825bb8 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -32,6 +32,12 @@ $ODIN build ../test_issue_5043.odin $COMMON $ODIN build ../test_issue_5097.odin $COMMON $ODIN build ../test_issue_5097-2.odin $COMMON $ODIN build ../test_issue_5265.odin $COMMON +if [[ $($ODIN build ../test_issue_5573.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then + echo "SUCCESSFUL 1/1" +else + echo "SUCCESSFUL 0/1" + exit 1 +fi $ODIN test ../test_issue_5699.odin $COMMON $ODIN test ../test_issue_6068.odin $COMMON $ODIN test ../test_issue_6101.odin $COMMON @@ -74,7 +80,7 @@ else exit 1 fi $ODIN check ../test_issue_6484.odin -no-entry-point $COMMON -$ODIN test ../test_issue_6753.odin -no-entry-point $COMMON +$ODIN test ../test_issue_6753.odin $COMMON if [[ $($ODIN check ../test_issue_6874.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 1 ]] ; then echo "SUCCESSFUL 1/1" else diff --git a/tests/issues/test_issue_5573.odin b/tests/issues/test_issue_5573.odin new file mode 100644 index 000000000..dd154a89a --- /dev/null +++ b/tests/issues/test_issue_5573.odin @@ -0,0 +1,17 @@ +// Tests issue #5573 https://github.com/odin-lang/Odin/issues/5573 +package test_issues + +poly :: proc(x: $T) -> string { + return "poly" +} + +takes_concrete :: proc(f: proc(a: int, b: f32, c: rawptr) -> ^int) { +} + +main :: proc() { + // should error - wrong arity, wrong parameter types, wrong return type + mismatched: proc(a: int, b: f32, c: rawptr) -> ^int = poly + + // should error - same, as a procedure argument + takes_concrete(poly) +} diff --git a/tests/issues/test_issue_6753.odin b/tests/issues/test_issue_6753.odin index d4c668c6d..a14b2dc01 100644 --- a/tests/issues/test_issue_6753.odin +++ b/tests/issues/test_issue_6753.odin @@ -1,23 +1,64 @@ // test issue for #6753 https://github.com/odin-lang/odin/issues/6753 package test_issues import "core:testing" +import "core:fmt" -identity :: proc(x: $T) -> T { return x } - -foo :: proc(x: int, poly: proc(int) -> int = identity) -> int { - return foo(identity(x)) +foo_concrete :: proc(x: int, g: proc(int) -> int) -> int { + return g(x) +} +foo_impossible :: proc(x: int, g: proc(int, int) -> string) -> string { + return "impossible" +} +foo_group :: proc { + foo_concrete, + foo_impossible, +} + +f_poly :: proc(x: $T) -> T { return x } +foo_poly :: proc(x: $T, g: proc(T) -> T = f_poly) -> T { + return g(x) } -// failing as returns before specialized @test -test_issue_6753 :: proc(t: ^testing.T) { - p: proc(int) -> int = identity +test_issue_6753_ambiguous_poly_argumentment :: proc (t: ^testing.T) { + testing.expect_value(t, foo_group(1, f_poly), 1) // should be no ambiguity whether foo_concrete or foo_impossible +} + +@test +test_issue_6753_default_poly_proc :: proc (t: ^testing.T) { + testing.expect_value(t, foo_poly(1), 1) +} + +@test +test_issue_6753_parapoly_proc_variable :: proc(t: ^testing.T) { + p: proc(int) -> int = f_poly testing.expect(t, p != nil, "polymorphic procedure was not instantiated") testing.expect_value(t, p(123), 123) } -// failing as returns before specialized +// -- Fixing above led to some new bugs surfacing -- @test -test_issue_default_poly_parameter_6753 :: proc(t: ^testing.T) { - testing.expect_value(t, foo(123), 123) -} \ No newline at end of file +test_issue_6753_parapoly_proc_as_argument :: proc(t: ^testing.T) { + testing.expect(t, foo_concrete(123, f_poly) == 123, "failed to pass poly proc as argument") +} + +@test +test_issue_6753_parapoly_with_default_proc_same_generic_type_T :: proc(t: ^testing.T) { + testing.expect_value(t, foo_poly(123), 123) + testing.expect_value(t, foo_poly(123, f_poly), 123) +} + +// all together now +describe :: proc(x: $T) -> string { return fmt.tprintf("#%v", x) } +describe_bytes :: proc(x: []byte) -> string { return "bytes" } + +bar_poly :: proc(x: $T, g: proc(x: T) -> string = describe) -> string { return g(x) } +bar_bytes :: proc(x: []byte, g: proc(x: []byte) -> string) -> string { return g(x) } +bar_group :: proc { bar_poly, bar_bytes } + +@test +test_issue_6753_parapoly_default_in_group :: proc(t: ^testing.T) { + testing.expect_value(t, bar_group(123, describe), "#123") + testing.expect_value(t, bar_group("hi"), "#hi") + testing.expect_value(t, bar_group([]byte{1, 2}, describe_bytes), "bytes") +}