diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2c4985ac8..acb34d5a0 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8309,6 +8309,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O bool named_fields = false; { + if (ce->ellipsis.pos.line != 0) { + error(ce->ellipsis, "Invalid use of '..' in a polymorphic type call"); + } + // NOTE(bill, 2019-10-26): Allow a cycle in the parameters but not in the fields themselves auto prev_type_path = c->type_path; @@ -8347,11 +8351,6 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O check_expr_or_type(c, &operands[i], fv->value); } - bool vari_expand = (ce->ellipsis.pos.line != 0); - if (vari_expand) { - error(ce->ellipsis, "Invalid use of '..' in a polymorphic type call'"); - } - } else { operands = array_make(temporary_allocator(), 0, 2*ce->args.count); diff --git a/src/parser.cpp b/src/parser.cpp index 64f73e0ab..d9d07cf57 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3660,7 +3660,10 @@ gb_internal Ast *parse_call_expr(AstFile *f, Ast *operand) { } else if (seen_ellipsis) { syntax_error(arg, "Positional arguments are not allowed after '..'"); } - array_add(&args, arg); + if (arg != nullptr) { + // `parse_atom_expr` returns nothing when `allow_type` is set and there is no operand + array_add(&args, arg); + } if (ellipsis.pos.line != 0) { seen_ellipsis = true; diff --git a/tests/issues/run.bat b/tests/issues/run.bat index 7db64dc39..1a210d911 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -42,6 +42,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused ..\..\..\odin check ..\test_issue_6979.odin -no-entry-point %COMMON% || exit /b ..\..\..\odin check ..\test_issue_7012.odin -no-entry-point %COMMON% || exit /b ..\..\..\odin check ..\test_issue_7260.odin -no-entry-point %COMMON% || exit /b +..\..\..\odin check ..\test_issue_ellipsis_type_call.odin -no-entry-point %COMMON% 2>&1 | find /c "Error:" | findstr /x "10" || exit /b ..\..\..\odin check ..\test_issue_foreign_redeclaration.odin -no-entry-point %COMMON% || exit /b ..\..\..\odin check ..\test_issue_foreign_redeclaration_mismatch.odin -no-entry-point %COMMON% 2>&1 | find /c "Error:" | findstr /x "1" || exit /b ..\..\..\odin build ..\test_issue_7037.odin %COMMON% -o:none || exit /b diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 7ee6270a0..47ee8f1f0 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -102,6 +102,13 @@ else exit 1 fi +if [[ $($ODIN check ../test_issue_ellipsis_type_call.odin -no-entry-point $COMMON_CHECK 2>&1 >/dev/null | grep -c "Error:") -eq 10 ]]; then + echo "SUCCESSFUL 1/1" +else + echo "SUCCESSFUL 0/1" + exit 1 +fi + if [[ $($ODIN build ../test_issue_7108.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]]; then echo "SUCCESSFUL 1/1" else diff --git a/tests/issues/test_issue_ellipsis_type_call.odin b/tests/issues/test_issue_ellipsis_type_call.odin new file mode 100644 index 000000000..221eeec72 --- /dev/null +++ b/tests/issues/test_issue_ellipsis_type_call.odin @@ -0,0 +1,45 @@ +// Tests that a bare `..` in a type position call is rejected rather than left as a +// null argument for the checker to walk off of. +package test_issues + +Foo :: struct($T: typeid) { + x: T, +} + +S :: struct { + a: int, +} + +bare :: proc() { + v: Foo(..) + _ = v +} + +named_then_bare :: proc() { + v: Foo(T = int, ..) + _ = v +} + +bare_then_named :: proc() { + v: Foo(.., T = int) + _ = v +} + +positional_then_bare :: proc() { + v: Foo(int, ..) + _ = v +} + +conversion_to_struct :: proc() { + v: S(..) + _ = v +} + +conversion_to_builtin :: proc() { + v: int(..) + _ = v +} + +result_type :: proc() -> Foo(..) { + return {} +}