v4 / vlib / v / checker / fn.v
5695 lines · 5558 sloc · 203.71 KB · 5e934d589db08febfd9c80d6351e3b0f5cb626c2
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 && c.table.fully_unaliased_type(unwrapped_typ).is_ptr() {
1720 c.error('${fn_name}: cannot decode into a pointer type', expr.pos)
1721 } else if is_json_decode && kind !in [.struct, .sum_type, .map, .array] {
1722 c.error('${fn_name}: expected sum type, struct, map or array, found ${kind}',
1723 expr.pos)
1724 }
1725 } else {
1726 c.error('${fn_name}: unknown type `${sym.name}`', node.pos)
1727 }
1728 } else {
1729 typ := expr.type_name()
1730 c.error('${fn_name}: first argument needs to be a type, got `${typ}`', node.pos)
1731 return ast.void_type
1732 }
1733 c.expected_type = ast.string_type
1734 node.args[1].typ = c.expr(mut node.args[1].expr)
1735 if is_json_decode && node.args[1].typ != ast.string_type {
1736 c.error('json.decode: second argument needs to be a string', node.pos)
1737 }
1738 typ := expr as ast.TypeNode
1739 node.return_type = if is_json_decode { typ.typ.set_flag(.result) } else { typ.typ }
1740 if typ.typ.has_flag(.generic) {
1741 c.table.used_features.comptime_syms[c.unwrap_generic(typ.typ)] = true
1742 }
1743 return node.return_type
1744 } else if node.kind == .addr {
1745 if !c.inside_unsafe {
1746 c.error('`__addr` must be called from an unsafe block', node.pos)
1747 }
1748 if args_len != 1 {
1749 c.error('`__addr` requires 1 argument', node.pos)
1750 return ast.void_type
1751 }
1752 typ := c.expr(mut node.args[0].expr)
1753 node.args[0].typ = typ
1754 node.return_type = typ.ref()
1755 return node.return_type
1756 }
1757 // look for function in format `mod.fn` or `fn` (builtin)
1758 mut func := ast.Fn{}
1759 mut found := false
1760 mut found_in_args := false
1761 defer {
1762 if found {
1763 c.check_must_use_call_result(node, func, 'function')
1764 }
1765 }
1766 // anon fn direct call
1767 if node.left is ast.AnonFn {
1768 // it was set to anon for checker errors, clear for gen
1769 node.name = ''
1770 left := node.left as ast.AnonFn
1771 if left.typ != ast.no_type {
1772 anon_fn_sym := c.table.sym(left.typ)
1773 func = (anon_fn_sym.info as ast.FnType).func
1774 found = true
1775 }
1776 }
1777 // try prefix with current module as it would have never gotten prefixed
1778 if !found && node.mod != 'builtin' && !fn_name_has_dot {
1779 name_prefixed := '${node.mod}.${fn_name}'
1780 if f := c.table.find_fn(name_prefixed) {
1781 node.name = name_prefixed
1782 found = true
1783 func = f
1784 unsafe { c.table.fns[name_prefixed].usages++ }
1785 c.mark_fn_decl_as_referenced(f.fkey())
1786 }
1787 }
1788 if !found && node.left is ast.IndexExpr {
1789 left := node.left as ast.IndexExpr
1790 sym := c.table.final_sym(left.left_type)
1791 if sym.info is ast.Array {
1792 elem_sym := c.table.sym(sym.info.elem_type)
1793 if elem_sym.info is ast.FnType {
1794 func = elem_sym.info.func
1795 found = true
1796 node.is_fn_var = true
1797 node.fn_var_type = sym.info.elem_type
1798 } else {
1799 c.error('cannot call the element of the array, it is not a function', node.pos)
1800 }
1801 } else if sym.info is ast.Map {
1802 value_sym := c.table.sym(sym.info.value_type)
1803 if value_sym.info is ast.FnType {
1804 func = value_sym.info.func
1805 found = true
1806 node.is_fn_var = true
1807 node.fn_var_type = sym.info.value_type
1808 } else {
1809 c.error('cannot call the value of the map, it is not a function', node.pos)
1810 }
1811 } else if sym.info is ast.ArrayFixed {
1812 elem_sym := c.table.sym(sym.info.elem_type)
1813 if elem_sym.info is ast.FnType {
1814 func = elem_sym.info.func
1815 found = true
1816 node.is_fn_var = true
1817 node.fn_var_type = sym.info.elem_type
1818 } else {
1819 c.error('cannot call the element of the array, it is not a function', node.pos)
1820 }
1821 }
1822 }
1823 if !found && node.left is ast.CallExpr {
1824 left := node.left as ast.CallExpr
1825 if left.return_type != 0 {
1826 sym := c.table.sym(left.return_type)
1827 if sym.info is ast.FnType {
1828 node.return_type = sym.info.func.return_type
1829 found = true
1830 func = sym.info.func
1831 }
1832 }
1833 }
1834 if !found && node.name == '' && node.left_type != 0 {
1835 left_sym := c.table.final_sym(c.unwrap_generic(node.left_type))
1836 if left_sym.info is ast.FnType {
1837 func = left_sym.info.func
1838 found = true
1839 node.is_fn_var = true
1840 node.fn_var_type = node.left_type
1841 } else if left_sym.info is ast.GenericInst {
1842 parent_sym := c.table.sym(ast.new_type(left_sym.info.parent_idx))
1843 if parent_sym.info is ast.FnType {
1844 func = parent_sym.info.func
1845 found = true
1846 node.is_fn_var = true
1847 node.fn_var_type = node.left_type
1848 }
1849 }
1850 }
1851 // already prefixed (mod.fn) or C/builtin/main
1852 if !found {
1853 if f := c.table.find_fn(fn_name) {
1854 found = true
1855 func = f
1856 unsafe { c.table.fns[fn_name].usages++ }
1857 c.mark_fn_decl_as_referenced(f.fkey())
1858 }
1859 }
1860
1861 // static method resolution
1862 if !found && node.is_static_method {
1863 if index := fn_name.index('__static__') {
1864 owner_name := fn_name#[..index]
1865 // already imported symbol (static Foo.new() in another module)
1866 for import_sym in c.file.imports.filter(it.syms.any(it.name == owner_name)) {
1867 qualified_name := '${import_sym.mod}.${fn_name}'
1868 if f := c.table.find_fn(qualified_name) {
1869 found = true
1870 func = f
1871 node.name = qualified_name
1872 unsafe { c.table.fns[qualified_name].usages++ }
1873 c.mark_fn_decl_as_referenced(f.fkey())
1874 if !c.table.register_fn_concrete_types(f.name, concrete_types) {
1875 c.need_recheck_generic_fns = true
1876 }
1877 break
1878 }
1879 }
1880 if !found {
1881 // aliased static method on current mod
1882 full_type_name := if !fn_name_has_dot {
1883 c.mod + '.' + owner_name
1884 } else {
1885 owner_name
1886 }
1887 typ := c.table.find_type(full_type_name)
1888 if typ != 0 {
1889 final_sym := c.table.final_sym(typ)
1890 // try to find the unaliased static method name
1891 orig_name := final_sym.name + fn_name#[index..]
1892 if f := c.table.find_fn(orig_name) {
1893 found = true
1894 func = f
1895 unsafe { c.table.fns[orig_name].usages++ }
1896 c.mark_fn_decl_as_referenced(f.fkey())
1897 node.name = orig_name
1898 node.left_type = typ
1899 }
1900 }
1901 }
1902 }
1903 // Enum.from_string, `mod.Enum.from_string('item')`, `Enum.from_string('item')`
1904 if !found && fn_name.ends_with('__static__from_string') {
1905 enum_name := fn_name.all_before('__static__')
1906 mut full_enum_name := if !enum_name.contains('.') {
1907 c.mod + '.' + enum_name
1908 } else {
1909 enum_name
1910 }
1911 mut idx := c.table.type_idxs[full_enum_name]
1912 if idx > 0 {
1913 // is from another mod.
1914 if enum_name.contains('.') {
1915 if !c.check_type_and_visibility(full_enum_name, idx, .enum, node.pos) {
1916 return ast.void_type
1917 }
1918 } else {
1919 if !c.check_type_sym_kind(full_enum_name, idx, .enum, node.pos) {
1920 return ast.void_type
1921 }
1922 }
1923 } else if !enum_name.contains('.') {
1924 // find from another mods.
1925 for import_sym in c.file.imports {
1926 full_enum_name = '${import_sym.mod}.${enum_name}'
1927 idx = c.table.type_idxs[full_enum_name]
1928 if idx < 1 {
1929 continue
1930 }
1931 if !c.check_type_and_visibility(full_enum_name, idx, .enum, node.pos) {
1932 return ast.void_type
1933 }
1934 break
1935 }
1936 }
1937 if idx == 0 {
1938 c.error('unknown enum `${enum_name}`', node.pos)
1939 continue_check = false
1940 return ast.void_type
1941 }
1942
1943 ret_typ := ast.idx_to_type(idx).set_flag(.option)
1944 if args_len != 1 {
1945 c.error('expected 1 argument, but got ${args_len}', node.pos)
1946 } else {
1947 node.args[0].typ = c.expr(mut node.args[0].expr)
1948 if node.args[0].typ != ast.string_type {
1949 styp := c.table.type_to_str(node.args[0].typ)
1950 c.error('expected `string` argument, but got `${styp}`', node.pos)
1951 }
1952 }
1953 node.return_type = ret_typ
1954 return ret_typ
1955 }
1956 }
1957 if !found && c.pref.is_vsh {
1958 // TODO: test this hack more extensively
1959 os_name := 'os.${fn_name}'
1960 if f := c.table.find_fn(os_name) {
1961 if f.generic_names.len == node.concrete_types.len {
1962 node_alias_name := fkey
1963 mut existing := c.table.fn_generic_types[os_name] or { [] }
1964 existing << c.table.fn_generic_types[node_alias_name]
1965 existing << node.concrete_types
1966 c.table.fn_generic_types[os_name] = existing
1967 }
1968 node.name = os_name
1969 found = true
1970 func = f
1971 unsafe { c.table.fns[os_name].usages++ }
1972 c.mark_fn_decl_as_referenced(f.fkey())
1973 }
1974 }
1975 // check for arg (var) of fn type
1976 if !found {
1977 mut typ := ast.no_type
1978 if mut obj := node.scope.find(node.name) {
1979 match mut obj {
1980 ast.GlobalField {
1981 typ = obj.typ
1982 node.is_fn_var = true
1983 node.fn_var_type = typ
1984 }
1985 ast.Var {
1986 if obj.smartcasts.len != 0 {
1987 typ = c.exposed_smartcast_type(obj.orig_type, obj.smartcasts.last(),
1988 obj.is_mut)
1989 } else {
1990 if obj.typ == 0 {
1991 if mut obj.expr is ast.IfGuardExpr {
1992 typ = c.expr(mut obj.expr.expr).clear_option_and_result()
1993 } else {
1994 typ = c.expr(mut obj.expr)
1995 }
1996 } else {
1997 typ = obj.typ
1998 }
1999 }
2000 node.is_fn_var = true
2001 node.fn_var_type = typ
2002 if typ.nr_muls() > 0 {
2003 c.error('function pointer must be undereferenced first', node.pos)
2004 }
2005 }
2006 else {}
2007 }
2008 }
2009
2010 // XTODO document
2011 if typ != 0 {
2012 if node.concrete_types.len == 0 && typ.has_flag(.generic)
2013 && c.table.cur_fn != unsafe { nil } && c.table.cur_fn.is_method
2014 && node.name == c.table.cur_fn.receiver.name
2015 && c.table.cur_fn.receiver.typ.has_flag(.generic)
2016 && c.table.cur_fn.generic_names.len == c.table.cur_concrete_types.len {
2017 if fn_typ := c.table.convert_generic_type(typ, c.table.cur_fn.generic_names,
2018 c.table.cur_concrete_types)
2019 {
2020 typ = fn_typ
2021 node.fn_var_type = fn_typ
2022 }
2023 }
2024 generic_vts := c.table.final_sym(typ)
2025 if generic_vts.info is ast.FnType {
2026 func = generic_vts.info.func
2027 found = true
2028 found_in_args = true
2029 } else if generic_vts.info is ast.GenericInst {
2030 parent_sym := c.table.sym(ast.new_type(generic_vts.info.parent_idx))
2031 if parent_sym.info is ast.FnType {
2032 func = parent_sym.info.func
2033 found = true
2034 found_in_args = true
2035 }
2036 } else {
2037 vts := c.table.sym(c.unwrap_generic(typ))
2038 if vts.info is ast.FnType {
2039 func = vts.info.func
2040 found = true
2041 found_in_args = true
2042 } else if vts.info is ast.GenericInst {
2043 parent_sym := c.table.sym(ast.new_type(vts.info.parent_idx))
2044 if parent_sym.info is ast.FnType {
2045 func = parent_sym.info.func
2046 found = true
2047 found_in_args = true
2048 }
2049 }
2050 }
2051 }
2052 }
2053 // global fn?
2054 if !found {
2055 if obj := c.file.global_scope.find(fn_name) {
2056 if obj.typ != 0 {
2057 sym := c.table.sym(obj.typ)
2058 if sym.info is ast.FnType {
2059 func = sym.info.func
2060 found = true
2061 }
2062 }
2063 }
2064 }
2065 // a same module constant?
2066 if !found {
2067 // allow for `const abc = myfunc`, then calling `abc()`
2068 qualified_const_name := if fn_name_has_dot { fn_name } else { '${c.mod}.${fn_name}' }
2069 if mut obj := c.table.global_scope.find_const(qualified_const_name) {
2070 if obj.typ == 0 {
2071 obj.typ = c.expr(mut obj.expr)
2072 }
2073 if obj.typ != 0 {
2074 sym := c.table.sym(obj.typ)
2075 if sym.info is ast.FnType {
2076 // at this point, the const metadata should be already known,
2077 // and we are sure that it is just a function
2078 unsafe { c.table.fns[qualified_const_name].usages++ }
2079 unsafe { c.table.fns[func.name].usages++ }
2080 found = true
2081 func = sym.info.func
2082 node.is_fn_a_const = true
2083 node.fn_var_type = obj.typ
2084 node.const_name = qualified_const_name
2085 c.mark_const_decl_as_referenced(qualified_const_name)
2086 }
2087 }
2088 }
2089 }
2090
2091 if !found {
2092 if typ := c.try_resolve_c_type_cast_call(mut node) {
2093 return typ
2094 }
2095 if c.resolve_self_method_call(mut node) {
2096 return c.method_call(mut node, mut continue_check)
2097 }
2098 continue_check = false
2099 if dot_index := fn_name.index('.') {
2100 if !fn_name[0].is_capital() {
2101 mod_name := fn_name#[..dot_index]
2102 mut mod_func_names := []string{}
2103 for ctfnk, ctfnv in c.table.fns {
2104 if ctfnv.is_pub && ctfnk.starts_with(mod_name) {
2105 mod_func_names << ctfnk
2106 }
2107 }
2108 suggestion := util.new_suggestion(fn_name, mod_func_names)
2109 c.error(suggestion.say('unknown function: ${fn_name} '), node.pos)
2110 return ast.void_type
2111 }
2112 }
2113 name := node.get_name()
2114 if c.pref.experimental && name.starts_with('C.') {
2115 println('unknown function ${name}, ' +
2116 'searching for the C definition in one of the #includes')
2117 mut includes := []string{cap: 5}
2118 for stmt in c.file.stmts {
2119 if stmt is ast.HashStmt {
2120 if stmt.kind == 'include' {
2121 includes << '#include ${stmt.main}'
2122 }
2123 }
2124 }
2125 mut tmp_c_file_with_includes := os.create('tmp.c') or { panic(err) }
2126 tmp_c_file_with_includes.write_string(includes.join('\n')) or { panic(err) }
2127 tmp_c_file_with_includes.close()
2128
2129 os.execute('${os.quoted_path(@VEXE)} translate fndef ${name[2..]} tmp.c')
2130 x := os.read_file('__cdefs_autogen.v') or {
2131 for mut arg in node.args {
2132 c.expr(mut arg.expr)
2133 }
2134 return ast.void_type
2135 }
2136 if x.contains('fn ${name}') {
2137 println(
2138 'function definition for ${name} has been generated in __cdefs_autogen.v. ' +
2139 'Please re-run the compilation with `v .` or `v run .`')
2140 os.rm('tmp.c') or {}
2141 exit(0)
2142 } else {
2143 println('Failed to generate function definition. Please report it via github.com/vlang/v/issues')
2144 }
2145 os.rm('tmp.c') or {}
2146 }
2147 for mut arg in node.args {
2148 c.expr(mut arg.expr)
2149 }
2150 if name.starts_with('C.') {
2151 c.error('unknown C function: `${name}`. `C.` calls are external C calls; declare the function with `fn ${name}(...)` and include/link the C header/library that provides it.',
2152 node.pos)
2153 return ast.void_type
2154 }
2155 c.error('unknown function: ${node.get_name()}', node.pos)
2156 return ast.void_type
2157 }
2158
2159 node.is_file_translated = func.is_file_translated
2160 node.is_noreturn = func.is_noreturn
2161 node.is_expand_simple_interpolation = func.is_expand_simple_interpolation
2162 node.is_ctor_new = func.is_ctor_new
2163 if node.is_fn_var && node.concrete_types.len > 0 && func.generic_names.len == 0 {
2164 if node.raw_concrete_types.len == 0 {
2165 node.raw_concrete_types = node.concrete_types.clone()
2166 }
2167 node.concrete_types = []
2168 }
2169 if !found_in_args {
2170 if node.scope.known_var(fn_name) {
2171 c.error('ambiguous call to: `${fn_name}`, may refer to fn `${fn_name}` or variable `${fn_name}`',
2172 node.pos)
2173 }
2174 }
2175 if !func.is_pub && func.language == .v && func.name != '' && func.mod.len > 0
2176 && func.mod != c.mod && !c.pref.is_test {
2177 c.error('function `${func.name}` is private', node.pos)
2178 }
2179 if c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.is_deprecated && func.is_deprecated {
2180 c.deprecate('function', func.name, func.attrs, node.pos)
2181 }
2182 if func.is_unsafe && !c.inside_unsafe
2183 && (func.language != .c || (func.name[2] in [`m`, `s`] && func.mod == 'builtin')) {
2184 // builtin C.m*, C.s* only - temp
2185 if !c.pref.translated && !c.file.is_translated {
2186 c.warn('function `${func.name}` must be called from an `unsafe` block', node.pos)
2187 }
2188 }
2189 node.is_keep_alive = func.is_keep_alive
2190 if func.language == .v && func.no_body && !c.pref.translated && !c.file.is_translated
2191 && !func.is_unsafe && !func.is_file_translated && func.mod != 'builtin' {
2192 c.error('cannot call a function that does not have a body', node.pos)
2193 }
2194 if node.concrete_types.len > 0 && func.generic_names.len > 0
2195 && node.concrete_types.len != func.generic_names.len {
2196 plural := if func.generic_names.len == 1 { '' } else { 's' }
2197 c.error('expected ${func.generic_names.len} generic parameter${plural}, got ${node.concrete_types.len}',
2198 node.concrete_list_pos)
2199 }
2200 for concrete_type in node.concrete_types {
2201 c.ensure_type_exists(concrete_type, node.concrete_list_pos)
2202 }
2203 if func.generic_names.len > 0 && args_len == 0 && node.concrete_types.len == 0 {
2204 c.error('no argument generic function must add concrete types, e.g. foo[int]()', node.pos)
2205 return func.return_type
2206 }
2207 if func.return_type == ast.void_type && func.is_conditional
2208 && func.ctdefine_idx != ast.invalid_type_idx {
2209 node.should_be_skipped =
2210 c.evaluate_once_comptime_if_attribute(mut func.attrs[func.ctdefine_idx])
2211 }
2212 if node.kind == .free && func.mod == 'builtin' && args_len == 1
2213 && c.table.cur_fn != unsafe { nil } && c.table.cur_fn.is_method
2214 && c.table.cur_fn.short_name != 'free' && !c.is_builtin_mod && !c.inside_recheck {
2215 if node.args[0].expr is ast.Ident {
2216 if node.args[0].expr.name == c.table.cur_fn.receiver.name {
2217 receiver_sym := c.table.sym(c.table.cur_fn.receiver.typ)
2218 if !receiver_sym.is_heap() {
2219 c.warn('calling builtin `free()` on a method receiver will cause a' +
2220 ' runtime crash when the receiver is stack-allocated; free individual fields instead',
2221 node.pos)
2222 }
2223 }
2224 }
2225 }
2226
2227 // dont check number of args for JS functions since arguments are not required
2228 if node.language != .js {
2229 for i, mut call_arg in node.args {
2230 is_call_expr := call_arg.expr is ast.CallExpr
2231 if is_call_expr {
2232 mut arg_expr := call_arg.expr
2233 node.args[i].typ = c.expr(mut arg_expr)
2234 call_arg.expr = arg_expr
2235 } else if mut call_arg.expr is ast.LambdaExpr {
2236 if node.concrete_types.len > 0 {
2237 call_arg.expr.call_ctx = unsafe { node }
2238 }
2239 }
2240 }
2241 c.check_expected_arg_count(mut node, func) or {
2242 node.return_type = func.return_type
2243 return func.return_type
2244 }
2245 args_len = node.args.len
2246 }
2247 // println / eprintln / panic can print anything
2248 if args_len > 0 && fn_name in print_everything_fns && func.mod == 'builtin' {
2249 node.args[0].ct_expr = c.comptime.is_comptime(node.args[0].expr)
2250 c.builtin_args(mut node, fn_name, func)
2251 c.markused_print_call(mut node)
2252 return func.return_type
2253 }
2254 // `return error(err)` -> `return err`
2255 if args_len == 1 && node.kind == .error {
2256 mut arg := node.args[0]
2257 node.args[0].typ = c.expr(mut arg.expr)
2258 node.args[0].ct_expr = c.comptime.is_comptime(node.args[0].expr)
2259 if node.args[0].typ == ast.error_type {
2260 c.warn('`error(${arg})` can be shortened to just `${arg}`', node.pos)
2261 }
2262 }
2263 c.set_node_expected_arg_types(mut node, func)
2264 if !c.is_js_backend && args_len > 0 && func.params.len == 0 {
2265 c.error('too many arguments in call to `${func.name}` (non-js backend: ${c.pref.backend})',
2266 node.pos)
2267 }
2268 mut has_decompose := false
2269 mut has_unresolved_generic_param := false
2270 mut nr_multi_values := 0
2271 variadic_start := variadic_call_arg_start_idx(func, false)
2272 has_typed_variadic := func.is_variadic && !func.is_c_variadic
2273 for i, mut call_arg in node.args {
2274 mut variadic_arg_handled := false
2275 if func.params.len == 0 {
2276 continue
2277 }
2278 if !c.inside_recheck {
2279 call_arg.ct_expr = c.comptime.is_comptime(call_arg.expr)
2280 }
2281 if !func.is_variadic && has_decompose {
2282 c.error('cannot have parameter after array decompose', node.pos)
2283 }
2284 param_i := i + nr_multi_values
2285 mut param := call_arg_param_for_fn(func, param_i, false)
2286 if node.is_fn_var && param.typ.has_flag(.generic) && c.table.cur_fn != unsafe { nil }
2287 && c.table.cur_fn.generic_names.len > 0
2288 && c.table.cur_fn.generic_names.len == c.table.cur_concrete_types.len {
2289 mut unwrapped := param
2290 unwrapped.typ = c.table.unwrap_generic_param_type(param, c.table.cur_fn.generic_names,
2291 c.table.cur_concrete_types)
2292 param = unwrapped
2293 }
2294 param.typ = c.resolve_call_arg_param_type(call_arg, param, func.generic_names,
2295 concrete_types)
2296 // registers if the arg must be passed by ref to disable auto deref args
2297 call_arg.should_be_ptr = param.typ.is_ptr() && !param.is_mut
2298 if func.is_variadic && call_arg.expr is ast.ArrayDecompose {
2299 if param_i > variadic_start {
2300 c.error('too many arguments in call to `${func.name}`', node.pos)
2301 }
2302 }
2303 has_decompose = call_arg.expr is ast.ArrayDecompose
2304 if !func.is_variadic && call_arg.expr is ast.ArrayDecompose {
2305 array_decompose_expr := call_arg.expr as ast.ArrayDecompose
2306 if array_decompose_expr.expr is ast.ArrayInit {
2307 extra_params := func.params.len - i
2308 array_init := array_decompose_expr.expr as ast.ArrayInit
2309 if array_init.exprs.len < extra_params {
2310 elem_word := if array_init.exprs.len == 1 { 'element' } else { 'elements' }
2311 verb_word := if extra_params == 1 { 'is' } else { 'are' }
2312 c.error('array decompose has ${array_init.exprs.len} ${elem_word} but ${extra_params} ${verb_word} needed for `${func.name}`',
2313 call_arg.pos)
2314 }
2315 }
2316 }
2317 already_checked := node.language != .js && call_arg.expr is ast.CallExpr
2318 if has_typed_variadic && param_i >= variadic_start {
2319 param_sym := c.table.sym(param.typ)
2320 mut expected_type := param.typ
2321 if param_sym.info is ast.Array {
2322 expected_type = param_sym.info.elem_type
2323 c.expected_type = expected_type
2324 }
2325 typ := if already_checked && mut call_arg.expr is ast.CallExpr {
2326 node.args[i].typ
2327 } else {
2328 c.expr(mut call_arg.expr)
2329 }
2330 if i == args_len - 1 {
2331 variadic_arg_handled = c.check_variadic_arg(call_arg.expr, typ, expected_type,
2332 param.typ, i + 1, func.name, func.is_method, func.is_variadic, args_len == 1
2333 && i == 0, func.generic_names.len > 0, node.pos, call_arg.pos)
2334 }
2335 } else {
2336 c.expected_type = param.typ
2337 }
2338
2339 e_sym := c.table.sym(c.expected_type)
2340 if call_arg.expr is ast.MapInit && e_sym.kind == .struct {
2341 c.error('cannot initialize a struct with a map', call_arg.pos)
2342 continue
2343 } else if call_arg.expr is ast.StructInit && e_sym.kind == .map
2344 && !call_arg.expr.typ.has_flag(.generic) {
2345 c.error('cannot initialize a map with a struct', call_arg.pos)
2346 continue
2347 }
2348 mut arg_typ := c.check_expr_option_or_result_call(call_arg.expr, if already_checked {
2349 node.args[i].typ
2350 } else {
2351 c.expr(mut call_arg.expr)
2352 })
2353 arg_typ = c.maybe_wrap_index_expr_smartcast(mut call_arg.expr, arg_typ)
2354 is_struct_init_arg := call_arg.expr is ast.StructInit
2355 if is_struct_init_arg {
2356 mut arg_expr := call_arg.expr
2357 arg_typ = c.expr(mut arg_expr)
2358 }
2359 node.args[i].expr = call_arg.expr
2360 node.args[i].typ = arg_typ
2361 call_arg.typ = arg_typ
2362 if c.comptime.comptime_for_field_var != '' {
2363 if mut call_arg.expr is ast.Ident
2364 && call_arg.expr.name == c.comptime.comptime_for_field_var
2365 && call_arg.expr.obj is ast.Var {
2366 node.args[i].typ = call_arg.expr.obj.typ
2367 }
2368 }
2369 // sumtype coercion
2370 param_type_sym := c.table.sym(param.typ)
2371 if param_type_sym.kind == .placeholder {
2372 base_type := c.table.find_type(param_type_sym.ngname)
2373 if base_type != 0 {
2374 base_sym := c.table.sym(base_type)
2375 if base_sym.kind == .sum_type && base_sym.info is ast.SumType {
2376 base_info := base_sym.info as ast.SumType
2377 arg_typ_sym := c.table.sym(arg_typ)
2378 for variant in base_info.variants {
2379 variant_sym := c.table.sym(variant)
2380 variant_base_name := variant_sym.ngname
2381 if variant_base_name == arg_typ_sym.ngname {
2382 node.args[i].expr = ast.CastExpr{
2383 expr: call_arg.expr
2384 typ: param.typ
2385 typname: c.table.type_to_str(param.typ)
2386 pos: call_arg.expr.pos()
2387 }
2388 node.args[i].typ = param.typ
2389 arg_typ = param.typ
2390 break
2391 }
2392 }
2393 }
2394 }
2395 }
2396 if param_type_sym.kind == .sum_type
2397 && !c.table.sumtype_has_variant(param.typ, arg_typ, false)
2398 && c.table.sumtype_has_variant_recursive(param.typ, arg_typ, false) {
2399 call_arg.expr = ast.CastExpr{
2400 expr: call_arg.expr
2401 typ: param.typ
2402 typname: c.table.type_to_str(param.typ)
2403 expr_type: arg_typ
2404 pos: call_arg.expr.pos()
2405 }
2406 call_arg.typ = param.typ
2407 node.args[i].expr = call_arg.expr
2408 node.args[i].typ = param.typ
2409 arg_typ = param.typ
2410 }
2411 mut arg_typ_sym := c.table.sym(arg_typ)
2412 if param.typ.has_flag(.generic) {
2413 if arg_typ_sym.kind == .none && !param.typ.has_flag(.option) {
2414 c.error('cannot use `none` as generic argument', call_arg.pos)
2415 }
2416 has_unresolved_generic_param = c.check_unresolved_generic_param(node, call_arg)
2417 || has_unresolved_generic_param
2418 }
2419 param_typ_sym := c.table.sym(param.typ)
2420 if has_typed_variadic && arg_typ.has_flag(.variadic) && args_len - 1 > i {
2421 c.error('when forwarding a variadic variable, it must be the final argument',
2422 call_arg.pos)
2423 }
2424 arg_share := param.typ.share()
2425 if arg_share == .shared_t && (c.locked_names.len > 0 || c.rlocked_names.len > 0) {
2426 c.error('function with `shared` arguments cannot be called inside `lock`/`rlock` block',
2427 call_arg.pos)
2428 }
2429 call_arg = c.implicit_mut_call_arg(param, call_arg)
2430 node.args[i] = call_arg
2431 if call_arg.is_mut {
2432 to_lock, pos := c.fail_if_immutable(mut call_arg.expr)
2433 call_arg_expr_pos := call_arg.expr.pos()
2434 if !call_arg.expr.is_lvalue() {
2435 if call_arg.expr is ast.StructInit {
2436 c.error('cannot pass a struct initialization as `mut`, you may want to use a variable `mut var := ${ast.Expr(call_arg.expr)}`',
2437 call_arg_expr_pos)
2438 } else {
2439 c.error('cannot pass expression as `mut`', call_arg_expr_pos)
2440 }
2441 }
2442 if !param.is_mut {
2443 tok := call_arg.share.str()
2444 c.error('`${node.name}` parameter `${param.name}` is not `${tok}`, `${tok}` is not needed`',
2445 call_arg.expr.pos())
2446 } else {
2447 if param.typ.share() != call_arg.share {
2448 c.error('wrong shared type `${call_arg.share.str()}`, expected: `${param.typ.share().str()}`',
2449 call_arg.expr.pos())
2450 }
2451 if to_lock != '' && !param.typ.has_flag(.shared_f) {
2452 c.error('${to_lock} is `shared` and must be `lock`ed to be passed as `mut`',
2453 pos)
2454 }
2455 }
2456 } else {
2457 if param.is_mut {
2458 tok := param.specifier()
2459 param_sym := c.table.sym(param.typ)
2460 if !(param_sym.info is ast.Struct && param_sym.info.attrs.any(it.name == 'params')) {
2461 c.error('function `${node.name}` parameter `${param.name}` is `${tok}`, so use `${tok} ${call_arg.expr}` instead',
2462 call_arg.expr.pos())
2463 }
2464 } else {
2465 c.fail_if_unreadable(call_arg.expr, arg_typ, 'argument')
2466 }
2467 }
2468 array_param_typ := if func.generic_names.len > 0 && concrete_types.len > 0 {
2469 c.table.convert_generic_param_type(param, func.generic_names, concrete_types) or {
2470 param.typ
2471 }
2472 } else {
2473 param.typ
2474 }
2475 arg_typ = c.lower_fixed_array_call_arg_to_array(mut call_arg, array_param_typ,
2476 node.language)
2477 node.args[i] = call_arg
2478 node.args[i].typ = arg_typ
2479 arg_typ_sym = c.table.sym(arg_typ)
2480 mut final_param_sym := unsafe { param_typ_sym }
2481 mut final_param_typ := param.typ
2482 if has_typed_variadic && param_typ_sym.info is ast.Array {
2483 final_param_typ = param_typ_sym.info.elem_type
2484 final_param_sym = c.table.sym(final_param_typ)
2485 }
2486 // Note: Casting to voidptr is used as an escape mechanism, so:
2487 // 1. allow passing *explicit* voidptr (native or through cast) to functions
2488 // expecting voidptr or ...voidptr
2489 // ... but 2. disallow passing non-pointers - that is very rarely what the user wanted,
2490 // it can lead to codegen errors (except for 'magic' functions like `json.encode` that,
2491 // the compiler has special codegen support for), so it should be opt in, that is it
2492 // should require an explicit voidptr(x) cast (and probably unsafe{} ?) .
2493 // V variadic ...voidptr calls are boxed in cgen, so rvalues are safe there.
2494 if call_arg.typ != param.typ && (param.typ == ast.voidptr_type
2495 || final_param_sym.idx == ast.voidptr_type_idx
2496 || param.typ == ast.nil_type || final_param_sym.idx == ast.nil_type_idx)
2497 && !call_arg.typ.is_any_kind_of_pointer() && func.language == .v
2498 && !call_arg.expr.is_lvalue() && !c.pref.translated && !c.file.is_translated
2499 && !(has_typed_variadic && final_param_sym.idx == ast.voidptr_type_idx)
2500 && !func.is_c_variadic && func.name !in ['json.encode', 'json.encode_pretty'] {
2501 c.error('expression cannot be passed as `voidptr`', call_arg.expr.pos())
2502 }
2503 // Handle expected interface
2504 mut is_generic_interface := false
2505 if final_param_sym.kind == .generic_inst {
2506 gi := final_param_sym.info
2507 if gi is ast.GenericInst {
2508 is_generic_interface = c.table.type_symbols[gi.parent_idx].kind == .interface
2509 }
2510 }
2511 if final_param_sym.kind == .interface || is_generic_interface {
2512 // For generic interface parameters, resolve the generic type to its concrete
2513 // instantiation before checking implementation.
2514 mut resolved_param_typ := final_param_typ
2515 if final_param_typ.has_flag(.generic) && func.generic_names.len > 0
2516 && node.concrete_types.len == func.generic_names.len {
2517 if t := c.table.convert_generic_type(final_param_typ, func.generic_names,
2518 node.concrete_types)
2519 {
2520 resolved_param_typ = t
2521 }
2522 }
2523 if c.type_implements_with_mut_receiver(arg_typ, resolved_param_typ,
2524 call_arg.expr.pos(), param.is_mut)
2525 {
2526 if !arg_typ.is_any_kind_of_pointer() && !c.inside_unsafe
2527 && arg_typ_sym.kind != .interface {
2528 c.mark_as_referenced(mut &call_arg.expr, true)
2529 }
2530 }
2531
2532 // For non-generic interfaces, check pointer compatibility.
2533 // For generic_inst interfaces, the param.typ may still have unresolved
2534 // generic flags, so skip the ptr check — type_implements already validated.
2535 if final_param_sym.kind == .interface && arg_typ !in [ast.voidptr_type, ast.nil_type]
2536 && !c.check_multiple_ptr_match(arg_typ, param.typ, param, call_arg) {
2537 got_typ_str, expected_typ_str := c.get_string_names_of(arg_typ, param.typ)
2538 c.error('cannot use `${got_typ_str}` as `${expected_typ_str}` in argument ${i + 1} to `${fn_name}`',
2539 call_arg.pos)
2540 }
2541 if call_arg.expr is ast.ArrayDecompose && arg_typ.idx() != final_param_typ.idx()
2542 && c.table.cur_concrete_types.len == 0 {
2543 expected_type_str := c.table.type_to_str(param.typ)
2544 got_type_str := c.table.type_to_str(arg_typ)
2545 c.error('cannot use `${got_type_str}` as `${expected_type_str}` in argument ${i + 1} to `${fn_name}`',
2546 call_arg.pos)
2547 }
2548 continue
2549 }
2550 if !c.inside_unsafe && !param.is_mut && node.language == .v
2551 && c.is_nocopy_struct(final_param_typ) {
2552 c.error('cannot pass @[nocopy] struct by value: use a reference instead', call_arg.pos)
2553 }
2554 if param.typ.is_ptr() && !param.is_mut && !call_arg.typ.is_any_kind_of_pointer()
2555 && call_arg.expr.is_literal() && func.language == .v && !c.pref.translated {
2556 c.error('literal argument cannot be passed as reference parameter `${c.table.type_to_str(param.typ)}`',
2557 call_arg.pos)
2558 }
2559 if !variadic_arg_handled {
2560 c.check_expected_call_arg(arg_typ, c.unwrap_generic(param.typ), node.language, call_arg) or {
2561 if param.typ.has_flag(.generic) {
2562 continue
2563 }
2564 // When decomposing a generic variadic arg into a non-variadic function,
2565 // each generic instantiation re-checks all branches (e.g. match arms),
2566 // so the decomposed type may not match the target param type for
2567 // unreachable branches. Skip the error in this case.
2568 if has_decompose && call_arg.expr is ast.ArrayDecompose
2569 && c.table.cur_concrete_types.len > 0 {
2570 continue
2571 }
2572 if param_typ_sym.info is ast.Array && arg_typ_sym.info is ast.Array {
2573 param_elem_type := c.table.unaliased_type(param_typ_sym.info.elem_type)
2574 arg_elem_type := c.table.unaliased_type(arg_typ_sym.info.elem_type)
2575 param_nr_muls := param.typ.nr_muls()
2576 arg_nr_muls := if call_arg.is_mut {
2577 arg_typ.nr_muls() + 1
2578 } else {
2579 arg_typ.nr_muls()
2580 }
2581 if param.typ.has_flag(.option) == arg_typ.has_flag(.option)
2582 && param.typ.has_flag(.result) == arg_typ.has_flag(.result)
2583 && param_nr_muls == arg_nr_muls
2584 && param_typ_sym.info.nr_dims == arg_typ_sym.info.nr_dims
2585 && param_elem_type == arg_elem_type {
2586 continue
2587 }
2588 } else if arg_typ_sym.info is ast.MultiReturn {
2589 arg_typs := arg_typ_sym.info.types
2590 if !(has_typed_variadic && param_i >= variadic_start) {
2591 if arg_typ_sym.info.types.len > func.params.len {
2592 c.error('trying to pass ${arg_typ_sym.info.types.len} argument(s), but function expects ${func.params.len} argument(s)',
2593 node.pos)
2594 continue_check = false
2595 return ast.void_type
2596 }
2597 }
2598 if !func.is_variadic && func.params.len < (param_i + arg_typ_sym.info.types.len) {
2599 c.fn_call_error_have_want(
2600 nr_params: func.params.len
2601 nr_args: param_i + arg_typ_sym.info.types.len
2602 params: func.params
2603 args: node.args
2604 pos: node.pos
2605 )
2606 return ast.void_type
2607 }
2608 out: for n in 0 .. arg_typ_sym.info.types.len {
2609 curr_arg := arg_typs[n]
2610 multi_param := call_arg_param_for_fn(func, n + param_i, false)
2611 c.check_expected_call_arg(curr_arg, c.unwrap_generic(multi_param.typ),
2612 node.language, call_arg) or {
2613 c.error('${err.msg()} in argument ${param_i + n + 1} to `${fn_name}` from ${c.table.type_to_str(arg_typ)}',
2614 call_arg.pos)
2615 continue out
2616 }
2617 }
2618 nr_multi_values += arg_typ_sym.info.types.len - 1
2619 continue
2620 } else if param_typ_sym.info is ast.Struct && arg_typ_sym.info is ast.Struct
2621 && param_typ_sym.info.is_anon {
2622 if c.is_anon_struct_compatible(param_typ_sym.info, arg_typ_sym.info) {
2623 continue
2624 }
2625 } else if c.embeds_expected_call_arg_type(arg_typ, final_param_typ) {
2626 continue
2627 }
2628 if c.pref.translated || c.file.is_translated {
2629 // in case of variadic make sure to use array elem type for checks
2630 // check_expected_call_arg already does this before checks also.
2631 param_type := if param.typ.has_flag(.variadic) {
2632 param_typ_sym.array_info().elem_type
2633 } else {
2634 param.typ
2635 }
2636 // TODO: duplicated logic in check_types() (check_types.v)
2637 // Allow enums to be used as ints and vice versa in translated code
2638 if param_type.idx() in ast.integer_type_idxs && arg_typ_sym.kind == .enum {
2639 continue
2640 }
2641 if arg_typ.idx() in ast.integer_type_idxs && param_typ_sym.kind == .enum {
2642 continue
2643 }
2644
2645 if (arg_typ == ast.bool_type && param_type.is_int())
2646 || (arg_typ.is_int() && param_type == ast.bool_type) {
2647 continue
2648 }
2649
2650 // In C unsafe number casts are used all the time (e.g. `char*` where
2651 // `int*` is expected etc), so just allow them all.
2652 mut param_is_number := c.table.unaliased_type(param_type).is_number()
2653 if param_type.is_ptr() {
2654 param_is_number = param_type.deref().is_number()
2655 }
2656 mut typ_is_number := c.table.unaliased_type(arg_typ).is_number()
2657 if arg_typ.is_ptr() {
2658 typ_is_number = arg_typ.deref().is_number()
2659 }
2660 if param_is_number && typ_is_number {
2661 continue
2662 }
2663 // Allow voidptrs for everything
2664 if param_type == ast.voidptr_type_idx || param_type == ast.nil_type_idx
2665 || arg_typ == ast.voidptr_type_idx || arg_typ == ast.nil_type_idx {
2666 continue
2667 }
2668 if param_type.is_any_kind_of_pointer() && arg_typ.is_any_kind_of_pointer() {
2669 continue
2670 }
2671 unaliased_param_sym := c.table.sym(c.table.unaliased_type(param_type))
2672 unaliased_arg_sym := c.table.sym(c.table.unaliased_type(arg_typ))
2673 // Allow `[32]i8` as `&i8` etc
2674 arg_is_array_like := unaliased_arg_sym.kind in [.array_fixed, .array]
2675 param_is_array_like := unaliased_param_sym.kind in [.array_fixed, .array]
2676 if arg_is_array_like && (param_is_number
2677 || c.table.unaliased_type(param_type).is_any_kind_of_pointer()) {
2678 continue
2679 }
2680 if param_is_array_like && (typ_is_number
2681 || c.table.unaliased_type(arg_typ).is_any_kind_of_pointer()) {
2682 continue
2683 }
2684 // Allow `[N]anyptr` as `[N]anyptr`
2685 if unaliased_arg_sym.info is ast.Array && unaliased_param_sym.info is ast.Array {
2686 if unaliased_arg_sym.info.elem_type.is_any_kind_of_pointer()
2687 && unaliased_param_sym.info.elem_type.is_any_kind_of_pointer() {
2688 continue
2689 }
2690 } else if unaliased_arg_sym.info is ast.ArrayFixed
2691 && unaliased_param_sym.info is ast.ArrayFixed {
2692 if unaliased_arg_sym.info.elem_type.is_any_kind_of_pointer()
2693 && unaliased_param_sym.info.elem_type.is_any_kind_of_pointer() {
2694 continue
2695 }
2696 }
2697 // Allow `int` as `&i8`
2698 if param_type.is_any_kind_of_pointer() && typ_is_number {
2699 continue
2700 }
2701 // Allow `&i8` as `int`
2702 if arg_typ.is_any_kind_of_pointer() && param_is_number {
2703 continue
2704 }
2705 }
2706 // if first_sym.name == 'VContext' && f.params[0].name == 'ctx' { // TODO use int comparison for perf
2707 //}
2708 /*
2709 if param_typ_sym.info is ast.Struct && param_typ_sym.name == 'VContext' {
2710 c.note('ok', call_arg.pos)
2711 continue
2712 }
2713 */
2714 c.error('${err.msg()} in argument ${i + nr_multi_values + 1} to `${fn_name}`',
2715 call_arg.pos)
2716 }
2717 }
2718 if final_param_sym.kind == .struct && arg_typ !in [ast.voidptr_type, ast.nil_type]
2719 && !c.check_multiple_ptr_match(arg_typ, param.typ, param, call_arg) {
2720 got_typ_str, expected_typ_str := c.get_string_names_of(arg_typ, param.typ)
2721 c.error('cannot use `${got_typ_str}` as `${expected_typ_str}` in argument ${i +
2722 nr_multi_values + 1} to `${fn_name}`', call_arg.pos)
2723 }
2724 // Warn about automatic (de)referencing, which will be removed soon.
2725 if func.language != .c && !c.inside_unsafe && !(call_arg.is_mut && param.is_mut) {
2726 if arg_typ.nr_muls() != param.typ.nr_muls()
2727 && param.typ !in [ast.byteptr_type, ast.charptr_type, ast.voidptr_type, ast.nil_type]
2728 && arg_typ != ast.voidptr_type && !(!call_arg.is_mut && !param.is_mut) //&& !(!call_arg.is_mut && !param.is_mut)
2729 {
2730 c.warn('automatic referencing/dereferencing is deprecated and will be removed soon (got: ${arg_typ.nr_muls()} references, expected: ${param.typ.nr_muls()} references)',
2731 call_arg.pos)
2732 }
2733 // A special case of the check to not allow voidptr params like in the recently reported raylib
2734 // bug with fn...
2735 // fn f(p &Foo) => f(foo) -- do not allow this, force f(&foo)
2736 // if !c.is_builtin_mod
2737 else if param.typ == ast.voidptr_type && func.language == .v
2738 && arg_typ !in [ast.voidptr_type, ast.nil_type] && arg_typ.nr_muls() == 0
2739 && func.name !in ['isnil', 'ptr_str'] && !func.name.starts_with('json.')
2740 && arg_typ_sym.kind !in [.float_literal, .int_literal, .charptr, .function]
2741 && !c.is_js_backend {
2742 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)`',
2743 call_arg.pos)
2744 }
2745 }
2746 }
2747 if has_unresolved_generic_param {
2748 node.return_type = func.return_type
2749 return func.return_type
2750 }
2751 if is_json_encode {
2752 // json.encode param is set voidptr, we should bound the proper type here
2753 node.expected_arg_types = [node.args[0].typ]
2754 }
2755 if func.generic_names.len != node.concrete_types.len {
2756 // no type arguments given in call, attempt implicit instantiation
2757 c.infer_fn_generic_types(func, mut node)
2758 concrete_types = node.concrete_types.map(c.unwrap_generic(it))
2759 need_recheck, _ := c.type_resolver.resolve_fn_generic_args(c.table.cur_fn, func, mut node)
2760 if need_recheck {
2761 c.need_recheck_generic_fns = true
2762 }
2763 }
2764 if func.generic_names.len > 0 {
2765 for i, mut call_arg in node.args {
2766 param := call_arg_param_for_fn(func, i, false)
2767 if param.typ.has_flag(.generic) {
2768 if unwrap_typ := c.table.convert_generic_param_type(param, func.generic_names,
2769 concrete_types)
2770 {
2771 c.expected_type = unwrap_typ
2772 }
2773 } else {
2774 c.expected_type = param.typ
2775 }
2776 already_checked := node.language != .js && call_arg.expr is ast.CallExpr
2777 mut typ := c.check_expr_option_or_result_call(call_arg.expr, if already_checked
2778 && mut call_arg.expr is ast.CallExpr {
2779 call_arg.expr.return_type
2780 } else {
2781 c.expr(mut call_arg.expr)
2782 })
2783
2784 if param.typ.has_flag(.generic) && func.generic_names.len == node.concrete_types.len {
2785 if unwrap_typ := c.table.convert_generic_param_type(param, func.generic_names,
2786 concrete_types)
2787 {
2788 call_arg.typ = typ
2789 typ = c.lower_fixed_array_call_arg_to_array(mut call_arg, unwrap_typ,
2790 node.language)
2791 node.args[i].expr = call_arg.expr
2792 node.args[i].typ = typ
2793 utyp := c.unwrap_generic(typ)
2794 unwrap_sym := c.table.sym(unwrap_typ)
2795 if unwrap_sym.kind == .interface {
2796 if c.type_implements_with_mut_receiver(utyp, unwrap_typ,
2797 call_arg.expr.pos(), param.is_mut)
2798 {
2799 if !utyp.is_any_kind_of_pointer() && !c.inside_unsafe
2800 && c.table.sym(utyp).kind != .interface {
2801 c.mark_as_referenced(mut &call_arg.expr, true)
2802 }
2803 }
2804 continue
2805 }
2806 c.check_expected_call_arg(utyp, unwrap_typ, node.language, call_arg) or {
2807 if c.type_resolver.type_map.len > 0 {
2808 continue
2809 }
2810 if mut call_arg.expr is ast.LambdaExpr {
2811 // Calling fn is generic and lambda arg also is generic
2812 c.handle_generic_lambda_arg(node, func.generic_names, mut call_arg.expr)
2813 continue
2814 }
2815 if mut call_arg.expr is ast.AnonFn {
2816 c.handle_generic_anon_fn_arg(node, func.generic_names, mut
2817 call_arg.expr)
2818 }
2819 if c.is_optional_array_arg_compatible(utyp, unwrap_typ) {
2820 continue
2821 }
2822 c.error('${err.msg()} in argument ${i + 1} to `${fn_name}`', call_arg.pos)
2823 }
2824 // When check succeeds (e.g. after lambda re-check with concrete types),
2825 // still set call_ctx on lambda args for generic context in cgen:
2826 if mut call_arg.expr is ast.LambdaExpr {
2827 c.handle_generic_lambda_arg(node, func.generic_names, mut call_arg.expr)
2828 } else if mut call_arg.expr is ast.AnonFn {
2829 c.handle_generic_anon_fn_arg(node, func.generic_names, mut call_arg.expr)
2830 }
2831 }
2832 }
2833 }
2834 if c.pref.skip_unused && node.concrete_types.len > 0 {
2835 for concrete_type in node.concrete_types {
2836 c.table.used_features.comptime_syms[c.unwrap_generic(concrete_type)] = true
2837 }
2838 }
2839 }
2840 raw_io_arg_offset := if func.is_method { 1 } else { 0 }
2841 c.check_os_raw_io_call(node, func, concrete_types, raw_io_arg_offset)
2842
2843 // resolve return generics struct to concrete type
2844 if func.generic_names.len > 0 && func.return_type.has_flag(.generic)
2845 && c.table.cur_fn != unsafe { nil } && c.needs_unwrap_generic_type(func.return_type) {
2846 node.return_type = c.table.unwrap_generic_type(func.return_type, func.generic_names,
2847 concrete_types)
2848 } else {
2849 node.return_type = func.return_type
2850 }
2851 if func.return_type.has_flag(.generic) {
2852 node.return_type_generic = func.return_type
2853 }
2854 if node.concrete_types.len > 0 && func.return_type != 0 && c.table.cur_fn != unsafe { nil }
2855 && c.table.cur_fn.generic_names.len == 0 {
2856 if typ := c.table.convert_generic_type(func.return_type, func.generic_names, concrete_types) {
2857 node.return_type = typ
2858 c.register_trace_call(node, func)
2859 if func.return_type.has_flag(.generic) {
2860 c.table.used_features.comptime_syms[typ.clear_option_and_result()] = true
2861 c.table.used_features.comptime_syms[func.return_type] = true
2862 }
2863 return typ
2864 }
2865 }
2866 if node.concrete_types.len > 0 && func.generic_names.len == 0 {
2867 c.error('a non generic function called like a generic one', node.concrete_list_pos)
2868 }
2869
2870 // resolve generic fn return type
2871 if func.generic_names.len > 0 && node.return_type != ast.void_type {
2872 ret_type := c.resolve_fn_return_type(func, node, concrete_types)
2873 c.register_trace_call(node, func)
2874 node.return_type = ret_type
2875 if ret_type.has_flag(.generic) {
2876 unwrapped_ret := c.unwrap_generic(ret_type)
2877 if c.table.sym(unwrapped_ret).kind == .multi_return {
2878 c.table.used_features.comptime_syms[unwrapped_ret] = true
2879 }
2880 }
2881 return ret_type
2882 }
2883 c.register_trace_call(node, func)
2884 return func.return_type
2885}
2886
2887// register_trace_call registers the wrapper funcs for calling funcs for callstack feature
2888fn (mut c Checker) register_trace_call(node &ast.CallExpr, func &ast.Fn) {
2889 if !(c.pref.is_callstack || c.pref.is_trace) || c.table.cur_fn == unsafe { nil }
2890 || node.language != .v {
2891 return
2892 }
2893 if node.name in ['v.debug.callstack', 'v.debug.add_after_call', 'v.debug.add_before_call',
2894 'v.debug.remove_after_call', 'v.debug.remove_before_call'] {
2895 return
2896 }
2897 if !c.file.imports.any(it.mod == 'v.debug') {
2898 return
2899 }
2900 hash_fn, fn_name := c.table.get_trace_fn_name(c.table.cur_fn, node)
2901 calling_fn := if func.is_method {
2902 '${c.table.type_to_str(c.unwrap_generic(node.left_type))}_${fn_name}'
2903 } else {
2904 fn_name
2905 }
2906 c.table.cur_fn.trace_fns[hash_fn] = ast.FnTrace{
2907 name: calling_fn
2908 file: c.file.path
2909 line: node.pos.line_nr + 1
2910 return_type: node.return_type
2911 func: &ast.Fn{
2912 ...func
2913 }
2914 is_fn_var: node.is_fn_var
2915 }
2916}
2917
2918// cast_fixed_array_ret casts a ArrayFixed type created to return to a non returning one
2919fn (mut c Checker) cast_fixed_array_ret(typ ast.Type, sym ast.TypeSymbol) ast.Type {
2920 if sym.info is ast.ArrayFixed && sym.info.is_fn_ret {
2921 return c.table.find_or_register_array_fixed(sym.info.elem_type, sym.info.size,
2922 sym.info.size_expr, false)
2923 }
2924 return typ
2925}
2926
2927// cast_to_fixed_array_ret casts a ArrayFixed type created to do not return to a returning one
2928fn (mut c Checker) cast_to_fixed_array_ret(typ ast.Type, sym ast.TypeSymbol) ast.Type {
2929 if sym.info is ast.ArrayFixed && !sym.info.is_fn_ret {
2930 return c.table.find_or_register_array_fixed(sym.info.elem_type, sym.info.size,
2931 sym.info.size_expr, true)
2932 }
2933 return typ
2934}
2935
2936// checks if a symbol kind is an expected kind
2937fn (mut c Checker) check_type_sym_kind(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 return true
2948}
2949
2950// checks if a type from another module is as expected and visible(`is_pub`)
2951fn (mut c Checker) check_type_and_visibility(name string, type_idx int, expected_kind ast.Kind, pos token.Pos) bool {
2952 mut sym := c.table.sym_by_idx(type_idx)
2953 if sym.kind == .alias {
2954 parent_type := (sym.info as ast.Alias).parent_type
2955 sym = c.table.sym(parent_type)
2956 }
2957 if sym.kind != expected_kind {
2958 c.error('expected ${expected_kind}, but `${name}` is ${sym.kind}', pos)
2959 return false
2960 }
2961 if !sym.is_pub {
2962 c.error('module `${sym.mod}` type `${sym.name}` is private', pos)
2963 return false
2964 }
2965 return true
2966}
2967
2968fn (c &Checker) is_valid_os_file_struct_io_type(typ ast.Type) bool {
2969 if typ.nr_muls() > 0 || typ.has_option_or_result() {
2970 return false
2971 }
2972 mut current_typ := typ
2973 mut sym := c.table.sym(current_typ)
2974 for {
2975 if sym.info !is ast.Alias {
2976 break
2977 }
2978 alias_info := sym.info as ast.Alias
2979 current_typ = alias_info.parent_type
2980 if current_typ.nr_muls() > 0 || current_typ.has_option_or_result() {
2981 return false
2982 }
2983 sym = c.table.sym(current_typ)
2984 }
2985 return sym.kind == .struct
2986}
2987
2988fn (mut c Checker) check_os_file_struct_io_method_call(node &ast.CallExpr, method ast.Fn, concrete_types []ast.Type) {
2989 if method.name !in ['read_struct', 'read_struct_at', 'write_struct', 'write_struct_at'] {
2990 return
2991 }
2992 if method.params.len == 0 || concrete_types.len != 1 {
2993 return
2994 }
2995 receiver_sym := c.table.final_sym(method.params[0].typ)
2996 if receiver_sym.name != 'os.File' {
2997 return
2998 }
2999 concrete_type := concrete_types[0]
3000 if concrete_type.has_flag(.generic) || c.is_valid_os_file_struct_io_type(concrete_type) {
3001 return
3002 }
3003 err_pos := if node.raw_concrete_types.len > 0 {
3004 node.concrete_list_pos
3005 } else if node.args.len > 0 {
3006 node.args[0].pos
3007 } else {
3008 node.pos
3009 }
3010 c.error('`${receiver_sym.name}.${method.name}` expects a struct type, but got `${c.table.type_to_str(concrete_type)}`',
3011 err_pos)
3012}
3013
3014// is_optional_array_arg_compatible allows the generic recheck fallback for `[]?T -> []T`
3015// without also accepting `[]&T -> []T` or other pointedness mismatches.
3016fn (mut c Checker) is_optional_array_arg_compatible(got ast.Type, expected ast.Type) bool {
3017 if expected.has_flag(.variadic) {
3018 return false
3019 }
3020 if c.table.final_sym(got).kind != .array || c.table.final_sym(expected).kind != .array {
3021 return false
3022 }
3023 got_value_type := c.table.value_type(got)
3024 expected_value_type := c.table.value_type(expected)
3025 if !got_value_type.has_flag(.option) || expected_value_type.has_flag(.option) {
3026 return false
3027 }
3028 if got_value_type.nr_muls() != expected_value_type.nr_muls() {
3029 return false
3030 }
3031 return c.check_types(got_value_type.clear_flag(.option), expected_value_type)
3032}
3033
3034fn (mut c Checker) fixed_array_arg_as_array_type(got ast.Type, expected ast.Type) ast.Type {
3035 if expected.has_flag(.variadic) {
3036 return ast.no_type
3037 }
3038 got_sym := c.table.final_sym(c.unwrap_generic(got).clear_option_and_result())
3039 expected_sym :=
3040 c.table.final_sym(c.unwrap_generic(expected).clear_option_and_result().set_nr_muls(0))
3041 if got_sym.kind != .array_fixed || expected_sym.kind != .array {
3042 return ast.no_type
3043 }
3044 return ast.new_type(c.table.find_or_register_array(got_sym.array_fixed_info().elem_type))
3045}
3046
3047fn (mut c Checker) lower_fixed_array_call_arg_to_array(mut arg ast.CallArg, expected ast.Type, language ast.Language) ast.Type {
3048 array_typ := c.fixed_array_arg_as_array_type(arg.typ, expected)
3049 if array_typ == ast.no_type {
3050 return arg.typ
3051 }
3052 expected_array_typ := c.unwrap_generic(expected).clear_option_and_result().set_nr_muls(0)
3053 c.check_expected_call_arg(array_typ, expected_array_typ, language, arg) or { return arg.typ }
3054 original_expr := arg.expr
3055 arg.expr = ast.IndexExpr{
3056 pos: original_expr.pos()
3057 left: original_expr
3058 left_type: arg.typ
3059 index: ast.RangeExpr{
3060 pos: original_expr.pos()
3061 }
3062 }
3063 arg.typ = c.expr(mut arg.expr)
3064 return arg.typ
3065}
3066
3067fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool) ast.Type {
3068 // `(if true { 'foo.bar' } else { 'foo.bar.baz' }).all_after('foo.')`
3069 node.concrete_types = node.raw_concrete_types.clone()
3070 mut left_expr := node.left
3071 left_expr = left_expr.remove_par()
3072 if mut left_expr is ast.IfExpr {
3073 if left_expr.branches.len > 0 && left_expr.has_else {
3074 mut last_stmt := left_expr.branches[0].stmts.last()
3075 if mut last_stmt is ast.ExprStmt {
3076 c.expected_type = c.expr(mut last_stmt.expr)
3077 }
3078 }
3079 }
3080 left_type := node.left_type
3081 if left_type == ast.void_type {
3082 // c.error('cannot call a method using an invalid expression', node.pos)
3083 continue_check = false
3084 return ast.void_type
3085 }
3086 c.markused_method_call(mut node, mut left_expr, left_type)
3087 c.expected_type = left_type
3088 mut is_generic := left_type.has_flag(.generic)
3089 node.left_type = left_type
3090 // Set default values for .return_type & .receiver_type too,
3091 // or there will be hard tRo diagnose 0 type panics in cgen.
3092 node.return_type = left_type
3093 node.receiver_type = left_type
3094
3095 if is_generic {
3096 c.table.used_features.comptime_syms[c.unwrap_generic(left_type)] = true
3097 }
3098
3099 if c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0 {
3100 c.table.unwrap_generic_type(left_type, c.table.cur_fn.generic_names,
3101 c.table.cur_concrete_types)
3102 }
3103 unwrapped_left_type := c.unwrap_generic(left_type)
3104 left_sym := c.table.sym(unwrapped_left_type)
3105 final_left_sym := c.table.final_sym(unwrapped_left_type)
3106 mut final_left_kind := final_left_sym.kind
3107 if final_left_sym.kind == .generic_inst && final_left_sym.info is ast.GenericInst {
3108 final_left_kind = c.table.sym(ast.new_type(final_left_sym.info.parent_idx)).kind
3109 }
3110
3111 method_name := node.name
3112 if left_type.has_flag(.option) {
3113 c.error('Option type `${left_sym.name}` cannot be called directly, you should unwrap it first',
3114 node.left.pos())
3115 return ast.void_type
3116 } else if left_type.has_flag(.result) {
3117 c.error('Result type cannot be called directly', node.left.pos())
3118 return ast.void_type
3119 }
3120 if left_sym.kind in [.sum_type, .interface] {
3121 if node.kind == .type_name {
3122 return ast.string_type
3123 }
3124 if node.kind == .type_idx {
3125 return ast.int_type
3126 }
3127 }
3128 if left_type == ast.void_type {
3129 // No need to print this error, since this means that the variable is unknown,
3130 // and there already was an error before.
3131 // c.error('`void` type has no methods', node.left.pos())
3132 continue_check = false
3133 return ast.void_type
3134 }
3135 mut use_builtin_array_sort := false
3136 if final_left_sym.kind == .array && node.kind in [.sort, .sorted] && node.args.len > 0 {
3137 if method := left_sym.find_method(method_name) {
3138 use_builtin_array_sort = method.params.len == 1
3139 }
3140 }
3141 if final_left_sym.kind == .array && array_builtin_methods_chk.matches(method_name)
3142 && (!(left_sym.has_method(method_name)) || use_builtin_array_sort) {
3143 return c.array_builtin_method_call(mut node, left_type)
3144 } else if final_left_sym.kind == .array_fixed
3145 && fixed_array_builtin_methods_chk.matches(method_name) && !(left_sym.kind == .alias
3146 && left_sym.has_method(method_name)) {
3147 return c.fixed_array_builtin_method_call(mut node, left_type)
3148 } else if final_left_sym.kind == .map && node.kind in [.clone, .keys, .values, .move, .delete]
3149 && !(left_sym.kind == .alias && left_sym.has_method(method_name)) {
3150 unaliased_left_type := c.table.unaliased_type(left_type)
3151 return c.map_builtin_method_call(mut node, unaliased_left_type)
3152 } else if c.is_js_backend && left_sym.name.starts_with('Promise[') && node.kind == .wait {
3153 info := left_sym.info as ast.Struct
3154 if node.args.len > 0 {
3155 c.error('wait() does not have any arguments', node.args[0].pos)
3156 }
3157 if c.table.cur_fn != unsafe { nil } {
3158 c.table.cur_fn.has_await = true
3159 }
3160 node.return_type = info.concrete_types[0]
3161 node.return_type.set_flag(.option)
3162 return node.return_type
3163 } else if left_sym.info is ast.Thread && node.kind == .wait {
3164 if node.args.len > 0 {
3165 c.error('wait() does not have any arguments', node.args[0].pos)
3166 }
3167 node.return_type = left_sym.info.return_type
3168 return left_sym.info.return_type
3169 } else if left_sym.kind == .char && left_type.nr_muls() == 0 && node.kind == .str {
3170 c.error('calling `.str()` on type `char` is not allowed, use its address or cast it to an integer instead',
3171 node.left.pos().extend(node.pos))
3172 return ast.void_type
3173 }
3174
3175 mut unknown_method_msg := ''
3176 mut method := ast.Fn{}
3177 mut has_method := false
3178 mut is_method_from_embed := false
3179 mut structured_receiver_concrete_types := []ast.Type{}
3180 mut is_structured_receiver_method := false
3181 defer {
3182 if has_method && node.is_method {
3183 c.check_must_use_call_result(node, method, 'method')
3184 }
3185 }
3186 lookup_sym := c.table.sym(left_type)
3187 if structured_method := c.table.find_structured_receiver_method_with_types(left_type,
3188 method_name)
3189 {
3190 if m := lookup_sym.find_method(method_name) {
3191 method = m
3192 has_method = true
3193 } else if m := c.table.find_alias_parent_exact_method(left_type, method_name) {
3194 method = m
3195 has_method = true
3196 } else {
3197 method = structured_method.method
3198 structured_receiver_concrete_types = structured_method.concrete_types.clone()
3199 is_structured_receiver_method = true
3200 has_method = true
3201 }
3202 if lookup_sym.kind == .interface && method.from_embedded_type != 0 {
3203 is_method_from_embed = true
3204 node.from_embed_types = [method.from_embedded_type]
3205 }
3206 } else if m := left_sym.find_method_with_generic_parent(method_name) {
3207 method = m
3208 has_method = true
3209 if left_sym.kind == .interface && m.from_embedded_type != 0 {
3210 is_method_from_embed = true
3211 node.from_embed_types = [m.from_embedded_type]
3212 }
3213 } else if m := c.table.find_method(left_sym, method_name) {
3214 method = m
3215 has_method = true
3216 if left_sym.kind == .interface && m.from_embedded_type != 0 {
3217 is_method_from_embed = true
3218 node.from_embed_types = [m.from_embedded_type]
3219 }
3220 } else {
3221 if final_left_sym.kind in [.struct, .sum_type, .interface, .array] {
3222 mut parent_type := ast.void_type
3223 match final_left_sym.info {
3224 ast.Struct, ast.SumType, ast.Interface {
3225 parent_type = final_left_sym.info.parent_type
3226 }
3227 ast.Array {
3228 typ := c.table.unaliased_type(final_left_sym.info.elem_type)
3229 parent_type = ast.idx_to_type(c.table.find_or_register_array(typ))
3230 }
3231 else {}
3232 }
3233
3234 if parent_type != 0 {
3235 type_sym := c.table.sym(parent_type)
3236 if m := c.table.find_method(type_sym, method_name) {
3237 method = m
3238 has_method = true
3239 is_generic = true
3240 if left_sym.kind == .interface && m.from_embedded_type != 0 {
3241 is_method_from_embed = true
3242 node.from_embed_types = [m.from_embedded_type]
3243 }
3244 }
3245 }
3246 }
3247 if !has_method {
3248 has_method = true
3249 mut embed_types := []ast.Type{}
3250 method, embed_types = c.table.find_method_from_embeds(final_left_sym, method_name) or {
3251 emsg := err.str()
3252 if emsg != '' {
3253 c.error(emsg, node.pos)
3254 }
3255 has_method = false
3256 ast.Fn{}, []ast.Type{}
3257 }
3258 if embed_types.len != 0 {
3259 is_method_from_embed = true
3260 node.from_embed_types = embed_types
3261 c.markused_comptime_call(node.left_type.has_flag(.generic),
3262 '${int(method.receiver_type)}.${method.name}')
3263 }
3264 }
3265 if final_left_sym.kind == .aggregate {
3266 // the error message contains the problematic type
3267 unknown_method_msg = err.msg()
3268 if unknown_method_msg == 'unknown method' {
3269 unknown_method_msg += ' `' + method_name + '`'
3270 }
3271 }
3272 }
3273
3274 if !has_method {
3275 // TODO: str methods
3276 if node.kind == .str {
3277 if left_sym.kind == .interface {
3278 iname := left_sym.name
3279 c.error('interface `${iname}` does not have a .str() method. Use typeof() instead',
3280 node.pos)
3281 }
3282 if c.fail_if_private_implicit_str(left_type, node.pos,
3283 'call auto-generated `.str()` on')
3284 {
3285 return ast.string_type
3286 }
3287 node.receiver_type = left_type.clear_ref()
3288 node.return_type = ast.string_type
3289 if node.args.len > 0 {
3290 c.error('.str() method calls should have no arguments', node.pos)
3291 }
3292 c.fail_if_unreadable(node.left, left_type, 'receiver')
3293 if !c.is_builtin_mod {
3294 c.table.used_features.auto_str = true
3295 c.markused_auto_str_dependencies(left_type)
3296 }
3297 return ast.string_type
3298 } else if node.kind == .free {
3299 if !c.is_builtin_mod && !c.inside_unsafe && !method.is_unsafe