checker: allow omitting `{}` in trailing struct args (#10832)
parent
ec47cda386
commit
22fcbe70a2
|
@ -1964,6 +1964,47 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, call_exp
|
|||
}
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) check_expected_arg_count(mut call_expr ast.CallExpr, f &ast.Fn) ? {
|
||||
nr_args := call_expr.args.len
|
||||
nr_params := if call_expr.is_method && f.params.len > 0 {
|
||||
f.params.len - 1
|
||||
} else {
|
||||
f.params.len
|
||||
}
|
||||
mut min_required_params := f.params.len
|
||||
if call_expr.is_method {
|
||||
min_required_params--
|
||||
}
|
||||
if f.is_variadic {
|
||||
min_required_params--
|
||||
}
|
||||
if min_required_params < 0 {
|
||||
min_required_params = 0
|
||||
}
|
||||
if nr_args < min_required_params {
|
||||
if min_required_params == nr_args + 1 {
|
||||
last_typ := f.params.last().typ
|
||||
last_sym := c.table.get_type_symbol(last_typ)
|
||||
if last_sym.kind == .struct_ {
|
||||
// allow empty trailing struct syntax arg (`f()` where `f` is `fn(ConfigStruct)`)
|
||||
call_expr.args << {
|
||||
expr: ast.StructInit{
|
||||
typ: last_typ
|
||||
}
|
||||
typ: last_typ
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
c.error('expected $min_required_params arguments, but got $nr_args', call_expr.pos)
|
||||
return error('')
|
||||
} else if !f.is_variadic && nr_args > nr_params {
|
||||
unexpected_args_pos := call_expr.args[min_required_params].pos.extend(call_expr.args.last().pos)
|
||||
c.error('expected $min_required_params arguments, but got $nr_args', unexpected_args_pos)
|
||||
return error('')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
||||
left_type := c.expr(call_expr.left)
|
||||
c.expected_type = left_type
|
||||
|
@ -2124,21 +2165,7 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
if method.return_type == ast.void_type && method.is_conditional && method.ctdefine_idx != -1 {
|
||||
call_expr.should_be_skipped = c.evaluate_once_comptime_if_attribute(mut method.attrs[method.ctdefine_idx])
|
||||
}
|
||||
nr_args := if method.params.len == 0 { 0 } else { method.params.len - 1 }
|
||||
min_required_args := method.params.len - if method.is_variadic && method.params.len > 1 {
|
||||
2
|
||||
} else {
|
||||
1
|
||||
}
|
||||
if call_expr.args.len < min_required_args {
|
||||
c.error('expected $min_required_args arguments, but got $call_expr.args.len',
|
||||
call_expr.pos)
|
||||
} else if !method.is_variadic && call_expr.args.len > nr_args {
|
||||
unexpected_arguments := call_expr.args[min_required_args..]
|
||||
unexpected_arguments_pos := unexpected_arguments[0].pos.extend(unexpected_arguments.last().pos)
|
||||
c.error('expected $nr_args arguments, but got $call_expr.args.len', unexpected_arguments_pos)
|
||||
return method.return_type
|
||||
}
|
||||
c.check_expected_arg_count(mut call_expr, method) or { return method.return_type }
|
||||
mut exp_arg_typ := ast.Type(0) // type of 1st arg for special builtin methods
|
||||
mut param_is_mut := false
|
||||
mut no_type_promotion := false
|
||||
|
@ -2696,17 +2723,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
}
|
||||
// dont check number of args for JS functions since arguments are not required
|
||||
if call_expr.language != .js {
|
||||
min_required_args := if func.is_variadic { func.params.len - 1 } else { func.params.len }
|
||||
if call_expr.args.len < min_required_args {
|
||||
c.error('expected $min_required_args arguments, but got $call_expr.args.len',
|
||||
call_expr.pos)
|
||||
} else if !func.is_variadic && call_expr.args.len > func.params.len {
|
||||
unexpected_arguments := call_expr.args[min_required_args..]
|
||||
unexpected_arguments_pos := unexpected_arguments[0].pos.extend(unexpected_arguments.last().pos)
|
||||
c.error('expected $min_required_args arguments, but got $call_expr.args.len',
|
||||
unexpected_arguments_pos)
|
||||
return func.return_type
|
||||
}
|
||||
c.check_expected_arg_count(mut call_expr, func) or { return func.return_type }
|
||||
}
|
||||
// println / eprintln / panic can print anything
|
||||
if fn_name in ['println', 'print', 'eprintln', 'eprint', 'panic'] && call_expr.args.len > 0 {
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
struct Foo {
|
||||
x int
|
||||
}
|
||||
|
||||
fn foo(f Foo) int {
|
||||
return f.x
|
||||
}
|
||||
|
||||
struct Bar {
|
||||
x int
|
||||
y int = 1234
|
||||
}
|
||||
|
||||
fn bar(b Bar) Bar {
|
||||
return b
|
||||
}
|
||||
|
||||
fn test_missing_config_struct_arg() {
|
||||
assert foo() == 0
|
||||
assert bar() == {
|
||||
x: 0
|
||||
y: 1234
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue