v2 / vlib / v / checker / fn.v
5522 lines · 5387 sloc · 196.38 KB · f5bce0cb784f7f76327597400c327e95769c0d10
Raw
1module checker
2
3import strings
4import v.ast
5import v.util
6import v.token
7import os
8
9const print_everything_fns = ['println', 'print', 'eprintln', 'eprint', 'panic']
10
11fn first_attr_by_name(attrs []ast.Attr, name string) (ast.Attr, bool) {
12 for attr in attrs {
13 if attr.name == name {
14 return attr, true
15 }
16 }
17 return ast.Attr{}, false
18}
19
20fn comptime_define_attr_idx(attrs []ast.Attr) int {
21 for idx in 0 .. attrs.len {
22 if attrs[idx].kind == .comptime_define {
23 return idx
24 }
25 }
26 return ast.invalid_type_idx
27}
28
29@[inline]
30fn (c &Checker) implicit_mutability_enabled() bool {
31 return c.pref.disable_explicit_mutability
32 && (!os.dir(c.file.path).contains('vlib') || c.file.path.ends_with('.vv'))
33}
34
35@[inline]
36fn (c &Checker) implicit_mut_call_arg(param ast.Param, arg ast.CallArg) ast.CallArg {
37 if !c.implicit_mutability_enabled() || arg.is_mut || !param.is_mut
38 || param.typ.share() != .mut_t {
39 return arg
40 }
41 return ast.CallArg{
42 ...arg
43 is_mut: true
44 }
45}
46
47fn (mut c Checker) check_os_raw_io_call(node &ast.CallExpr, func &ast.Fn, concrete_types []ast.Type, arg_offset int) {
48 if func.mod != 'os' || !func.is_method {
49 return
50 }
51 match func.name {
52 'write_struct', 'write_struct_at', 'write_raw', 'write_raw_at', 'read_struct',
53 'read_struct_at' {
54 if node.args.len > arg_offset {
55 c.ensure_os_raw_io_type(node.args[arg_offset].typ, func.name,
56 node.args[arg_offset].pos)
57 }
58 }
59 'read_raw', 'read_raw_at' {
60 if concrete_types.len > 0 {
61 c.ensure_os_raw_io_type(concrete_types.last(), func.name, node.pos)
62 }
63 }
64 else {}
65 }
66}
67
68fn (mut c Checker) refresh_generic_fn_scope_vars(node &ast.FnDecl) {
69 generic_names := c.effective_fn_generic_names(node)
70 if c.table.cur_concrete_types.len == 0 || generic_names.len != c.table.cur_concrete_types.len {
71 return
72 }
73 if node.is_method {
74 receiver_type := c.recheck_concrete_type(node.receiver.typ)
75 if mut receiver_var := c.fn_scope.find_var(node.receiver.name) {
76 if receiver_var.generic_typ == 0 && (node.receiver.typ.has_flag(.generic)
77 || c.type_has_unresolved_generic_parts(node.receiver.typ)) {
78 receiver_var.generic_typ = node.receiver.typ
79 }
80 receiver_var.typ = receiver_type
81 receiver_var.orig_type = ast.no_type
82 receiver_var.smartcasts = []
83 receiver_var.is_unwrapped = false
84 }
85 }
86 for param in node.params {
87 param_source_type := if param.is_mut && param.orig_typ != 0
88 && (param.orig_typ.has_flag(.generic)
89 || c.type_has_unresolved_generic_parts(param.orig_typ)) {
90 param.orig_typ
91 } else {
92 param.typ
93 }
94 param_type := c.recheck_concrete_type(param_source_type)
95 if mut param_var := c.fn_scope.find_var(param.name) {
96 if param_var.generic_typ == 0 && (param_source_type.has_flag(.generic)
97 || c.type_has_unresolved_generic_parts(param_source_type)) {
98 param_var.generic_typ = param_source_type
99 }
100 param_var.typ = param_type
101 param_var.orig_type = ast.no_type
102 param_var.smartcasts = []
103 param_var.is_unwrapped = false
104 }
105 }
106}
107
108fn (c &Checker) struct_embeds_type(got ast.Type, expected ast.Type) bool {
109 got_sym := c.table.final_sym(got)
110 if got_sym.info !is ast.Struct {
111 return false
112 }
113 got_info := got_sym.info as ast.Struct
114 expected_unaliased := c.table.unaliased_type(expected)
115 for embed in got_info.embeds {
116 embed_unaliased := c.table.unaliased_type(embed)
117 if embed_unaliased == expected_unaliased
118 || c.struct_embeds_type(embed_unaliased, expected_unaliased) {
119 return true
120 }
121 }
122 return false
123}
124
125fn (c &Checker) embeds_expected_call_arg_type(got ast.Type, expected ast.Type) bool {
126 if got == 0 || expected == 0 {
127 return false
128 }
129 got_base := if got.is_ptr() { got.deref() } else { got }
130 expected_base := if expected.is_ptr() { expected.deref() } else { expected }
131 if got_base == expected_base {
132 return false
133 }
134 got_sym := c.table.final_sym(got_base)
135 if got_sym.info !is ast.Struct {
136 return false
137 }
138 return c.struct_embeds_type(got_base, expected_base)
139}
140
141fn (mut c Checker) effective_fn_generic_names(node &ast.FnDecl) []string {
142 if node.generic_names.len > 0 {
143 return node.generic_names.clone()
144 }
145 if !node.is_method {
146 return []string{}
147 }
148 if !node.receiver.typ.has_flag(.generic)
149 && !c.type_has_unresolved_generic_parts(node.receiver.typ) {
150 return []string{}
151 }
152 rec_sym := c.table.sym(c.unwrap_generic(node.receiver.typ))
153 match rec_sym.info {
154 ast.Struct, ast.Interface, ast.SumType {
155 if rec_sym.info.generic_types.len > 0 {
156 return rec_sym.info.generic_types.map(c.table.sym(it).name)
157 }
158 }
159 else {}
160 }
161
162 return c.table.generic_type_names(node.receiver.typ)
163}
164
165fn (mut c Checker) generic_anon_fn_can_use_current_context(generic_names []string) bool {
166 if generic_names.len == 0 || c.table.cur_fn == unsafe { nil } {
167 return false
168 }
169 current_generic_names := c.effective_fn_generic_names(c.table.cur_fn)
170 if current_generic_names.len == 0 {
171 return false
172 }
173 return generic_names.all(it in current_generic_names)
174}
175
176fn (mut c Checker) receiver_requires_generic_names(node &ast.FnDecl) bool {
177 if !node.is_method {
178 return false
179 }
180 return node.receiver.typ.has_flag(.generic)
181}
182
183fn (mut c Checker) check_receiver_decl_generic_type_names(node &ast.FnDecl) {
184 if !node.is_method {
185 return
186 }
187 receiver_sym := c.table.final_sym(node.receiver.typ)
188 match receiver_sym.info {
189 ast.Struct {
190 if receiver_sym.info.generic_types.len > 0 && !node.receiver.typ.has_flag(.generic)
191 && receiver_sym.info.concrete_types.len == 0 {
192 pure_sym_name := receiver_sym.embed_name()
193 c.error('generic struct `${pure_sym_name}` in fn declaration must specify the generic type names, e.g. ${pure_sym_name}[T]',
194 node.receiver.type_pos)
195 }
196 }
197 ast.Interface {
198 if receiver_sym.info.generic_types.len > 0 && !node.receiver.typ.has_flag(.generic)
199 && receiver_sym.info.concrete_types.len == 0 {
200 pure_sym_name := receiver_sym.embed_name()
201 c.error('generic interface `${pure_sym_name}` in fn declaration must specify the generic type names, e.g. ${pure_sym_name}[T]',
202 node.receiver.type_pos)
203 }
204 }
205 ast.SumType {
206 if receiver_sym.info.generic_types.len > 0 && !node.receiver.typ.has_flag(.generic)
207 && receiver_sym.info.concrete_types.len == 0 {
208 pure_sym_name := receiver_sym.embed_name()
209 c.error('generic sumtype `${pure_sym_name}` in fn declaration must specify the generic type names, e.g. ${pure_sym_name}[T]',
210 node.receiver.type_pos)
211 }
212 }
213 else {}
214 }
215}
216
217fn (mut c Checker) check_receiver_decl_generic_name_mentions(node &ast.FnDecl) {
218 if !node.is_method || !node.receiver.typ.has_flag(.generic) {
219 return
220 }
221 generic_names := c.table.generic_type_names(node.receiver.typ)
222 for name in generic_names {
223 if name !in node.generic_names {
224 fn_generic_names := node.generic_names.join(', ')
225 c.error('generic type name `${name}` is not mentioned in fn `${node.name}[${fn_generic_names}]`',
226 node.receiver.type_pos)
227 }
228 }
229}
230
231fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
232 // handle vls go to definition for method receiver types
233 if c.pref.is_vls {
234 // Hover over fn keyword or function name on the declaration line — show full declaration.
235 on_fn_name := c.vls_is_the_node(node.name_pos)
236 on_fn_keyword := c.pref.linfo.line_nr == node.name_pos.line_nr
237 && c.pref.linfo.col >= int(node.pos.col) - 1 && c.pref.linfo.col < node.name_pos.col
238 && node.name_pos.file_idx >= 0
239 && os.real_path(c.pref.linfo.path) == os.real_path(c.table.filelist[node.name_pos.file_idx])
240 if c.pref.linfo.method == .completion && (on_fn_name || on_fn_keyword) {
241 mut params := []string{cap: node.params.len}
242 for param in node.params {
243 if param.is_hidden {
244 continue
245 }
246 params << '${param.name} ${c.table.type_to_str(param.typ)}'
247 }
248 ret_str := if node.return_type != ast.no_type && node.return_type != ast.void_type {
249 ' ' + c.table.type_to_str(node.return_type)
250 } else {
251 ''
252 }
253 declaration := 'fn ${node.short_name}(${params.join(', ')})${ret_str}'
254 mut doc := ''
255 mod := node.name.all_before_last('.')
256 if info := c.table.vls_info['fn_${mod}[]${node.short_name}'] {
257 doc = info.doc
258 }
259 c.vls_write_details([
260 Detail{
261 kind: .function
262 label: node.short_name
263 declaration: declaration
264 documentation: doc
265 },
266 ])
267 exit(0)
268 }
269 if node.is_method && node.receiver.type_pos.line_nr > 0 {
270 if c.vls_is_the_node(node.receiver.type_pos) {
271 typ_str := c.table.type_to_str(node.receiver.typ)
272 if np := c.name_pos_gotodef(typ_str) {
273 if np.file_idx != -1 {
274 println('${c.table.filelist[np.file_idx]}:${np.line_nr + 1}:${np.col}')
275 }
276 exit(0)
277 }
278 }
279 }
280 if node.return_type_pos.line_nr > 0 {
281 if c.vls_is_the_node(node.return_type_pos) {
282 typ_str := c.table.type_to_str(node.return_type)
283 if np := c.name_pos_gotodef(typ_str) {
284 if np.file_idx != -1 {
285 println('${c.table.filelist[np.file_idx]}:${np.line_nr + 1}:${np.col}')
286 }
287 exit(0)
288 }
289 }
290 }
291 }
292 $if trace_post_process_generic_fns_types ? {
293 if node.generic_names.len > 0 {
294 eprintln('>>> post processing node.name: ${node.name:-30} | ${node.generic_names} <=> ${c.table.cur_concrete_types}')
295 }
296 }
297 if node.language in [.c, .js] && node.generic_names.len > 0 {
298 lang := if node.language == .c { 'C' } else { 'JS' }
299 c.error('${lang} functions cannot be declared as generic', node.pos)
300 }
301 // record the veb route methods (public non-generic methods):
302 if node.generic_names.len > 0 && node.is_pub {
303 typ_veb_result := c.table.find_type('veb.Result')
304 if node.return_type == typ_veb_result {
305 rec_sym := c.table.sym(node.receiver.typ)
306 if rec_sym.kind == .struct {
307 if _ := c.table.find_field_with_embeds(rec_sym, 'Context') {
308 // there is no point in the message here, for methods
309 // that are not public; since they will not be available as routes anyway
310 c.note('generic method routes of veb will be skipped', node.pos)
311 }
312 }
313 }
314 }
315 mut need_generic_names := false
316 if node.generic_names.len == 0 {
317 if node.return_type.has_flag(.generic) {
318 need_generic_names = true
319 } else if c.receiver_requires_generic_names(node) {
320 need_generic_names = true
321 } else {
322 for param in node.params {
323 if param.typ.has_flag(.generic) {
324 need_generic_names = true
325 break
326 }
327 }
328 }
329 if need_generic_names {
330 if node.is_method {
331 c.add_error_detail('use `fn (r SomeType[T]) foo[T]() {`, not just `fn (r SomeType[T]) foo() {`')
332 c.error('generic method declaration must specify generic type names', node.pos)
333 } else {
334 c.add_error_detail('use `fn foo[T](x T) {`, not just `fn foo(x T) {`')
335 c.error('generic function declaration must specify generic type names', node.pos)
336 }
337 }
338 }
339 c.check_receiver_decl_generic_type_names(node)
340 c.check_receiver_decl_generic_name_mentions(node)
341 effective_generic_names := c.effective_fn_generic_names(node)
342 if effective_generic_names.len > 0 && c.table.cur_concrete_types.len == 0 {
343 // Just remember the generic function for now.
344 // It will be processed later in c.post_process_generic_fns,
345 // after all other normal functions are processed.
346 // This is done so that all generic function calls can
347 // have a chance to populate c.table.fn_generic_types with
348 // the correct concrete types.
349 fkey := node.fkey()
350 if !c.generic_fns[fkey] {
351 c.need_recheck_generic_fns = true
352 c.generic_fns[fkey] = true
353 c.file.generic_fns << node
354 }
355 return
356 }
357 node.ninstances++
358 // save all the state that fn_decl or inner statements/expressions
359 // could potentially modify, since functions can be nested, due to
360 // anonymous function support, and ensure that it is restored, when
361 // fn_decl returns:
362 prev_fn_scope := c.fn_scope
363 prev_in_for_count := c.in_for_count
364 prev_inside_defer := c.inside_defer
365 prev_inside_unsafe := c.inside_unsafe
366 prev_inside_anon_fn := c.inside_anon_fn
367 prev_returns := c.returns
368 prev_stmt_level := c.stmt_level
369 prev_assert_autocasts := c.assert_autocasts.clone()
370 c.fn_level++
371 c.in_for_count = 0
372 c.inside_defer = false
373 c.inside_unsafe = node.is_unsafe
374 c.returns = false
375 c.assert_autocasts = map[string]AssertAutocast{}
376 defer {
377 c.stmt_level = prev_stmt_level
378 c.fn_level--
379 c.returns = prev_returns
380 c.inside_anon_fn = prev_inside_anon_fn
381 c.inside_unsafe = prev_inside_unsafe
382 c.inside_defer = prev_inside_defer
383 c.in_for_count = prev_in_for_count
384 c.fn_scope = prev_fn_scope
385 c.assert_autocasts = prev_assert_autocasts.clone()
386 }
387 // Check generics fn/method without generic type parameters
388 if node.language == .v && !c.is_builtin_mod && !node.is_anon
389 && !node.get_name().contains('veb_tmpl_') {
390 c.check_valid_snake_case(node.get_name(), 'function name', node.pos)
391 if !node.is_method && node.mod == 'main' && node.short_name in c.table.builtin_pub_fns {
392 c.error('cannot redefine builtin public function `${node.short_name}`', node.pos)
393 }
394 c.check_module_name_conflict(node.short_name, node.pos)
395 }
396 if node.kind == .main_main {
397 c.main_fn_decl_node = *node
398 }
399 if node.language == .v && node.attrs.len > 0 {
400 required_args_attr := ['export', '_linker_section']
401 for attr_name in required_args_attr {
402 attr, has_attr := first_attr_by_name(node.attrs, attr_name)
403 if has_attr {
404 if attr.arg == '' {
405 c.error('missing argument for @[${attr_name}] attribute', attr.pos)
406 } else if attr_name == 'export' {
407 // export fn name
408 fn_name := attr.arg
409 if !fn_name.is_identifier() {
410 c.error('export name `${fn_name}` should be a valid identifier', node.pos)
411 }
412 if fn_name in c.table.export_names.values() {
413 c.error('duplicate export name `${fn_name}`', node.pos)
414 } else {
415 mut node_name := node.name
416 if node.is_method {
417 node_name = c.table.type_to_str(node.receiver.typ) + '.' + node_name
418 }
419 c.table.export_names[node_name] = fn_name
420 }
421 }
422 }
423 }
424 }
425 if node.return_type == ast.no_type {
426 c.error('invalid return type in fn `${node.name}`', node.pos)
427 return
428 }
429 c.fn_return_type = node.return_type
430 return_type_unaliased := c.table.unaliased_type(node.return_type)
431 if node.return_type.has_flag(.option) && return_type_unaliased.has_flag(.result) {
432 c.error('the fn returns ${c.error_type_name(node.return_type)}, but ${c.error_type_name(node.return_type.clear_flag(.option))} is a Result alias, you can not mix them',
433 node.return_type_pos)
434 }
435 if node.return_type.has_flag(.result) && return_type_unaliased.has_flag(.option) {
436 c.error('the fn returns ${c.error_type_name(node.return_type)}, but ${c.error_type_name(node.return_type.clear_flag(.result))} is an Option alias, you can not mix them',
437 node.return_type_pos)
438 }
439 if node.return_type != ast.void_type {
440 if node.language == .v && node.return_type.clear_option_and_result() == ast.any_type {
441 c.error('cannot use type `any` here', node.return_type_pos)
442 }
443 ct_attr_idx := comptime_define_attr_idx(node.attrs)
444 if ct_attr_idx != ast.invalid_type_idx {
445 sexpr := node.attrs[ct_attr_idx].ct_expr.str()
446 c.error('only functions that do NOT return values can have `@[if ${sexpr}]` tags',
447 node.pos)
448 }
449 if node.generic_names.len > 0 {
450 gs := c.table.sym(node.return_type)
451 mut has_missing_generic_return_type := false
452 if gs.info is ast.Struct {
453 if gs.info.is_generic && !node.return_type.has_flag(.generic) {
454 has_missing_generic_return_type = true
455 c.error('return generic struct `${gs.name}` in fn declaration must specify the generic type names, e.g. ${gs.name}[T]',
456 node.return_type_pos)
457 }
458 }
459 if gs.kind == .struct && !has_missing_generic_return_type
460 && c.needs_unwrap_generic_type(node.return_type) {
461 // resolve generic Array[T], Map[T] generics, avoid recursive generic resolving type
462 if c.ensure_generic_type_specify_type_names(node.return_type, node.return_type_pos,
463 false, false)
464 {
465 c.table.unwrap_generic_type_ex(node.return_type, c.table.cur_fn.generic_names,
466 c.table.cur_concrete_types, true)
467 }
468 }
469 }
470 return_sym := c.table.sym(node.return_type)
471 if return_sym.info is ast.Alias {
472 parent_sym := c.table.sym(return_sym.info.parent_type)
473 if parent_sym.info is ast.ArrayFixed {
474 c.table.find_or_register_array_fixed(parent_sym.info.elem_type,
475 parent_sym.info.size, parent_sym.info.size_expr, true)
476 }
477 if return_sym.name == 'byte' {
478 c.error('byte is deprecated, use u8 instead', node.return_type_pos)
479 }
480 }
481 if return_sym.info is ast.ArrayFixed && c.array_fixed_has_unresolved_size(return_sym.info) {
482 c.unresolved_fixed_sizes << node
483 }
484
485 final_return_sym := c.table.final_sym(node.return_type)
486 if final_return_sym.info is ast.MultiReturn {
487 for multi_type in final_return_sym.info.types {
488 if multi_type == ast.error_type {
489 c.error('type `IError` cannot be used in multi-return, return an Option instead',
490 node.return_type_pos)
491 } else if multi_type.has_flag(.result) {
492 c.error('result cannot be used in multi-return, return a Result instead',
493 node.return_type_pos)
494 }
495 }
496 }
497 // Ensure each generic type of the parameter was declared in the function's definition
498 if node.return_type.has_flag(.generic) {
499 ret_sym := c.table.sym(node.return_type)
500 // Skip check for forward-declared types (placeholder) where the
501 // generic param names haven't been resolved yet
502 if ret_sym.kind != .placeholder {
503 generic_names := c.table.generic_type_names(node.return_type)
504 for name in generic_names {
505 if name !in node.generic_names {
506 // When a generic struct is used as return type and the struct's
507 // generic param names differ from the fn's (e.g. struct uses T
508 // but fn uses B), skip if the return type sym is the base generic
509 // struct (not yet instantiated with concrete types)
510 if ret_sym.info is ast.Struct && ret_sym.info.is_generic
511 && ret_sym.generic_types.len == 0 {
512 continue
513 }
514 fn_generic_names := node.generic_names.join(', ')
515 c.error('generic type name `${name}` is not mentioned in fn `${node.name}[${fn_generic_names}]`',
516 node.return_type_pos)
517 }
518 }
519 }
520 }
521 } else {
522 for mut a in node.attrs {
523 if a.kind == .comptime_define {
524 node.should_be_skipped = c.evaluate_once_comptime_if_attribute(mut a)
525 }
526 }
527 }
528 if node.is_method {
529 if node.receiver.name in c.global_names {
530 c.error('cannot use global variable name `${node.receiver.name}` as receiver',
531 node.receiver_pos)
532 }
533 if node.receiver.typ.has_flag(.option) {
534 c.error('option types cannot have methods', node.receiver_pos)
535 }
536 mut sym := c.table.sym(node.receiver.typ)
537 if sym.kind == .array && !c.is_builtin_mod && node.kind == .map {
538 // TODO: `node.map in array_builtin_methods`
539 c.error('method overrides built-in array method', node.pos)
540 } else if sym.kind == .sum_type && node.kind == .type_name {
541 c.error('method overrides built-in sum type method', node.pos)
542 } else if sym.kind == .sum_type && node.kind == .type_idx {
543 c.error('method overrides built-in sum type method', node.pos)
544 } else if sym.kind == .multi_return {
545 c.error('cannot define method on multi-value', node.method_type_pos)
546 }
547 if sym.name.len == 1 {
548 // One letter types are reserved for generics.
549 c.error('unknown type `${sym.name}`', node.receiver_pos)
550 return
551 }
552 // make sure interface does not implement its own interface methods
553 if mut sym.info is ast.Interface && sym.has_method(node.name) {
554 // if the method is in info.methods then it is an interface method
555 if sym.info.has_method(node.name) {
556 c.error('interface `${sym.name}` cannot implement its own interface method `${node.name}`',
557 node.pos)
558 }
559 }
560 if mut sym.info is ast.Struct {
561 if field := c.table.find_field(sym, node.name) {
562 field_sym := c.table.sym(field.typ)
563 if field_sym.kind == .function {
564 c.error('type `${sym.name}` has both field and method named `${node.name}`',
565 node.pos)
566 }
567 }
568 if node.kind == .free {
569 if node.return_type != ast.void_type {
570 c.error('`.free()` methods should not have a return type', node.return_type_pos)
571 }
572 if !node.receiver.typ.is_ptr() {
573 tname := sym.name.after_char(`.`)
574 c.error('`.free()` methods should be defined on either a `(mut x &${tname})`, or a `(x &${tname})` receiver',
575 node.receiver_pos)
576 }
577 if node.params.len != 1 {
578 c.error('`.free()` methods should have 0 arguments', node.pos)
579 }
580 }
581 }
582 // needed for proper error reporting during veb route checking
583 if node.method_idx < sym.methods.len {
584 sym.methods[node.method_idx].source_fn = voidptr(node)
585 } else {
586 c.error('method index: ${node.method_idx} >= sym.methods.len: ${sym.methods.len}',
587 node.pos)
588 }
589 }
590 if node.language == .v {
591 // Make sure all types are valid
592 for mut param in node.params {
593 param.typ = c.preferred_c_symbol_type(param.typ)
594 if mut scoped_param := node.scope.find_var(param.name) {
595 scoped_param.typ = param.typ
596 }
597 // handle vls go to definition for parameter types
598 if c.pref.is_vls && c.pref.linfo.method == .definition {
599 if c.vls_is_the_node(param.type_pos) {
600 typ_str := c.table.type_to_str(param.typ)
601 if np := c.name_pos_gotodef(typ_str) {
602 if np.file_idx != -1 {
603 println('${c.table.filelist[np.file_idx]}:${np.line_nr + 1}:${np.col}')
604 }
605 exit(0)
606 }
607 }
608 }
609 if !c.ensure_type_exists(param.typ, param.type_pos) {
610 return
611 }
612 if reserved_type_names_chk.matches(param.name) {
613 c.error('invalid use of reserved type `${param.name}` as a parameter name',
614 param.pos)
615 }
616 if param.typ.has_flag(.result) {
617 c.error('result type arguments are not supported', param.type_pos)
618 }
619 arg_typ_sym := c.table.sym(param.typ)
620 if arg_typ_sym.language == .v && param.typ == ast.any_type
621 && c.file.mod.name != 'builtin' {
622 c.note('the `any` type is deprecated and will be removed soon - either use an empty interface, or a sum type',
623 param.pos)
624 }
625 // resolve unresolved fixed array size e.g. [mod.const]array_type
626 if arg_typ_sym.info is ast.ArrayFixed
627 && c.array_fixed_has_unresolved_size(arg_typ_sym.info) {
628 mut size_expr := unsafe { arg_typ_sym.info.size_expr }
629 param.typ = c.eval_array_fixed_sizes(mut size_expr, 0, arg_typ_sym.info.elem_type)
630 mut v := node.scope.find_var(param.name) or { continue }
631 v.typ = param.typ
632 } else if arg_typ_sym.info is ast.Struct {
633 if !param.typ.is_ptr() && arg_typ_sym.info.is_heap { // set auto_heap to promote value parameter
634 mut v := node.scope.find_var(param.name) or { continue }
635 v.is_auto_heap = true
636 }
637 if arg_typ_sym.info.generic_types.len > 0 && !param.typ.has_flag(.generic)
638 && arg_typ_sym.info.concrete_types.len == 0 {
639 pure_sym_name := arg_typ_sym.embed_name()
640 c.error('generic struct `${pure_sym_name}` in fn declaration must specify the generic type names, e.g. ${pure_sym_name}[T]',
641 param.type_pos)
642 }
643 if param.is_mut && arg_typ_sym.info.attrs.any(it.name == 'params') {
644 c.error('declaring a mutable parameter that accepts a struct with the `@[params]` attribute is not allowed',
645 param.type_pos)
646 }
647 } else if arg_typ_sym.info is ast.Interface {
648 if arg_typ_sym.info.generic_types.len > 0 && !param.typ.has_flag(.generic)
649 && arg_typ_sym.info.concrete_types.len == 0 {
650 pure_sym_name := arg_typ_sym.embed_name()
651 c.error('generic interface `${pure_sym_name}` in fn declaration must specify the generic type names, e.g. ${pure_sym_name}[T]',
652 param.type_pos)
653 }
654 } else if arg_typ_sym.info is ast.SumType {
655 if arg_typ_sym.info.generic_types.len > 0 && !param.typ.has_flag(.generic)
656 && arg_typ_sym.info.concrete_types.len == 0 {
657 pure_sym_name := arg_typ_sym.embed_name()
658 c.error('generic sumtype `${pure_sym_name}` in fn declaration must specify the generic type names, e.g. ${pure_sym_name}[T]',
659 param.type_pos)
660 }
661 } else if arg_typ_sym.info is ast.FnType {
662 if arg_typ_sym.info.func.generic_names.len > 0 && !param.typ.has_flag(.generic) {
663 pure_sym_name := arg_typ_sym.embed_name()
664 c.error('generic function `${pure_sym_name}` in fn declaration must specify the generic type names, e.g. ${pure_sym_name}[T]',
665 param.type_pos)
666 }
667 }
668 // Ensure each generic type of the parameter was declared in the function's definition
669 if param.typ.has_flag(.generic) {
670 generic_names := c.table.generic_type_names(param.typ)
671 for name in generic_names {
672 if name !in node.generic_names {
673 fn_generic_names := node.generic_names.join(', ')
674 c.error('generic type name `${name}` is not mentioned in fn `${node.name}[${fn_generic_names}]`',
675 param.type_pos)
676 }
677 }
678 }
679 if c.pref.skip_unused {
680 if param.typ.has_flag(.generic) {
681 c.table.used_features.comptime_syms[c.unwrap_generic(param.typ)] = true
682 c.table.used_features.comptime_syms[param.typ] = true
683 }
684 if node.return_type.has_flag(.generic) {
685 c.table.used_features.comptime_syms[c.unwrap_generic(node.return_type)] = true
686 c.table.used_features.comptime_syms[node.return_type] = true
687 }
688 if node.receiver.typ.has_flag(.generic) {
689 c.table.used_features.comptime_syms[node.receiver.typ] = true
690 c.table.used_features.comptime_syms[c.unwrap_generic(node.receiver.typ)] = true
691 }
692 }
693 if param.name == node.mod && param.name != 'main' {
694 c.error('duplicate of a module name `${param.name}`', param.pos)
695 }
696 // Check if parameter name is already registered as imported module symbol
697 if c.check_import_sym_conflict(param.name) {
698 c.error('duplicate of an import symbol `${param.name}`', param.pos)
699 }
700 if arg_typ_sym.kind == .alias && arg_typ_sym.name == 'byte' {
701 c.error('byte is deprecated, use u8 instead', param.type_pos)
702 }
703 }
704 if !node.is_method {
705 // Check if function name is already registered as imported module symbol
706 if c.check_import_sym_conflict(node.short_name) {
707 c.error('duplicate of an import symbol `${node.short_name}`', node.pos)
708 }
709 if node.params.len == 0 && node.name.after_char(`.`) == 'init' {
710 if node.is_pub {
711 c.error('fn `init` must not be public', node.pos)
712 }
713 if node.return_type != ast.void_type {
714 c.error('fn `init` cannot have a return type', node.pos)
715 }
716 }
717 if !c.is_builtin_mod && node.mod == 'main'
718 && node.name.after_char(`.`) in reserved_type_names {
719 c.error('top level declaration cannot shadow builtin type', node.pos)
720 }
721 if node.is_static_type_method {
722 if sym := c.table.find_sym(node.name.all_before('__static__')) {
723 if sym.kind == .placeholder {
724 c.error('unknown type `${sym.name}`', node.static_type_pos)
725 }
726 }
727 }
728 }
729 }
730 if node.return_type != ast.no_type {
731 node.return_type = c.preferred_c_symbol_type(node.return_type)
732 if !c.ensure_type_exists(node.return_type, node.return_type_pos) {
733 return
734 }
735 if node.language == .v && node.is_method && node.kind == .str {
736 if node.return_type != ast.string_type {
737 c.error('.str() methods should return `string`', node.pos)
738 }
739 if node.params.len != 1 {
740 c.error('.str() methods should have 0 arguments', node.pos)
741 }
742 }
743 if node.language == .v && node.is_method
744 && node.name in ['+', '-', '*', '%', '/', '<', '=='] {
745 if node.params.len != 2 {
746 c.error('operator methods should have exactly 1 argument', node.pos)
747 } else {
748 receiver_type := node.receiver.typ
749 receiver_sym := c.table.sym(receiver_type)
750
751 param_type := node.params[1].typ
752 param_sym := c.table.sym(param_type)
753
754 if param_sym.kind == .string && receiver_sym.kind == .string {
755 // bypass check for strings
756 // TODO: there must be a better way to handle that
757 } else if param_sym.kind !in [.struct, .alias]
758 || receiver_sym.kind !in [.struct, .alias] {
759 c.error('operator methods are only allowed for struct and type alias', node.pos)
760 } else {
761 parent_sym := c.table.final_sym(node.receiver.typ)
762 if node.rec_mut {
763 c.error('receiver cannot be `mut` for operator overloading',
764 node.receiver_pos)
765 } else if node.params[1].is_mut {
766 c.error('argument cannot be `mut` for operator overloading', node.pos)
767 } else if !c.check_same_type_ignoring_pointers(node.receiver.typ,
768 node.params[1].typ) {
769 c.error('expected `${receiver_sym.name}` not `${param_sym.name}` - both operands must be the same type for operator overloading',
770 node.params[1].type_pos)
771 } else if node.return_type != ast.bool_type && node.name in ['<', '=='] {
772 c.error('operator comparison methods should return `bool`', node.pos)
773 } else if parent_sym.is_primitive() {
774 if node.return_type.has_option_or_result() {
775 c.error('return type cannot be Option or Result', node.return_type_pos)
776 } else if node.name in ['+', '-', '*', '**', '%', '/']
777 && node.return_type != receiver_type {
778 srtype := c.table.type_to_str(receiver_type)
779 c.error('operator `${node.name}` methods on primitive aliases should return `${srtype}`',
780 node.return_type_pos)
781 }
782 // aliases of primitive types are explicitly allowed
783 } else if receiver_type != param_type {
784 srtype := c.table.type_to_str(receiver_type)
785 sptype := c.table.type_to_str(param_type)
786 c.error('the receiver type `${srtype}` should be the same type as the operand `${sptype}`',
787 node.pos)
788 } else if node.return_type.has_option_or_result() {
789 c.error('return type cannot be Option or Result', node.return_type_pos)
790 }
791 }
792 }
793 }
794 if node.language == .v && node.is_method && node.name == '[]' {
795 if node.params.len != 2 {
796 c.error('index operator methods should have exactly 1 argument', node.pos)
797 } else {
798 receiver_type := node.receiver.typ
799 receiver_sym := c.table.sym(receiver_type)
800 index_sym := c.table.sym(node.params[1].typ)
801 if index_sym.kind == .placeholder {
802 c.error('unknown type `${index_sym.name}`', node.params[1].type_pos)
803 }
804 if receiver_sym.kind !in [.struct, .alias] {
805 c.error('index operator methods are only allowed for struct and type alias',
806 node.pos)
807 } else if node.rec_mut {
808 c.error('receiver cannot be `mut` for `[]`, use `[]=` for writable indexing',
809 node.receiver_pos)
810 } else if node.params[1].is_mut {
811 c.error('argument cannot be `mut` for operator overloading', node.pos)
812 } else if node.return_type == ast.void_type {
813 c.error('index operator methods should return a value', node.return_type_pos)
814 }
815 }
816 }
817 if node.language == .v && node.is_method && node.name == '[]=' {
818 if node.params.len != 3 {
819 c.error('index assignment operator methods should have exactly 2 arguments',
820 node.pos)
821 } else {
822 receiver_sym := c.table.sym(node.receiver.typ)
823 index_sym := c.table.sym(node.params[1].typ)
824 value_sym := c.table.sym(node.params[2].typ)
825 if index_sym.kind == .placeholder {
826 c.error('unknown type `${index_sym.name}`', node.params[1].type_pos)
827 }
828 if value_sym.kind == .placeholder {
829 c.error('unknown type `${value_sym.name}`', node.params[2].type_pos)
830 }
831 if receiver_sym.kind !in [.struct, .alias] {
832 c.error('index assignment operator methods are only allowed for struct and type alias',
833 node.pos)
834 } else if !node.rec_mut {
835 c.error('receiver must be `mut` for `[]=` operator overloading',
836 node.receiver_pos)
837 } else if node.params[1].is_mut || node.params[2].is_mut {
838 c.error('arguments cannot be `mut` for operator overloading', node.pos)
839 } else if node.return_type != ast.void_type {
840 c.error('index assignment operator methods cannot return a value',
841 node.return_type_pos)
842 }
843 }
844 }
845 }
846 // TODO: c.pref.is_vet
847 if c.file.is_test && (!node.is_method && (node.short_name.starts_with('test_')
848 || node.short_name.starts_with('testsuite_')
849 || node.short_name in ['before_each', 'after_each'])) {
850 if !c.pref.is_test {
851 // simple heuristic
852 for st in node.stmts {
853 if st is ast.AssertStmt {
854 c.warn('tests will not be run, because filename does not end with `_test.v`',
855 node.pos)
856 break
857 }
858 }
859 }
860
861 if node.params.len != 0 {
862 c.error('test functions should take 0 parameters', node.pos)
863 }
864
865 if node.return_type != ast.void_type_idx
866 && node.return_type.clear_flag(.option) != ast.void_type_idx
867 && node.return_type.clear_flag(.result) != ast.void_type_idx {
868 c.error('test functions should either return nothing at all, or be marked to return `?` or `!`',
869 node.pos)
870 }
871 }
872 c.expected_type = ast.void_type
873 saved_generic_names := node.generic_names
874 mut needs_generic_names_restore := false
875 saved_return_type := node.return_type
876 if c.table.cur_concrete_types.len > 0
877 && effective_generic_names.len == c.table.cur_concrete_types.len
878 && node.generic_names != effective_generic_names {
879 unsafe {
880 mut p := &[]string(&node.generic_names)
881 *p = effective_generic_names.clone()
882 }
883 needs_generic_names_restore = true
884 }
885 c.table.cur_fn = unsafe { node }
886 if c.table.cur_concrete_types.len > 0 {
887 resolved_return_type := c.recheck_concrete_type(node.return_type)
888 if resolved_return_type != ast.void_type && resolved_return_type != 0 {
889 node.return_type = resolved_return_type
890 }
891 }
892 // Add return if `fn(...) ? {...}` have no return at end
893 if node.return_type != ast.void_type && node.return_type.has_flag(.option)
894 && (node.stmts.len == 0 || node.stmts.last() !is ast.Return) {
895 sym := c.table.sym(node.return_type)
896 if sym.kind == .void {
897 return_pos := if node.stmts.len == 0 { node.pos } else { node.stmts.last().pos }
898 node.stmts << ast.Return{
899 scope: node.scope
900 pos: return_pos // node.pos
901 }
902 }
903 }
904 // same for result `fn (...) ! { ... }`
905 if node.return_type != ast.void_type && node.return_type.has_flag(.result)
906 && (node.stmts.len == 0 || node.stmts.last() !is ast.Return) {
907 sym := c.table.sym(node.return_type)
908 if sym.kind == .void {
909 node.stmts << ast.Return{
910 scope: node.scope
911 pos: node.pos
912 }
913 }
914 }
915 c.fn_scope = node.scope
916 c.refresh_generic_fn_scope_vars(node)
917 // Register implicit context var
918 typ_veb_result := c.table.get_veb_result_type_idx() // c.table.find_type('veb.Result')
919 if node.is_method && node.return_type == typ_veb_result {
920 is_veb_app_method := !c.has_veb_context(node.receiver.typ)
921 for param in node.params[1..] {
922 if is_veb_app_method && c.has_veb_context(param.typ) && !param.is_mut {
923 c.error('veb app method `${node.name}` must declare context parameter `${param.name}` as mutable, e.g. `mut ${param.name} ${c.table.type_to_str(param.typ)}`',
924 param.pos)
925 break
926 }
927 }
928 // Find a custom user Context type first
929 mut ctx_idx := c.table.find_type('main.Context')
930 if ctx_idx < 1 {
931 // If it doesn't exist, use veb.Context
932 ctx_idx = c.table.find_type('veb.Context')
933 }
934 typ_veb_context := ctx_idx.set_nr_muls(1)
935 // No Context type param? Add it
936 if !node.params.any(c.has_veb_context(it.typ)) && node.params.len >= 1 {
937 params := node.params.clone()
938 ctx_param := ast.Param{
939 name: 'ctx'
940 typ: typ_veb_context
941 is_mut: true
942 }
943 node.params = [node.params[0], ctx_param]
944 node.params << params[1..]
945 // println('new params ${node.name}')
946 // println(node.params)
947 // We've added ctx to the FnDecl node.
948 // Now update the existing method, already registered in Table.
949 mut rec_sym := c.table.sym(node.receiver.typ)
950 if mut m := c.table.find_method(rec_sym, node.name) {
951 p := m.params.clone()
952 m.params = [m.params[0], ctx_param]
953 m.params << p[1..]
954 rec_sym.update_method(m)
955 }
956 }
957 // sym := c.table.sym(typ_veb_context)
958 // println('reging ${typ_veb_context} ${sym}')
959 // println(c.fn_scope)
960 // println(node.params)
961 // Finally add ctx to the scope
962 c.fn_scope.register(ast.Var{
963 name: 'ctx'
964 typ: typ_veb_context
965 pos: node.pos
966 is_used: true
967 is_mut: true
968 is_stack_obj: false // true
969 })
970 if is_veb_app_method {
971 for param in node.params[1..] {
972 if c.has_veb_context(param.typ) || c.supports_veb_string_bound_param(param.typ) {
973 continue
974 }
975 c.error('veb app method `${node.name}` parameter `${param.name}` has unsupported type `${c.table.type_to_str(param.typ)}`; parameters after the context are populated from strings and must be `string`, integer, or `bool`',
976 param.pos)
977 }
978 }
979 }
980 c.stmts(mut node.stmts)
981 node_has_top_return := c.has_top_return(node.stmts)
982 node.has_return = c.returns || node_has_top_return
983 c.check_noreturn_fn_decl(mut node)
984 if node.language == .v && !node.no_body && node.return_type != ast.void_type && !node.has_return
985 && !node.is_noreturn {
986 if c.inside_anon_fn {
987 c.error('missing return at the end of an anonymous function', node.pos)
988 } else if !node.attrs.contains('_naked') {
989 c.error('missing return at end of function `${node.name}`', node.pos)
990 }
991 }
992 if !node.has_return {
993 // for `node.has_return`, checking in `return.v` `return_stmt`
994 old_inside_defer := c.inside_defer
995 c.inside_defer = true
996 for i := c.table.cur_fn.defer_stmts.len - 1; i >= 0; i-- {
997 c.stmts(mut c.table.cur_fn.defer_stmts[i].stmts)
998 }
999 c.inside_defer = old_inside_defer
1000 }
1001
1002 node.source_file = c.file
1003
1004 if node.name in c.table.fns {
1005 if node.name != 'main.main' {
1006 mut dep_names := []string{}
1007 for stmt in node.stmts {
1008 dnames := c.table.dependent_names_in_stmt(stmt)
1009 for dname in dnames {
1010 if dname in dep_names {
1011 continue
1012 }
1013 dep_names << dname
1014 }
1015 }
1016 if dep_names.len > 0 {
1017 unsafe {
1018 c.table.fns[node.name].dep_names = dep_names
1019 }
1020 }
1021 }
1022 unsafe {
1023 c.table.fns[node.name].source_fn = voidptr(node)
1024 }
1025 }
1026
1027 if node.is_expand_simple_interpolation {
1028 match true {
1029 !node.is_method {
1030 c.error('@[expand_simple_interpolation] is supported only on methods', node.pos)
1031 }
1032 node.params.len != 2 {
1033 c.error('methods tagged with @[expand_simple_interpolation], should have exactly 1 argument',
1034 node.pos)
1035 }
1036 !node.params[1].typ.is_string() {
1037 c.error('methods tagged with @[expand_simple_interpolation], should accept a single string',
1038 node.pos)
1039 }
1040 else {}
1041 }
1042 }
1043 if needs_generic_names_restore {
1044 unsafe {
1045 mut p := &[]string(&node.generic_names)
1046 *p = saved_generic_names
1047 }
1048 }
1049 node.return_type = saved_return_type
1050}
1051
1052// check_same_type_ignoring_pointers util function to check if the Types are the same, including all
1053// corner cases.
1054// FIXME: if the optimization is done after the checker, we can safely remove this util function
1055fn (c &Checker) check_same_type_ignoring_pointers(type_a ast.Type, type_b ast.Type) bool {
1056 // FIXME: if possible pass the ast.Node and check the property `is_auto_rec`
1057 if type_a != type_b {
1058 // before failing we must be sure that the parser didn't optimize the function
1059 clean_type_a := type_a.set_nr_muls(0)
1060 clean_type_b := type_b.set_nr_muls(0)
1061 return clean_type_a == clean_type_b
1062 }
1063 return true
1064}
1065
1066fn (mut c Checker) expected_callback_fn() ?ast.Fn {
1067 if c.expected_type in [0, ast.void_type] {
1068 return none
1069 }
1070 expected_type := c.unwrap_generic(c.recheck_concrete_type(c.expected_type))
1071 expected_sym := c.table.final_sym(expected_type)
1072 if expected_sym.kind != .function || expected_sym.info !is ast.FnType {
1073 return none
1074 }
1075 return (expected_sym.info as ast.FnType).func
1076}
1077
1078fn (mut c Checker) omitted_callback_param(expected_param ast.Param, idx int, pos token.Pos, prefix string) ast.Param {
1079 param_type := c.recheck_concrete_type(expected_param.typ)
1080 return ast.Param{
1081 pos: pos
1082 name: '${prefix}${idx}'
1083 is_mut: expected_param.is_mut
1084 is_shared: expected_param.is_shared
1085 is_atomic: expected_param.is_atomic
1086 typ: param_type
1087 orig_typ: if expected_param.orig_typ == 0 { param_type } else { expected_param.orig_typ }
1088 type_pos: pos
1089 on_newline: expected_param.on_newline
1090 }
1091}
1092
1093fn (mut c Checker) append_omitted_callback_params(mut params []ast.Param, expected_params []ast.Param, pos token.Pos, prefix string, scope &ast.Scope) {
1094 if params.len >= expected_params.len {
1095 return
1096 }
1097 for idx in params.len .. expected_params.len {
1098 param := c.omitted_callback_param(expected_params[idx], idx, pos, prefix)
1099 params << param
1100 if scope != unsafe { nil } {
1101 unsafe {
1102 mut scope_ := &ast.Scope(scope)
1103 scope_.register(ast.Var{
1104 name: param.name
1105 typ: param.typ
1106 generic_typ: if param.typ.has_flag(.generic) { param.typ } else { ast.Type(0) }
1107 is_mut: c.implicit_mutability_enabled() || param.is_mut
1108 is_auto_deref: param.is_mut
1109 pos: param.pos
1110 is_used: true
1111 is_arg: true
1112 is_stack_obj: !param.typ.has_flag(.shared_f)
1113 && (param.is_mut || param.typ.is_ptr())
1114 })
1115 }
1116 }
1117 }
1118}
1119
1120fn (mut c Checker) expand_anon_fn_callback_signature(mut node ast.AnonFn) {
1121 expected_fn := c.expected_callback_fn() or { return }
1122 if node.decl.params.len >= expected_fn.params.len || node.decl.is_variadic
1123 || expected_fn.is_variadic {
1124 return
1125 }
1126 mut params := node.decl.params.clone()
1127 c.append_omitted_callback_params(mut params, expected_fn.params, node.decl.pos,
1128 '__v_anon_unused_param_', node.decl.scope)
1129 node.decl.params = params
1130 mut func := ast.Fn{
1131 params: params
1132 is_variadic: node.decl.is_variadic
1133 return_type: node.decl.return_type
1134 is_method: false
1135 }
1136 name := c.table.get_anon_fn_name(c.file.unique_prefix, func, node.decl.pos)
1137 func.name = name
1138 node.decl = ast.FnDecl{
1139 ...node.decl
1140 name: name
1141 params: params
1142 }
1143 idx := c.table.find_or_register_fn_type(func, true, false)
1144 node.typ = if node.decl.generic_names.len > 0 {
1145 ast.new_type(idx).set_flag(.generic)
1146 } else {
1147 ast.new_type(idx)
1148 }
1149}
1150
1151fn (mut c Checker) anon_fn(mut node ast.AnonFn) ast.Type {
1152 keep_fn := c.table.cur_fn
1153 keep_inside_anon := c.inside_anon_fn
1154 keep_anon_fn := c.cur_anon_fn
1155 keep_anon_fn_generic_names := c.anon_fn_generic_names.clone()
1156 keep_anon_fn_concrete_types := c.anon_fn_concrete_types.clone()
1157 c.table.used_features.anon_fn = true
1158 defer {
1159 c.table.cur_fn = keep_fn
1160 c.inside_anon_fn = keep_inside_anon
1161 c.cur_anon_fn = keep_anon_fn
1162 c.anon_fn_generic_names = keep_anon_fn_generic_names
1163 c.anon_fn_concrete_types = keep_anon_fn_concrete_types
1164 }
1165 if node.decl.no_body {
1166 c.error('anonymous function must declare a body', node.decl.pos)
1167 }
1168 c.expand_anon_fn_callback_signature(mut node)
1169 for param in node.decl.params {
1170 if param.name == '' {
1171 c.error('use `_` to name an unused parameter', param.pos)
1172 }
1173 }
1174 mut can_use_outer_generic_context := node.decl.generic_names.len > 0
1175 c.table.cur_fn = unsafe { &node.decl }
1176 c.inside_anon_fn = true
1177 c.cur_anon_fn = unsafe { node }
1178 mut has_generic := false
1179 for mut var in node.inherited_vars {
1180 parent_var := node.decl.scope.parent.find_var(var.name) or {
1181 panic('unexpected checker error: cannot find parent of inherited variable `${var.name}`')
1182 }
1183 captures_auto_deref_by_value := parent_var.is_auto_deref && !var.is_mut
1184 mut declared_parent_typ := parent_var.typ
1185 if keep_fn != unsafe { nil } {
1186 if keep_fn.is_method && keep_fn.receiver.name == var.name {
1187 declared_parent_typ = keep_fn.receiver.typ
1188 } else {
1189 for param in keep_fn.params {
1190 if param.name == var.name {
1191 declared_parent_typ = param.typ
1192 break
1193 }
1194 }
1195 }
1196 }
1197 if var.is_mut && !parent_var.is_mut {
1198 c.error('original `${parent_var.name}` is immutable, declare it with `mut` to make it mutable',
1199 var.pos)
1200 }
1201 ptyp := c.visible_var_type_for_read(parent_var)
1202 node.has_ct_var = node.has_ct_var
1203 || var.name in [c.comptime.comptime_for_field_var, c.comptime.comptime_for_method_var]
1204 if declared_parent_typ != ast.no_type {
1205 parent_var_sym := c.table.final_sym(declared_parent_typ)
1206 if parent_var_sym.info is ast.FnType {
1207 ret_typ := parent_var_sym.info.func.return_type
1208 if c.type_has_unresolved_generic_parts(ret_typ) {
1209 generic_names := c.table.generic_type_names(ret_typ)
1210 curr_list := node.decl.generic_names.join(', ')
1211 for name in generic_names {
1212 if name !in node.decl.generic_names {
1213 can_use_outer_generic_context = false
1214 c.error('Add the generic type `${name}` to the anon fn generic list type, that is currently `[${curr_list}]`',
1215 var.pos)
1216 }
1217 }
1218 }
1219 }
1220 }
1221 if parent_var.expr is ast.IfGuardExpr {
1222 sym := c.table.sym(parent_var.expr.expr_type)
1223 if sym.info is ast.MultiReturn {
1224 for i, v in parent_var.expr.vars {
1225 if v.name == var.name {
1226 var.typ = sym.info.types[i]
1227 break
1228 }
1229 }
1230 } else {
1231 var.typ = parent_var.expr.expr_type.clear_option_and_result()
1232 }
1233 } else {
1234 var.typ = ptyp
1235 }
1236 if captures_auto_deref_by_value && var.typ.is_ptr() {
1237 var.typ = var.typ.deref()
1238 }
1239 if c.is_nocopy_struct(var.typ) {
1240 c.error('cannot capture @[nocopy] struct by value: use a reference instead', var.pos)
1241 }
1242 if c.type_has_unresolved_generic_parts(declared_parent_typ) {
1243 has_generic = true
1244 }
1245 node.decl.scope.update_var_type(var.name, var.typ)
1246 if captures_auto_deref_by_value {
1247 if mut captured_var := node.decl.scope.find_var(var.name) {
1248 captured_var.is_auto_deref = false
1249 captured_var.typ = var.typ
1250 if captured_var.orig_type.is_ptr() {
1251 captured_var.orig_type = captured_var.orig_type.deref()
1252 }
1253 if captured_var.smartcasts.len > 0 {
1254 captured_var.smartcasts = captured_var.smartcasts.map(if it.is_ptr() {
1255 it.deref()
1256 } else {
1257 it
1258 })
1259 }
1260 }
1261 }
1262 }
1263 c.anon_fn_generic_names = []string{}
1264 c.anon_fn_concrete_types = []ast.Type{}
1265 if can_use_outer_generic_context && keep_fn != unsafe { nil }
1266 && keep_fn.generic_names.len == c.table.cur_concrete_types.len {
1267 for generic_name in node.decl.generic_names {
1268 generic_idx := keep_fn.generic_names.index(generic_name)
1269 if generic_idx >= 0 {
1270 c.anon_fn_generic_names << generic_name
1271 c.anon_fn_concrete_types << c.table.cur_concrete_types[generic_idx]
1272 }
1273 }
1274 for i, generic_name in keep_fn.generic_names {
1275 if generic_name !in c.anon_fn_generic_names {
1276 c.anon_fn_generic_names << generic_name
1277 c.anon_fn_concrete_types << c.table.cur_concrete_types[i]
1278 }
1279 }
1280 }
1281 if has_generic && node.decl.generic_names.len == 0 {
1282 c.error('generic closure fn must specify type parameter, e.g. fn [foo] [T]()',
1283 node.decl.pos)
1284 }
1285 // Refresh param scope vars before checking stmts, so that generic params
1286 // resolve to the current concrete types (not stale types from a previous
1287 // generic instantiation pass).
1288 if c.table.cur_concrete_types.len > 0 && node.decl.generic_names.len > 0
1289 && node.decl.generic_names.len == c.table.cur_concrete_types.len {
1290 for param in node.decl.params {
1291 param_type := if resolved := c.table.convert_generic_type(param.typ,
1292 node.decl.generic_names, c.table.cur_concrete_types)
1293 {
1294 c.unwrap_generic(resolved)
1295 } else {
1296 c.table.unwrap_generic_type_ex(param.typ, node.decl.generic_names,
1297 c.table.cur_concrete_types, true)
1298 }
1299 if mut param_var := node.decl.scope.find_var(param.name) {
1300 if param_var.generic_typ == 0 && (param.typ.has_flag(.generic)
1301 || c.type_has_unresolved_generic_parts(param.typ)) {
1302 param_var.generic_typ = param.typ
1303 }
1304 param_var.typ = param_type
1305 }
1306 }
1307 }
1308 c.stmts(mut node.decl.stmts)
1309 c.fn_decl(mut node.decl)
1310 return node.typ
1311}
1312
1313fn (mut c Checker) resolve_self_method_call(mut node ast.CallExpr) bool {
1314 if node.is_method || node.name == '' {
1315 return false
1316 }
1317 if c.table.cur_fn == unsafe { nil } || !c.table.cur_fn.is_method {
1318 return false
1319 }
1320 if node.name.contains('.') && !node.name.starts_with('${c.mod}.') {
1321 return false
1322 }
1323 call_name := node.name.all_after_last('.')
1324 current_method_name := c.table.cur_fn.name.all_after_last('.')
1325 if call_name != current_method_name {
1326 return false
1327 }
1328 receiver_name := c.table.cur_fn.receiver.name
1329 node.left = ast.Ident{
1330 pos: node.pos
1331 scope: node.scope
1332 mod: c.mod
1333 name: receiver_name
1334 }
1335 node.name = call_name
1336 node.left_type = c.expr(mut node.left)
1337 if node.left_type == ast.void_type {
1338 return false
1339 }
1340 node.is_method = true
1341 return true
1342}
1343
1344fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type {
1345 // Check whether the inner function definition is before the call
1346 if node.scope != unsafe { nil } {
1347 if var := node.scope.find_var(node.name) {
1348 if var.expr is ast.AnonFn && var.pos.pos > node.pos.pos {
1349 c.error('unknown function: ${node.name}', node.pos)
1350 }
1351 }
1352 }
1353 // If the left expr has an or_block, it needs to be checked for legal or_block statement.
1354 mut left_type := ast.void_type
1355 match mut node.left {
1356 ast.SelectorExpr {
1357 if node.name == '' && node.left.or_block.kind != .absent {
1358 left_type = c.selector_expr(mut node.left)
1359 } else {
1360 left_type = c.expr(mut node.left)
1361 }
1362 }
1363 else {
1364 left_type = c.expr(mut node.left)
1365 }
1366 }
1367
1368 if node.name == '' {
1369 left_type = c.check_expr_option_or_result_call(node.left, left_type)
1370 } else {
1371 c.check_expr_option_or_result_call(node.left, left_type)
1372 }
1373 // TODO: merge logic from method_call and fn_call
1374 // First check everything that applies to both fns and methods
1375 old_inside_fn_arg := c.inside_fn_arg
1376 c.inside_fn_arg = true
1377 mut continue_check := true
1378 node.left_type = left_type
1379 // Now call `method_call` or `fn_call` for specific checks.
1380 mut typ := ast.void_type
1381 if node.is_method {
1382 typ = c.method_call(mut node, mut continue_check)
1383 } else {
1384 typ = c.fn_call(mut node, mut continue_check)
1385 }
1386 if c.pref.is_vls {
1387 c.autocomplete_for_fn_call_expr(node)
1388 }
1389 if !continue_check {
1390 return ast.void_type
1391 }
1392 c.inside_fn_arg = old_inside_fn_arg
1393 arg0 := if node.args.len > 0 { node.args[0] } else { ast.CallArg{} }
1394 // autofree: mark args that have to be freed (after saving them in tmp exprs)
1395 free_tmp_arg_vars := c.pref.autofree && !c.is_builtin_mod && node.args.len > 0
1396 && !c.inside_const && !arg0.typ.has_flag(.option) && !arg0.typ.has_flag(.result)
1397 && !(arg0.expr is ast.CallExpr
1398 && (arg0.expr.return_type.has_flag(.option) || arg0.expr.return_type.has_flag(.result)))
1399 if free_tmp_arg_vars {
1400 for i, arg in node.args {
1401 if arg.typ != ast.string_type {
1402 continue
1403 }
1404 if arg.expr in [ast.Ident, ast.StringLiteral, ast.SelectorExpr, ast.ComptimeSelector]
1405 || autofree_expr_has_or_block_in_chain(arg.expr) {
1406 // Simple expressions like variables, string literals, selector expressions
1407 // (`x.field`) can't result in allocations and don't need to be assigned to
1408 // temporary vars.
1409 // Only expressions like `str + 'b'` need to be freed.
1410 // Expressions with result/option propagation in the call chain (e.g.
1411 // `get_str()!.to_upper()`) cannot be pre-generated safely by
1412 // autofree_call_pregen, because the or_block unwrapping internally calls
1413 // go_before_last_stmt() which garbles the output buffer.
1414 continue
1415 }
1416 if arg.expr is ast.CallExpr && arg.expr.name in ['json.encode', 'json.encode_pretty'] {
1417 continue
1418 }
1419 node.args[i].is_tmp_autofree = true
1420 }
1421 // TODO: copy pasta from above
1422 if node.receiver_type == ast.string_type
1423 && node.left !in [ast.Ident, ast.StringLiteral, ast.SelectorExpr] {
1424 node.free_receiver = true
1425 }
1426 }
1427 if node.nr_ret_values == -1 && node.return_type != 0 {
1428 if node.return_type == ast.void_type {
1429 node.nr_ret_values = 0
1430 } else {
1431 ret_sym := c.table.sym(node.return_type)
1432 if ret_sym.info is ast.MultiReturn {
1433 node.nr_ret_values = ret_sym.info.types.len
1434 } else {
1435 node.nr_ret_values = 1
1436 }
1437 }
1438 }
1439 old_expected_or_type := c.expected_or_type
1440 c.expected_or_type = node.return_type.clear_flag(.result)
1441 c.stmts_ending_with_expression(mut node.or_block.stmts, c.expected_or_type)
1442 if node.or_block.kind == .block && !node.or_block.err_used {
1443 if err_var := node.or_block.scope.find_var('err') {
1444 node.or_block.err_used = err_var.is_used
1445 }
1446 }
1447
1448 if node.or_block.kind == .block {
1449 mut return_context_type := ast.no_type
1450 if c.inside_return && c.table.cur_fn != unsafe { nil } && node.or_block.stmts.len > 0 {
1451 last_stmt := node.or_block.stmts.last()
1452 if last_stmt is ast.ExprStmt {
1453 if last_stmt.typ == ast.none_type && c.table.cur_fn.return_type.has_flag(.option) {
1454 return_context_type = c.table.cur_fn.return_type
1455 } else if last_stmt.typ == ast.error_type
1456 && c.table.cur_fn.return_type.has_flag(.result) {
1457 return_context_type = c.table.cur_fn.return_type
1458 }
1459 }
1460 }
1461 if return_context_type != ast.no_type {
1462 typ = return_context_type
1463 } else {
1464 old_inside_or_block_value := c.inside_or_block_value
1465 c.inside_or_block_value = true
1466 last_cur_or_expr := c.cur_or_expr
1467 c.cur_or_expr = &node.or_block
1468 c.check_or_expr(node.or_block, typ, c.expected_or_type, node)
1469 c.cur_or_expr = last_cur_or_expr
1470 c.inside_or_block_value = old_inside_or_block_value
1471 }
1472 }
1473 c.expected_or_type = old_expected_or_type
1474 c.markused_call_expr(left_type, mut node)
1475 if !c.inside_const && c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.is_main
1476 && !c.table.cur_fn.is_test {
1477 // TODO: use just `if node.or_block.kind == .propagate_result && !c.table.cur_fn.return_type.has_flag(.result) {` after the deprecation for ?!Type
1478 if node.or_block.kind == .propagate_result && !c.table.cur_fn.return_type.has_flag(.result)
1479 && !c.table.cur_fn.return_type.has_flag(.option) {
1480 c.add_instruction_for_result_type()
1481 c.error('to propagate the Result call, `${c.table.cur_fn.name}` must return a Result',
1482 node.or_block.pos)
1483 }
1484 if node.or_block.kind == .propagate_option && !c.table.cur_fn.return_type.has_flag(.option) {
1485 c.add_instruction_for_option_type()
1486 c.error('to propagate the Option call, `${c.table.cur_fn.name}` must return an Option',
1487 node.or_block.pos)
1488 }
1489 }
1490 return typ
1491}
1492
1493fn (mut c Checker) builtin_args(mut node ast.CallExpr, fn_name string, func &ast.Fn) {
1494 c.inside_interface_deref = true
1495 c.expected_type = ast.string_type
1496 if !(node.language != .js && node.args[0].expr is ast.CallExpr) {
1497 node.args[0].typ = c.expr(mut node.args[0].expr)
1498 }
1499 arg := node.args[0]
1500 c.check_expr_option_or_result_call(arg.expr, arg.typ)
1501 if arg.typ.is_void() {
1502 c.error('`${fn_name}` can not print void expressions', node.pos)
1503 } else if arg.typ == ast.char_type && arg.typ.nr_muls() == 0 {
1504 c.error('`${fn_name}` cannot print type `char` directly, print its address or cast it to an integer instead',
1505 node.pos)
1506 } else if arg.expr is ast.ArrayDecompose {
1507 c.error('`${fn_name}` cannot print variadic values', node.pos)
1508 } else if c.fail_if_private_implicit_str(arg.typ, node.pos, 'print') {
1509 return
1510 }
1511 c.fail_if_unreadable(arg.expr, arg.typ, 'argument to print')
1512 c.inside_interface_deref = false
1513 node.return_type = ast.void_type
1514 c.set_node_expected_arg_types(mut node, func)
1515
1516 /*
1517 // TODO: optimize `struct T{} fn (t &T) str() string {return 'abc'} mut a := []&T{} a << &T{} println(a[0])`
1518 // It currently generates:
1519 // `println(T_str_no_ptr(*(*(T**)array_get(a, 0))));`
1520 // ... which works, but could be just:
1521 // `println(T_str(*(T**)array_get(a, 0)));`
1522 prexpr := node.args[0].expr
1523 prtyp := node.args[0].typ
1524 prtyp_sym := c.table.sym(prtyp)
1525 prtyp_is_ptr := prtyp.is_ptr()
1526 prhas_str, prexpects_ptr, prnr_args := prtyp_sym.str_method_info()
1527 eprintln('>>> println hack typ: ${prtyp} | sym.name: ${prtyp_sym.name} | is_ptr: ${prtyp_is_ptr} | has_str: ${prhas_str} | expects_ptr: ${prexpects_ptr} | nr_args: ${prnr_args} | expr: ${prexpr.str()} ')
1528 */
1529}
1530
1531fn (mut c Checker) try_resolve_c_type_cast_call(mut node ast.CallExpr) ?ast.Type {
1532 if node.language != .c || !node.name.starts_with('C.') || node.args.len != 1 {
1533 return none
1534 }
1535 c_name := node.name.all_after('C.')
1536 if c_name.len == 0 || !c_name[0].is_capital() {
1537 return none
1538 }
1539 to_type := c.table.find_type(node.name)
1540 if to_type == 0 {
1541 return none
1542 }
1543 to_sym := c.table.sym(to_type)
1544 if to_sym.kind == .placeholder {
1545 return none
1546 }
1547 mut cast_expr := ast.CastExpr{
1548 typ: to_type
1549 typname: to_sym.name
1550 expr: node.args[0].expr
1551 pos: node.pos
1552 }
1553 typ := c.cast_expr(mut cast_expr)
1554 node.is_c_type_cast = true
1555 node.args[0].expr = cast_expr.expr
1556 node.args[0].typ = cast_expr.expr_type
1557 node.return_type = typ
1558 return typ
1559}
1560
1561fn (mut c Checker) needs_unwrap_generic_type(typ ast.Type) bool {
1562 if typ == 0 {
1563 return false
1564 }
1565 if c.type_has_unresolved_generic_parts(typ) {
1566 return true
1567 }
1568 if !typ.has_flag(.generic) {
1569 return false
1570 }
1571 sym := c.table.sym(typ)
1572 match sym.info {
1573 ast.Struct, ast.Interface, ast.SumType {
1574 return true
1575 }
1576 ast.Array {
1577 return c.needs_unwrap_generic_type(sym.info.elem_type)
1578 }
1579 ast.ArrayFixed {
1580 return c.needs_unwrap_generic_type(sym.info.elem_type)
1581 }
1582 ast.Map {
1583 if c.needs_unwrap_generic_type(sym.info.key_type) {
1584 return true
1585 }
1586 if c.needs_unwrap_generic_type(sym.info.value_type) {
1587 return true
1588 }
1589 }
1590 ast.Chan {
1591 return c.needs_unwrap_generic_type(sym.info.elem_type)
1592 }
1593 ast.Thread {
1594 return c.needs_unwrap_generic_type(sym.info.return_type)
1595 }
1596 else {
1597 return false
1598 }
1599 }
1600
1601 return false
1602}
1603
1604fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.Type {
1605 is_va_arg := node.kind == .va_arg
1606 is_json_decode := node.kind == .json_decode
1607 is_json_encode := node.kind == .json_encode
1608 mut fn_name := node.name
1609 if node.is_static_method {
1610 // resolve static call T.name()
1611 if c.table.cur_fn != unsafe { nil } {
1612 node.left_type, fn_name = c.table.convert_generic_static_type_name(fn_name,
1613 c.table.cur_fn.generic_names, c.table.cur_concrete_types)
1614 c.table.used_features.comptime_calls[fn_name] = true
1615 }
1616 }
1617 if !c.file.is_test && node.kind == .main {
1618 c.error('the `main` function cannot be called in the program', node.pos)
1619 }
1620 mut has_generic := false // foo[T]() instead of foo[int]()
1621 mut concrete_types := []ast.Type{}
1622 node.concrete_types = node.raw_concrete_types
1623 for concrete_type in node.concrete_types {
1624 if concrete_type.has_flag(.generic)
1625 || (c.type_has_unresolved_generic_parts(concrete_type)
1626 && c.table.sym(concrete_type).kind != .placeholder) {
1627 has_generic = true
1628 concrete_types << c.unwrap_generic(concrete_type)
1629 } else {
1630 concrete_types << concrete_type
1631 }
1632 }
1633 if c.table.cur_fn != unsafe { nil } && c.table.cur_concrete_types.len == 0 && has_generic {
1634 c.error('generic fn using generic types cannot be called outside of generic fn', node.pos)
1635 }
1636 fkey := node.fkey()
1637 fn_name_has_dot := fn_name.contains('.')
1638 if concrete_types.len > 0 {
1639 mut no_exists := true
1640 if fn_name_has_dot {
1641 no_exists = c.table.register_fn_concrete_types(fkey, concrete_types)
1642 } else {
1643 no_exists = c.table.register_fn_concrete_types(c.mod + '.' + fkey, concrete_types)
1644 // if the generic fn does not exist in the current fn calling module, continue
1645 // to look in builtin module
1646 if !no_exists {
1647 no_exists = c.table.register_fn_concrete_types(fkey, concrete_types)
1648 }
1649 }
1650 if no_exists {
1651 c.need_recheck_generic_fns = true
1652 }
1653 full_fkey := if fn_name_has_dot { fkey } else { c.mod + '.' + fkey }
1654 c.generic_call_positions[c.build_generic_call_key(full_fkey, concrete_types)] = node.pos
1655 }
1656 mut args_len := node.args.len
1657 if node.kind == .jsawait {
1658 if node.args.len > 1 {
1659 c.error('JS.await expects 1 argument, a promise value (e.g `JS.await(fs.read())`',
1660 node.pos)
1661 return ast.void_type
1662 }
1663
1664 typ := c.expr(mut node.args[0].expr)
1665 tsym := c.table.sym(typ)
1666
1667 if !tsym.name.starts_with('Promise[') {
1668 c.error('JS.await: first argument must be a promise, got `${tsym.name}`', node.pos)
1669 return ast.void_type
1670 }
1671 if c.table.cur_fn != unsafe { nil } {
1672 c.table.cur_fn.has_await = true
1673 }
1674 match tsym.info {
1675 ast.Struct {
1676 mut ret_type := tsym.info.concrete_types[0]
1677 ret_type = ret_type.set_flag(.option)
1678 node.return_type = ret_type
1679 return ret_type
1680 }
1681 else {
1682 c.error('JS.await: Promise must be a struct type', node.pos)
1683 return ast.void_type
1684 }
1685 }
1686
1687 panic('unreachable')
1688 } else if args_len > 0 && node.args[0].typ.has_flag(.shared_f) && node.kind == .json_encode {
1689 c.error('json.encode cannot handle shared data', node.pos)
1690 return ast.void_type
1691 } else if args_len > 0 && (is_va_arg || is_json_decode) {
1692 if args_len != 2 {
1693 if is_json_decode {
1694 c.error("json.decode expects 2 arguments, a type and a string (e.g `json.decode(T, '')`)",
1695 node.pos)
1696 } else {
1697 c.error('C.va_arg expects 2 arguments, a type and va_list (e.g `C.va_arg(int, va)`)',
1698 node.pos)
1699 }
1700 return ast.void_type
1701 }
1702 mut expr := node.args[0].expr
1703 if mut expr is ast.TypeNode {
1704 expr.typ = c.expr(mut expr)
1705 mut unwrapped_typ := c.unwrap_generic(expr.typ)
1706 if c.needs_unwrap_generic_type(expr.typ) {
1707 unwrapped_typ = c.table.unwrap_generic_type(expr.typ, c.table.cur_fn.generic_names,
1708 c.table.cur_concrete_types)
1709 }
1710 sym := c.table.sym(unwrapped_typ)
1711 if c.table.known_type(sym.name) && sym.kind != .placeholder {
1712 mut kind := sym.kind
1713 if sym.info is ast.Alias {
1714 kind = c.table.sym(sym.info.parent_type).kind
1715 } else if sym.kind == .generic_inst && sym.info is ast.GenericInst {
1716 parent_sym := c.table.sym(ast.new_type(sym.info.parent_idx))
1717 kind = parent_sym.kind
1718 }
1719 if is_json_decode && kind !in [.struct, .sum_type, .map, .array] {
1720 c.error('${fn_name}: expected sum type, struct, map or array, found ${kind}',
1721 expr.pos)
1722 }
1723 } else {
1724 c.error('${fn_name}: unknown type `${sym.name}`', node.pos)
1725 }
1726 } else {
1727 typ := expr.type_name()
1728 c.error('${fn_name}: first argument needs to be a type, got `${typ}`', node.pos)
1729 return ast.void_type
1730 }
1731 c.expected_type = ast.string_type
1732 node.args[1].typ = c.expr(mut node.args[1].expr)
1733 if is_json_decode && node.args[1].typ != ast.string_type {
1734 c.error('json.decode: second argument needs to be a string', node.pos)
1735 }
1736 typ := expr as ast.TypeNode
1737 node.return_type = if is_json_decode { typ.typ.set_flag(.result) } else { typ.typ }
1738 if typ.typ.has_flag(.generic) {
1739 c.table.used_features.comptime_syms[c.unwrap_generic(typ.typ)] = true
1740 }
1741 return node.return_type
1742 } else if node.kind == .addr {
1743 if !c.inside_unsafe {
1744 c.error('`__addr` must be called from an unsafe block', node.pos)
1745 }
1746 if args_len != 1 {
1747 c.error('`__addr` requires 1 argument', node.pos)
1748 return ast.void_type
1749 }
1750 typ := c.expr(mut node.args[0].expr)
1751 node.args[0].typ = typ
1752 node.return_type = typ.ref()
1753 return node.return_type
1754 }
1755 // look for function in format `mod.fn` or `fn` (builtin)
1756 mut func := ast.Fn{}
1757 mut found := false
1758 mut found_in_args := false
1759 defer {
1760 if found {
1761 c.check_must_use_call_result(node, func, 'function')
1762 }
1763 }
1764 // anon fn direct call
1765 if node.left is ast.AnonFn {
1766 // it was set to anon for checker errors, clear for gen
1767 node.name = ''
1768 left := node.left as ast.AnonFn
1769 if left.typ != ast.no_type {
1770 anon_fn_sym := c.table.sym(left.typ)
1771 func = (anon_fn_sym.info as ast.FnType).func
1772 found = true
1773 }
1774 }
1775 // try prefix with current module as it would have never gotten prefixed
1776 if !found && node.mod != 'builtin' && !fn_name_has_dot {
1777 name_prefixed := '${node.mod}.${fn_name}'
1778 if f := c.table.find_fn(name_prefixed) {
1779 node.name = name_prefixed
1780 found = true
1781 func = f
1782 unsafe { c.table.fns[name_prefixed].usages++ }
1783 c.mark_fn_decl_as_referenced(f.fkey())
1784 }
1785 }
1786 if !found && node.left is ast.IndexExpr {
1787 left := node.left as ast.IndexExpr
1788 sym := c.table.final_sym(left.left_type)
1789 if sym.info is ast.Array {
1790 elem_sym := c.table.sym(sym.info.elem_type)
1791 if elem_sym.info is ast.FnType {
1792 func = elem_sym.info.func
1793 found = true
1794 node.is_fn_var = true
1795 node.fn_var_type = sym.info.elem_type
1796 } else {
1797 c.error('cannot call the element of the array, it is not a function', node.pos)
1798 }
1799 } else if sym.info is ast.Map {
1800 value_sym := c.table.sym(sym.info.value_type)
1801 if value_sym.info is ast.FnType {
1802 func = value_sym.info.func
1803 found = true
1804 node.is_fn_var = true
1805 node.fn_var_type = sym.info.value_type
1806 } else {
1807 c.error('cannot call the value of the map, it is not a function', node.pos)
1808 }
1809 } else if sym.info is ast.ArrayFixed {
1810 elem_sym := c.table.sym(sym.info.elem_type)
1811 if elem_sym.info is ast.FnType {
1812 func = elem_sym.info.func
1813 found = true
1814 node.is_fn_var = true
1815 node.fn_var_type = sym.info.elem_type
1816 } else {
1817 c.error('cannot call the element of the array, it is not a function', node.pos)
1818 }
1819 }
1820 }
1821 if !found && node.left is ast.CallExpr {
1822 left := node.left as ast.CallExpr
1823 if left.return_type != 0 {
1824 sym := c.table.sym(left.return_type)
1825 if sym.info is ast.FnType {
1826 node.return_type = sym.info.func.return_type
1827 found = true
1828 func = sym.info.func
1829 }
1830 }
1831 }
1832 if !found && node.name == '' && node.left_type != 0 {
1833 left_sym := c.table.final_sym(c.unwrap_generic(node.left_type))
1834 if left_sym.info is ast.FnType {
1835 func = left_sym.info.func
1836 found = true
1837 node.is_fn_var = true
1838 node.fn_var_type = node.left_type
1839 } else if left_sym.info is ast.GenericInst {
1840 parent_sym := c.table.sym(ast.new_type(left_sym.info.parent_idx))
1841 if parent_sym.info is ast.FnType {
1842 func = parent_sym.info.func
1843 found = true
1844 node.is_fn_var = true
1845 node.fn_var_type = node.left_type
1846 }
1847 }
1848 }
1849 // already prefixed (mod.fn) or C/builtin/main
1850 if !found {
1851 if f := c.table.find_fn(fn_name) {
1852 found = true
1853 func = f
1854 unsafe { c.table.fns[fn_name].usages++ }
1855 c.mark_fn_decl_as_referenced(f.fkey())
1856 }
1857 }
1858
1859 // static method resolution
1860 if !found && node.is_static_method {
1861 if index := fn_name.index('__static__') {
1862 owner_name := fn_name#[..index]
1863 // already imported symbol (static Foo.new() in another module)
1864 for import_sym in c.file.imports.filter(it.syms.any(it.name == owner_name)) {
1865 qualified_name := '${import_sym.mod}.${fn_name}'
1866 if f := c.table.find_fn(qualified_name) {
1867 found = true
1868 func = f
1869 node.name = qualified_name
1870 unsafe { c.table.fns[qualified_name].usages++ }
1871 c.mark_fn_decl_as_referenced(f.fkey())
1872 if !c.table.register_fn_concrete_types(f.name, concrete_types) {
1873 c.need_recheck_generic_fns = true
1874 }
1875 break
1876 }
1877 }
1878 if !found {
1879 // aliased static method on current mod
1880 full_type_name := if !fn_name_has_dot {
1881 c.mod + '.' + owner_name
1882 } else {
1883 owner_name
1884 }
1885 typ := c.table.find_type(full_type_name)
1886 if typ != 0 {
1887 final_sym := c.table.final_sym(typ)
1888 // try to find the unaliased static method name
1889 orig_name := final_sym.name + fn_name#[index..]
1890 if f := c.table.find_fn(orig_name) {
1891 found = true
1892 func = f
1893 unsafe { c.table.fns[orig_name].usages++ }
1894 c.mark_fn_decl_as_referenced(f.fkey())
1895 node.name = orig_name
1896 node.left_type = typ
1897 }
1898 }
1899 }
1900 }
1901 // Enum.from_string, `mod.Enum.from_string('item')`, `Enum.from_string('item')`
1902 if !found && fn_name.ends_with('__static__from_string') {
1903 enum_name := fn_name.all_before('__static__')
1904 mut full_enum_name := if !enum_name.contains('.') {
1905 c.mod + '.' + enum_name
1906 } else {
1907 enum_name
1908 }
1909 mut idx := c.table.type_idxs[full_enum_name]
1910 if idx > 0 {
1911 // is from another mod.
1912 if enum_name.contains('.') {
1913 if !c.check_type_and_visibility(full_enum_name, idx, .enum, node.pos) {
1914 return ast.void_type
1915 }
1916 } else {
1917 if !c.check_type_sym_kind(full_enum_name, idx, .enum, node.pos) {
1918 return ast.void_type
1919 }
1920 }
1921 } else if !enum_name.contains('.') {
1922 // find from another mods.
1923 for import_sym in c.file.imports {
1924 full_enum_name = '${import_sym.mod}.${enum_name}'
1925 idx = c.table.type_idxs[full_enum_name]
1926 if idx < 1 {
1927 continue
1928 }
1929 if !c.check_type_and_visibility(full_enum_name, idx, .enum, node.pos) {
1930 return ast.void_type
1931 }
1932 break
1933 }
1934 }
1935 if idx == 0 {
1936 c.error('unknown enum `${enum_name}`', node.pos)
1937 continue_check = false
1938 return ast.void_type
1939 }
1940
1941 ret_typ := ast.idx_to_type(idx).set_flag(.option)
1942 if args_len != 1 {
1943 c.error('expected 1 argument, but got ${args_len}', node.pos)
1944 } else {
1945 node.args[0].typ = c.expr(mut node.args[0].expr)
1946 if node.args[0].typ != ast.string_type {
1947 styp := c.table.type_to_str(node.args[0].typ)
1948 c.error('expected `string` argument, but got `${styp}`', node.pos)
1949 }
1950 }
1951 node.return_type = ret_typ
1952 return ret_typ
1953 }
1954 }
1955 if !found && c.pref.is_vsh {
1956 // TODO: test this hack more extensively
1957 os_name := 'os.${fn_name}'
1958 if f := c.table.find_fn(os_name) {
1959 if f.generic_names.len == node.concrete_types.len {
1960 node_alias_name := fkey
1961 mut existing := c.table.fn_generic_types[os_name] or { [] }
1962 existing << c.table.fn_generic_types[node_alias_name]
1963 existing << node.concrete_types
1964 c.table.fn_generic_types[os_name] = existing
1965 }
1966 node.name = os_name
1967 found = true
1968 func = f
1969 unsafe { c.table.fns[os_name].usages++ }
1970 c.mark_fn_decl_as_referenced(f.fkey())
1971 }
1972 }
1973 // check for arg (var) of fn type
1974 if !found {
1975 mut typ := ast.no_type
1976 if mut obj := node.scope.find(node.name) {
1977 match mut obj {
1978 ast.GlobalField {
1979 typ = obj.typ
1980 node.is_fn_var = true
1981 node.fn_var_type = typ
1982 }
1983 ast.Var {
1984 if obj.smartcasts.len != 0 {
1985 typ = c.exposed_smartcast_type(obj.orig_type, obj.smartcasts.last(),
1986 obj.is_mut)
1987 } else {
1988 if obj.typ == 0 {
1989 if mut obj.expr is ast.IfGuardExpr {
1990 typ = c.expr(mut obj.expr.expr).clear_option_and_result()
1991 } else {
1992 typ = c.expr(mut obj.expr)
1993 }
1994 } else {
1995 typ = obj.typ
1996 }
1997 }
1998 node.is_fn_var = true
1999 node.fn_var_type = typ
2000 if typ.nr_muls() > 0 {
2001 c.error('function pointer must be undereferenced first', node.pos)
2002 }
2003 }
2004 else {}
2005 }
2006 }
2007
2008 // XTODO document
2009 if typ != 0 {
2010 if node.concrete_types.len == 0 && typ.has_flag(.generic)
2011 && c.table.cur_fn != unsafe { nil } && c.table.cur_fn.is_method
2012 && node.name == c.table.cur_fn.receiver.name
2013 && c.table.cur_fn.receiver.typ.has_flag(.generic)
2014 && c.table.cur_fn.generic_names.len == c.table.cur_concrete_types.len {
2015 if fn_typ := c.table.convert_generic_type(typ, c.table.cur_fn.generic_names,
2016 c.table.cur_concrete_types)
2017 {
2018 typ = fn_typ
2019 node.fn_var_type = fn_typ
2020 }
2021 }
2022 generic_vts := c.table.final_sym(typ)
2023 if generic_vts.info is ast.FnType {
2024 func = generic_vts.info.func
2025 found = true
2026 found_in_args = true
2027 } else if generic_vts.info is ast.GenericInst {
2028 parent_sym := c.table.sym(ast.new_type(generic_vts.info.parent_idx))
2029 if parent_sym.info is ast.FnType {
2030 func = parent_sym.info.func
2031 found = true
2032 found_in_args = true
2033 }
2034 } else {
2035 vts := c.table.sym(c.unwrap_generic(typ))
2036 if vts.info is ast.FnType {
2037 func = vts.info.func
2038 found = true
2039 found_in_args = true
2040 } else if vts.info is ast.GenericInst {
2041 parent_sym := c.table.sym(ast.new_type(vts.info.parent_idx))
2042 if parent_sym.info is ast.FnType {
2043 func = parent_sym.info.func
2044 found = true
2045 found_in_args = true
2046 }
2047 }
2048 }
2049 }
2050 }
2051 // global fn?
2052 if !found {
2053 if obj := c.file.global_scope.find(fn_name) {
2054 if obj.typ != 0 {
2055 sym := c.table.sym(obj.typ)
2056 if sym.info is ast.FnType {
2057 func = sym.info.func
2058 found = true
2059 }
2060 }
2061 }
2062 }
2063 // a same module constant?
2064 if !found {
2065 // allow for `const abc = myfunc`, then calling `abc()`
2066 qualified_const_name := if fn_name_has_dot { fn_name } else { '${c.mod}.${fn_name}' }
2067 if mut obj := c.table.global_scope.find_const(qualified_const_name) {
2068 if obj.typ == 0 {
2069 obj.typ = c.expr(mut obj.expr)
2070 }
2071 if obj.typ != 0 {
2072 sym := c.table.sym(obj.typ)
2073 if sym.info is ast.FnType {
2074 // at this point, the const metadata should be already known,
2075 // and we are sure that it is just a function
2076 unsafe { c.table.fns[qualified_const_name].usages++ }
2077 unsafe { c.table.fns[func.name].usages++ }
2078 found = true
2079 func = sym.info.func
2080 node.is_fn_a_const = true
2081 node.fn_var_type = obj.typ
2082 node.const_name = qualified_const_name
2083 c.mark_const_decl_as_referenced(qualified_const_name)
2084 }
2085 }
2086 }
2087 }
2088
2089 if !found {
2090 if typ := c.try_resolve_c_type_cast_call(mut node) {
2091 return typ
2092 }
2093 if c.resolve_self_method_call(mut node) {
2094 return c.method_call(mut node, mut continue_check)
2095 }
2096 continue_check = false
2097 if dot_index := fn_name.index('.') {
2098 if !fn_name[0].is_capital() {
2099 mod_name := fn_name#[..dot_index]
2100 mut mod_func_names := []string{}
2101 for ctfnk, ctfnv in c.table.fns {
2102 if ctfnv.is_pub && ctfnk.starts_with(mod_name) {
2103 mod_func_names << ctfnk
2104 }
2105 }
2106 suggestion := util.new_suggestion(fn_name, mod_func_names)
2107 c.error(suggestion.say('unknown function: ${fn_name} '), node.pos)
2108 return ast.void_type
2109 }
2110 }
2111 name := node.get_name()
2112 if c.pref.experimental && name.starts_with('C.') {
2113 println('unknown function ${name}, ' +
2114 'searching for the C definition in one of the #includes')
2115 mut includes := []string{cap: 5}
2116 for stmt in c.file.stmts {
2117 if stmt is ast.HashStmt {
2118 if stmt.kind == 'include' {
2119 includes << '#include ${stmt.main}'
2120 }
2121 }
2122 }
2123 mut tmp_c_file_with_includes := os.create('tmp.c') or { panic(err) }
2124 tmp_c_file_with_includes.write_string(includes.join('\n')) or { panic(err) }
2125 tmp_c_file_with_includes.close()
2126
2127 os.execute('${os.quoted_path(@VEXE)} translate fndef ${name[2..]} tmp.c')
2128 x := os.read_file('__cdefs_autogen.v') or {
2129 for mut arg in node.args {
2130 c.expr(mut arg.expr)
2131 }
2132 return ast.void_type
2133 }
2134 if x.contains('fn ${name}') {
2135 println(
2136 'function definition for ${name} has been generated in __cdefs_autogen.v. ' +
2137 'Please re-run the compilation with `v .` or `v run .`')
2138 os.rm('tmp.c') or {}
2139 exit(0)
2140 } else {
2141 println('Failed to generate function definition. Please report it via github.com/vlang/v/issues')
2142 }
2143 os.rm('tmp.c') or {}
2144 }
2145 for mut arg in node.args {
2146 c.expr(mut arg.expr)
2147 }
2148 c.error('unknown function: ${node.get_name()}', node.pos)
2149 return ast.void_type
2150 }
2151
2152 node.is_file_translated = func.is_file_translated
2153 node.is_noreturn = func.is_noreturn
2154 node.is_expand_simple_interpolation = func.is_expand_simple_interpolation
2155 node.is_ctor_new = func.is_ctor_new
2156 if node.is_fn_var && node.concrete_types.len > 0 && func.generic_names.len == 0 {
2157 if node.raw_concrete_types.len == 0 {
2158 node.raw_concrete_types = node.concrete_types.clone()
2159 }
2160 node.concrete_types = []
2161 }
2162 if !found_in_args {
2163 if node.scope.known_var(fn_name) {
2164 c.error('ambiguous call to: `${fn_name}`, may refer to fn `${fn_name}` or variable `${fn_name}`',
2165 node.pos)
2166 }
2167 }
2168 if !func.is_pub && func.language == .v && func.name != '' && func.mod.len > 0
2169 && func.mod != c.mod && !c.pref.is_test {
2170 c.error('function `${func.name}` is private', node.pos)
2171 }
2172 if c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.is_deprecated && func.is_deprecated {
2173 c.deprecate('function', func.name, func.attrs, node.pos)
2174 }
2175 if func.is_unsafe && !c.inside_unsafe
2176 && (func.language != .c || (func.name[2] in [`m`, `s`] && func.mod == 'builtin')) {
2177 // builtin C.m*, C.s* only - temp
2178 if !c.pref.translated && !c.file.is_translated {
2179 c.warn('function `${func.name}` must be called from an `unsafe` block', node.pos)
2180 }
2181 }
2182 node.is_keep_alive = func.is_keep_alive
2183 if func.language == .v && func.no_body && !c.pref.translated && !c.file.is_translated
2184 && !func.is_unsafe && !func.is_file_translated && func.mod != 'builtin' {
2185 c.error('cannot call a function that does not have a body', node.pos)
2186 }
2187 if node.concrete_types.len > 0 && func.generic_names.len > 0
2188 && node.concrete_types.len != func.generic_names.len {
2189 plural := if func.generic_names.len == 1 { '' } else { 's' }
2190 c.error('expected ${func.generic_names.len} generic parameter${plural}, got ${node.concrete_types.len}',
2191 node.concrete_list_pos)
2192 }
2193 for concrete_type in node.concrete_types {
2194 c.ensure_type_exists(concrete_type, node.concrete_list_pos)
2195 }
2196 if func.generic_names.len > 0 && args_len == 0 && node.concrete_types.len == 0 {
2197 c.error('no argument generic function must add concrete types, e.g. foo[int]()', node.pos)
2198 return func.return_type
2199 }
2200 if func.return_type == ast.void_type && func.is_conditional
2201 && func.ctdefine_idx != ast.invalid_type_idx {
2202 node.should_be_skipped =
2203 c.evaluate_once_comptime_if_attribute(mut func.attrs[func.ctdefine_idx])
2204 }
2205 if node.kind == .free && func.mod == 'builtin' && args_len == 1
2206 && c.table.cur_fn != unsafe { nil } && c.table.cur_fn.is_method
2207 && c.table.cur_fn.short_name != 'free' && !c.is_builtin_mod && !c.inside_recheck {
2208 if node.args[0].expr is ast.Ident {
2209 if node.args[0].expr.name == c.table.cur_fn.receiver.name {
2210 receiver_sym := c.table.sym(c.table.cur_fn.receiver.typ)
2211 if !receiver_sym.is_heap() {
2212 c.warn('calling builtin `free()` on a method receiver will cause a' +
2213 ' runtime crash when the receiver is stack-allocated; free individual fields instead',
2214 node.pos)
2215 }
2216 }
2217 }
2218 }
2219
2220 // dont check number of args for JS functions since arguments are not required
2221 if node.language != .js {
2222 for i, mut call_arg in node.args {
2223 is_call_expr := call_arg.expr is ast.CallExpr
2224 if is_call_expr {
2225 mut arg_expr := call_arg.expr
2226 node.args[i].typ = c.expr(mut arg_expr)
2227 call_arg.expr = arg_expr
2228 } else if mut call_arg.expr is ast.LambdaExpr {
2229 if node.concrete_types.len > 0 {
2230 call_arg.expr.call_ctx = unsafe { node }
2231 }
2232 }
2233 }
2234 c.check_expected_arg_count(mut node, func) or {
2235 node.return_type = func.return_type
2236 return func.return_type
2237 }
2238 args_len = node.args.len
2239 }
2240 // println / eprintln / panic can print anything
2241 if args_len > 0 && fn_name in print_everything_fns && func.mod == 'builtin' {
2242 node.args[0].ct_expr = c.comptime.is_comptime(node.args[0].expr)
2243 c.builtin_args(mut node, fn_name, func)
2244 c.markused_print_call(mut node)
2245 return func.return_type
2246 }
2247 // `return error(err)` -> `return err`
2248 if args_len == 1 && node.kind == .error {
2249 mut arg := node.args[0]
2250 node.args[0].typ = c.expr(mut arg.expr)
2251 node.args[0].ct_expr = c.comptime.is_comptime(node.args[0].expr)
2252 if node.args[0].typ == ast.error_type {
2253 c.warn('`error(${arg})` can be shortened to just `${arg}`', node.pos)
2254 }
2255 }
2256 c.set_node_expected_arg_types(mut node, func)
2257 if !c.is_js_backend && args_len > 0 && func.params.len == 0 {
2258 c.error('too many arguments in call to `${func.name}` (non-js backend: ${c.pref.backend})',
2259 node.pos)
2260 }
2261 mut has_decompose := false
2262 mut has_unresolved_generic_param := false
2263 mut nr_multi_values := 0
2264 variadic_start := variadic_call_arg_start_idx(func, false)
2265 has_typed_variadic := func.is_variadic && !func.is_c_variadic
2266 for i, mut call_arg in node.args {
2267 if func.params.len == 0 {
2268 continue
2269 }
2270 if !c.inside_recheck {
2271 call_arg.ct_expr = c.comptime.is_comptime(call_arg.expr)
2272 }
2273 if !func.is_variadic && has_decompose {
2274 c.error('cannot have parameter after array decompose', node.pos)
2275 }
2276 param_i := i + nr_multi_values
2277 mut param := call_arg_param_for_fn(func, param_i, false)
2278 if node.is_fn_var && param.typ.has_flag(.generic) && c.table.cur_fn != unsafe { nil }
2279 && c.table.cur_fn.generic_names.len > 0
2280 && c.table.cur_fn.generic_names.len == c.table.cur_concrete_types.len {
2281 mut unwrapped := param
2282 unwrapped.typ = c.table.unwrap_generic_param_type(param, c.table.cur_fn.generic_names,
2283 c.table.cur_concrete_types)
2284 param = unwrapped
2285 }
2286 param.typ = c.resolve_short_syntax_call_arg_type(call_arg, param.typ, func.generic_names,
2287 concrete_types)
2288 // registers if the arg must be passed by ref to disable auto deref args
2289 call_arg.should_be_ptr = param.typ.is_ptr() && !param.is_mut
2290 if func.is_variadic && call_arg.expr is ast.ArrayDecompose {
2291 if param_i > variadic_start {
2292 c.error('too many arguments in call to `${func.name}`', node.pos)
2293 }
2294 }
2295 has_decompose = call_arg.expr is ast.ArrayDecompose
2296 if !func.is_variadic && call_arg.expr is ast.ArrayDecompose {
2297 array_decompose_expr := call_arg.expr as ast.ArrayDecompose
2298 if array_decompose_expr.expr is ast.ArrayInit {
2299 extra_params := func.params.len - i
2300 array_init := array_decompose_expr.expr as ast.ArrayInit
2301 if array_init.exprs.len < extra_params {
2302 elem_word := if array_init.exprs.len == 1 { 'element' } else { 'elements' }
2303 verb_word := if extra_params == 1 { 'is' } else { 'are' }
2304 c.error('array decompose has ${array_init.exprs.len} ${elem_word} but ${extra_params} ${verb_word} needed for `${func.name}`',
2305 call_arg.pos)
2306 }
2307 }
2308 }
2309 already_checked := node.language != .js && call_arg.expr is ast.CallExpr
2310 if has_typed_variadic && param_i >= variadic_start {
2311 param_sym := c.table.sym(param.typ)
2312 mut expected_type := param.typ
2313 if param_sym.info is ast.Array {
2314 expected_type = param_sym.info.elem_type
2315 c.expected_type = expected_type
2316 }
2317 typ := if already_checked && mut call_arg.expr is ast.CallExpr {
2318 node.args[i].typ
2319 } else {
2320 c.expr(mut call_arg.expr)
2321 }
2322 if i == args_len - 1 {
2323 c.check_variadic_arg(call_arg.expr, typ, expected_type, param.typ, i + 1,
2324 func.name, func.is_method, func.is_variadic, args_len == 1 && i == 0,
2325 func.generic_names.len > 0, node.pos, call_arg.pos)
2326 }
2327 } else {
2328 c.expected_type = param.typ
2329 }
2330
2331 e_sym := c.table.sym(c.expected_type)
2332 if call_arg.expr is ast.MapInit && e_sym.kind == .struct {
2333 c.error('cannot initialize a struct with a map', call_arg.pos)
2334 continue
2335 } else if call_arg.expr is ast.StructInit && e_sym.kind == .map
2336 && !call_arg.expr.typ.has_flag(.generic) {
2337 c.error('cannot initialize a map with a struct', call_arg.pos)
2338 continue
2339 }
2340 mut arg_typ := c.check_expr_option_or_result_call(call_arg.expr, if already_checked {
2341 node.args[i].typ
2342 } else {
2343 c.expr(mut call_arg.expr)
2344 })
2345 arg_typ = c.maybe_wrap_index_expr_smartcast(mut call_arg.expr, arg_typ)
2346 is_struct_init_arg := call_arg.expr is ast.StructInit
2347 if is_struct_init_arg {
2348 mut arg_expr := call_arg.expr
2349 arg_typ = c.expr(mut arg_expr)
2350 }
2351 node.args[i].expr = call_arg.expr
2352 node.args[i].typ = arg_typ
2353 call_arg.typ = arg_typ
2354 if c.comptime.comptime_for_field_var != '' {
2355 if mut call_arg.expr is ast.Ident
2356 && call_arg.expr.name == c.comptime.comptime_for_field_var
2357 && call_arg.expr.obj is ast.Var {
2358 node.args[i].typ = call_arg.expr.obj.typ
2359 }
2360 }
2361 // sumtype coercion
2362 param_type_sym := c.table.sym(param.typ)
2363 if param_type_sym.kind == .placeholder {
2364 base_type := c.table.find_type(param_type_sym.ngname)
2365 if base_type != 0 {
2366 base_sym := c.table.sym(base_type)
2367 if base_sym.kind == .sum_type && base_sym.info is ast.SumType {
2368 base_info := base_sym.info as ast.SumType
2369 arg_typ_sym := c.table.sym(arg_typ)
2370 for variant in base_info.variants {
2371 variant_sym := c.table.sym(variant)
2372 variant_base_name := variant_sym.ngname
2373 if variant_base_name == arg_typ_sym.ngname {
2374 node.args[i].expr = ast.CastExpr{
2375 expr: call_arg.expr
2376 typ: param.typ
2377 typname: c.table.type_to_str(param.typ)
2378 pos: call_arg.expr.pos()
2379 }
2380 node.args[i].typ = param.typ
2381 arg_typ = param.typ
2382 break
2383 }
2384 }
2385 }
2386 }
2387 }
2388 if param_type_sym.kind == .sum_type
2389 && !c.table.sumtype_has_variant(param.typ, arg_typ, false)
2390 && c.table.sumtype_has_variant_recursive(param.typ, arg_typ, false) {
2391 call_arg.expr = ast.CastExpr{
2392 expr: call_arg.expr
2393 typ: param.typ
2394 typname: c.table.type_to_str(param.typ)
2395 expr_type: arg_typ
2396 pos: call_arg.expr.pos()
2397 }
2398 call_arg.typ = param.typ
2399 node.args[i].expr = call_arg.expr
2400 node.args[i].typ = param.typ
2401 arg_typ = param.typ
2402 }
2403 mut arg_typ_sym := c.table.sym(arg_typ)
2404 if param.typ.has_flag(.generic) {
2405 if arg_typ_sym.kind == .none && !param.typ.has_flag(.option) {
2406 c.error('cannot use `none` as generic argument', call_arg.pos)
2407 }
2408 has_unresolved_generic_param = c.check_unresolved_generic_param(node, call_arg)
2409 || has_unresolved_generic_param
2410 }
2411 param_typ_sym := c.table.sym(param.typ)
2412 if has_typed_variadic && arg_typ.has_flag(.variadic) && args_len - 1 > i {
2413 c.error('when forwarding a variadic variable, it must be the final argument',
2414 call_arg.pos)
2415 }
2416 arg_share := param.typ.share()
2417 if arg_share == .shared_t && (c.locked_names.len > 0 || c.rlocked_names.len > 0) {
2418 c.error('function with `shared` arguments cannot be called inside `lock`/`rlock` block',
2419 call_arg.pos)
2420 }
2421 call_arg = c.implicit_mut_call_arg(param, call_arg)
2422 node.args[i] = call_arg
2423 if call_arg.is_mut {
2424 to_lock, pos := c.fail_if_immutable(mut call_arg.expr)
2425 call_arg_expr_pos := call_arg.expr.pos()
2426 if !call_arg.expr.is_lvalue() {
2427 if call_arg.expr is ast.StructInit {
2428 c.error('cannot pass a struct initialization as `mut`, you may want to use a variable `mut var := ${ast.Expr(call_arg.expr)}`',
2429 call_arg_expr_pos)
2430 } else {
2431 c.error('cannot pass expression as `mut`', call_arg_expr_pos)
2432 }
2433 }
2434 if !param.is_mut {
2435 tok := call_arg.share.str()
2436 c.error('`${node.name}` parameter `${param.name}` is not `${tok}`, `${tok}` is not needed`',
2437 call_arg.expr.pos())
2438 } else {
2439 if param.typ.share() != call_arg.share {
2440 c.error('wrong shared type `${call_arg.share.str()}`, expected: `${param.typ.share().str()}`',
2441 call_arg.expr.pos())
2442 }
2443 if to_lock != '' && !param.typ.has_flag(.shared_f) {
2444 c.error('${to_lock} is `shared` and must be `lock`ed to be passed as `mut`',
2445 pos)
2446 }
2447 }
2448 } else {
2449 if param.is_mut {
2450 tok := param.specifier()
2451 param_sym := c.table.sym(param.typ)
2452 if !(param_sym.info is ast.Struct && param_sym.info.attrs.any(it.name == 'params')) {
2453 c.error('function `${node.name}` parameter `${param.name}` is `${tok}`, so use `${tok} ${call_arg.expr}` instead',
2454 call_arg.expr.pos())
2455 }
2456 } else {
2457 c.fail_if_unreadable(call_arg.expr, arg_typ, 'argument')
2458 }
2459 }
2460 array_param_typ := if func.generic_names.len > 0 && concrete_types.len > 0 {
2461 c.table.convert_generic_param_type(param, func.generic_names, concrete_types) or {
2462 param.typ
2463 }
2464 } else {
2465 param.typ
2466 }
2467 arg_typ = c.lower_fixed_array_call_arg_to_array(mut call_arg, array_param_typ,
2468 node.language)
2469 node.args[i] = call_arg
2470 node.args[i].typ = arg_typ
2471 arg_typ_sym = c.table.sym(arg_typ)
2472 mut final_param_sym := unsafe { param_typ_sym }
2473 mut final_param_typ := param.typ
2474 if has_typed_variadic && param_typ_sym.info is ast.Array {
2475 final_param_typ = param_typ_sym.info.elem_type
2476 final_param_sym = c.table.sym(final_param_typ)
2477 }
2478 // Note: Casting to voidptr is used as an escape mechanism, so:
2479 // 1. allow passing *explicit* voidptr (native or through cast) to functions
2480 // expecting voidptr or ...voidptr
2481 // ... but 2. disallow passing non-pointers - that is very rarely what the user wanted,
2482 // it can lead to codegen errors (except for 'magic' functions like `json.encode` that,
2483 // the compiler has special codegen support for), so it should be opt in, that is it
2484 // should require an explicit voidptr(x) cast (and probably unsafe{} ?) .
2485 // V variadic ...voidptr calls are boxed in cgen, so rvalues are safe there.
2486 if call_arg.typ != param.typ && (param.typ == ast.voidptr_type
2487 || final_param_sym.idx == ast.voidptr_type_idx
2488 || param.typ == ast.nil_type || final_param_sym.idx == ast.nil_type_idx)
2489 && !call_arg.typ.is_any_kind_of_pointer() && func.language == .v
2490 && !call_arg.expr.is_lvalue() && !c.pref.translated && !c.file.is_translated
2491 && !(has_typed_variadic && final_param_sym.idx == ast.voidptr_type_idx)
2492 && !func.is_c_variadic && func.name !in ['json.encode', 'json.encode_pretty'] {
2493 c.error('expression cannot be passed as `voidptr`', call_arg.expr.pos())
2494 }
2495 // Handle expected interface
2496 mut is_generic_interface := false
2497 if final_param_sym.kind == .generic_inst {
2498 gi := final_param_sym.info
2499 if gi is ast.GenericInst {
2500 is_generic_interface = c.table.type_symbols[gi.parent_idx].kind == .interface
2501 }
2502 }
2503 if final_param_sym.kind == .interface || is_generic_interface {
2504 // For generic interface parameters, resolve the generic type to its concrete
2505 // instantiation before checking implementation.
2506 mut resolved_param_typ := final_param_typ
2507 if final_param_typ.has_flag(.generic) && func.generic_names.len > 0
2508 && node.concrete_types.len == func.generic_names.len {
2509 if t := c.table.convert_generic_type(final_param_typ, func.generic_names,
2510 node.concrete_types)
2511 {
2512 resolved_param_typ = t
2513 }
2514 }
2515 if c.type_implements_with_mut_receiver(arg_typ, resolved_param_typ,
2516 call_arg.expr.pos(), param.is_mut)
2517 {
2518 if !arg_typ.is_any_kind_of_pointer() && !c.inside_unsafe
2519 && arg_typ_sym.kind != .interface {
2520 c.mark_as_referenced(mut &call_arg.expr, true)
2521 }
2522 }
2523
2524 // For non-generic interfaces, check pointer compatibility.
2525 // For generic_inst interfaces, the param.typ may still have unresolved
2526 // generic flags, so skip the ptr check — type_implements already validated.
2527 if final_param_sym.kind == .interface && arg_typ !in [ast.voidptr_type, ast.nil_type]
2528 && !c.check_multiple_ptr_match(arg_typ, param.typ, param, call_arg) {
2529 got_typ_str, expected_typ_str := c.get_string_names_of(arg_typ, param.typ)
2530 c.error('cannot use `${got_typ_str}` as `${expected_typ_str}` in argument ${i + 1} to `${fn_name}`',
2531 call_arg.pos)
2532 }
2533 if call_arg.expr is ast.ArrayDecompose && arg_typ.idx() != final_param_typ.idx()
2534 && c.table.cur_concrete_types.len == 0 {
2535 expected_type_str := c.table.type_to_str(param.typ)
2536 got_type_str := c.table.type_to_str(arg_typ)
2537 c.error('cannot use `${got_type_str}` as `${expected_type_str}` in argument ${i + 1} to `${fn_name}`',
2538 call_arg.pos)
2539 }
2540 continue
2541 }
2542 if !c.inside_unsafe && !param.is_mut && node.language == .v
2543 && c.is_nocopy_struct(final_param_typ) {
2544 c.error('cannot pass @[nocopy] struct by value: use a reference instead', call_arg.pos)
2545 }
2546 if param.typ.is_ptr() && !param.is_mut && !call_arg.typ.is_any_kind_of_pointer()
2547 && call_arg.expr.is_literal() && func.language == .v && !c.pref.translated {
2548 c.error('literal argument cannot be passed as reference parameter `${c.table.type_to_str(param.typ)}`',
2549 call_arg.pos)
2550 }
2551 c.check_expected_call_arg(arg_typ, c.unwrap_generic(param.typ), node.language, call_arg) or {
2552 if param.typ.has_flag(.generic) {
2553 continue
2554 }
2555 // When decomposing a generic variadic arg into a non-variadic function,
2556 // each generic instantiation re-checks all branches (e.g. match arms),
2557 // so the decomposed type may not match the target param type for
2558 // unreachable branches. Skip the error in this case.
2559 if has_decompose && call_arg.expr is ast.ArrayDecompose
2560 && c.table.cur_concrete_types.len > 0 {
2561 continue
2562 }
2563 if param_typ_sym.info is ast.Array && arg_typ_sym.info is ast.Array {
2564 param_elem_type := c.table.unaliased_type(param_typ_sym.info.elem_type)
2565 arg_elem_type := c.table.unaliased_type(arg_typ_sym.info.elem_type)
2566 param_nr_muls := param.typ.nr_muls()
2567 arg_nr_muls := if call_arg.is_mut {
2568 arg_typ.nr_muls() + 1
2569 } else {
2570 arg_typ.nr_muls()
2571 }
2572 if param_nr_muls == arg_nr_muls
2573 && param_typ_sym.info.nr_dims == arg_typ_sym.info.nr_dims
2574 && param_elem_type == arg_elem_type {
2575 continue
2576 }
2577 } else if arg_typ_sym.info is ast.MultiReturn {
2578 arg_typs := arg_typ_sym.info.types
2579 if !(has_typed_variadic && param_i >= variadic_start) {
2580 if arg_typ_sym.info.types.len > func.params.len {
2581 c.error('trying to pass ${arg_typ_sym.info.types.len} argument(s), but function expects ${func.params.len} argument(s)',
2582 node.pos)
2583 continue_check = false
2584 return ast.void_type
2585 }
2586 }
2587 if !func.is_variadic && func.params.len < (param_i + arg_typ_sym.info.types.len) {
2588 c.fn_call_error_have_want(
2589 nr_params: func.params.len
2590 nr_args: param_i + arg_typ_sym.info.types.len
2591 params: func.params
2592 args: node.args
2593 pos: node.pos
2594 )
2595 return ast.void_type
2596 }
2597 out: for n in 0 .. arg_typ_sym.info.types.len {
2598 curr_arg := arg_typs[n]
2599 multi_param := call_arg_param_for_fn(func, n + param_i, false)
2600 c.check_expected_call_arg(curr_arg, c.unwrap_generic(multi_param.typ),
2601 node.language, call_arg) or {
2602 c.error('${err.msg()} in argument ${param_i + n + 1} to `${fn_name}` from ${c.table.type_to_str(arg_typ)}',
2603 call_arg.pos)
2604 continue out
2605 }
2606 }
2607 nr_multi_values += arg_typ_sym.info.types.len - 1
2608 continue
2609 } else if param_typ_sym.info is ast.Struct && arg_typ_sym.info is ast.Struct
2610 && param_typ_sym.info.is_anon {
2611 if c.is_anon_struct_compatible(param_typ_sym.info, arg_typ_sym.info) {
2612 continue
2613 }
2614 } else if c.embeds_expected_call_arg_type(arg_typ, final_param_typ) {
2615 continue
2616 }
2617 if c.pref.translated || c.file.is_translated {
2618 // in case of variadic make sure to use array elem type for checks
2619 // check_expected_call_arg already does this before checks also.
2620 param_type := if param.typ.has_flag(.variadic) {
2621 param_typ_sym.array_info().elem_type
2622 } else {
2623 param.typ
2624 }
2625 // TODO: duplicated logic in check_types() (check_types.v)
2626 // Allow enums to be used as ints and vice versa in translated code
2627 if param_type.idx() in ast.integer_type_idxs && arg_typ_sym.kind == .enum {
2628 continue
2629 }
2630 if arg_typ.idx() in ast.integer_type_idxs && param_typ_sym.kind == .enum {
2631 continue
2632 }
2633
2634 if (arg_typ == ast.bool_type && param_type.is_int())
2635 || (arg_typ.is_int() && param_type == ast.bool_type) {
2636 continue
2637 }
2638
2639 // In C unsafe number casts are used all the time (e.g. `char*` where
2640 // `int*` is expected etc), so just allow them all.
2641 mut param_is_number := c.table.unaliased_type(param_type).is_number()
2642 if param_type.is_ptr() {
2643 param_is_number = param_type.deref().is_number()
2644 }
2645 mut typ_is_number := c.table.unaliased_type(arg_typ).is_number()
2646 if arg_typ.is_ptr() {
2647 typ_is_number = arg_typ.deref().is_number()
2648 }
2649 if param_is_number && typ_is_number {
2650 continue
2651 }
2652 // Allow voidptrs for everything
2653 if param_type == ast.voidptr_type_idx || param_type == ast.nil_type_idx
2654 || arg_typ == ast.voidptr_type_idx || arg_typ == ast.nil_type_idx {
2655 continue
2656 }
2657 if param_type.is_any_kind_of_pointer() && arg_typ.is_any_kind_of_pointer() {
2658 continue
2659 }
2660 unaliased_param_sym := c.table.sym(c.table.unaliased_type(param_type))
2661 unaliased_arg_sym := c.table.sym(c.table.unaliased_type(arg_typ))
2662 // Allow `[32]i8` as `&i8` etc
2663 if ((unaliased_arg_sym.kind == .array_fixed || unaliased_arg_sym.kind == .array)
2664 && (param_is_number
2665 || c.table.unaliased_type(param_type).is_any_kind_of_pointer()))
2666 || ((unaliased_param_sym.kind == .array_fixed
2667 || unaliased_param_sym.kind == .array)
2668 && (typ_is_number || c.table.unaliased_type(arg_typ).is_any_kind_of_pointer())) {
2669 continue
2670 }
2671 // Allow `[N]anyptr` as `[N]anyptr`
2672 if unaliased_arg_sym.info is ast.Array && unaliased_param_sym.info is ast.Array {
2673 if unaliased_arg_sym.info.elem_type.is_any_kind_of_pointer()
2674 && unaliased_param_sym.info.elem_type.is_any_kind_of_pointer() {
2675 continue
2676 }
2677 } else if unaliased_arg_sym.info is ast.ArrayFixed
2678 && unaliased_param_sym.info is ast.ArrayFixed {
2679 if unaliased_arg_sym.info.elem_type.is_any_kind_of_pointer()
2680 && unaliased_param_sym.info.elem_type.is_any_kind_of_pointer() {
2681 continue
2682 }
2683 }
2684 // Allow `int` as `&i8`
2685 if param_type.is_any_kind_of_pointer() && typ_is_number {
2686 continue
2687 }
2688 // Allow `&i8` as `int`
2689 if arg_typ.is_any_kind_of_pointer() && param_is_number {
2690 continue
2691 }
2692 }
2693 // if first_sym.name == 'VContext' && f.params[0].name == 'ctx' { // TODO use int comparison for perf
2694 //}
2695 /*
2696 if param_typ_sym.info is ast.Struct && param_typ_sym.name == 'VContext' {
2697 c.note('ok', call_arg.pos)
2698 continue
2699 }
2700 */
2701 c.error('${err.msg()} in argument ${i + nr_multi_values + 1} to `${fn_name}`',
2702 call_arg.pos)
2703 }
2704 if final_param_sym.kind == .struct && arg_typ !in [ast.voidptr_type, ast.nil_type]
2705 && !c.check_multiple_ptr_match(arg_typ, param.typ, param, call_arg) {
2706 got_typ_str, expected_typ_str := c.get_string_names_of(arg_typ, param.typ)
2707 c.error('cannot use `${got_typ_str}` as `${expected_typ_str}` in argument ${i +
2708 nr_multi_values + 1} to `${fn_name}`', call_arg.pos)
2709 }
2710 // Warn about automatic (de)referencing, which will be removed soon.
2711 if func.language != .c && !c.inside_unsafe && !(call_arg.is_mut && param.is_mut) {
2712 if arg_typ.nr_muls() != param.typ.nr_muls()
2713 && param.typ !in [ast.byteptr_type, ast.charptr_type, ast.voidptr_type, ast.nil_type]
2714 && arg_typ != ast.voidptr_type && !(!call_arg.is_mut && !param.is_mut) //&& !(!call_arg.is_mut && !param.is_mut)
2715 {
2716 c.warn('automatic referencing/dereferencing is deprecated and will be removed soon (got: ${arg_typ.nr_muls()} references, expected: ${param.typ.nr_muls()} references)',
2717 call_arg.pos)
2718 }
2719 // A special case of the check to not allow voidptr params like in the recently reported raylib
2720 // bug with fn...
2721 // fn f(p &Foo) => f(foo) -- do not allow this, force f(&foo)
2722 // if !c.is_builtin_mod
2723 else if param.typ == ast.voidptr_type && func.language == .v
2724 && arg_typ !in [ast.voidptr_type, ast.nil_type] && arg_typ.nr_muls() == 0
2725 && func.name !in ['isnil', 'ptr_str'] && !func.name.starts_with('json.')
2726 && arg_typ_sym.kind !in [.float_literal, .int_literal, .charptr, .function]
2727 && !c.is_js_backend {
2728 c.warn('automatic ${arg_typ_sym.name} referencing/dereferencing into voidptr is deprecated and will be removed soon; use `foo(&x)` instead of `foo(x)`',
2729 call_arg.pos)
2730 }
2731 }
2732 }
2733 if has_unresolved_generic_param {
2734 node.return_type = func.return_type
2735 return func.return_type
2736 }
2737 if is_json_encode {
2738 // json.encode param is set voidptr, we should bound the proper type here
2739 node.expected_arg_types = [node.args[0].typ]
2740 }
2741 if func.generic_names.len != node.concrete_types.len {
2742 // no type arguments given in call, attempt implicit instantiation
2743 c.infer_fn_generic_types(func, mut node)
2744 concrete_types = node.concrete_types.map(c.unwrap_generic(it))
2745 need_recheck, _ := c.type_resolver.resolve_fn_generic_args(c.table.cur_fn, func, mut node)
2746 if need_recheck {
2747 c.need_recheck_generic_fns = true
2748 }
2749 }
2750 if func.generic_names.len > 0 {
2751 for i, mut call_arg in node.args {
2752 param := call_arg_param_for_fn(func, i, false)
2753 if param.typ.has_flag(.generic) {
2754 if unwrap_typ := c.table.convert_generic_param_type(param, func.generic_names,
2755 concrete_types)
2756 {
2757 c.expected_type = unwrap_typ
2758 }
2759 } else {
2760 c.expected_type = param.typ
2761 }
2762 already_checked := node.language != .js && call_arg.expr is ast.CallExpr
2763 mut typ := c.check_expr_option_or_result_call(call_arg.expr, if already_checked
2764 && mut call_arg.expr is ast.CallExpr {
2765 call_arg.expr.return_type
2766 } else {
2767 c.expr(mut call_arg.expr)
2768 })
2769
2770 if param.typ.has_flag(.generic) && func.generic_names.len == node.concrete_types.len {
2771 if unwrap_typ := c.table.convert_generic_param_type(param, func.generic_names,
2772 concrete_types)
2773 {
2774 call_arg.typ = typ
2775 typ = c.lower_fixed_array_call_arg_to_array(mut call_arg, unwrap_typ,
2776 node.language)
2777 node.args[i].expr = call_arg.expr
2778 node.args[i].typ = typ
2779 utyp := c.unwrap_generic(typ)
2780 unwrap_sym := c.table.sym(unwrap_typ)
2781 if unwrap_sym.kind == .interface {
2782 if c.type_implements_with_mut_receiver(utyp, unwrap_typ,
2783 call_arg.expr.pos(), param.is_mut)
2784 {
2785 if !utyp.is_any_kind_of_pointer() && !c.inside_unsafe
2786 && c.table.sym(utyp).kind != .interface {
2787 c.mark_as_referenced(mut &call_arg.expr, true)
2788 }
2789 }
2790 continue
2791 }
2792 c.check_expected_call_arg(utyp, unwrap_typ, node.language, call_arg) or {
2793 if c.type_resolver.type_map.len > 0 {
2794 continue
2795 }
2796 if mut call_arg.expr is ast.LambdaExpr {
2797 // Calling fn is generic and lambda arg also is generic
2798 c.handle_generic_lambda_arg(node, func.generic_names, mut call_arg.expr)
2799 continue
2800 }
2801 if mut call_arg.expr is ast.AnonFn {
2802 c.handle_generic_anon_fn_arg(node, func.generic_names, mut
2803 call_arg.expr)
2804 }
2805 if c.is_optional_array_arg_compatible(utyp, unwrap_typ) {
2806 continue
2807 }
2808 c.error('${err.msg()} in argument ${i + 1} to `${fn_name}`', call_arg.pos)
2809 }
2810 // When check succeeds (e.g. after lambda re-check with concrete types),
2811 // still set call_ctx on lambda args for generic context in cgen:
2812 if mut call_arg.expr is ast.LambdaExpr {
2813 c.handle_generic_lambda_arg(node, func.generic_names, mut call_arg.expr)
2814 } else if mut call_arg.expr is ast.AnonFn {
2815 c.handle_generic_anon_fn_arg(node, func.generic_names, mut call_arg.expr)
2816 }
2817 }
2818 }
2819 }
2820 if c.pref.skip_unused && node.concrete_types.len > 0 {
2821 for concrete_type in node.concrete_types {
2822 c.table.used_features.comptime_syms[c.unwrap_generic(concrete_type)] = true
2823 }
2824 }
2825 }
2826 raw_io_arg_offset := if func.is_method { 1 } else { 0 }
2827 c.check_os_raw_io_call(node, func, concrete_types, raw_io_arg_offset)
2828
2829 // resolve return generics struct to concrete type
2830 if func.generic_names.len > 0 && func.return_type.has_flag(.generic)
2831 && c.table.cur_fn != unsafe { nil } && c.needs_unwrap_generic_type(func.return_type) {
2832 node.return_type = c.table.unwrap_generic_type(func.return_type, func.generic_names,
2833 concrete_types)
2834 } else {
2835 node.return_type = func.return_type
2836 }
2837 if func.return_type.has_flag(.generic) {
2838 node.return_type_generic = func.return_type
2839 }
2840 if node.concrete_types.len > 0 && func.return_type != 0 && c.table.cur_fn != unsafe { nil }
2841 && c.table.cur_fn.generic_names.len == 0 {
2842 if typ := c.table.convert_generic_type(func.return_type, func.generic_names, concrete_types) {
2843 node.return_type = typ
2844 c.register_trace_call(node, func)
2845 if func.return_type.has_flag(.generic) {
2846 c.table.used_features.comptime_syms[typ.clear_option_and_result()] = true
2847 c.table.used_features.comptime_syms[func.return_type] = true
2848 }
2849 return typ
2850 }
2851 }
2852 if node.concrete_types.len > 0 && func.generic_names.len == 0 {
2853 c.error('a non generic function called like a generic one', node.concrete_list_pos)
2854 }
2855
2856 // resolve generic fn return type
2857 if func.generic_names.len > 0 && node.return_type != ast.void_type {
2858 ret_type := c.resolve_fn_return_type(func, node, concrete_types)
2859 c.register_trace_call(node, func)
2860 node.return_type = ret_type
2861 if ret_type.has_flag(.generic) {
2862 unwrapped_ret := c.unwrap_generic(ret_type)
2863 if c.table.sym(unwrapped_ret).kind == .multi_return {
2864 c.table.used_features.comptime_syms[unwrapped_ret] = true
2865 }
2866 }
2867 return ret_type
2868 }
2869 c.register_trace_call(node, func)
2870 return func.return_type
2871}
2872
2873// register_trace_call registers the wrapper funcs for calling funcs for callstack feature
2874fn (mut c Checker) register_trace_call(node &ast.CallExpr, func &ast.Fn) {
2875 if !(c.pref.is_callstack || c.pref.is_trace) || c.table.cur_fn == unsafe { nil }
2876 || node.language != .v {
2877 return
2878 }
2879 if node.name in ['v.debug.callstack', 'v.debug.add_after_call', 'v.debug.add_before_call',
2880 'v.debug.remove_after_call', 'v.debug.remove_before_call'] {
2881 return
2882 }
2883 if !c.file.imports.any(it.mod == 'v.debug') {
2884 return
2885 }
2886 hash_fn, fn_name := c.table.get_trace_fn_name(c.table.cur_fn, node)
2887 calling_fn := if func.is_method {
2888 '${c.table.type_to_str(c.unwrap_generic(node.left_type))}_${fn_name}'
2889 } else {
2890 fn_name
2891 }
2892 c.table.cur_fn.trace_fns[hash_fn] = ast.FnTrace{
2893 name: calling_fn
2894 file: c.file.path
2895 line: node.pos.line_nr + 1
2896 return_type: node.return_type
2897 func: &ast.Fn{
2898 ...func
2899 }
2900 is_fn_var: node.is_fn_var
2901 }
2902}
2903
2904// cast_fixed_array_ret casts a ArrayFixed type created to return to a non returning one
2905fn (mut c Checker) cast_fixed_array_ret(typ ast.Type, sym ast.TypeSymbol) ast.Type {
2906 if sym.info is ast.ArrayFixed && sym.info.is_fn_ret {
2907 return c.table.find_or_register_array_fixed(sym.info.elem_type, sym.info.size,
2908 sym.info.size_expr, false)
2909 }
2910 return typ
2911}
2912
2913// cast_to_fixed_array_ret casts a ArrayFixed type created to do not return to a returning one
2914fn (mut c Checker) cast_to_fixed_array_ret(typ ast.Type, sym ast.TypeSymbol) ast.Type {
2915 if sym.info is ast.ArrayFixed && !sym.info.is_fn_ret {
2916 return c.table.find_or_register_array_fixed(sym.info.elem_type, sym.info.size,
2917 sym.info.size_expr, true)
2918 }
2919 return typ
2920}
2921
2922// checks if a symbol kind is an expected kind
2923fn (mut c Checker) check_type_sym_kind(name string, type_idx int, expected_kind ast.Kind, pos token.Pos) bool {
2924 mut sym := c.table.sym_by_idx(type_idx)
2925 if sym.kind == .alias {
2926 parent_type := (sym.info as ast.Alias).parent_type
2927 sym = c.table.sym(parent_type)
2928 }
2929 if sym.kind != expected_kind {
2930 c.error('expected ${expected_kind}, but `${name}` is ${sym.kind}', pos)
2931 return false
2932 }
2933 return true
2934}
2935
2936// checks if a type from another module is as expected and visible(`is_pub`)
2937fn (mut c Checker) check_type_and_visibility(name string, type_idx int, expected_kind ast.Kind, pos token.Pos) bool {
2938 mut sym := c.table.sym_by_idx(type_idx)
2939 if sym.kind == .alias {
2940 parent_type := (sym.info as ast.Alias).parent_type
2941 sym = c.table.sym(parent_type)
2942 }
2943 if sym.kind != expected_kind {
2944 c.error('expected ${expected_kind}, but `${name}` is ${sym.kind}', pos)
2945 return false
2946 }
2947 if !sym.is_pub {
2948 c.error('module `${sym.mod}` type `${sym.name}` is private', pos)
2949 return false
2950 }
2951 return true
2952}
2953
2954fn (c &Checker) is_valid_os_file_struct_io_type(typ ast.Type) bool {
2955 if typ.nr_muls() > 0 || typ.has_option_or_result() {
2956 return false
2957 }
2958 mut current_typ := typ
2959 mut sym := c.table.sym(current_typ)
2960 for {
2961 if sym.info !is ast.Alias {
2962 break
2963 }
2964 alias_info := sym.info as ast.Alias
2965 current_typ = alias_info.parent_type
2966 if current_typ.nr_muls() > 0 || current_typ.has_option_or_result() {
2967 return false
2968 }
2969 sym = c.table.sym(current_typ)
2970 }
2971 return sym.kind == .struct
2972}
2973
2974fn (mut c Checker) check_os_file_struct_io_method_call(node &ast.CallExpr, method ast.Fn, concrete_types []ast.Type) {
2975 if method.name !in ['read_struct', 'read_struct_at', 'write_struct', 'write_struct_at'] {
2976 return
2977 }
2978 if method.params.len == 0 || concrete_types.len != 1 {
2979 return
2980 }
2981 receiver_sym := c.table.final_sym(method.params[0].typ)
2982 if receiver_sym.name != 'os.File' {
2983 return
2984 }
2985 concrete_type := concrete_types[0]
2986 if concrete_type.has_flag(.generic) || c.is_valid_os_file_struct_io_type(concrete_type) {
2987 return
2988 }
2989 err_pos := if node.raw_concrete_types.len > 0 {
2990 node.concrete_list_pos
2991 } else if node.args.len > 0 {
2992 node.args[0].pos
2993 } else {
2994 node.pos
2995 }
2996 c.error('`${receiver_sym.name}.${method.name}` expects a struct type, but got `${c.table.type_to_str(concrete_type)}`',
2997 err_pos)
2998}
2999
3000// is_optional_array_arg_compatible allows the generic recheck fallback for `[]?T -> []T`
3001// without also accepting `[]&T -> []T` or other pointedness mismatches.
3002fn (mut c Checker) is_optional_array_arg_compatible(got ast.Type, expected ast.Type) bool {
3003 if expected.has_flag(.variadic) {
3004 return false
3005 }
3006 if c.table.final_sym(got).kind != .array || c.table.final_sym(expected).kind != .array {
3007 return false
3008 }
3009 got_value_type := c.table.value_type(got)
3010 expected_value_type := c.table.value_type(expected)
3011 if !got_value_type.has_flag(.option) || expected_value_type.has_flag(.option) {
3012 return false
3013 }
3014 if got_value_type.nr_muls() != expected_value_type.nr_muls() {
3015 return false
3016 }
3017 return c.check_types(got_value_type.clear_flag(.option), expected_value_type)
3018}
3019
3020fn (mut c Checker) fixed_array_arg_as_array_type(got ast.Type, expected ast.Type) ast.Type {
3021 if expected.has_flag(.variadic) {
3022 return ast.no_type
3023 }
3024 got_sym := c.table.final_sym(c.unwrap_generic(got).clear_option_and_result())
3025 expected_sym :=
3026 c.table.final_sym(c.unwrap_generic(expected).clear_option_and_result().set_nr_muls(0))
3027 if got_sym.kind != .array_fixed || expected_sym.kind != .array {
3028 return ast.no_type
3029 }
3030 return ast.new_type(c.table.find_or_register_array(got_sym.array_fixed_info().elem_type))
3031}
3032
3033fn (mut c Checker) lower_fixed_array_call_arg_to_array(mut arg ast.CallArg, expected ast.Type, language ast.Language) ast.Type {
3034 array_typ := c.fixed_array_arg_as_array_type(arg.typ, expected)
3035 if array_typ == ast.no_type {
3036 return arg.typ
3037 }
3038 expected_array_typ := c.unwrap_generic(expected).clear_option_and_result().set_nr_muls(0)
3039 c.check_expected_call_arg(array_typ, expected_array_typ, language, arg) or { return arg.typ }
3040 original_expr := arg.expr
3041 arg.expr = ast.IndexExpr{
3042 pos: original_expr.pos()
3043 left: original_expr
3044 left_type: arg.typ
3045 index: ast.RangeExpr{
3046 pos: original_expr.pos()
3047 }
3048 }
3049 arg.typ = c.expr(mut arg.expr)
3050 return arg.typ
3051}
3052
3053fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool) ast.Type {
3054 // `(if true { 'foo.bar' } else { 'foo.bar.baz' }).all_after('foo.')`
3055 node.concrete_types = node.raw_concrete_types.clone()
3056 mut left_expr := node.left
3057 left_expr = left_expr.remove_par()
3058 if mut left_expr is ast.IfExpr {
3059 if left_expr.branches.len > 0 && left_expr.has_else {
3060 mut last_stmt := left_expr.branches[0].stmts.last()
3061 if mut last_stmt is ast.ExprStmt {
3062 c.expected_type = c.expr(mut last_stmt.expr)
3063 }
3064 }
3065 }
3066 left_type := node.left_type
3067 if left_type == ast.void_type {
3068 // c.error('cannot call a method using an invalid expression', node.pos)
3069 continue_check = false
3070 return ast.void_type
3071 }
3072 c.markused_method_call(mut node, mut left_expr, left_type)
3073 c.expected_type = left_type
3074 mut is_generic := left_type.has_flag(.generic)
3075 node.left_type = left_type
3076 // Set default values for .return_type & .receiver_type too,
3077 // or there will be hard tRo diagnose 0 type panics in cgen.
3078 node.return_type = left_type
3079 node.receiver_type = left_type
3080
3081 if is_generic {
3082 c.table.used_features.comptime_syms[c.unwrap_generic(left_type)] = true
3083 }
3084
3085 if c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0 {
3086 c.table.unwrap_generic_type(left_type, c.table.cur_fn.generic_names,
3087 c.table.cur_concrete_types)
3088 }
3089 unwrapped_left_type := c.unwrap_generic(left_type)
3090 left_sym := c.table.sym(unwrapped_left_type)
3091 final_left_sym := c.table.final_sym(unwrapped_left_type)
3092 mut final_left_kind := final_left_sym.kind
3093 if final_left_sym.kind == .generic_inst && final_left_sym.info is ast.GenericInst {
3094 final_left_kind = c.table.sym(ast.new_type(final_left_sym.info.parent_idx)).kind
3095 }
3096
3097 method_name := node.name
3098 if left_type.has_flag(.option) {
3099 c.error('Option type `${left_sym.name}` cannot be called directly, you should unwrap it first',
3100 node.left.pos())
3101 return ast.void_type
3102 } else if left_type.has_flag(.result) {
3103 c.error('Result type cannot be called directly', node.left.pos())
3104 return ast.void_type
3105 }
3106 if left_sym.kind in [.sum_type, .interface] {
3107 if node.kind == .type_name {
3108 return ast.string_type
3109 }
3110 if node.kind == .type_idx {
3111 return ast.int_type
3112 }
3113 }
3114 if left_type == ast.void_type {
3115 // No need to print this error, since this means that the variable is unknown,
3116 // and there already was an error before.
3117 // c.error('`void` type has no methods', node.left.pos())
3118 continue_check = false
3119 return ast.void_type
3120 }
3121 mut use_builtin_array_sort := false
3122 if final_left_sym.kind == .array && node.kind in [.sort, .sorted] && node.args.len > 0 {
3123 if method := left_sym.find_method(method_name) {
3124 use_builtin_array_sort = method.params.len == 1
3125 }
3126 }
3127 if final_left_sym.kind == .array && array_builtin_methods_chk.matches(method_name)
3128 && (!(left_sym.has_method(method_name)) || use_builtin_array_sort) {
3129 return c.array_builtin_method_call(mut node, left_type)
3130 } else if final_left_sym.kind == .array_fixed
3131 && fixed_array_builtin_methods_chk.matches(method_name) && !(left_sym.kind == .alias
3132 && left_sym.has_method(method_name)) {
3133 return c.fixed_array_builtin_method_call(mut node, left_type)
3134 } else if final_left_sym.kind == .map && node.kind in [.clone, .keys, .values, .move, .delete]
3135 && !(left_sym.kind == .alias && left_sym.has_method(method_name)) {
3136 unaliased_left_type := c.table.unaliased_type(left_type)
3137 return c.map_builtin_method_call(mut node, unaliased_left_type)
3138 } else if c.is_js_backend && left_sym.name.starts_with('Promise[') && node.kind == .wait {
3139 info := left_sym.info as ast.Struct
3140 if node.args.len > 0 {
3141 c.error('wait() does not have any arguments', node.args[0].pos)
3142 }
3143 if c.table.cur_fn != unsafe { nil } {
3144 c.table.cur_fn.has_await = true
3145 }
3146 node.return_type = info.concrete_types[0]
3147 node.return_type.set_flag(.option)
3148 return node.return_type
3149 } else if left_sym.info is ast.Thread && node.kind == .wait {
3150 if node.args.len > 0 {
3151 c.error('wait() does not have any arguments', node.args[0].pos)
3152 }
3153 node.return_type = left_sym.info.return_type
3154 return left_sym.info.return_type
3155 } else if left_sym.kind == .char && left_type.nr_muls() == 0 && node.kind == .str {
3156 c.error('calling `.str()` on type `char` is not allowed, use its address or cast it to an integer instead',
3157 node.left.pos().extend(node.pos))
3158 return ast.void_type
3159 }
3160
3161 mut unknown_method_msg := ''
3162 mut method := ast.Fn{}
3163 mut has_method := false
3164 mut is_method_from_embed := false
3165 defer {
3166 if has_method && node.is_method {
3167 c.check_must_use_call_result(node, method, 'method')
3168 }
3169 }
3170 if m := left_sym.find_method_with_generic_parent(method_name) {
3171 method = m
3172 has_method = true
3173 if left_sym.kind == .interface && m.from_embedded_type != 0 {
3174 is_method_from_embed = true
3175 node.from_embed_types = [m.from_embedded_type]
3176 }
3177 } else if m := c.table.find_method(left_sym, method_name) {
3178 method = m
3179 has_method = true
3180 if left_sym.kind == .interface && m.from_embedded_type != 0 {
3181 is_method_from_embed = true
3182 node.from_embed_types = [m.from_embedded_type]
3183 }
3184 } else {
3185 if final_left_sym.kind in [.struct, .sum_type, .interface, .array] {
3186 mut parent_type := ast.void_type
3187 match final_left_sym.info {
3188 ast.Struct, ast.SumType, ast.Interface {
3189 parent_type = final_left_sym.info.parent_type
3190 }
3191 ast.Array {
3192 typ := c.table.unaliased_type(final_left_sym.info.elem_type)
3193 parent_type = ast.idx_to_type(c.table.find_or_register_array(typ))
3194 }
3195 else {}
3196 }
3197
3198 if parent_type != 0 {
3199 type_sym := c.table.sym(parent_type)
3200 if m := c.table.find_method(type_sym, method_name) {
3201 method = m
3202 has_method = true
3203 is_generic = true
3204 if left_sym.kind == .interface && m.from_embedded_type != 0 {
3205 is_method_from_embed = true
3206 node.from_embed_types = [m.from_embedded_type]
3207 }
3208 }
3209 }
3210 }
3211 if !has_method {
3212 has_method = true
3213 mut embed_types := []ast.Type{}
3214 method, embed_types = c.table.find_method_from_embeds(final_left_sym, method_name) or {
3215 emsg := err.str()
3216 if emsg != '' {
3217 c.error(emsg, node.pos)
3218 }
3219 has_method = false
3220 ast.Fn{}, []ast.Type{}
3221 }
3222 if embed_types.len != 0 {
3223 is_method_from_embed = true
3224 node.from_embed_types = embed_types
3225 c.markused_comptime_call(node.left_type.has_flag(.generic),
3226 '${int(method.receiver_type)}.${method.name}')
3227 }
3228 }
3229 if final_left_sym.kind == .aggregate {
3230 // the error message contains the problematic type
3231 unknown_method_msg = err.msg()
3232 if unknown_method_msg == 'unknown method' {
3233 unknown_method_msg += ' `' + method_name + '`'
3234 }
3235 }
3236 }
3237
3238 if !has_method {
3239 // TODO: str methods
3240 if node.kind == .str {
3241 if left_sym.kind == .interface {
3242 iname := left_sym.name
3243 c.error('interface `${iname}` does not have a .str() method. Use typeof() instead',
3244 node.pos)
3245 }
3246 if c.fail_if_private_implicit_str(left_type, node.pos,
3247 'call auto-generated `.str()` on')
3248 {
3249 return ast.string_type
3250 }
3251 node.receiver_type = left_type.clear_ref()
3252 node.return_type = ast.string_type
3253 if node.args.len > 0 {
3254 c.error('.str() method calls should have no arguments', node.pos)
3255 }
3256 c.fail_if_unreadable(node.left, left_type, 'receiver')
3257 if !c.is_builtin_mod {
3258 c.table.used_features.auto_str = true
3259 }
3260 return ast.string_type
3261 } else if node.kind == .free {
3262 if !c.is_builtin_mod && !c.inside_unsafe && !method.is_unsafe {
3263 c.warn('manual memory management with `free()` is only allowed in unsafe code',
3264 node.pos)
3265 }
3266 if left_sym.kind == .array_fixed {
3267 name := left_sym.symbol_name_except_generic().replace_each(['<', '[', '>', ']'])
3268 c.error('unknown method or field: ${name}.free()', node.pos)
3269 }
3270 return ast.void_type
3271 }
3272 // call struct field fn type
3273 // TODO: can we use SelectorExpr for all? this dosent really belong here
3274 if field := c.table.find_field_with_embeds(left_sym, method_name) {
3275 mut field_typ := field.typ
3276 if left_sym.info is ast.Struct && left_sym.info.generic_types.len > 0
3277 && left_sym.info.generic_types.len == left_sym.info.concrete_types.len {
3278 generic_names := c.table.get_generic_names(left_sym.info.generic_types)
3279 if resolved_typ := c.table.convert_generic_type(field_typ, generic_names,
3280 left_sym.info.concrete_types)
3281 {
3282 field_typ = resolved_typ
3283 }
3284 }
3285 if field_typ.has_flag(.option) {
3286 // unwrapped callback (if f.func != none {})
3287 scope_field := node.scope.find_struct_field(node.left.str(), node.left_type,
3288 method_name)
3289 if scope_field != unsafe { nil } {
3290 field_typ = c.exposed_smartcast_type(scope_field.orig_type,
3291 scope_field.smartcasts.last(), scope_field.is_mut)
3292 node.is_unwrapped_fn_selector = true
3293 } else {
3294 c.error('Option function field must be unwrapped first', node.pos)
3295 }
3296 }
3297 field_sym := c.table.sym(c.unwrap_generic(field_typ))
3298 if field_sym.kind == .function {
3299 node.is_method = false
3300 node.is_field = true
3301 info := field_sym.info as ast.FnType
3302 c.check_expected_arg_count(mut node, info.func) or {
3303 node.return_type = info.func.return_type
3304 if info.func.return_type.has_flag(.generic) {
3305 node.return_type_generic = info.func.return_type
3306 }
3307 return info.func.return_type
3308 }
3309 match left_sym.info {
3310 ast.Struct, ast.Interface, ast.SumType {
3311 if left_sym.info.parent_type != 0 {
3312 parent_sym := c.table.sym(left_sym.info.parent_type)
3313 if generic_field := c.table.find_field_with_embeds(parent_sym,
3314 method_name)
3315 {
3316 generic_field_sym := c.table.sym(generic_field.typ)
3317 if generic_field_sym.info is ast.FnType {
3318 generic_ret := generic_field_sym.info.func.return_type
3319 if generic_ret.has_flag(.generic) {
3320 node.return_type_generic = generic_ret
3321 }
3322 }
3323 }
3324 }
3325 }
3326 else {}
3327 }
3328
3329 node.return_type = info.func.return_type
3330 if info.func.return_type.has_flag(.generic) {
3331 node.return_type_generic = info.func.return_type
3332 }
3333 mut earg_types := []ast.Type{}
3334
3335 for i, mut arg in node.args {
3336 targ := c.check_expr_option_or_result_call(arg.expr, c.expr(mut arg.expr))
3337 arg.typ = targ
3338
3339 param := call_arg_param_for_fn(info.func, i, false)
3340 // registers if the arg must be passed by ref to disable auto deref args
3341 arg.should_be_ptr = param.typ.is_ptr() && !param.is_mut
3342 if c.table.sym(param.typ).kind == .interface {
3343 // cannot hide interface expected type to make possible to pass its interface type automatically
3344 earg_types << if targ.idx() != param.typ.idx() { param.typ } else { targ }
3345 } else {
3346 earg_types << param.typ
3347 }
3348 param_share := param.typ.share()
3349 if param_share == .shared_t
3350 && (c.locked_names.len > 0 || c.rlocked_names.len > 0) {
3351 c.error('method with `shared` arguments cannot be called inside `lock`/`rlock` block',
3352 arg.pos)
3353 }
3354 arg = c.implicit_mut_call_arg(param, arg)
3355 node.args[i] = arg
3356 if arg.is_mut {
3357 to_lock, pos := c.fail_if_immutable(mut arg.expr)
3358 if !param.is_mut {
3359 tok := arg.share.str()
3360 c.error('`${node.name}` parameter ${i + 1} is not `${tok}`, `${tok}` is not needed`',
3361 arg.expr.pos())
3362 } else {
3363 if param_share != arg.share {
3364 c.error('wrong shared type `${arg.share.str()}`, expected: `${param_share.str()}`',
3365 arg.expr.pos())
3366 }
3367 if to_lock != '' && param_share != .shared_t {
3368 c.error('${to_lock} is `shared` and must be `lock`ed to be passed as `mut`',
3369 pos)
3370 }
3371 }
3372 } else {
3373 if param.is_mut {
3374 tok := param.specifier()
3375 c.error('method `${node.name}` parameter ${i + 1} is `${tok}`, so use `${tok} ${arg.expr}` instead',
3376 arg.expr.pos())
3377 } else {
3378 c.fail_if_unreadable(arg.expr, targ, 'argument')
3379 }
3380 }
3381
3382 if i < info.func.params.len {
3383 exp_arg_typ := info.func.params[i].typ
3384 c.check_expected_call_arg(targ, c.unwrap_generic(exp_arg_typ),
3385 node.language, arg) or {
3386 if targ != ast.void_type {
3387 c.error('${err.msg()} in argument ${i + 1} to `${left_sym.name}.${method_name}`',
3388 arg.pos)
3389 }
3390 }
3391 }
3392 }
3393 node.expected_arg_types = earg_types
3394 node.is_method = true
3395 _, node.from_embed_types = c.table.find_field_from_embeds(left_sym, method_name) or {
3396 return info.func.return_type
3397 }
3398 return info.func.return_type
3399 }
3400 }
3401 if left_sym.kind in [.struct, .aggregate, .interface, .sum_type] {
3402 if c.smartcast_mut_pos != token.Pos{} && !c.implicit_mutability_enabled() {
3403 c.note('smartcasting requires either an immutable value, or an explicit mut keyword before the value',
3404 c.smartcast_mut_pos)
3405 }
3406 if c.smartcast_cond_pos != token.Pos{} {
3407 c.note('smartcast can only be used on ident, selector or index expressions, e.g. match foo, match foo.bar, match foo[0]',
3408 c.smartcast_cond_pos)
3409 }
3410 }
3411 if left_type != ast.void_type {
3412 suggestion := util.new_suggestion(method_name, left_sym.methods.map(it.name))
3413 if unknown_method_msg == '' {
3414 if field := c.table.find_field(left_sym, method_name) {
3415 unknown_method_msg = 'unknown method `${field.name}` did you mean to access the field with the same name instead?'
3416 } else {
3417 mut sname := left_sym.symbol_name_except_generic()
3418 match left_sym.info {
3419 ast.Struct, ast.Interface, ast.SumType {
3420 if left_sym.info.concrete_types.len > 0
3421 && left_sym.info.parent_type.has_flag(.generic) {
3422 sname =
3423 c.table.sym(left_sym.info.parent_type).symbol_name_except_generic()
3424 }
3425 }
3426 else {}
3427 }
3428
3429 if left_sym.generic_types.len > 0 {
3430 generic_names := left_sym.generic_types.map(c.table.sym(it).name).join(', ')
3431 sname = '${left_sym.ngname}<${generic_names}>'
3432 }
3433 name := sname.replace_each(['<', '[', '>', ']'])
3434 unknown_method_msg = 'unknown method or field: `${name}.${method_name}`'
3435 }
3436 }
3437 c.error(suggestion.say(unknown_method_msg), node.pos)
3438 }
3439 return ast.void_type
3440 }
3441 c.mark_fn_decl_as_referenced(method.fkey())
3442
3443 // x is Bar[T], x.foo() -> x.foo[T]()
3444 rec_sym := if is_method_from_embed {
3445 c.table.final_sym(node.from_embed_types.last())
3446 } else {
3447 c.table.final_sym(node.left_type)
3448 }
3449 rec_is_generic := if is_method_from_embed {
3450 node.from_embed_types.last().has_flag(.generic)
3451 } else {
3452 left_type.has_flag(.generic)
3453 }
3454 mut rec_concrete_types := []ast.Type{}
3455 mut method_generic_names_len := method.generic_names.len
3456 match rec_sym.info {
3457 ast.Struct, ast.SumType, ast.Interface {
3458 receiver_generic_names := rec_sym.info.generic_types.map(c.table.sym(it).name)
3459 receiver_generics_in_method := receiver_generic_names.len > 0
3460 && method.generic_names.len >= receiver_generic_names.len
3461 && method.generic_names[..receiver_generic_names.len] == receiver_generic_names
3462 if rec_sym.info.concrete_types.len > 0 {
3463 rec_concrete_types = rec_sym.info.concrete_types.clone()
3464 }
3465 concrete_types_len := node.concrete_types.len
3466 if rec_is_generic && concrete_types_len == 0 && receiver_generics_in_method {
3467 node.concrete_types = rec_sym.info.generic_types
3468 } else if rec_is_generic && concrete_types_len > 0 && receiver_generics_in_method
3469 && method_generic_names_len > concrete_types_len
3470 && rec_sym.info.generic_types.len + concrete_types_len == method_generic_names_len {
3471 t_concrete_types := node.concrete_types.clone()
3472 node.concrete_types = rec_sym.info.generic_types
3473 node.concrete_types << t_concrete_types
3474 } else if !rec_is_generic && rec_sym.info.concrete_types.len > 0
3475 && receiver_generics_in_method && concrete_types_len > 0
3476 && rec_sym.info.concrete_types.len + concrete_types_len == method_generic_names_len {
3477 t_concrete_types := node.concrete_types.clone()
3478 node.concrete_types = rec_sym.info.concrete_types
3479 node.concrete_types << t_concrete_types
3480 } else if !rec_is_generic && receiver_generics_in_method && rec_concrete_types.len > 0
3481 && concrete_types_len == 0 {
3482 node.concrete_types = rec_concrete_types
3483 }
3484 }
3485 ast.GenericInst {
3486 // Concrete generic instance (e.g. Vec2[f64]): resolve from parent struct
3487 parent_sym := c.table.sym(ast.new_type(rec_sym.info.parent_idx))
3488 match parent_sym.info {
3489 ast.Struct, ast.SumType, ast.Interface {
3490 receiver_generic_names :=
3491 parent_sym.info.generic_types.map(c.table.sym(it).name)
3492 receiver_generics_in_method := receiver_generic_names.len > 0
3493 && method.generic_names.len >= receiver_generic_names.len
3494 && method.generic_names[..receiver_generic_names.len] == receiver_generic_names
3495 rec_concrete_types = rec_sym.info.concrete_types.clone()
3496 concrete_types_len := node.concrete_types.len
3497 if !rec_is_generic && receiver_generics_in_method && rec_concrete_types.len > 0
3498 && concrete_types_len == 0 {
3499 node.concrete_types = rec_concrete_types
3500 } else if !rec_is_generic && receiver_generics_in_method
3501 && rec_concrete_types.len > 0 && concrete_types_len > 0
3502 && rec_concrete_types.len + concrete_types_len == method_generic_names_len {
3503 t_concrete_types := node.concrete_types.clone()
3504 node.concrete_types = rec_concrete_types
3505 node.concrete_types << t_concrete_types
3506 }
3507 }
3508 else {}
3509 }
3510 }
3511 ast.FnType {
3512 if rec_sym.parent_idx > 0 {
3513 parent_sym := c.table.sym(ast.idx_to_type(rec_sym.parent_idx))
3514 if parent_sym.info is ast.FnType {
3515 rec_concrete_types = rec_sym.generic_types.clone()
3516 if rec_concrete_types.len > 0
3517 && method_generic_names_len == rec_concrete_types.len {
3518 node.concrete_types = rec_concrete_types
3519 }
3520 }
3521 }
3522 }
3523 else {}
3524 }
3525
3526 mut concrete_types := node.concrete_types.map(c.unwrap_generic(it))
3527 if method_generic_names_len > 0 && concrete_types.len == method_generic_names_len
3528 && concrete_types.all(!it.has_flag(.generic))
3529 && c.table.register_fn_concrete_types(method.fkey(), concrete_types) {
3530 c.need_recheck_generic_fns = true
3531 }
3532 node.is_noreturn = method.is_noreturn
3533 node.is_expand_simple_interpolation = method.is_expand_simple_interpolation
3534 node.is_ctor_new = method.is_ctor_new
3535 node.return_type = method.return_type
3536 if method.return_type.has_flag(.generic) {
3537 node.return_type_generic = method.return_type
3538 }
3539 is_used_outside_receiver_module := left_sym.mod != c.mod && method.mod != c.mod
3540 if !method.is_pub && is_used_outside_receiver_module {
3541 // If a private method is called outside of the module
3542 // its receiver type is defined in, show an error.
3543 // println('warn ${method_name} lef.mod=${left_type_sym.mod} c.mod=${c.mod}')
3544 c.error('method `${left_sym.name}.${method_name}` is private', node.pos)
3545 }
3546 rec_share := method.params[0].typ.share()
3547 if rec_share == .shared_t && (c.locked_names.len > 0 || c.rlocked_names.len > 0) {
3548 c.error('method with `shared` receiver cannot be called inside `lock`/`rlock` block',
3549 node.pos)
3550 }
3551 requires_mut_receiver := method.params[0].is_mut
3552 && (!is_used_outside_receiver_module || c.fn_has_visible_mutation_for_param(method, 0))
3553 if requires_mut_receiver {
3554 to_lock, pos := c.check_for_mut_receiver(mut node.left)
3555 // node.is_mut = true
3556 if to_lock != '' && rec_share != .shared_t {
3557 c.error('${to_lock} is `shared` and must be `lock`ed to be passed as `mut`', pos)
3558 }
3559 } else {
3560 c.fail_if_unreadable(node.left, left_type, 'receiver')
3561 }
3562 if left_sym.language != .js && (!left_sym.is_builtin() && method.mod != 'builtin')
3563 && method.language == .v && final_left_kind != .interface && method.no_body {
3564 c.error('cannot call a method that does not have a body', node.pos)
3565 }
3566 if node.raw_concrete_types.len > 0 && method_generic_names_len > 0
3567 && node.concrete_types.len != method_generic_names_len {
3568 plural := if method_generic_names_len == 1 { '' } else { 's' }
3569 c.error('expected ${method_generic_names_len} generic parameter${plural}, got ${node.concrete_types.len}',
3570 node.concrete_list_pos)
3571 }
3572 for concrete_type in node.concrete_types {
3573 c.ensure_type_exists(concrete_type, node.concrete_list_pos)
3574 }
3575 if method.return_type == ast.void_type && method.is_conditional
3576 && method.ctdefine_idx != ast.invalid_type_idx {
3577 node.should_be_skipped =
3578 c.evaluate_once_comptime_if_attribute(mut method.attrs[method.ctdefine_idx])
3579 }
3580 c.check_expected_arg_count(mut node, method) or {
3581 node.return_type = method.return_type
3582 return method.return_type
3583 }
3584 mut exp_arg_typ := ast.no_type // type of 1st arg for special builtin methods
3585 mut has_unresolved_generic_param := false
3586 mut param_is_mut := false
3587 mut no_type_promotion := false
3588 if left_sym.info is ast.Chan {
3589 if node.kind == .try_push {
3590 exp_arg_typ = left_sym.info.elem_type.ref()
3591 } else if node.kind == .try_pop {
3592 exp_arg_typ = left_sym.info.elem_type
3593 param_is_mut = true
3594 no_type_promotion = true
3595 }
3596 }
3597
3598 for i, mut arg in node.args {
3599 if i > 0 || exp_arg_typ == ast.no_type {
3600 exp_arg_typ = call_arg_param_for_fn(method, i, true).typ
3601 if !c.inside_recheck {
3602 arg.ct_expr = c.comptime.is_comptime(arg.expr)
3603 }
3604 // If initialize a generic struct with short syntax,
3605 // need to get the parameter information from the original generic method
3606 if is_method_from_embed && arg.expr is ast.StructInit {
3607 expr := arg.expr as ast.StructInit
3608 is_short_syntax := expr.is_short_syntax && expr.typ == ast.void_type
3609 if is_short_syntax {
3610 embed_type := node.from_embed_types.last()
3611 embed_sym := c.table.sym(embed_type)
3612 if embed_sym.info is ast.Struct {
3613 info := embed_sym.info as ast.Struct
3614 if info.concrete_types.len > 0 {
3615 parent_type := info.parent_type
3616 parent_sym := c.table.sym(parent_type)
3617 if parent_sym.info is ast.Struct && parent_sym.info.is_generic {
3618 if f := parent_sym.find_method(method_name) {
3619 exp_arg_typ = call_arg_param_for_fn(f, i, true).typ
3620 }
3621 }
3622 }
3623 }
3624 }
3625 }
3626 param_is_mut = false
3627 no_type_promotion = false
3628 }
3629 resolved_method_concrete_types := if method_generic_names_len == rec_concrete_types.len {
3630 rec_concrete_types
3631 } else {
3632 concrete_types
3633 }
3634 mut resolved_method_generic_names := method.generic_names.clone()
3635 if resolved_method_generic_names.len == 0 {
3636 match rec_sym.info {
3637 ast.Struct, ast.Interface, ast.SumType {
3638 if rec_sym.info.generic_types.len == resolved_method_concrete_types.len {
3639 resolved_method_generic_names =
3640 rec_sym.info.generic_types.map(c.table.sym(it).name)
3641 }
3642 }
3643 else {}
3644 }
3645 }
3646 exp_arg_typ = c.resolve_short_syntax_call_arg_type(arg, exp_arg_typ,
3647 resolved_method_generic_names, resolved_method_concrete_types)
3648 exp_arg_sym := c.table.sym(exp_arg_typ)
3649 c.expected_type = exp_arg_typ
3650
3651 mut got_arg_typ := c.check_expr_option_or_result_call(arg.expr, c.expr(mut arg.expr))
3652 node.args[i].typ = got_arg_typ
3653 arg.typ = got_arg_typ
3654 if no_type_promotion {
3655 if got_arg_typ != exp_arg_typ {
3656 c.error('cannot use `${c.table.sym(got_arg_typ).name}` as argument for `${method.name}` (`${exp_arg_sym.name}` expected)',
3657 arg.pos)
3658 }
3659 }
3660 variadic_start := variadic_call_arg_start_idx(method, true)
3661 has_typed_variadic := method.is_variadic && !method.is_c_variadic
3662 if has_typed_variadic && got_arg_typ.has_flag(.variadic) && node.args.len - 1 > i {
3663 c.error('when forwarding a variadic variable, it must be the final argument', arg.pos)
3664 }
3665 mut final_arg_sym := unsafe { exp_arg_sym }
3666 mut final_arg_typ := exp_arg_typ
3667 if has_typed_variadic && exp_arg_sym.info is ast.Array {
3668 final_arg_typ = exp_arg_sym.info.elem_type
3669 final_arg_sym = c.table.sym(final_arg_typ)
3670 }
3671 param := call_arg_param_for_fn(method, i, true)
3672
3673 if method.is_variadic && arg.expr is ast.ArrayDecompose {
3674 if i > variadic_start {
3675 c.error('too many arguments in call to `${method.name}`', node.pos)
3676 }
3677 }
3678 if has_typed_variadic && i >= variadic_start {
3679 param_sym := c.table.sym(param.typ)
3680 mut expected_type := param.typ
3681 if param_sym.kind == .array {
3682 info := param_sym.array_info()
3683 expected_type = info.elem_type
3684 c.expected_type = expected_type
3685 }
3686 typ := c.expr(mut arg.expr)
3687 if i == node.args.len - 1 {
3688 c.check_variadic_arg(arg.expr, typ, expected_type, param.typ, i + 1, method.name,
3689 true, method.is_variadic, node.args.len == 1 && i == 0,
3690 method.generic_names.len > 0, node.pos, arg.pos)
3691 }
3692 } else {
3693 c.expected_type = param.typ
3694 }
3695
3696 param_is_mut = param_is_mut || param.is_mut
3697 param_share := param.typ.share()
3698 if param_share == .shared_t && (c.locked_names.len > 0 || c.rlocked_names.len > 0) {
3699 c.error('method with `shared` arguments cannot be called inside `lock`/`rlock` block',
3700 arg.pos)
3701 }
3702 arg = c.implicit_mut_call_arg(param, arg)
3703 node.args[i] = arg
3704 if arg.is_mut {
3705 to_lock, pos := c.fail_if_immutable(mut arg.expr)
3706 if !param_is_mut {
3707 tok := arg.share.str()
3708 c.error('`${node.name}` parameter `${param.name}` is not `${tok}`, `${tok}` is not needed`',
3709 arg.expr.pos())
3710 } else {
3711 if param_share != arg.share {
3712 c.error('wrong shared type `${arg.share.str()}`, expected: `${param_share.str()}`',
3713 arg.expr.pos())
3714 }
3715 if to_lock != '' && param_share != .shared_t {
3716 c.error('${to_lock} is `shared` and must be `lock`ed to be passed as `mut`',
3717 pos)
3718 }
3719 }
3720 } else {
3721 if param_is_mut {
3722 tok := if param.typ.has_flag(.shared_f) { 'shared' } else { arg.share.str() }
3723 c.error('method `${node.name}` parameter `${param.name}` is `${tok}`, so use `${tok} ${arg.expr}` instead',
3724 arg.expr.pos())
3725 } else {
3726 c.fail_if_unreadable(arg.expr, got_arg_typ, 'argument')
3727 }
3728 }
3729 if concrete_types.len > 0 && method_generic_names_len != rec_concrete_types.len {
3730 need_recheck, mut new_concrete_types := c.type_resolver.resolve_fn_generic_args(c.table.cur_fn,
3731 method, mut node)
3732 concrete_types = new_concrete_types.clone()
3733 if need_recheck {
3734 c.need_recheck_generic_fns = true
3735 }
3736 if concrete_types.len == method_generic_names_len
3737 && concrete_types.all(!it.has_flag(.generic)) {
3738 c.table.register_fn_concrete_types(method.fkey(), concrete_types)
3739 }
3740 }
3741 method_concrete_types := if method_generic_names_len == rec_concrete_types.len {
3742 rec_concrete_types
3743 } else {
3744 concrete_types
3745 }
3746 if exp_arg_typ.has_flag(.generic) {
3747 has_unresolved_generic_param = c.check_unresolved_generic_param(node, arg)
3748 || has_unresolved_generic_param
3749 if exp_utyp := c.table.convert_generic_param_type(param, method.generic_names,
3750 method_concrete_types)
3751 {
3752 exp_arg_typ = exp_utyp
3753 } else {
3754 continue
3755 }
3756 if got_arg_typ.has_flag(.generic) {
3757 if c.table.cur_fn != unsafe { nil } && c.table.cur_concrete_types.len > 0 {
3758 got_arg_typ = c.unwrap_generic(got_arg_typ)
3759 } else {
3760 if got_utyp := c.table.convert_generic_type(got_arg_typ, method.generic_names,
3761 method_concrete_types)
3762 {
3763 got_arg_typ = got_utyp
3764 } else {
3765 continue
3766 }
3767 }
3768 }
3769 }
3770 got_arg_typ = c.lower_fixed_array_call_arg_to_array(mut arg, exp_arg_typ, node.language)
3771 node.args[i] = arg
3772 node.args[i].typ = got_arg_typ
3773 // Handle expected interface
3774 if final_arg_sym.kind == .interface {
3775 if c.type_implements_with_mut_receiver(got_arg_typ, final_arg_typ, arg.expr.pos(),
3776 param.is_mut)
3777 {
3778 if !got_arg_typ.is_any_kind_of_pointer() && !c.inside_unsafe {
3779 got_arg_typ_sym := c.table.sym(got_arg_typ)
3780 if got_arg_typ_sym.kind != .interface {
3781 c.mark_as_referenced(mut &arg.expr, true)
3782 }
3783 }
3784 }
3785
3786 if got_arg_typ !in [ast.voidptr_type, ast.nil_type]
3787 && !c.check_multiple_ptr_match(got_arg_typ, param.typ, param, arg) {
3788 got_typ_str, expected_typ_str := c.get_string_names_of(got_arg_typ, param.typ)
3789 c.error('cannot use `${got_typ_str}` as `${expected_typ_str}` in argument ${i + 1} to `${method_name}`',
3790 arg.pos)
3791 }
3792 continue
3793 }
3794 if final_arg_sym.kind == .none && param.typ.has_flag(.generic)
3795 && !param.typ.has_flag(.option) {
3796 c.error('cannot use `none` as generic argument', arg.pos)
3797 }
3798 if param.typ.is_ptr() && !arg.typ.is_any_kind_of_pointer() && arg.expr.is_literal()
3799 && !c.pref.translated {
3800 c.error('literal argument cannot be passed as reference parameter `${c.table.type_to_str(param.typ)}`',
3801 arg.pos)
3802 }
3803 c.check_expected_call_arg(c.unwrap_generic(got_arg_typ), exp_arg_typ, node.language, arg) or {
3804 // str method, allow type with str method if fn arg is string
3805 // Passing an int or a string array produces a c error here
3806 // Deleting this condition results in proper V error messages
3807 // if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
3808 // continue
3809 // }
3810 param_typ_sym := c.table.sym(exp_arg_typ)
3811 arg_typ_sym := c.table.sym(got_arg_typ)
3812 if param_typ_sym.info is ast.Array && arg_typ_sym.info is ast.Array {
3813 param_elem_type := c.table.unaliased_type(param_typ_sym.info.elem_type)
3814 arg_elem_type := c.table.unaliased_type(arg_typ_sym.info.elem_type)
3815 if exp_arg_typ.nr_muls() == got_arg_typ.nr_muls()
3816 && param_typ_sym.info.nr_dims == arg_typ_sym.info.nr_dims
3817 && param_elem_type == arg_elem_type {
3818 continue
3819 }
3820 }
3821 if c.is_optional_array_arg_compatible(got_arg_typ, exp_arg_typ) {
3822 continue
3823 }
3824 receiver_name := if method.receiver_type.has_flag(.generic)
3825 && method_concrete_types.len > 0 {
3826 c.table.type_to_str(c.table.unwrap_generic_type(method.receiver_type.set_nr_muls(0),
3827 method.generic_names, method_concrete_types))
3828 } else {
3829 left_sym.name
3830 }
3831 c.error('${err.msg()} in argument ${i + 1} to `${receiver_name}.${method_name}`',
3832 arg.pos)
3833 }
3834 if mut arg.expr is ast.LambdaExpr {
3835 // Calling fn is generic and lambda arg also is generic
3836 c.handle_generic_lambda_arg(node, method.generic_names, mut arg.expr)
3837 } else if mut arg.expr is ast.AnonFn {
3838 c.handle_generic_anon_fn_arg(node, method.generic_names, mut arg.expr)
3839 }
3840 param_typ_sym := c.table.sym(exp_arg_typ)
3841 if param_typ_sym.kind == .struct && got_arg_typ !in [ast.voidptr_type, ast.nil_type]
3842 && !c.check_multiple_ptr_match(got_arg_typ, param.typ, param, arg) {
3843 got_typ_str, expected_typ_str := c.get_string_names_of(got_arg_typ, param.typ)
3844 c.error('cannot use `${got_typ_str}` as `${expected_typ_str}` in argument ${i + 1} to `${method_name}`',
3845 arg.pos)
3846 }
3847 }
3848 if has_unresolved_generic_param {
3849 return method.return_type
3850 }
3851 if method.is_unsafe && !c.inside_unsafe {
3852 if !c.pref.translated && !c.file.is_translated {
3853 c.warn('method `${left_sym.name}.${method_name}` must be called from an `unsafe` block',
3854 node.pos)
3855 }
3856 }
3857 if c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.is_deprecated && method.is_deprecated {
3858 c.deprecate('method', '${left_sym.name}.${method.name}', method.attrs, node.pos)
3859 }
3860 c.set_node_expected_arg_types(mut node, method)
3861 if is_method_from_embed {
3862 node.receiver_type = node.from_embed_types.last().derive(method.params[0].typ)
3863 } else if is_generic {
3864 // if receiver is generic, then cgen requires `receiver_type` to be T.
3865 // and the concrete type is stored in `receiver_concrete_type` below.
3866 node.receiver_type = method.params[0].typ
3867 } else {
3868 node.receiver_type = method.params[0].typ
3869 }
3870 if node.receiver_type.has_flag(.shared_f) && !node.left_type.has_flag(.shared_f) {
3871 c.error('cannot use shared method `${node.name}` as `${node.left}` is not a shared var',
3872 node.left.pos())
3873 }
3874 // if receiver_type is T, then `receiver_concrete_type` is concrete type, otherwise it is the same as `receiver_type`.
3875 node.receiver_concrete_type = if is_method_from_embed {
3876 node.from_embed_types.last().derive(method.params[0].typ)
3877 } else if is_generic {
3878 left_type.derive(method.params[0].typ).clear_flag(.generic)
3879 } else {
3880 method.params[0].typ
3881 }
3882 if left_sym.kind == .interface && is_method_from_embed && method.return_type.has_flag(.generic)
3883 && method_generic_names_len == 0 {
3884 method.generic_names =
3885 c.table.get_generic_names((rec_sym.info as ast.Interface).generic_types)
3886 method_generic_names_len = method.generic_names.len
3887 }
3888 if method_generic_names_len != node.concrete_types.len {
3889 // no type arguments given in call, attempt implicit instantiation
3890 c.infer_fn_generic_types(method, mut node)
3891 concrete_types = node.concrete_types.map(c.unwrap_generic(it))
3892 }
3893 if method_generic_names_len > 0 && node.concrete_types.len > 0 {
3894 for i, mut arg in node.args {
3895 if mut arg.expr is ast.LambdaExpr {
3896 c.handle_generic_lambda_arg(node, method.generic_names, mut arg.expr)
3897 } else if mut arg.expr is ast.AnonFn {
3898 c.handle_generic_anon_fn_arg(node, method.generic_names, mut arg.expr)
3899 }
3900 node.args[i] = arg
3901 }
3902 }
3903 if concrete_types.len == method_generic_names_len && concrete_types.all(!it.has_flag(.generic)) {
3904 c.table.register_fn_concrete_types(method.fkey(), concrete_types)
3905 need_recheck, _ := c.type_resolver.resolve_fn_generic_args(c.table.cur_fn, method, mut node)
3906 if need_recheck {
3907 c.need_recheck_generic_fns = true
3908 }
3909 }
3910 c.check_os_file_struct_io_method_call(node, method, concrete_types)
3911
3912 if node.concrete_types.len > 0 && method_generic_names_len == 0 {
3913 c.error('a non generic function called like a generic one', node.concrete_list_pos)
3914 }
3915 c.check_os_raw_io_call(node, method, concrete_types, 0)
3916 // resolve return generics struct to concrete type
3917 if method_generic_names_len > 0 && method.return_type.has_flag(.generic)
3918 && c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len == 0 {
3919 node.return_type = c.table.unwrap_generic_type(method.return_type, method.generic_names,
3920 concrete_types)
3921 } else {
3922 node.return_type = method.return_type
3923 }
3924 // resolve generic fn return type
3925 if method_generic_names_len > 0 && method.return_type.has_flag(.generic) {
3926 ret_type := c.resolve_fn_return_type(method, node, concrete_types)
3927 c.register_trace_call(node, method)
3928 node.return_type = ret_type
3929 return ret_type
3930 }
3931 if method_generic_names_len > 0 {
3932 if !left_type.has_flag(.generic) {
3933 if left_sym.info is ast.Struct {
3934 if method_generic_names_len == left_sym.info.concrete_types.len {
3935 node.concrete_types = left_sym.info.concrete_types
3936 }
3937 }
3938 }
3939 }
3940 c.register_trace_call(node, method)
3941 return node.return_type
3942}
3943
3944fn (c &Checker) generic_lambda_concrete_types(lambda &ast.LambdaExpr, caller_generic_names []string, caller_concrete_types []ast.Type) []ast.Type {
3945 if lambda == unsafe { nil } || lambda.func == unsafe { nil } {
3946 return []ast.Type{}
3947 }
3948 return c.generic_callback_concrete_types(lambda.func.decl.generic_names, caller_generic_names,
3949 caller_concrete_types)
3950}
3951
3952fn (c &Checker) generic_callback_concrete_types(generic_names []string, caller_generic_names []string, caller_concrete_types []ast.Type) []ast.Type {
3953 if generic_names.len == 0 {
3954 return []ast.Type{}
3955 }
3956 if caller_concrete_types.len == generic_names.len
3957 && (caller_generic_names.len == 0 || caller_generic_names.len == caller_concrete_types.len) {
3958 return caller_concrete_types.clone()
3959 }
3960 if caller_generic_names.len == 0 || caller_generic_names.len != caller_concrete_types.len {
3961 return []ast.Type{}
3962 }
3963 mut concrete_types := []ast.Type{cap: generic_names.len}
3964 for generic_name in generic_names {
3965 idx := caller_generic_names.index(generic_name)
3966 if idx < 0 || idx >= caller_concrete_types.len {
3967 return []ast.Type{}
3968 }
3969 concrete_types << caller_concrete_types[idx]
3970 }
3971 return concrete_types
3972}
3973
3974fn (mut c Checker) handle_generic_lambda_arg(node &ast.CallExpr, generic_names []string, mut lambda ast.LambdaExpr) {
3975 // Calling fn is generic and lambda arg also is generic
3976 if node.concrete_types.len > 0 && lambda.func != unsafe { nil }
3977 && lambda.func.decl.generic_names.len > 0 {
3978 if generic_names.len == node.concrete_types.len {
3979 unsafe {
3980 mut p := &[]string(&lambda.func.decl.generic_names)
3981 *p = generic_names.clone()
3982 }
3983 }
3984 lambda.call_ctx = unsafe { node }
3985 lambda_concrete_types := c.generic_lambda_concrete_types(lambda, generic_names,
3986 node.concrete_types)
3987 if lambda_concrete_types.len == 0 {
3988 return
3989 }
3990 if c.table.register_fn_concrete_types(lambda.func.decl.fkey(), lambda_concrete_types) {
3991 lambda.func.decl.ninstances++
3992 }
3993 }
3994}
3995
3996fn (mut c Checker) handle_generic_anon_fn_arg(node &ast.CallExpr, generic_names []string, mut anon ast.AnonFn) {
3997 if node.concrete_types.len == 0 || anon.decl.generic_names.len == 0 {
3998 return
3999 }
4000 anon_concrete_types := c.generic_callback_concrete_types(anon.decl.generic_names,
4001 generic_names, node.concrete_types)
4002 if anon_concrete_types.len == 0 {
4003 return
4004 }
4005 if anon.decl.fkey() !in c.table.fn_generic_types {
4006 c.table.register_fn_generic_types(anon.decl.fkey())
4007 }
4008 if c.table.register_fn_concrete_types(anon.decl.fkey(), anon_concrete_types) {
4009 anon.decl.ninstances++
4010 }
4011}
4012
4013fn (mut c Checker) resolve_short_syntax_call_arg_type(arg ast.CallArg, param_typ ast.Type, generic_names []string, concrete_types []ast.Type) ast.Type {
4014 if !param_typ.has_flag(.generic) || generic_names.len == 0
4015 || generic_names.len != concrete_types.len {
4016 return param_typ
4017 }
4018 if arg.expr is ast.StructInit {
4019 expr := arg.expr as ast.StructInit
4020 if expr.is_short_syntax && expr.typ == ast.void_type {
4021 return c.table.convert_generic_type(param_typ, generic_names, concrete_types) or {
4022 param_typ
4023 }
4024 }
4025 }
4026 return param_typ
4027}
4028
4029fn (mut c Checker) check_unresolved_generic_param(node &ast.CallExpr, arg ast.CallArg) bool {
4030 if node.raw_concrete_types.len == 0 && arg.expr is ast.ArrayInit
4031 && arg.expr.typ == ast.void_type {
4032 c.error('cannot use empty array as generic argument', arg.pos)
4033 return true
4034 }
4035 return false
4036}
4037
4038fn (mut c Checker) spawn_expr(mut node ast.SpawnExpr) ast.Type {
4039 ret_type := c.call_expr(mut node.call_expr)
4040 if node.call_expr.or_block.kind != .absent {
4041 c.error('option handling cannot be done in `spawn` call. Do it when calling `.wait()`',
4042 node.call_expr.or_block.pos)
4043 }
4044 c.mark_spawn_expr_ref_args(node.call_expr)
4045 // Make sure there are no mutable arguments
4046 for arg in node.call_expr.args {
4047 if arg.is_mut && !arg.typ.is_ptr() {
4048 if arg.typ == 0 {
4049 c.error('invalid expr', node.pos)
4050 return 0
4051 }
4052 if c.table.final_sym(arg.typ).kind == .array {
4053 // allow mutable []array to be passed as mut
4054 continue
4055 }
4056 c.error('function in `spawn` statement cannot contain mutable non-reference arguments',
4057 arg.expr.pos())
4058 }
4059 }
4060 if node.call_expr.is_method && node.call_expr.receiver_type.is_ptr()
4061 && !node.call_expr.left_type.is_ptr() {
4062 c.error('method in `spawn` statement cannot have non-reference mutable receiver',
4063 node.call_expr.left.pos())
4064 }
4065
4066 if c.is_js_backend {
4067 return c.table.find_or_register_promise(c.unwrap_generic(ret_type))
4068 } else {
4069 return c.table.find_or_register_thread(c.unwrap_generic(ret_type))
4070 }
4071}
4072
4073fn (mut c Checker) mark_spawn_expr_ref_args(call ast.CallExpr) {
4074 if call.is_method && call.receiver_type.is_ptr() {
4075 c.mark_spawn_expr_ref_arg(call.left)
4076 }
4077 for arg in call.args {
4078 c.mark_spawn_expr_ref_arg(arg.expr)
4079 }
4080}
4081
4082fn (mut c Checker) mark_spawn_expr_ref_arg(expr ast.Expr) {
4083 mut clean_expr := expr
4084 clean_expr = clean_expr.remove_par()
4085 if mut clean_expr is ast.PrefixExpr {
4086 if clean_expr.op == .amp {
4087 mut referenced_expr := clean_expr.right
4088 c.mark_as_referenced(mut &referenced_expr, false)
4089 }
4090 }
4091}
4092
4093fn (mut c Checker) thread_array_wait_return_type(thread_ret_type ast.Type) ast.Type {
4094 payload_type := thread_ret_type.clear_option_and_result()
4095 if payload_type == ast.void_type {
4096 return thread_ret_type
4097 }
4098 mut return_type := ast.idx_to_type(c.table.find_or_register_array(payload_type))
4099 if thread_ret_type.has_flag(.option) {
4100 return_type = return_type.set_flag(.option)
4101 }
4102 if thread_ret_type.has_flag(.result) {
4103 return_type = return_type.set_flag(.result)
4104 }
4105 return return_type
4106}
4107
4108fn (mut c Checker) go_expr(mut node ast.GoExpr) ast.Type {
4109 // TODO: copypasta from spawn_expr
4110 ret_type := c.call_expr(mut node.call_expr)
4111 if node.call_expr.or_block.kind != .absent {
4112 c.error('option handling cannot be done in `go` call. Do it when calling `.wait()`',
4113 node.call_expr.or_block.pos)
4114 }
4115 // Make sure there are no mutable arguments
4116 for arg in node.call_expr.args {
4117 if arg.is_mut && !arg.typ.is_ptr() {
4118 c.error('function in `go` statement cannot contain mutable non-reference arguments',
4119 arg.expr.pos())
4120 }
4121 }
4122 if node.call_expr.is_method && node.call_expr.receiver_type.is_ptr()
4123 && !node.call_expr.left_type.is_ptr() {
4124 c.error('method in `go` statement cannot have non-reference mutable receiver',
4125 node.call_expr.left.pos())
4126 }
4127
4128 if c.is_js_backend {
4129 return c.table.find_or_register_promise(c.unwrap_generic(ret_type))
4130 } else {
4131 return c.table.find_or_register_thread(c.unwrap_generic(ret_type))
4132 }
4133}
4134
4135@[direct_array_access]
4136fn (mut c Checker) set_node_expected_arg_types(mut node ast.CallExpr, func &ast.Fn) {
4137 if node.expected_arg_types.len == 0 {
4138 start_idx := if func.is_method { 1 } else { 0 }
4139 for i in start_idx .. func.params.len {
4140 node.expected_arg_types << func.params[i].typ
4141 }
4142 }
4143 if func.generic_names.len > 0 {
4144 for t in node.expected_arg_types {
4145 c.unwrap_generic(t) // TODO: the result is not used, have to see if this is called just for the side effects
4146 }
4147 }
4148}
4149
4150fn (mut c Checker) post_process_generic_fns() ! {
4151 mut all_generic_fns := map[string]int{}
4152 // Loop thru each generic function concrete type.
4153 // Check each specific fn instantiation.
4154 for i in 0 .. c.file.generic_fns.len {
4155 c.mod = c.file.generic_fns[i].mod
4156 fkey := c.file.generic_fns[i].fkey()
4157 all_generic_fns[fkey]++
4158 if all_generic_fns[fkey] > generic_fn_cutoff_limit_per_fn {
4159 c.error('${fkey} generic function visited more than ${generic_fn_cutoff_limit_per_fn} times',
4160 c.file.generic_fns[i].pos)
4161 return error('fkey: ${fkey}')
4162 }
4163 gtypes := c.table.fn_generic_types[fkey]
4164 $if trace_post_process_generic_fns ? {
4165 eprintln('> post_process_generic_fns ${c.file.generic_fns[i].mod} | ${c.file.generic_fns[i].name} | fkey: ${fkey} | gtypes: ${gtypes} | c.file.generic_fns.len: ${c.file.generic_fns.len}')
4166 }
4167 for concrete_types in gtypes {
4168 c.table.cur_concrete_types = concrete_types
4169 mut concrete_fn := c.file.generic_fns[i]
4170 original_generic_names := concrete_fn.generic_names.clone()
4171 if concrete_fn.is_method && concrete_types.len > original_generic_names.len {
4172 receiver_generic_names := c.table.generic_type_names(concrete_fn.receiver.typ)
4173 if receiver_generic_names.len > 0 {
4174 mut effective_generic_names := []string{cap: receiver_generic_names.len +
4175 original_generic_names.len}
4176 for name in receiver_generic_names {
4177 if name !in effective_generic_names {
4178 effective_generic_names << name
4179 }
4180 }
4181 for name in original_generic_names {
4182 if name !in effective_generic_names {
4183 effective_generic_names << name
4184 }
4185 }
4186 if effective_generic_names.len == concrete_types.len {
4187 unsafe {
4188 mut p := &[]string(&concrete_fn.generic_names)
4189 *p = effective_generic_names
4190 }
4191 }
4192 }
4193 }
4194 c.fn_decl(mut concrete_fn)
4195 if concrete_fn.name in ['veb.run', 'veb.run_at'] {
4196 for ct in concrete_types {
4197 if ct !in c.veb_gen_types {
4198 c.veb_gen_types << ct
4199 }
4200 }
4201 }
4202 }
4203 c.table.cur_concrete_types = []
4204 $if trace_post_process_generic_fns ? {
4205 if c.file.generic_fns[i].generic_names.len > 0 {
4206 eprintln(' > fn_decl node.name: ${c.file.generic_fns[i].name} | generic_names: ${c.file.generic_fns[i].generic_names} | ninstances: ${c.file.generic_fns[i].ninstances}')
4207 }
4208 }
4209 }
4210}
4211
4212fn min_required_call_params(f &ast.Fn, is_method_call bool) int {
4213 start_idx := if is_method_call && f.params.len > 0 { 1 } else { 0 }
4214 if start_idx >= f.params.len {
4215 return 0
4216 }
4217 mut required := f.params.len - start_idx
4218 mut idx := f.params.len - 1
4219 for idx >= start_idx {
4220 if f.params[idx].typ.has_flag(.option) {
4221 required--
4222 idx--
4223 continue
4224 }
4225 break
4226 }
4227 return required
4228}
4229
4230@[inline]
4231fn variadic_call_arg_start_idx(f &ast.Fn, is_method_call bool) int {
4232 start_idx := if is_method_call && f.params.len > 0 { 1 } else { 0 }
4233 mut fixed_args := f.params.len - start_idx
4234 if f.is_variadic && !f.is_c_variadic && fixed_args > 0 {
4235 fixed_args--
4236 }
4237 return if fixed_args >= 0 { fixed_args } else { 0 }
4238}
4239
4240@[inline]
4241fn call_arg_param_for_fn(f &ast.Fn, arg_idx int, is_method_call bool) ast.Param {
4242 start_idx := if is_method_call && f.params.len > 0 { 1 } else { 0 }
4243 variadic_start := variadic_call_arg_start_idx(f, is_method_call)
4244 if f.is_variadic && !f.is_c_variadic && arg_idx >= variadic_start {
4245 return f.params.last()
4246 }
4247 param_idx := start_idx + arg_idx
4248 if param_idx < f.params.len {
4249 return f.params[param_idx]
4250 }
4251 return ast.Param{
4252 typ: ast.any_type
4253 }
4254}
4255
4256fn call_can_fill_optional_args(node &ast.CallExpr) bool {
4257 if node.args.any(it.expr is ast.ArrayDecompose) {
4258 return false
4259 }
4260 return !node.args.any(it.expr is ast.CallExpr && it.expr.nr_ret_values > 1)
4261}
4262
4263fn fill_trailing_optional_call_args(mut node ast.CallExpr, f &ast.Fn) {
4264 start_idx := if node.is_method && f.params.len > 0 { 1 } else { 0 }
4265 expected_args := f.params.len - start_idx
4266 for i := node.args.len; i < expected_args; i++ {
4267 if !f.params[start_idx + i].typ.has_flag(.option) {
4268 break
4269 }
4270 node.args << ast.CallArg{
4271 expr: ast.None{
4272 pos: node.pos
4273 }
4274 pos: node.pos
4275 }
4276 }
4277}
4278
4279fn (mut c Checker) check_expected_arg_count(mut node ast.CallExpr, f &ast.Fn) ! {
4280 mut nr_args := node.args.len
4281 nr_params := if node.is_method && f.params.len > 0 { f.params.len - 1 } else { f.params.len }
4282 optional_required_params := min_required_call_params(f, node.is_method)
4283 mut min_required_params := optional_required_params
4284 can_fill_optional_args := call_can_fill_optional_args(node)
4285 if f.is_variadic {
4286 node.is_variadic = f.is_variadic
4287 node.is_c_variadic = f.is_c_variadic
4288 if !f.is_c_variadic {
4289 min_required_params--
4290 c.markused_array_method(!c.is_builtin_mod, '')
4291 }
4292 } else {
4293 has_decompose := node.args.any(it.expr is ast.ArrayDecompose)
4294 if has_decompose {
4295 // if call(...args) is present
4296 min_required_params = nr_args - 1
4297 }
4298 }
4299 // check if multi-return is used as unique argument to the function
4300 if node.args.len == 1 && mut node.args[0].expr is ast.CallExpr {
4301 is_multi := node.args[0].expr.nr_ret_values > 1
4302 if is_multi && !(node.name in print_everything_fns && f.mod == 'builtin') {
4303 // it is a multi-return argument
4304 nr_args = node.args[0].expr.nr_ret_values
4305 if nr_args != nr_params {
4306 unexpected_args_pos := node.args[0].pos.extend(node.args.last().pos)
4307 // TODO use this here as well
4308 /*
4309 c.fn_call_error_have_want(
4310 nr_params: min_required_params
4311 nr_args: nr_args
4312 params: f.params
4313 args: node.args
4314 pos: node.pos
4315 )
4316 */
4317 c.error('expected ${min_required_params} arguments, but got ${nr_args} from multi-return ${c.table.type_to_str(node.args[0].expr.return_type)}',
4318 unexpected_args_pos)
4319 return error('')
4320 }
4321 }
4322 } else if node.args.len > 1 && node.args.any(it.expr is ast.CallExpr
4323 && it.expr.nr_ret_values > 1) {
4324 mut check_args := 0
4325 for arg in node.args {
4326 if arg.expr is ast.CallExpr && arg.expr.nr_ret_values > 0 {
4327 check_args += arg.expr.nr_ret_values
4328 } else {
4329 check_args += 1
4330 }
4331 }
4332 nr_args = check_args
4333 }
4334 if min_required_params < 0 {
4335 min_required_params = 0
4336 }
4337 if nr_args < min_required_params {
4338 if min_required_params == nr_args + 1 {
4339 start_idx := if node.is_method && f.params.len > 0 { 1 } else { 0 }
4340 last_required_param := f.params[start_idx + min_required_params - 1]
4341 // params struct?
4342 last_typ := last_required_param.typ
4343 last_sym := c.table.sym(last_typ)
4344 if last_sym.info is ast.Struct {
4345 is_params := last_sym.info.attrs.any(it.name == 'params' && !it.has_arg)
4346 if is_params {
4347 // allow empty trailing struct syntax arg (`f()` where `f` is `fn(ConfigStruct)`)
4348 node.args << ast.CallArg{
4349 pos: node.pos
4350 expr: ast.StructInit{
4351 typ: last_typ
4352 pos: node.pos
4353 name_pos: node.name_pos
4354 }
4355 }
4356 return
4357 }
4358 }
4359 if c.try_add_implicit_veb_context_arg(mut node, f) {
4360 return
4361 }
4362 }
4363 c.fn_call_error_have_want(
4364 nr_params: min_required_params
4365 nr_args: nr_args
4366 params: f.params
4367 args: node.args
4368 pos: node.pos
4369 )
4370 return error('')
4371 } else if !f.is_variadic && nr_args > nr_params {
4372 unexpected_args_pos :=
4373 node.args[int_min(min_required_params, node.args.len - 1)].pos.extend(node.args.last().pos)
4374 // c.error('3expected ${min_required_params} arguments, but got ${nr_args}', unexpected_args_pos)
4375 c.fn_call_error_have_want(
4376 nr_params: min_required_params
4377 nr_args: nr_args
4378 params: f.params
4379 args: node.args
4380 pos: unexpected_args_pos
4381 )
4382 return error('')
4383 } else if !f.is_variadic && nr_args < nr_params && optional_required_params < nr_params {
4384 if !can_fill_optional_args {
4385 c.fn_call_error_have_want(
4386 nr_params: nr_params
4387 nr_args: nr_args
4388 params: f.params
4389 args: node.args
4390 pos: node.pos
4391 )
4392 return error('')
4393 }
4394 fill_trailing_optional_call_args(mut node, f)
4395 }
4396}
4397
4398fn (mut c Checker) try_add_implicit_veb_context_arg(mut node ast.CallExpr, f &ast.Fn) bool {
4399 if f.params.len == 0 || f.params.last().name != 'ctx' || !c.has_veb_context(f.params.last().typ) {
4400 return false
4401 }
4402 scope := if c.fn_scope != unsafe { nil } { c.fn_scope } else { node.scope }
4403 if scope == unsafe { nil } {
4404 return false
4405 }
4406 ctx_var := scope.find_var('ctx') or { return false }
4407 node.args << ast.CallArg{
4408 is_mut: f.params.last().is_mut
4409 typ: ctx_var.typ
4410 pos: node.pos
4411 expr: ast.Ident{
4412 language: .v
4413 tok_kind: .name
4414 pos: node.pos
4415 scope: scope
4416 obj: *ctx_var
4417 mod: c.mod
4418 name: 'ctx'
4419 kind: .variable
4420 info: ast.IdentVar{
4421 typ: ctx_var.typ
4422 is_mut: ctx_var.is_mut
4423 }
4424 is_mut: f.params.last().is_mut
4425 }
4426 }
4427 return true
4428}
4429
4430@[params]
4431struct HaveWantParams {
4432 nr_params int
4433 nr_args int
4434 args []ast.CallArg
4435 params []ast.Param
4436 pos token.Pos
4437}
4438
4439fn (mut c Checker) fn_call_error_have_want(p HaveWantParams) {
4440 mut sb := strings.new_builder(20)
4441 sb.write_string('have (')
4442 // Fetch arg types, they are always 0 at this point
4443 // Duplicate logic, but we don't care, since this is an error, so no perf cost
4444 mut arg_types := []ast.Type{len: p.args.len}
4445 for i, arg in p.args {
4446 mut e := arg.expr
4447 arg_types[i] = c.expr(mut e)
4448 }
4449 // Args provided by the user
4450 for i, _ in p.args {
4451 if arg_types[i] == 0 { // arg.typ == 0 {
4452 // Arguments can have an unknown (invalid) type
4453 // This should never happen.
4454 sb.write_string('?')
4455 } else {
4456 sb.write_string(c.table.type_to_str(arg_types[i])) // arg.typ
4457 }
4458 if i < p.args.len - 1 {
4459 sb.write_string(', ')
4460 }
4461 }
4462 sb.write_string(')')
4463 c.add_error_detail(sb.str())
4464 // Actual parameters we expect
4465 sb.write_string(' want (')
4466 for i, param in p.params {
4467 if i == 0 && p.nr_params == p.params.len - 1 {
4468 // Skip receiver
4469 continue
4470 }
4471 sb.write_string(c.table.type_to_str(param.typ))
4472 if i < p.params.len - 1 {
4473 sb.write_string(', ')
4474 }
4475 }
4476 sb.write_string(')')
4477 c.add_error_detail(sb.str())
4478 args_plural := if p.nr_params == 1 { 'argument' } else { 'arguments' }
4479 c.error('expected ${p.nr_params} ${args_plural}, but got ${p.nr_args}', p.pos)
4480}
4481
4482fn (mut c Checker) check_predicate_param(is_map bool, elem_typ ast.Type, node ast.CallExpr) {
4483 if node.args.len != 1 {
4484 c.error('expected 1 argument, but got ${node.args.len}', node.pos)
4485 // Finish early so that it doesn't fail later
4486 return
4487 }
4488 mut arg_expr := node.args[0].expr
4489 match mut arg_expr {
4490 ast.AnonFn {
4491 if arg_expr.decl.return_type.has_flag(.option) {
4492 c.error('option needs to be unwrapped before using it in map/filter',
4493 node.args[0].pos)
4494 }
4495 if arg_expr.decl.params.len > 1 {
4496 c.error('function needs exactly 1 argument', arg_expr.decl.pos)
4497 } else if is_map && (arg_expr.decl.return_type == ast.void_type
4498 || arg_expr.decl.params[0].typ != elem_typ) {
4499 c.error('type mismatch, should use `fn(a ${c.table.type_to_str(elem_typ)}) T {...}`',
4500 arg_expr.decl.pos)
4501 } else if !is_map && (arg_expr.decl.return_type != ast.bool_type
4502 || arg_expr.decl.params[0].typ != elem_typ) {
4503 c.error('type mismatch, should use `fn(a ${c.table.type_to_str(elem_typ)}) bool {...}`',
4504 arg_expr.decl.pos)
4505 }
4506 }
4507 ast.Ident {
4508 if arg_expr.kind == .function {
4509 func := c.table.find_fn(arg_expr.name) or {
4510 c.error('${arg_expr.name} does not exist', arg_expr.pos)
4511 return
4512 }
4513 if func.return_type.has_flag(.option) {
4514 c.error('option needs to be unwrapped before using it in map/filter', node.pos)
4515 }
4516 if func.params.len > 1 {
4517 c.error('function needs exactly 1 argument', node.pos)
4518 } else if is_map
4519 && (func.return_type == ast.void_type || func.params[0].typ != elem_typ) {
4520 c.error('type mismatch, should use `fn(a ${c.table.type_to_str(elem_typ)}) T {...}`',
4521 arg_expr.pos)
4522 } else if !is_map
4523 && (func.return_type != ast.bool_type || func.params[0].typ != elem_typ) {
4524 c.error('type mismatch, should use `fn(a ${c.table.type_to_str(elem_typ)}) bool {...}`',
4525 arg_expr.pos)
4526 }
4527 } else if arg_expr.kind == .variable {
4528 if mut arg_expr.obj is ast.Var {
4529 expr := arg_expr.obj.expr
4530 if expr is ast.AnonFn {
4531 // copied from above
4532 if expr.decl.return_type.has_flag(.option) {
4533 c.error('option needs to be unwrapped before using it in map/filter',
4534 arg_expr.pos)
4535 }
4536 if expr.decl.params.len > 1 {
4537 c.error('function needs exactly 1 argument', expr.decl.pos)
4538 } else if is_map && (expr.decl.return_type == ast.void_type
4539 || expr.decl.params[0].typ != elem_typ) {
4540 c.error('type mismatch, should use `fn(a ${c.table.type_to_str(elem_typ)}) T {...}`',
4541 expr.decl.pos)
4542 } else if !is_map && (expr.decl.return_type != ast.bool_type
4543 || expr.decl.params[0].typ != elem_typ) {
4544 c.error('type mismatch, should use `fn(a ${c.table.type_to_str(elem_typ)}) bool {...}`',
4545 expr.decl.pos)
4546 }
4547 return
4548 }
4549 }
4550 // NOTE: using a local copy to avoid a cgen issue with mut match
4551 // and method calls on smartcast variants (double pointer).
4552 ident := arg_expr
4553 if !is_map && ident.var_info().typ != ast.bool_type {
4554 c.error('type mismatch, should be bool', arg_expr.pos)
4555 }
4556 }
4557 }
4558 ast.CallExpr {
4559 if is_map && arg_expr.return_type in [ast.void_type, 0] {
4560 c.error('type mismatch, `${arg_expr.name}` does not return anything', arg_expr.pos)
4561 } else if !is_map && arg_expr.return_type != ast.bool_type {
4562 if arg_expr.or_block.kind != .absent && (arg_expr.return_type.has_flag(.option)
4563 || arg_expr.return_type.has_flag(.result))
4564 && arg_expr.return_type.clear_option_and_result() == ast.bool_type {
4565 return
4566 }
4567 c.error('type mismatch, `${arg_expr.name}` must return a bool', arg_expr.pos)
4568 }
4569 if arg_expr.return_type.has_flag(.result) && arg_expr.or_block.kind != .block {
4570 if arg_expr.return_type.clear_option_and_result() in [ast.void_type, 0] {
4571 c.error('cannot use Result type in `${node.name}`', arg_expr.pos)
4572 }
4573 }
4574 }
4575 ast.StringLiteral, ast.StringInterLiteral {
4576 if !is_map {
4577 c.error('type mismatch, should use e.g. `${node.name}(it > 2)`', arg_expr.pos)
4578 }
4579 }
4580 ast.InfixExpr {
4581 if arg_expr.op == .left_shift && arg_expr.is_stmt
4582 && c.table.final_sym(arg_expr.left_type).kind == .array {
4583 c.error('array append cannot be used in an expression', arg_expr.pos)
4584 }
4585 }
4586 ast.LambdaExpr {
4587 if mut arg_expr.expr is ast.CallExpr && is_map
4588 && arg_expr.expr.return_type in [ast.void_type, 0] {
4589 c.error('type mismatch, `${arg_expr.expr.name}` does not return anything',
4590 arg_expr.expr.pos)
4591 }
4592 }
4593 else {
4594 if !is_map && c.expr(mut arg_expr) != ast.bool_type {
4595 c.error('invalid expression, expected infix expr, lambda or function',
4596 arg_expr.pos())
4597 }
4598 }
4599 }
4600}
4601
4602fn (mut c Checker) map_builtin_method_call(mut node ast.CallExpr, left_type_ ast.Type) ast.Type {
4603 method_name := node.name
4604 mut ret_type := ast.void_type
4605 // resolve T
4606 left_type := if c.table.final_sym(left_type_).kind == .any {
4607 c.unwrap_generic(left_type_)
4608 } else {
4609 left_type_
4610 }
4611 left_sym := c.table.final_sym(left_type)
4612 match node.kind {
4613 .clone, .move {
4614 if node.args.len != 0 {
4615 c.error('`.${method_name}()` does not have any arguments', node.args[0].pos)
4616 }
4617 if method_name[0] == `m` {
4618 c.check_for_mut_receiver(mut node.left)
4619 }
4620 if node.left.is_auto_deref_var() || left_type.has_flag(.shared_f) {
4621 ret_type = node.left_type.deref()
4622 } else {
4623 ret_type = node.left_type
4624 }
4625 ret_type = ret_type.clear_flag(.shared_f)
4626 }
4627 .keys, .values {
4628 if node.args.len != 0 {
4629 c.error('`.${method_name}()` does not have any arguments', node.args[0].pos)
4630 }
4631 info := left_sym.info as ast.Map
4632 typ := if node.kind == .keys {
4633 c.table.find_or_register_array(info.key_type)
4634 } else {
4635 c.table.find_or_register_array(info.value_type)
4636 }
4637 ret_type = ast.idx_to_type(typ)
4638 if info.key_type.has_flag(.generic) && node.kind == .keys {
4639 ret_type = ret_type.set_flag(.generic)
4640 }
4641 if info.value_type.has_flag(.generic) && node.kind == .values {
4642 ret_type = ret_type.set_flag(.generic)
4643 }
4644 }
4645 .delete {
4646 c.check_for_mut_receiver(mut node.left)
4647 if node.args.len == 1 {
4648 info := left_sym.info as ast.Map
4649 arg_type := c.expr(mut node.args[0].expr)
4650 c.check_expected_call_arg(arg_type, info.key_type, node.language, node.args[0]) or {
4651 c.error('${err.msg()} in argument 1 to `Map.delete`', node.args[0].pos)
4652 }
4653 } else {
4654 c.error('expected 1 argument, but got ${node.args.len}', node.pos)
4655 }
4656 }
4657 else {}
4658 }
4659
4660 node.receiver_type = node.left_type.ref()
4661 node.return_type = ret_type
4662 return node.return_type
4663}
4664
4665// ensure_same_array_return_type makes sure, that the return type of .clone(), .sorted(), .sorted_with_compare() etc,
4666// is `array_xxx`, instead of the plain `array` .
4667fn (mut c Checker) ensure_same_array_return_type(mut node ast.CallExpr, left_type ast.Type) {
4668 node.receiver_type = left_type.ref()
4669 if node.left.is_auto_deref_var() && left_type.nr_muls() > 0 {
4670 node.return_type = left_type.deref()
4671 } else {
4672 node.return_type = node.receiver_type.set_nr_muls(0)
4673 }
4674 if node.return_type.has_flag(.shared_f) {
4675 node.return_type = node.return_type.clear_flag(.shared_f)
4676 }
4677}
4678
4679fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type ast.Type) ast.Type {
4680 left_sym := c.table.final_sym(left_type)
4681 method_name := node.name
4682 mut elem_typ := ast.void_type
4683 if !c.is_builtin_mod && node.kind == .slice {
4684 c.error('.slice() is a private method, use `x[start..end]` instead', node.pos)
4685 return ast.void_type
4686 }
4687 unwrapped_left_type := c.unwrap_generic(left_type)
4688 unaliased_left_type := c.table.unaliased_type(unwrapped_left_type)
4689 array_info := if left_sym.info is ast.Array {
4690 left_sym.info as ast.Array
4691 } else {
4692 c.table.sym(unaliased_left_type).info as ast.Array
4693 }
4694 elem_typ = array_info.elem_type
4695 node_args_len := node.args.len
4696 mut arg0 := if node_args_len > 0 { node.args[0] } else { ast.CallArg{} }
4697 if ast.builtin_array_generic_methods_no_sort_matcher.matches(method_name) {
4698 if node_args_len > 0 && mut arg0.expr is ast.LambdaExpr {
4699 if arg0.expr.params.len != 1 {
4700 c.error('lambda expressions used in the builtin array methods require exactly 1 parameter',
4701 arg0.expr.pos)
4702 return ast.void_type
4703 }
4704 if node.kind == .map {
4705 c.lambda_expr_fix_type_of_param(mut arg0.expr, mut arg0.expr.params[0], elem_typ)
4706 le_type := c.expr(mut arg0.expr.expr)
4707 // eprintln('>>>>> node.args[0].expr: ${ast.Expr(node.args[0].expr)} | elem_typ: ${elem_typ} | etype: ${le_type}')
4708 c.support_lambda_expr_one_param(elem_typ, le_type, mut arg0.expr)
4709 } else {
4710 c.support_lambda_expr_one_param(elem_typ, ast.bool_type, mut arg0.expr)
4711 }
4712 } else {
4713 // position of `it` doesn't matter
4714 scope_register_it(mut node.scope, node.pos, elem_typ)
4715 }
4716 } else if node.kind in [.insert, .prepend] {
4717 if node.kind == .insert {
4718 if node_args_len != 2 {
4719 c.error('`array.insert()` should have 2 arguments, e.g. `insert(1, val)`', node.pos)
4720 return ast.void_type
4721 } else {
4722 arg_type := c.expr(mut arg0.expr)
4723 if arg_type !in [ast.int_type, ast.int_literal_type] {
4724 c.error('the first argument of `array.insert()` should be integer',
4725 arg0.expr.pos())
4726 return ast.void_type
4727 }
4728 }
4729 c.table.used_features.arr_insert = true
4730 } else {
4731 c.table.used_features.arr_prepend = true
4732 if node_args_len != 1 {
4733 c.error('`array.prepend()` should have 1 argument, e.g. `prepend(val)`', node.pos)
4734 return ast.void_type
4735 }
4736 }
4737 c.check_for_mut_receiver(mut node.left)
4738 info := left_sym.info as ast.Array
4739 val_arg_n := if node.kind == .insert { 1 } else { 0 }
4740 node.receiver_type = ast.array_type.ref()
4741 node.return_type = ast.void_type
4742
4743 if method := c.table.find_method(left_sym, method_name) {
4744 for i, mut arg in node.args {
4745 node.args[i].typ = c.expr(mut arg.expr)
4746 if i == val_arg_n {
4747 arg_sym := c.table.sym(node.args[i].typ)
4748 base_arg_type := c.unwrap_generic(node.args[i].typ)
4749 if c.check_types(base_arg_type, info.elem_type) {
4750 if !base_arg_type.is_ptr() && info.elem_type.is_ptr()
4751 && info.elem_type.share() == .mut_t {
4752 c.error('cannot ${method_name} `${arg_sym.name}` to `${left_sym.name}`',
4753 arg.expr.pos())
4754 continue
4755 }
4756 } else if !c.check_types(base_arg_type, unwrapped_left_type)
4757 && !c.check_types(elem_typ, base_arg_type) {
4758 c.error('cannot ${method_name} `${arg_sym.name}` to `${left_sym.name}`',
4759 arg.expr.pos())
4760 continue
4761 }
4762 }
4763 c.check_expected_call_arg(arg.typ, method.params[i + 1].typ, node.language, arg) or {
4764 c.error('${err.msg()} in argument ${i + 1} to `${left_sym.name}.${method_name}`',
4765 node.args[i].pos)
4766 }
4767 }
4768 }
4769 } else if node.kind in [.sort_with_compare, .sorted_with_compare] {
4770 if node_args_len != 1 {
4771 c.error('`.${method_name}()` expected 1 argument, but got ${node_args_len}', node.pos)
4772 } else {
4773 if mut arg0.expr is ast.LambdaExpr {
4774 c.support_lambda_expr_in_sort(elem_typ.ref(), ast.int_type, mut arg0.expr)
4775 }
4776 arg_type := c.expr(mut arg0.expr)
4777 arg_sym := c.table.sym(arg_type)
4778 if arg_sym.kind == .function {
4779 func_info := arg_sym.info as ast.FnType
4780 if func_info.func.params.len == 2 {
4781 if func_info.func.params[0].typ.nr_muls() != elem_typ.nr_muls() + 1 {
4782 arg_typ_str := c.table.type_to_str(func_info.func.params[0].typ)
4783 expected_typ_str := c.table.type_to_str(elem_typ.ref())
4784 c.error('${method_name} callback function parameter `${func_info.func.params[0].name}` with type `${arg_typ_str}` should be `${expected_typ_str}`',
4785 func_info.func.params[0].type_pos)
4786 }
4787 if func_info.func.params[1].typ.nr_muls() != elem_typ.nr_muls() + 1 {
4788 arg_typ_str := c.table.type_to_str(func_info.func.params[1].typ)
4789 expected_typ_str := c.table.type_to_str(elem_typ.ref())
4790 c.error('${method_name} callback function parameter `${func_info.func.params[1].name}` with type `${arg_typ_str}` should be `${expected_typ_str}`',
4791 func_info.func.params[1].type_pos)
4792 }
4793 }
4794 }
4795 arg0.typ = arg_type
4796 if method := c.table.find_method(left_sym, method_name) {
4797 c.check_expected_call_arg(arg_type, method.params[1].typ, node.language, arg0) or {
4798 c.error('${err.msg()} in argument 1 to `${left_sym.name}.${method_name}`',
4799 arg0.pos)
4800 }
4801 }
4802 if node.kind == .sort_with_compare {
4803 c.check_for_mut_receiver(mut node.left)
4804 node.return_type = ast.void_type
4805 node.receiver_type = node.left_type.ref()
4806 } else {
4807 node.return_type = node.left_type
4808 node.receiver_type = node.left_type
4809 }
4810 }
4811 } else if node.kind in [.sort, .sorted] {
4812 if node.kind == .sort {
4813 if node.left is ast.CallExpr {
4814 c.error('the `sort()` method can be called only on mutable receivers, but `${ast.Expr(node.left)}` is a call expression',
4815 node.pos)
4816 }
4817 c.check_for_mut_receiver(mut node.left)
4818 }
4819 // position of `a` and `b` doesn't matter, they're the same
4820 scope_register_a_b(mut node.scope, node.pos, elem_typ)
4821
4822 if node_args_len > 1 {
4823 c.error('expected 0 or 1 argument, but got ${node_args_len}', node.pos)
4824 } else if node_args_len == 1 {
4825 if mut arg0.expr is ast.LambdaExpr {
4826 c.support_lambda_expr_in_sort(elem_typ.ref(), ast.bool_type, mut arg0.expr)
4827 } else if mut arg0.expr is ast.InfixExpr {
4828 c.check_sort_external_variable_access(ast.Expr(arg0.expr))
4829 if arg0.expr.op !in [.gt, .lt] {
4830 c.error('`.${method_name}()` can only use `<` or `>` comparison', node.pos)
4831 }
4832 left_name := '${arg0.expr.left}'[0]
4833 right_name := '${arg0.expr.right}'[0]
4834 if left_name !in [`a`, `b`] || right_name !in [`a`, `b`] {
4835 c.error('`.${method_name}()` can only use `a` or `b` as argument, e.g. `arr.${method_name}(a < b)`',
4836 node.pos)
4837 } else if left_name == right_name {
4838 c.error('`.${method_name}()` cannot use same argument', node.pos)
4839 }
4840 if arg0.expr.left !in [ast.CallExpr, ast.Ident, ast.SelectorExpr, ast.IndexExpr]
4841 || arg0.expr.right !in [ast.CallExpr, ast.Ident, ast.SelectorExpr, ast.IndexExpr] {
4842 c.error('`.${method_name}()` can only use ident, index, selector or call as argument, \ne.g. `arr.${method_name}(a < b)`, `arr.${method_name}(a.id < b.id)`, `arr.${method_name}(a[0] < b[0])`',
4843 node.pos)
4844 }
4845 } else {
4846 c.error(
4847 '`.${method_name}()` requires a `<` or `>` comparison as the first and only argument' +
4848 '\ne.g. `users.${method_name}(a.id < b.id)`', node.pos)
4849 }
4850 } else if !(c.table.sym(elem_typ).has_method('<')
4851 || c.table.unalias_num_type(elem_typ) in [ast.int_type, ast.int_type.ref(), ast.string_type, ast.string_type.ref(), ast.i8_type, ast.i16_type, ast.i32_type, ast.i64_type, ast.u8_type, ast.rune_type, ast.u16_type, ast.u32_type, ast.u64_type, ast.f32_type, ast.f64_type, ast.char_type, ast.bool_type, ast.float_literal_type, ast.int_literal_type]) {
4852 c.error('custom sorting condition must be supplied for type `${c.table.type_to_str(elem_typ)}`',
4853 node.pos)
4854 }
4855 } else if node.kind == .wait {
4856 elem_sym := c.table.sym(elem_typ)
4857 if elem_sym.kind == .thread {
4858 if node_args_len != 0 {
4859 c.error('`.wait()` does not have any arguments', arg0.pos)
4860 }
4861 thread_ret_type := c.unwrap_generic(elem_sym.thread_info().return_type)
4862 node.return_type = c.thread_array_wait_return_type(thread_ret_type)
4863 } else {
4864 c.error('`${left_sym.name}` has no method `wait()` (only thread handles and arrays of them have)',
4865 node.left.pos())
4866 }
4867 }
4868 // map/filter are supposed to have 1 arg only
4869 mut arg_type := unaliased_left_type
4870 for mut arg in node.args {
4871 mut expr_type := c.expr(mut arg.expr)
4872 if arg.expr is ast.AnonFn {
4873 // fix anon fn when return is a fixed array
4874 expr_sym := c.table.sym(expr_type)
4875 info := expr_sym.info as ast.FnType
4876 return_type_sym := c.table.sym(info.func.return_type)
4877 if return_type_sym.kind == .array_fixed {
4878 expr_type = c.cast_fixed_array_ret(info.func.return_type, return_type_sym)
4879 }
4880 }
4881 arg_type = c.check_expr_option_or_result_call(arg.expr, expr_type)
4882 }
4883 if node.kind == .map {
4884 // eprintln('>>>>>>> map node.args[0].expr: ${node.args[0].expr}, left_type: ${left_type} | elem_typ: ${elem_typ} | arg_type: ${arg_type}')
4885 // check fn
4886 c.check_predicate_param(true, elem_typ, node)
4887 arg_sym := c.table.sym(arg_type)
4888 ret_type := match arg_sym.info {
4889 ast.FnType {
4890 if arg0.expr is ast.SelectorExpr {
4891 arg_type
4892 } else {
4893 arg_sym.info.func.return_type
4894 }
4895 }
4896 else {
4897 arg_type
4898 }
4899 }
4900
4901 normalized_ret_type := if c.table.sym(ret_type).kind == .alias {
4902 unaliased_ret_type := c.table.unaliased_type(ret_type)
4903 if unaliased_ret_type.has_option_or_result() {
4904 unaliased_ret_type
4905 } else {
4906 ret_type
4907 }
4908 } else {
4909 ret_type
4910 }
4911 if normalized_ret_type.has_flag(.result) {
4912 c.error('cannot use Result type in `${node.name}`', arg0.expr.pos())
4913 }
4914 if c.pref.new_generic_solver {
4915 node.return_type = c.table.find_or_register_array(ret_type)
4916 } else {
4917 node.return_type = c.table.find_or_register_array(c.unwrap_generic(ret_type))
4918 }
4919 if node.return_type.has_flag(.shared_f) {
4920 node.return_type = node.return_type.clear_flag(.shared_f).deref()
4921 }
4922 ret_sym := c.table.sym(ret_type)
4923 if ret_sym.kind == .multi_return {
4924 c.error('returning multiple values is not supported in .map() calls', node.pos)
4925 }
4926
4927 if c.pref.new_generic_solver && ret_type.has_flag(.generic) {
4928 node.return_type = node.return_type.set_flag(.generic)
4929 }
4930 } else if node.kind == .filter {
4931 // check fn
4932 if node.return_type.has_flag(.shared_f) {
4933 node.return_type = node.return_type.clear_flag(.shared_f).deref()
4934 } else if node.left.is_auto_deref_var() {
4935 node.return_type = node.return_type.deref()
4936 }
4937 c.check_predicate_param(false, elem_typ, node)
4938 } else if node.kind in [.any, .all] {
4939 c.check_predicate_param(false, elem_typ, node)
4940 node.return_type = ast.bool_type
4941 } else if node.kind == .count {
4942 c.check_predicate_param(false, elem_typ, node)
4943 node.return_type = ast.int_type
4944 } else if node.kind == .clone {
4945 if node_args_len != 0 {
4946 c.error('`.clone()` does not have any arguments', arg0.pos)
4947 }
4948 c.ensure_same_array_return_type(mut node, left_type)
4949 } else if node.kind == .sorted {
4950 c.ensure_same_array_return_type(mut node, left_type)
4951 } else if node.kind in [.sort_with_compare, .sorted_with_compare] {
4952 if node.kind == .sorted_with_compare {
4953 c.ensure_same_array_return_type(mut node, left_type)
4954 }
4955 // Inject a (voidptr) cast for the callback argument, to pass -cstrict, otherwise:
4956 // error: incompatible function pointer types passing
4957 // 'int (string *, string *)' (aka 'int (struct string *, struct string *)')
4958 // to parameter of type 'int (*)(voidptr, voidptr)' (aka 'int (*)(void *, void *)')
4959 node.args[0].expr = ast.CastExpr{
4960 expr: arg0.expr
4961 typ: ast.voidptr_type
4962 typname: 'voidptr'
4963 expr_type: c.expr(mut arg0.expr)
4964 pos: node.pos
4965 }
4966 } else if node.kind == .sort {
4967 node.return_type = ast.void_type
4968 } else if node.kind == .contains {
4969 // c.warn('use `value in arr` instead of `arr.contains(value)`', node.pos)
4970 if node_args_len != 1 {
4971 c.error('`.contains()` expected 1 argument, but got ${node_args_len}', node.pos)
4972 } else if !left_sym.has_method('contains') {
4973 arg_typ := c.unwrap_generic(c.expr(mut arg0.expr))
4974 c.check_expected_call_arg(arg_typ, c.unwrap_generic(elem_typ), node.language, arg0) or {
4975 c.error('${err.msg()} in argument 1 to `.contains()`', arg0.pos)
4976 }
4977 }
4978 for i, mut arg in node.args {
4979 node.args[i].typ = c.expr(mut arg.expr)
4980 }
4981 node.return_type = ast.bool_type
4982 } else if node.kind in [.index, .last_index] {
4983 if node_args_len != 1 {
4984 c.error('`.${method_name}()` expected 1 argument, but got ${node_args_len}', node.pos)
4985 } else if !left_sym.has_method(method_name) {
4986 arg_typ := c.unwrap_generic(c.expr(mut arg0.expr))
4987 c.check_expected_call_arg(arg_typ, c.unwrap_generic(elem_typ), node.language, arg0) or {
4988 c.error('${err.msg()} in argument 1 to `.${method_name}()`', arg0.pos)
4989 }
4990 }
4991 for i, mut arg in node.args {
4992 node.args[i].typ = c.expr(mut arg.expr)
4993 }
4994 node.return_type = ast.int_type
4995 } else if method_name == 'get' {
4996 if node_args_len != 1 {
4997 c.error('`.get()` expected 1 argument, but got ${node_args_len}', node.pos)
4998 } else {
4999 arg_typ := c.unwrap_generic(c.expr(mut arg0.expr))
5000 c.check_expected_call_arg(arg_typ, ast.int_type, node.language, arg0) or {
5001 c.error('${err.msg()} in argument 1 to `.get()`', arg0.pos)
5002 }
5003 }
5004 for i, mut arg in node.args {
5005 node.args[i].typ = c.expr(mut arg.expr)
5006 }
5007 node.receiver_type = ast.array_type
5008 node.return_type = array_info.elem_type.set_flag(.option)
5009 } else if node.kind in [.first, .last, .pop_left, .pop] {
5010 c.markused_array_method(!c.is_builtin_mod, method_name)
5011 if node_args_len != 0 {
5012 c.error('`.${method_name}()` does not have any arguments', arg0.pos)
5013 }
5014 node.return_type = array_info.elem_type
5015 if node.kind in [.pop_left, .pop] {
5016 c.check_for_mut_receiver(mut node.left)
5017 node.receiver_type = node.left_type.ref()
5018 } else {
5019 node.receiver_type = node.left_type
5020 }
5021 } else if node.kind == .delete {
5022 c.markused_array_method(!c.is_builtin_mod, method_name)
5023 c.check_for_mut_receiver(mut node.left)
5024 unwrapped_left_sym := c.table.sym(unwrapped_left_type)
5025 if method := c.table.find_method(unwrapped_left_sym, method_name) {
5026 node.receiver_type = method.receiver_type
5027 }
5028 if node_args_len != 1 {
5029 c.error('`.delete()` expected 1 argument, but got ${node_args_len}', node.pos)
5030 } else {
5031 arg_typ := c.unwrap_generic(c.expr(mut arg0.expr))
5032 c.check_expected_call_arg(arg_typ, ast.int_type, node.language, arg0) or {
5033 c.error('${err.msg()} in argument 1 to `.delete()`', arg0.pos)
5034 }
5035 }
5036 node.return_type = ast.void_type
5037 } else if node.kind == .delete_many {
5038 if node_args_len != 2 {
5039 c.error('`.delete_many()` expected 2 arguments, but got ${node_args_len}', node.pos)
5040 } else {
5041 for i, mut arg in node.args {
5042 arg_typ := c.expr(mut arg.expr)
5043 c.check_expected_call_arg(arg_typ, ast.int_type, node.language, arg) or {
5044 c.error('${err.msg()} in argument ${i + 1} to `.delete_many()`', arg.pos)
5045 }
5046 }
5047 }
5048 node.return_type = ast.void_type
5049 } else if node.kind == .reverse {
5050 c.table.used_features.arr_reverse = true
5051 }
5052 return node.return_type
5053}
5054
5055fn (mut c Checker) fixed_array_builtin_method_call(mut node ast.CallExpr, left_type ast.Type) ast.Type {
5056 left_sym := c.table.final_sym(left_type)
5057 method_name := node.name
5058 unwrapped_left_type := c.unwrap_generic(left_type)
5059 unaliased_left_type := c.table.unaliased_type(unwrapped_left_type)
5060 array_info := if left_sym.info is ast.ArrayFixed {
5061 left_sym.info as ast.ArrayFixed
5062 } else {
5063 c.table.sym(unaliased_left_type).info as ast.ArrayFixed
5064 }
5065 node_args_len := node.args.len
5066 mut arg0 := if node_args_len > 0 { node.args[0] } else { ast.CallArg{} }
5067 elem_typ := array_info.elem_type
5068 if node.kind in [.index, .last_index] {
5069 if node_args_len != 1 {
5070 c.error('`.${method_name}()` expected 1 argument, but got ${node_args_len}', node.pos)
5071 return ast.int_type
5072 } else if (node.kind == .index && !left_sym.has_method('index'))
5073 || (node.kind == .last_index && !left_sym.has_method('last_index')) {
5074 arg_typ := c.expr(mut arg0.expr)
5075 c.check_expected_call_arg(arg_typ, elem_typ, node.language, arg0) or {
5076 c.error('${err.msg()} in argument 1 to `.${method_name}()`', arg0.pos)
5077 return ast.int_type
5078 }
5079 }
5080 for i, mut arg in node.args {
5081 node.args[i].typ = c.expr(mut arg.expr)
5082 }
5083 node.return_type = ast.int_type
5084 } else if node.kind == .contains {
5085 if node_args_len != 1 {
5086 c.error('`.contains()` expected 1 argument, but got ${node_args_len}', node.pos)
5087 return ast.bool_type
5088 } else if !left_sym.has_method('contains') {
5089 arg_typ := c.expr(mut arg0.expr)
5090 c.check_expected_call_arg(arg_typ, elem_typ, node.language, arg0) or {
5091 c.error('${err.msg()} in argument 1 to `.contains()`', arg0.pos)
5092 return ast.bool_type
5093 }
5094 }
5095 for i, mut arg in node.args {
5096 node.args[i].typ = c.expr(mut arg.expr)
5097 }
5098 node.return_type = ast.bool_type
5099 } else if node.kind in [.any, .all] {
5100 if node_args_len != 1 {
5101 c.error('`.${method_name}` expected 1 argument, but got ${node_args_len}', node.pos)
5102 return ast.bool_type
5103 }
5104 if node_args_len > 0 && mut arg0.expr is ast.LambdaExpr {
5105 if arg0.expr.params.len != 1 {
5106 c.error('lambda expressions used in the builtin array methods require exactly 1 parameter',
5107 arg0.expr.pos)
5108 return ast.bool_type
5109 }
5110 c.support_lambda_expr_one_param(elem_typ, ast.bool_type, mut arg0.expr)
5111 } else {
5112 // position of `it` doesn't matter
5113 scope_register_it(mut node.scope, node.pos, elem_typ)
5114 }
5115 c.expr(mut arg0.expr)
5116 c.check_predicate_param(false, elem_typ, node)
5117 node.return_type = ast.bool_type
5118 } else if node.kind == .count {
5119 if node_args_len != 1 {
5120 c.error('`.${method_name}` expected 1 argument, but got ${node_args_len}', node.pos)
5121 return ast.bool_type
5122 }
5123 if node_args_len > 0 && mut arg0.expr is ast.LambdaExpr {
5124 if arg0.expr.params.len != 1 {
5125 c.error('lambda expressions used in the builtin array methods require exactly 1 parameter',
5126 arg0.expr.pos)
5127 return ast.bool_type
5128 }
5129 c.support_lambda_expr_one_param(elem_typ, ast.bool_type, mut arg0.expr)
5130 } else {
5131 // position of `it` doesn't matter
5132 scope_register_it(mut node.scope, node.pos, elem_typ)
5133 }
5134 c.expr(mut arg0.expr)
5135 c.check_predicate_param(false, elem_typ, node)
5136 node.return_type = ast.int_type
5137 } else if node.kind == .filter {
5138 if node_args_len != 1 {
5139 c.error('`.${method_name}` expected 1 argument, but got ${node_args_len}', node.pos)
5140 }
5141 // position of `it` doesn't matter
5142 scope_register_it(mut node.scope, node.pos, elem_typ)
5143 c.expr(mut arg0.expr)
5144 c.check_predicate_param(false, elem_typ, node)
5145 node.return_type = c.table.find_or_register_array(elem_typ)
5146 } else if node.kind == .wait {
5147 elem_sym := c.table.sym(elem_typ)
5148 if elem_sym.kind == .thread {
5149 if node_args_len != 0 {
5150 c.error('`.wait()` does not have any arguments', arg0.pos)
5151 }
5152 thread_ret_type := c.unwrap_generic(elem_sym.thread_info().return_type)
5153 node.return_type = c.thread_array_wait_return_type(thread_ret_type)
5154 } else {
5155 c.error('`${left_sym.name}` has no method `wait()` (only thread handles and arrays of them have)',
5156 node.left.pos())
5157 }
5158 } else if node.kind == .map {
5159 if node_args_len != 1 {
5160 c.error('`.${method_name}` expected 1 argument, but got ${node_args_len}', node.pos)
5161 return ast.void_type
5162 }
5163 if mut arg0.expr is ast.LambdaExpr {
5164 if arg0.expr.params.len != 1 {
5165 c.error('lambda expressions used in the builtin array methods require exactly 1 parameter',
5166 arg0.expr.pos)
5167 return ast.void_type
5168 }
5169 c.lambda_expr_fix_type_of_param(mut arg0.expr, mut arg0.expr.params[0], elem_typ)
5170 le_type := c.expr(mut arg0.expr.expr)
5171 c.support_lambda_expr_one_param(elem_typ, le_type, mut arg0.expr)
5172 } else {
5173 // position of `it` doesn't matter
5174 scope_register_it(mut node.scope, node.pos, elem_typ)
5175 }
5176
5177 c.check_predicate_param(true, elem_typ, node)
5178 arg_type := c.check_expr_option_or_result_call(arg0.expr, c.expr(mut arg0.expr))
5179 arg_sym := c.table.sym(arg_type)
5180 ret_type := match arg_sym.info {
5181 ast.FnType {
5182 if arg0.expr is ast.SelectorExpr {
5183 arg_type
5184 } else {
5185 arg_sym.info.func.return_type
5186 }
5187 }
5188 else {
5189 arg_type
5190 }
5191 }
5192
5193 node.return_type = c.table.find_or_register_array_fixed(c.unwrap_generic(ret_type),
5194 array_info.size, array_info.size_expr, false)
5195 if node.return_type.has_flag(.shared_f) {
5196 node.return_type = node.return_type.clear_flag(.shared_f).deref()
5197 }
5198 ret_sym := c.table.sym(ret_type)
5199 if ret_sym.kind == .multi_return {
5200 c.error('returning multiple values is not supported in .map() calls', node.pos)
5201 }
5202 } else if node.kind in [.sort, .sorted] {
5203 if node.kind == .sort {
5204 if node.left is ast.CallExpr {
5205 c.error('the `sort()` method can be called only on mutable receivers, but `${ast.Expr(node.left)}` is a call expression',
5206 node.pos)
5207 }
5208 c.check_for_mut_receiver(mut node.left)
5209 }
5210 // position of `a` and `b` doesn't matter, they're the same
5211 scope_register_a_b(mut node.scope, node.pos, elem_typ)
5212
5213 if node_args_len > 1 {
5214 c.error('expected 0 or 1 argument, but got ${node_args_len}', node.pos)
5215 } else if node_args_len == 1 {
5216 if mut arg0.expr is ast.LambdaExpr {
5217 c.support_lambda_expr_in_sort(elem_typ.ref(), ast.bool_type, mut arg0.expr)
5218 } else if mut arg0.expr is ast.InfixExpr {
5219 c.check_sort_external_variable_access(ast.Expr(arg0.expr))
5220 if arg0.expr.op !in [.gt, .lt] {
5221 c.error('`.${method_name}()` can only use `<` or `>` comparison', node.pos)
5222 }
5223 left_name := '${arg0.expr.left}'[0]
5224 right_name := '${arg0.expr.right}'[0]
5225 if left_name !in [`a`, `b`] || right_name !in [`a`, `b`] {
5226 c.error('`.${method_name}()` can only use `a` or `b` as argument, e.g. `arr.${method_name}(a < b)`',
5227 node.pos)
5228 } else if left_name == right_name {
5229 c.error('`.${method_name}()` cannot use same argument', node.pos)
5230 }
5231 if arg0.expr.left !in [ast.Ident, ast.SelectorExpr, ast.IndexExpr]
5232 || arg0.expr.right !in [ast.Ident, ast.SelectorExpr, ast.IndexExpr] {
5233 c.error('`.${method_name}()` can only use ident, index or selector as argument, \ne.g. `arr.${method_name}(a < b)`, `arr.${method_name}(a.id < b.id)`, `arr.${method_name}(a[0] < b[0])`',
5234 node.pos)
5235 }
5236 } else {
5237 c.error(
5238 '`.${method_name}()` requires a `<` or `>` comparison as the first and only argument' +
5239 '\ne.g. `users.${method_name}(a.id < b.id)`', node.pos)
5240 }
5241 } else if !(c.table.sym(elem_typ).has_method('<')
5242 || c.table.unalias_num_type(elem_typ) in [ast.int_type, ast.int_type.ref(), ast.string_type, ast.string_type.ref(), ast.i8_type, ast.i16_type, ast.i32_type, ast.i64_type, ast.u8_type, ast.rune_type, ast.u16_type, ast.u32_type, ast.u64_type, ast.f32_type, ast.f64_type, ast.char_type, ast.bool_type, ast.float_literal_type, ast.int_literal_type]) {
5243 c.error('custom sorting condition must be supplied for type `${c.table.type_to_str(elem_typ)}`',
5244 node.pos)
5245 }
5246 for mut arg in node.args {
5247 c.check_expr_option_or_result_call(arg.expr, c.expr(mut arg.expr))
5248 }
5249 if node.kind == .sort {
5250 node.return_type = ast.void_type
5251 } else {
5252 node.return_type = node.left_type
5253 }
5254 } else if node.kind in [.sort_with_compare, .sorted_with_compare] {
5255 if node_args_len != 1 {
5256 c.error('`.${method_name}()` expected 1 argument, but got ${node_args_len}', node.pos)
5257 } else {
5258 if mut arg0.expr is ast.LambdaExpr {
5259 c.support_lambda_expr_in_sort(elem_typ.ref(), ast.int_type, mut arg0.expr)
5260 }
5261 arg_type := c.expr(mut arg0.expr)
5262 arg_sym := c.table.sym(arg_type)
5263 if arg_sym.kind == .function {
5264 func_info := arg_sym.info as ast.FnType
5265 if func_info.func.params.len == 2 {
5266 if func_info.func.params[0].typ.nr_muls() != elem_typ.nr_muls() + 1 {
5267 arg_typ_str := c.table.type_to_str(func_info.func.params[0].typ)
5268 expected_typ_str := c.table.type_to_str(elem_typ.ref())
5269 c.error('${method_name} callback function parameter `${func_info.func.params[0].name}` with type `${arg_typ_str}` should be `${expected_typ_str}`',
5270 func_info.func.params[0].type_pos)
5271 }
5272 if func_info.func.params[1].typ.nr_muls() != elem_typ.nr_muls() + 1 {
5273 arg_typ_str := c.table.type_to_str(func_info.func.params[1].typ)
5274 expected_typ_str := c.table.type_to_str(elem_typ.ref())
5275 c.error('${method_name} callback function parameter `${func_info.func.params[1].name}` with type `${arg_typ_str}` should be `${expected_typ_str}`',
5276 func_info.func.params[1].type_pos)
5277 }
5278 }
5279 }
5280 arg0.typ = arg_type
5281 if method := c.table.find_method(left_sym, method_name) {
5282 c.check_expected_call_arg(arg_type, method.params[1].typ, node.language, arg0) or {
5283 c.error('${err.msg()} in argument 1 to `${left_sym.name}.${method_name}`',
5284 arg0.pos)
5285 }
5286 }
5287 for mut arg in node.args {
5288 c.check_expr_option_or_result_call(arg.expr, c.expr(mut arg.expr))
5289 }
5290 if node.kind == .sort_with_compare {
5291 c.check_for_mut_receiver(mut node.left)
5292 node.return_type = ast.void_type
5293 node.receiver_type = node.left_type.ref()
5294 } else {
5295 node.return_type = node.left_type
5296 node.receiver_type = node.left_type
5297 }
5298 }
5299 } else if node.kind in [.reverse, .reverse_in_place] {
5300 if node_args_len != 0 {
5301 c.error('`.${method_name}` does not have any arguments', arg0.pos)
5302 } else {
5303 if node.kind == .reverse {
5304 node.return_type = node.left_type
5305 } else {
5306 c.check_for_mut_receiver(mut node.left)
5307 node.return_type = ast.void_type
5308 }
5309 }
5310 }
5311 return node.return_type
5312}
5313
5314fn (mut c Checker) check_for_mut_receiver(mut expr ast.Expr) (string, token.Pos) {
5315 to_lock, pos := c.fail_if_immutable(mut expr)
5316 if !expr.is_lvalue() {
5317 c.error('cannot pass expression as `mut`', expr.pos())
5318 }
5319 return to_lock, pos
5320}
5321
5322fn scope_register_it(mut s ast.Scope, pos token.Pos, typ ast.Type) {
5323 scope_register_special_var_name(mut s, pos, typ, 'it')
5324}
5325
5326fn scope_register_a_b(mut s ast.Scope, pos token.Pos, typ ast.Type) {
5327 scope_register_special_var_name(mut s, pos, typ.ref(), 'a')
5328 scope_register_special_var_name(mut s, pos, typ.ref(), 'b')
5329}
5330
5331fn scope_register_special_var_name(mut s ast.Scope, pos token.Pos, typ ast.Type, name string) {
5332 if name in s.objects {
5333 mut obj := unsafe { s.objects[name] }
5334 if mut obj is ast.Var {
5335 if obj.is_special {
5336 obj.pos = pos
5337 obj.typ = typ
5338 obj.orig_type = ast.no_type
5339 obj.smartcasts = []
5340 obj.is_unwrapped = false
5341 return
5342 }
5343 }
5344 }
5345 s.register(ast.Var{
5346 name: name
5347 pos: pos
5348 typ: typ
5349 is_used: false
5350 is_special: true
5351 })
5352}
5353
5354// resolve_fn_return_type resolves the generic return type of fn with its related CallExpr
5355fn (mut c Checker) resolve_fn_return_type(func &ast.Fn, node ast.CallExpr, concrete_types []ast.Type) ast.Type {
5356 mut ret_type := func.return_type
5357 if node.is_method {
5358 // generic method being called from a non-generic func
5359 if func.generic_names.len > 0 && func.return_type.has_flag(.generic)
5360 && c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len == 0 {
5361 ret_type = c.table.unwrap_generic_type(func.return_type, func.generic_names,
5362 concrete_types)
5363 }
5364 // generic method called without generic type to be resolved on call
5365 if node.concrete_types.len > 0 && node.concrete_types.all(!it.has_flag(.generic))
5366 && func.return_type.has_flag(.generic) && func.generic_names.len > 0
5367 && func.generic_names.len == node.concrete_types.len {
5368 if typ := c.table.convert_generic_type(func.return_type, func.generic_names,
5369 concrete_types)
5370 {
5371 return typ
5372 } else {
5373 return c.table.unwrap_generic_type(func.return_type, func.generic_names,
5374 concrete_types)
5375 }
5376 }
5377 } else {
5378 // generic func called from non-generic func
5379 if node.concrete_types.len > 0 && func.return_type != 0 && c.table.cur_fn != unsafe { nil }
5380 && c.table.cur_fn.generic_names.len == 0 {
5381 if typ := c.table.convert_generic_type(func.return_type, func.generic_names,
5382 concrete_types)
5383 {
5384 return typ
5385 }
5386 return ret_type
5387 }
5388 if func.generic_names.len > 0 {
5389 has_generic := node.raw_concrete_types.any(it.has_flag(.generic))
5390 has_any_generic := node.concrete_types.any(it.has_flag(.generic))
5391 needs_resolved_concrete_types :=
5392 node.raw_concrete_types.any(c.needs_unwrap_generic_type(it))
5393 // fn call with any generic type to be resolved on call (e.g. foo[T]())
5394 if has_generic || has_any_generic {
5395 if needs_resolved_concrete_types {
5396 if typ := c.table.convert_generic_type(func.return_type, func.generic_names,
5397 concrete_types)
5398 {
5399 return typ
5400 }
5401 }
5402 if typ := c.table.convert_generic_type(func.return_type, func.generic_names,
5403 node.concrete_types)
5404 {
5405 typ_sym := c.table.sym(typ)
5406 has_generic_concrete := typ_sym.kind == .generic_inst
5407 && typ_sym.info is ast.GenericInst
5408 && typ_sym.info.concrete_types.any(it.has_flag(.generic))
5409 if typ.has_flag(.generic) || has_generic_concrete {
5410 return typ
5411 }
5412 }
5413 } else {
5414 // fn call with all generic types already resolved to its concrete ones (e.g. foo[int]())
5415 if node.concrete_types.len > 0 && !has_any_generic {
5416 if typ := c.table.convert_generic_type(func.return_type, func.generic_names,
5417 node.concrete_types)
5418 {
5419 return typ
5420 }
5421 }
5422 // use fresh resolved concrete_types list
5423 if typ := c.table.convert_generic_type(func.return_type, func.generic_names,
5424 concrete_types)
5425 {
5426 return typ
5427 }
5428 }
5429 }
5430 }
5431 return ret_type
5432}
5433
5434fn (mut c Checker) check_must_use_call_result(node &ast.CallExpr, f &ast.Fn, label string) {
5435 if node.is_return_used {
5436 return
5437 }
5438 if f.return_type == ast.void_type {
5439 return
5440 }
5441 if f.is_must_use {
5442 c.warn('return value must be used, ${label} `${f.name}` was tagged with `@[must_use]`',
5443 node.pos)
5444 return
5445 }
5446 if c.pref.is_check_return {
5447 c.note('return value must be used', node.pos)
5448 }
5449}
5450
5451fn (mut c Checker) has_veb_context(typ ast.Type) bool {
5452 sym := c.table.final_sym(typ)
5453 if sym.name == 'veb.Context' {
5454 return true
5455 } else if sym.info is ast.Struct {
5456 for embed in sym.info.embeds {
5457 if c.table.sym(embed).name == 'veb.Context' {
5458 return true
5459 }
5460 }
5461 }
5462 return false
5463}
5464
5465fn (mut c Checker) supports_veb_string_bound_param(typ ast.Type) bool {
5466 unaliased_typ := c.table.unalias_num_type(c.unwrap_generic(typ))
5467 return unaliased_typ == ast.string_type || unaliased_typ.is_int()
5468 || unaliased_typ.idx() == ast.bool_type_idx
5469}
5470
5471fn (mut c Checker) check_variadic_arg(arg_expr ast.Expr, typ ast.Type, expected_type ast.Type, param_typ ast.Type,
5472 arg_num int, fn_name string, is_method bool, fn_is_variadic bool, is_single_array_arg bool,
5473 is_generic_fn bool, call_pos token.Pos, arg_pos token.Pos) {
5474 kind := c.table.sym(typ).kind
5475 is_decompose := arg_expr is ast.ArrayDecompose
5476 mut allow_variadic_pass := false
5477 if arg_expr is ast.Ident && !(is_method && is_generic_fn) {
5478 ident := arg_expr as ast.Ident
5479 if ident.obj is ast.Var {
5480 var_obj := ident.obj as ast.Var
5481 if var_obj.is_arg && c.table.cur_fn != unsafe { nil } && c.table.cur_fn.is_variadic
5482 && c.table.cur_fn.params.len > 0 && ident.name == c.table.cur_fn.params.last().name
5483 && fn_is_variadic {
5484 cur_fn_param_sym := c.table.sym(c.table.cur_fn.params.last().typ)
5485 if cur_fn_param_sym.info is ast.Array {
5486 allow_variadic_pass = cur_fn_param_sym.info.elem_type == expected_type
5487 }
5488 }
5489 }
5490 }
5491 styp := c.table.type_to_str(typ)
5492 elem_styp := c.table.type_to_str(expected_type)
5493 expected_kind := c.table.sym(expected_type).kind
5494 sum_type_needs_spread := expected_kind == .sum_type
5495 && !c.table.sumtype_has_variant(expected_type, typ, false) && is_single_array_arg
5496 if kind == .array && !is_decompose && !allow_variadic_pass
5497 && (expected_kind !in [.sum_type, .interface] || sum_type_needs_spread)
5498 && !param_typ.has_flag(.generic) && expected_type != typ {
5499 c.error('to pass `${arg_expr}` (${styp}) to `${fn_name}` (which accepts type `...${elem_styp}`), use `...${arg_expr}`',
5500 call_pos)
5501 } else if is_decompose && !param_typ.has_flag(.generic) && expected_kind != .interface
5502 && expected_type.idx() != typ.idx() && typ != ast.void_type {
5503 c.error('cannot use `...${styp}` as `...${elem_styp}` in argument ${arg_num} to `${fn_name}`',
5504 arg_pos)
5505 }
5506}
5507
5508// autofree_expr_has_or_block_in_chain returns true if expr is a CallExpr whose call chain
5509// contains an or_block (i.e. result/option propagation via `!` or `?`). Used by autofree to
5510// skip tmp-var pre-generation for arguments like `get_str()!.to_upper()`, where the inner
5511// call's or_block would interfere with output-buffer positioning in autofree_call_pregen.
5512fn autofree_expr_has_or_block_in_chain(expr ast.Expr) bool {
5513 if expr is ast.CallExpr {
5514 if expr.or_block.kind != .absent {
5515 return true
5516 }
5517 if expr.is_method {
5518 return autofree_expr_has_or_block_in_chain(expr.left)
5519 }
5520 }
5521 return false
5522}
5523