diff --git a/src/core/compile.c b/src/core/compile.c index e7e9578e..152b95cb 100644 --- a/src/core/compile.c +++ b/src/core/compile.c @@ -599,17 +599,22 @@ static JanetSlot janetc_call(JanetFopts opts, JanetSlot *slots, JanetSlot fun, c fun.constant, min, min == 1 ? "" : "s", min_arity); janetc_error(c, es); } - if (structarg && ((min_arity - min) & 1)) { + if (structarg && (min_arity > f->def->arity) && ((min_arity - f->def->arity) & 1)) { /* If we have an odd number of variadic arguments to a `&keys` function, that is almost certainly wrong. */ - janetc_lintf(c, JANET_C_LINT_NORMAL, - "odd number of variadic arguments to `&keys` function %v", fun.constant); + if (namedarg) { + janetc_lintf(c, JANET_C_LINT_NORMAL, + "odd number of named arguments to `&named` function %v", fun.constant); + } else { + janetc_lintf(c, JANET_C_LINT_NORMAL, + "odd number of named arguments to `&keys` function %v", fun.constant); + } } if (namedarg && f->def->named_args_count > 0) { /* For each argument passed in, check if it is one of the used named arguments * by checking the list defined in the function def. If not, raise a normal compiler * lint. We can also do a strict lint for _missing_ named arguments, although in many * cases those are assumed to have some kind of default, or we have dynamic keys. */ - int32_t first_arg_key_index = min + 1; + int32_t first_arg_key_index = f->def->arity + 1; for (int32_t i = first_arg_key_index; i < janet_tuple_length(form); i += 2) { Janet argkey = form[i]; /* Assumption: The first N constants of a function are its named argument keys. This diff --git a/test/suite-compile.janet b/test/suite-compile.janet index bb34ac62..ec543a1c 100644 --- a/test/suite-compile.janet +++ b/test/suite-compile.janet @@ -110,6 +110,9 @@ (defn fnamed2 [_a _b _c &named x y z] [x y z]) (defn fkeys2 [_a _b _c &keys ks] ks) (defn fnamed3 [{:x x} &named a b c] [x a b c]) +(defn fnamed4 [_y &opt _z &named a b c] [a b c]) +(defn fnamed5 [&opt _z &named a b c] [a b c]) +(defn g [x &opt y &named z] [x y z]) (defn check-good-compile [code msg] @@ -137,6 +140,15 @@ (check-lint-compile '(fkeys2 nil nil nil :a 1 :b) "keys 2 odd args") (check-good-compile '(fnamed3 {:x 1} :a 1 :b 2 :c 3) "named 3 good") (check-lint-compile '(fnamed3 {:x 1} :a 1 :b 2 :d 3) "named 3 lint") +(check-good-compile '(fnamed4 10 20 :a 1 :b 2 :c 3) "named 4 good") +(check-lint-compile '(fnamed4 10 20 :a 1 :b 2 :d 3) "named 4 lint") +(check-good-compile '(fnamed5 10 :a 1 :b 2 :c 3) "named 5 good") +(check-lint-compile '(fnamed5 10 :a 1 :b 2 :d 3) "named 5 lint") +(check-good-compile '(g 1) "g good 1") +(check-good-compile '(g 1 2) "g good 2") +(check-good-compile '(g 1 2 :z 10) "g good 3") +(check-lint-compile '(g 1 2 :z) "g lint 1") +(check-lint-compile '(g 1 2 :z 4 5) "g lint 2") (end-suite)