~sircmpwn/harec

42f9b39977ce8d94bab1655f07bb82eb08c85dda — Joe Finney 25 days ago 3d8c438
Allow optional parameters in variadic functions.

Signed-off-by: Joe Finney <me@spxtr.net>
3 files changed, 31 insertions(+), 28 deletions(-)

M src/check.c
M src/type_store.c
M tests/09-funcs.ha
M src/check.c => src/check.c +6 -8
@@ 1455,6 1455,12 @@ check_expr_call(struct context *ctx,
		next = &arg->next;
		param = param->next;
	}
	while (param && param->default_value) {
		arg = *next = xcalloc(1, sizeof(struct call_argument));
		arg->value = param->default_value;
		next = &arg->next;
		param = param->next;
	}
	if (param) {
		if (fntype->func.variadism == VARIADISM_HARE && !param->next) {
			// No variadic arguments, lower to empty slice


@@ 1471,12 1477,6 @@ check_expr_call(struct context *ctx,
				"Not enough arguments for function call");
			return;
		}
		while (param) {
			arg = *next = xcalloc(1, sizeof(struct call_argument));
			arg->value = param->default_value;
			next = &arg->next;
			param = param->next;
		}
	} else if (aarg) {
		if (fntype->func.variadism != VARIADISM_C) {
			error(ctx, aexpr->loc, expr,


@@ 1491,8 1491,6 @@ check_expr_call(struct context *ctx,
			next = &arg->next;
		}
	}


}

static void

M src/type_store.c => src/type_store.c +10 -17
@@ 884,6 884,12 @@ type_init_from_atype(struct context *ctx,
				aparam; aparam = aparam->next) {
			param = *next = xcalloc(1, sizeof(struct type_func_param));
			param->type = lookup_atype(ctx, aparam->type);
			if (param->type->size == SIZE_UNDEFINED) {
				error(ctx, atype->loc, NULL,
					"Function parameter types must have defined size");
				*type = builtin_type_error;
				return (struct dimensions){0};
			}
			if (aparam->default_value != NULL) {
				has_optional = true;
				if (!default_param_from_atype(ctx,


@@ 891,31 897,18 @@ type_init_from_atype(struct context *ctx,
					*type = builtin_type_error;
					return (struct dimensions){0};
				}
			} else if (atype->func.variadism == VARIADISM_HARE
					&& !aparam->next) {
				param->type = type_store_lookup_slice(
					ctx, aparam->loc, param->type);
			} else if (has_optional) {
				error(ctx, atype->loc, NULL,
					"Required function parameter may not follow optional parameters");
				*type = builtin_type_error;
				return (struct dimensions){0};
			}
			if (param->type->size == SIZE_UNDEFINED) {
				error(ctx, atype->loc, NULL,
					"Function parameter types must have defined size");
				*type = builtin_type_error;
				return (struct dimensions){0};
			}
			if (atype->func.variadism == VARIADISM_HARE
					&& !aparam->next) {
				param->type = type_store_lookup_slice(
					ctx, aparam->loc, param->type);
			}
			next = &param->next;
		}
		if (atype->func.variadism != VARIADISM_NONE && has_optional) {
			error(ctx, atype->loc, NULL,
				"Variadic function may not have optional parameters");
			*type = builtin_type_error;
			return (struct dimensions){0};
		}
		break;
	case STORAGE_POINTER:
		type->size = builtin_type_uintptr.size;

M tests/09-funcs.ha => tests/09-funcs.ha +15 -3
@@ 123,9 123,6 @@ fn reject() void = {

		// required params may not follow optional
		"fn f(a: int = 5, b: int) void = void;",
		// no variadism after optional params
		"fn f(a: int = 5, ...) void = void;",
		"fn f(a: int = 5, b: int...) void = void;",
		// default value must be assignable to type
		"fn f(a: str = 5) void = void;",



@@ 207,6 204,14 @@ fn optional_slc2(x: []int = [1, 2]) int = {
	return x[0];
};
fn optional_ptr(x: nullable *int = null) bool = x is null;
fn optional_variadic(a: int = 3, b: int...) bool = a == 3 || len(b) == 2;
fn optional_variadic_c(n: int = 0, ...) void = {
	let ap = vastart();
	defer vaend(ap);
	for (let i = 0; i < n; i += 1) {
		assert(vaarg(ap): int == i);
	};
};

fn optional_params() void = {
	assert(optional_simple(5, 1) == 1);


@@ 233,6 238,13 @@ fn optional_params() void = {
	assert(optional_ptr());
	let i = 0;
	assert(!optional_ptr(&i));
	assert(optional_variadic());
	assert(optional_variadic(3));
	assert(optional_variadic(0, 1, 2));
	optional_variadic_c();
	optional_variadic_c(0);
	optional_variadic_c(1, 0);
	optional_variadic_c(3, 0, 1, 2);
};

export fn main() void = {