vxx / vlib / v / checker / containers.v
1226 lines · 1194 sloc · 41.41 KB · 56e61c291d14aa83e2a8a3d362011bbe61149957
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
3module checker
4
5import v.ast
6import v.token
7
8@[inline]
9fn array_init_result_type(node ast.ArrayInit) ast.Type {
10 return if node.alias_type != 0 && node.alias_type != ast.void_type {
11 node.alias_type
12 } else {
13 node.typ
14 }
15}
16
17fn (mut c Checker) set_expected_array_literal_type(mut expr ast.Expr, expected_type ast.Type) {
18 if mut expr is ast.ArrayInit {
19 if expr.typ != ast.void_type || expr.elem_type != ast.void_type {
20 return
21 }
22 expected_array_type := expected_type.clear_option_and_result()
23 if expected_array_type.has_flag(.generic)
24 || c.type_has_unresolved_generic_parts(expected_array_type) {
25 return
26 }
27 mut concrete_array_type := expected_array_type
28 expected_sym := c.table.sym(expected_array_type)
29 if expected_sym.info is ast.Alias {
30 concrete_array_type = expected_sym.info.parent_type.clear_option_and_result()
31 if c.table.final_sym(concrete_array_type).kind !in [.array, .array_fixed] {
32 return
33 }
34 expr.alias_type = expected_array_type
35 } else if c.table.final_sym(expected_array_type).kind !in [.array, .array_fixed] {
36 return
37 }
38 expected_elem_type := c.table.value_type(concrete_array_type)
39 if expected_elem_type == ast.void_type {
40 return
41 }
42 expected_elem_sym := c.table.final_sym(expected_elem_type)
43 if expected_elem_sym.kind in [.interface, .sum_type] {
44 return
45 }
46 expr.typ = concrete_array_type
47 expr.elem_type = expected_elem_type
48 }
49}
50
51fn is_inferred_fixed_array_size_expr(expr ast.Expr) bool {
52 return expr is ast.RangeExpr && !expr.has_low && !expr.has_high
53}
54
55fn is_array_init_type_expr_field(name string) bool {
56 return name in ['idx', 'typ', 'unaliased_typ', 'key_type', 'value_type', 'element_type',
57 'pointee_type', 'payload_type', 'variant_types', 'indirections']
58}
59
60fn (mut c Checker) fixed_array_contains_inferred_size(typ ast.Type) bool {
61 mut current_type := typ.clear_option_and_result()
62 for {
63 current_sym := c.table.sym(current_type)
64 if current_sym.kind != .array_fixed {
65 return false
66 }
67 current_info := current_sym.array_fixed_info()
68 if is_inferred_fixed_array_size_expr(current_info.size_expr) {
69 return true
70 }
71 current_type = current_info.elem_type.clear_option_and_result()
72 }
73 return false
74}
75
76fn (mut c Checker) resolve_fixed_array_literal_type(typ ast.Type, elem_type ast.Type, expr_count int) ast.Type {
77 raw_typ := typ.clear_option_and_result()
78 sym := c.table.sym(raw_typ)
79 if sym.kind != .array_fixed {
80 return typ
81 }
82 info := sym.array_fixed_info()
83 mut fixed_size := info.size
84 mut size_expr := info.size_expr
85 if is_inferred_fixed_array_size_expr(size_expr) {
86 fixed_size = expr_count
87 size_expr = ast.empty_expr
88 } else if fixed_size <= 0 {
89 mut mutable_size_expr := size_expr
90 resolved_typ := c.eval_array_fixed_sizes(mut mutable_size_expr, fixed_size, elem_type)
91 resolved_info := c.table.sym(resolved_typ).array_fixed_info()
92 fixed_size = resolved_info.size
93 size_expr = resolved_info.size_expr
94 }
95 if fixed_size <= 0 {
96 c.error('fixed size cannot be zero or negative (fixed_size: ${fixed_size})',
97 size_expr.pos())
98 return typ
99 }
100 idx := c.table.find_or_register_array_fixed(elem_type, fixed_size, size_expr, info.is_fn_ret)
101 mut resolved_typ := ast.new_type(idx)
102 if typ.has_flag(.generic) || elem_type.has_flag(.generic) {
103 resolved_typ = resolved_typ.set_flag(.generic)
104 }
105 if typ.has_flag(.option) {
106 resolved_typ = resolved_typ.set_flag(.option)
107 }
108 return resolved_typ
109}
110
111fn (mut c Checker) array_init_elem_type_from_expr(expr ast.Expr) ast.Type {
112 match expr {
113 ast.ParExpr {
114 return c.array_init_elem_type_from_expr(expr.expr)
115 }
116 ast.TypeNode {
117 return c.unwrap_generic(expr.typ)
118 }
119 ast.TypeOf {
120 return c.unwrap_generic(c.type_resolver.typeof_type(expr.expr, expr.typ))
121 }
122 ast.SelectorExpr {
123 if expr.is_field_typ {
124 return c.unwrap_generic(c.type_resolver.get_type(expr))
125 }
126 if expr.name_type != 0 && is_array_init_type_expr_field(expr.field_name) {
127 return c.unwrap_generic(c.type_resolver.typeof_field_type(expr.name_type,
128 expr.field_name))
129 }
130 if is_array_init_type_expr_field(expr.field_name) {
131 base_type := c.array_init_elem_type_from_expr(expr.expr)
132 if base_type != ast.void_type {
133 return c.unwrap_generic(c.type_resolver.typeof_field_type(base_type,
134 expr.field_name))
135 }
136 }
137 return ast.void_type
138 }
139 else {
140 return ast.void_type
141 }
142 }
143}
144
145fn (mut c Checker) resolve_array_init_elem_type_expr(mut node ast.ArrayInit) {
146 if node.elem_type_expr is ast.EmptyExpr {
147 return
148 }
149 old_expected_type := c.expected_type
150 c.expected_type = ast.void_type
151 c.expr(mut node.elem_type_expr)
152 c.expected_type = old_expected_type
153 resolved_elem_type := c.array_init_elem_type_from_expr(node.elem_type_expr)
154 if resolved_elem_type == ast.void_type {
155 c.error('array_init: invalid comptime type expression, expected a type field such as `typeof(expr).idx` or `T.typ`',
156 node.elem_type_pos)
157 return
158 }
159 if resolved_elem_type.has_flag(.result) {
160 c.error('arrays do not support storing Result values', node.elem_type_pos)
161 return
162 }
163 node.elem_type = resolved_elem_type
164 idx := c.table.find_or_register_array(resolved_elem_type)
165 node.typ = if resolved_elem_type.has_flag(.generic)
166 || c.type_has_unresolved_generic_parts(resolved_elem_type) {
167 ast.new_type(idx).set_flag(.generic)
168 } else {
169 ast.new_type(idx)
170 }
171 if node.is_option {
172 node.typ = node.typ.set_flag(.option)
173 }
174}
175
176fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
177 is_inferred_array_literal := node.exprs.len > 0 && !node.is_fixed && !node.has_cap
178 && !node.has_len && !node.has_init && node.elem_type_pos.pos == node.pos.pos
179 && node.generic_typ == 0 && node.generic_elem_type == 0
180 if c.has_active_generic_recheck_context() {
181 is_untyped_empty_array := node.exprs.len == 0 && !node.is_fixed && !node.has_cap
182 && !node.has_len && !node.has_init && node.elem_type_pos.pos == node.pos.pos
183 if node.generic_typ == 0 && node.typ != ast.void_type
184 && (node.typ.has_flag(.generic) || c.type_has_unresolved_generic_parts(node.typ)) {
185 node.generic_typ = node.typ
186 }
187 if node.generic_elem_type == 0 && node.elem_type != ast.void_type
188 && (node.elem_type.has_flag(.generic)
189 || c.type_has_unresolved_generic_parts(node.elem_type)) {
190 node.generic_elem_type = node.elem_type
191 }
192 if (node.typ == ast.void_type || is_untyped_empty_array) && c.expected_type != ast.void_type {
193 expected_array_typ := c.recheck_concrete_type(c.expected_type.clear_option_and_result())
194 expected_array_sym := c.table.final_sym(expected_array_typ)
195 match expected_array_sym.info {
196 ast.Array {
197 node.typ = expected_array_typ
198 node.elem_type = expected_array_sym.info.elem_type
199 }
200 ast.ArrayFixed {
201 node.typ = expected_array_typ
202 node.elem_type = expected_array_sym.info.elem_type
203 }
204 else {}
205 }
206 }
207 base_node_typ := if node.generic_typ != 0 { node.generic_typ } else { node.typ }
208 base_elem_type := if node.generic_elem_type != 0 {
209 node.generic_elem_type
210 } else {
211 node.elem_type
212 }
213 if base_node_typ != ast.void_type {
214 resolved_node_typ := c.recheck_concrete_type(base_node_typ)
215 if resolved_node_typ != 0 && resolved_node_typ != ast.void_type {
216 node.typ = resolved_node_typ
217 }
218 }
219 if base_elem_type != ast.void_type {
220 resolved_elem_type := c.recheck_concrete_type(base_elem_type)
221 if resolved_elem_type != 0 && resolved_elem_type != ast.void_type {
222 node.elem_type = resolved_elem_type
223 }
224 }
225 }
226 if c.has_active_generic_recheck_context() && node.exprs.len > 0 && !node.is_fixed {
227 node.expr_types = []
228 node.init_type = ast.void_type
229 node.has_callexpr = false
230 if node.typ == ast.void_type || node.elem_type == ast.void_type || is_inferred_array_literal
231 || node.typ.has_flag(.generic) || c.type_has_unresolved_generic_parts(node.typ)
232 || node.elem_type.has_flag(.generic)
233 || c.type_has_unresolved_generic_parts(node.elem_type) {
234 node.typ = ast.void_type
235 node.elem_type = ast.void_type
236 }
237 }
238 if node.typ == ast.void_type && node.elem_type_expr !is ast.EmptyExpr {
239 c.resolve_array_init_elem_type_expr(mut node)
240 }
241 mut elem_type := ast.void_type
242 unwrap_elem_type := c.unwrap_generic(node.elem_type)
243 if node.typ.has_flag(.generic) {
244 c.table.used_features.comptime_syms[c.unwrap_generic(node.typ)] = true
245 }
246 if c.pref.warn_about_allocs {
247 c.warn_alloc('array initialization', node.pos)
248 }
249 // `x := []string{}` (the type was set in the parser)
250 if node.typ != ast.void_type {
251 if node.elem_type != 0 {
252 elem_sym := c.table.sym(node.elem_type)
253 c.check_any_type(node.elem_type, elem_sym, node.pos)
254 if node.typ.has_flag(.option) && (node.has_cap || node.has_len) {
255 c.error('Option array `${elem_sym.name}` cannot have initializers', node.pos)
256 }
257 match elem_sym.info {
258 ast.Struct {
259 if elem_sym.info.generic_types.len > 0 && elem_sym.info.concrete_types.len == 0
260 && !node.elem_type.has_flag(.generic) {
261 if c.table.cur_concrete_types.len == 0 {
262 c.error('generic struct `${elem_sym.name}` must specify type parameter, e.g. ${elem_sym.name}[int]',
263 node.elem_type_pos)
264 } else {
265 c.error('generic struct `${elem_sym.name}` must specify type parameter, e.g. ${elem_sym.name}[T]',
266 node.elem_type_pos)
267 }
268 }
269 }
270 ast.Interface {
271 if elem_sym.info.generic_types.len > 0 && elem_sym.info.concrete_types.len == 0
272 && !node.elem_type.has_flag(.generic) {
273 if c.table.cur_concrete_types.len == 0 {
274 c.error('generic interface `${elem_sym.name}` must specify type parameter, e.g. ${elem_sym.name}[int]',
275 node.elem_type_pos)
276 } else {
277 c.error('generic interface `${elem_sym.name}` must specify type parameter, e.g. ${elem_sym.name}[T]',
278 node.elem_type_pos)
279 }
280 }
281 }
282 ast.SumType {
283 if elem_sym.info.generic_types.len > 0 && elem_sym.info.concrete_types.len == 0
284 && !node.elem_type.has_flag(.generic) {
285 if c.table.cur_concrete_types.len == 0 {
286 c.error('generic sumtype `${elem_sym.name}` must specify type parameter, e.g. ${elem_sym.name}[int]',
287 node.elem_type_pos)
288 } else {
289 c.error('generic sumtype `${elem_sym.name}` must specify type parameter, e.g. ${elem_sym.name}[T]',
290 node.elem_type_pos)
291 }
292 }
293 }
294 ast.Alias {
295 if elem_sym.name == 'byte' {
296 c.error('byte is deprecated, use u8 instead', node.elem_type_pos)
297 }
298 }
299 ast.Map {
300 c.markused_array_method(!c.is_builtin_mod, 'map')
301 }
302 else {}
303 }
304 }
305 if node.exprs.len == 0 {
306 if node.has_cap {
307 c.check_array_init_para_type('cap', mut node.cap_expr, node.pos)
308 }
309 if node.has_len {
310 c.check_array_init_para_type('len', mut node.len_expr, node.pos)
311 }
312 }
313 if node.has_init {
314 c.check_array_init_default_expr(mut node)
315 }
316 if node.has_len {
317 len_typ := c.check_expr_option_or_result_call(node.len_expr, c.expr(mut node.len_expr))
318 if len_typ.has_flag(.option) {
319 c.error('cannot use unwrapped Option as length', node.len_expr.pos())
320 }
321 // check &int{}, interface, sum_type initialized
322 if !node.has_init {
323 c.check_elements_initialized(unwrap_elem_type) or {
324 c.warn('${err.msg()}, therefore `len:` cannot be used (unless inside `unsafe`, or if you also use `init:`)',
325 node.pos)
326 }
327 }
328 }
329 if node.has_cap {
330 cap_typ := c.check_expr_option_or_result_call(node.cap_expr, c.expr(mut node.cap_expr))
331 if cap_typ.has_flag(.option) {
332 c.error('cannot use unwrapped Option as capacity', node.cap_expr.pos())
333 }
334 }
335 c.ensure_type_exists(node.elem_type, node.elem_type_pos)
336 if node.typ.has_flag(.generic) && c.table.cur_fn != unsafe { nil }
337 && c.table.cur_fn.generic_names.len == 0 {
338 c.error('generic struct cannot be used in non-generic function', node.pos)
339 }
340
341 // `&Struct{} check
342 if node.has_len {
343 c.check_elements_ref_fields_initialized(unwrap_elem_type, node.pos)
344 }
345 // T{0} initialization when T is an array
346 if node.is_fixed && node.has_val && node.expr_types.len == 0 {
347 if c.table.final_sym(node.elem_type).kind == .array_fixed {
348 elem_info := c.table.final_sym(node.elem_type).array_fixed_info()
349 if c.array_fixed_has_unresolved_size(elem_info)
350 && !c.fixed_array_contains_inferred_size(node.elem_type) {
351 node.elem_type = c.resolve_fixed_array_literal_type(node.elem_type,
352 elem_info.elem_type, 0)
353 }
354 }
355 mut expected_elem_type := node.elem_type
356 mut should_infer_fixed_elem_type :=
357 c.table.final_sym(expected_elem_type).kind == .array_fixed
358 && c.fixed_array_contains_inferred_size(expected_elem_type)
359 for i, mut expr in node.exprs {
360 old_expected_type := c.expected_type
361 if should_infer_fixed_elem_type && i == 0 {
362 c.expected_type = ast.void_type
363 } else {
364 c.expected_type = expected_elem_type
365 }
366 mut typ := c.check_expr_option_or_result_call(expr, c.expr(mut expr))
367 c.expected_type = old_expected_type
368 if expr is ast.CallExpr {
369 ret_sym := c.table.sym(typ)
370 if ret_sym.kind == .array_fixed {
371 typ = c.cast_fixed_array_ret(typ, ret_sym)
372 }
373 node.has_callexpr = true
374 }
375 if should_infer_fixed_elem_type && i == 0
376 && c.table.final_sym(typ).kind == .array_fixed {
377 expected_elem_type = typ
378 node.elem_type = typ
379 should_infer_fixed_elem_type = false
380 }
381 c.check_expected(typ, expected_elem_type) or {
382 c.error('invalid array element: ${err.msg()}', expr.pos())
383 }
384 node.expr_types << typ
385 }
386 node.typ = c.resolve_fixed_array_literal_type(node.typ, node.elem_type, node.exprs.len)
387 resolved_info := c.table.sym(node.typ.clear_option_and_result()).array_fixed_info()
388 if resolved_info.size != node.exprs.len {
389 c.error('fixed array expects ${resolved_info.size} value(s), but got ${node.exprs.len}',
390 node.pos)
391 }
392 } else if !node.is_fixed && node.expr_types.len == 0 {
393 for mut expr in node.exprs {
394 typ := c.expr(mut expr)
395 c.check_expected(typ, node.elem_type) or {
396 c.error('invalid array element: ${err.msg()}', expr.pos())
397 }
398 node.expr_types << typ
399 }
400 }
401 // Resolve generic array type to concrete when inside generic function
402 if node.typ.has_flag(.generic) && c.table.cur_fn != unsafe { nil } {
403 resolved := c.recheck_concrete_type(node.typ)
404 if resolved != node.typ && !resolved.has_flag(.generic) {
405 return if node.alias_type != ast.void_type { node.alias_type } else { resolved }
406 }
407 }
408 return array_init_result_type(node)
409 }
410
411 if node.has_update_expr {
412 // `[...base, e1, e2]` — array update/spread literal
413 update_typ := c.expr(mut node.update_expr)
414 // Resolve through type aliases so `type Ints = []int; [...Ints(...)]`
415 // is accepted; use final_sym to look past aliases of arrays.
416 update_sym := c.table.final_sym(update_typ)
417 if update_sym.kind != .array {
418 c.error('invalid array update: non-array type `${c.table.type_to_str(update_typ)}`',
419 node.update_expr_pos)
420 return ast.void_type
421 }
422 array_info := update_sym.array_info()
423 node.elem_type = array_info.elem_type
424 node.typ = update_typ
425 elem_type = array_info.elem_type
426 c.expected_type = elem_type
427 for mut expr in node.exprs {
428 typ := c.check_expr_option_or_result_call(expr, c.expr(mut expr))
429 node.expr_types << typ
430 if expr is ast.CallExpr {
431 ret_sym := c.table.sym(typ)
432 if ret_sym.kind == .array_fixed {
433 node.expr_types[node.expr_types.len - 1] = c.cast_fixed_array_ret(typ, ret_sym)
434 }
435 node.has_callexpr = true
436 }
437 c.check_expected(typ, elem_type) or {
438 c.error('invalid array element: ${err.msg()}', expr.pos())
439 }
440 }
441 return array_init_result_type(node)
442 }
443 if node.is_fixed {
444 c.ensure_type_exists(node.elem_type, node.elem_type_pos)
445 if !c.is_builtin_mod {
446 c.check_elements_initialized(unwrap_elem_type) or {
447 c.warn('fixed ${err.msg()} (unless inside `unsafe`)', node.pos)
448 }
449 }
450 c.check_elements_ref_fields_initialized(unwrap_elem_type, node.pos)
451 }
452 // `a = []`
453 if node.exprs.len == 0 {
454 // `a := fn_returning_opt_array() or { [] }`
455 if c.expected_type == ast.void_type {
456 if c.expected_or_type != ast.void_type {
457 c.expected_type = c.expected_or_type
458 } else if c.expected_expr_type != ast.void_type {
459 c.expected_type = c.expected_expr_type
460 }
461 }
462 mut type_sym := c.table.sym(c.expected_type)
463 if type_sym.kind != .array || type_sym.array_info().elem_type == ast.void_type {
464 c.error('array_init: no type specified (maybe: `[]Type{}` instead of `[]`)', node.pos)
465 return ast.void_type
466 }
467 array_info := type_sym.array_info()
468 node.elem_type = array_info.elem_type
469 // clear option flag in case of: `fn opt_arr() ?[]int { return [] }`
470 return if c.expected_type.has_flag(.shared_f) {
471 c.expected_type.clear_flag(.shared_f).deref()
472 } else {
473 c.expected_type
474 }.clear_option_and_result()
475 }
476 // `[1,2,3]`
477 if node.exprs.len > 0 && node.elem_type == ast.void_type {
478 mut expected_value_type := ast.void_type
479 mut expecting_interface_array := false
480 mut expecting_sumtype_array := false
481 mut is_first_elem_ptr := false
482 if c.expected_type != 0 {
483 expected_value_type = c.table.value_type(c.expected_type)
484 expected_value_sym := c.table.sym(expected_value_type)
485 if expected_value_sym.kind == .interface {
486 // array of interfaces? (`[dog, cat]`) Save the interface type (`Animal`)
487 expecting_interface_array = true
488 } else if expected_value_sym.kind == .sum_type {
489 expecting_sumtype_array = true
490 }
491 }
492 for i, mut expr in node.exprs {
493 mut typ := ast.void_type
494 expr_pos := expr.pos()
495 is_array_init := expr is ast.ArrayInit
496 if is_array_init {
497 old_expected_type := c.expected_type
498 c.expected_type = c.table.value_type(c.expected_type)
499 mut expr_copy := expr
500 typ = c.check_expr_option_or_result_call(expr_copy, c.expr(mut expr_copy))
501 expr = expr_copy
502 c.expected_type = old_expected_type
503 } else {
504 // [none]
505 if c.expected_type == ast.none_type && expr is ast.None {
506 c.error('invalid expression `none`, it is not an array of Option type',
507 expr_pos)
508 continue
509 }
510 typ = c.check_expr_option_or_result_call(expr, c.expr(mut expr))
511 sym := c.table.sym(expected_value_type)
512 if sym.kind == .interface {
513 c.type_implements(typ, expected_value_type, expr.pos())
514 }
515 }
516 if expr is ast.CallExpr {
517 ret_sym := c.table.sym(typ)
518 if ret_sym.kind == .array_fixed {
519 typ = c.cast_fixed_array_ret(typ, ret_sym)
520 }
521 node.has_callexpr = true
522 }
523 if typ == ast.void_type {
524 c.error('invalid void array element type', expr.pos())
525 }
526 node.expr_types << typ
527 // the first element's type
528 if expecting_interface_array {
529 if i == 0 {
530 elem_type = expected_value_type
531 c.expected_type = elem_type
532 c.type_implements(typ, elem_type, expr.pos())
533 }
534 if !typ.is_any_kind_of_pointer() && !c.inside_unsafe {
535 typ_sym := c.table.sym(typ)
536 if typ_sym.kind != .interface {
537 c.mark_as_referenced(mut &node.exprs[i], true)
538 }
539 }
540 continue
541 } else if expecting_sumtype_array {
542 if i == 0 {
543 if c.table.is_sumtype_or_in_variant(expected_value_type, ast.mktyp(typ)) {
544 elem_type = expected_value_type
545 } else {
546 if expr.is_auto_deref_var() {
547 elem_type = ast.mktyp(typ.deref())
548 } else {
549 elem_type = ast.mktyp(typ)
550 }
551 }
552 c.expected_type = elem_type
553 }
554 continue
555 }
556 // the first element's type
557 if i == 0 {
558 if expr.is_auto_deref_var() {
559 elem_type = ast.mktyp(typ.deref())
560 } else {
561 elem_type = ast.mktyp(typ)
562 }
563 if typ.is_ptr() && c.in_for_count == 0 {
564 is_first_elem_ptr = true
565 }
566 c.expected_type = elem_type
567 continue
568 } else {
569 if !typ.is_any_kind_of_pointer() && !typ.is_int() && is_first_elem_ptr {
570 c.error('cannot have non-pointer of type `${c.table.type_to_str(typ)}` in a pointer array of type `${c.table.type_to_str(elem_type)}`',
571 expr.pos())
572 }
573 }
574 if expr !is ast.TypeNode {
575 if c.table.type_kind(elem_type) == .interface {
576 if c.type_implements(typ, elem_type, expr.pos()) {
577 continue
578 }
579 }
580 c.check_expected(typ, elem_type) or {
581 c.error('invalid array element: ${err.msg()}', expr.pos())
582 }
583 if !elem_type.has_flag(.option)
584 && (typ.has_flag(.option) || typ.idx() == ast.none_type_idx) {
585 typ_str, elem_type_str := c.get_string_names_of(typ, elem_type)
586 if typ.idx() == ast.none_type_idx {
587 c.error('cannot use `${typ_str}` as `${elem_type_str}`', expr.pos())
588 } else {
589 c.error('cannot use `${typ_str}` as `${elem_type_str}`, it must be unwrapped first',
590 expr.pos())
591 }
592 } else if elem_type.has_flag(.option) && !typ.has_flag(.option)
593 && typ.idx() != ast.none_type_idx && !expr.is_pure_literal() {
594 typ_str, elem_type_str := c.get_string_names_of(typ, elem_type)
595 c.error('cannot use `${typ_str}` as `${elem_type_str}`', expr.pos())
596 }
597 }
598 }
599 if node.is_fixed {
600 idx := c.table.find_or_register_array_fixed(elem_type, node.exprs.len, ast.empty_expr,
601 false)
602 if elem_type.has_flag(.generic) {
603 node.typ = ast.new_type(idx).set_flag(.generic)
604 } else {
605 node.typ = ast.new_type(idx)
606 }
607 } else {
608 idx := c.table.find_or_register_array(elem_type)
609 if elem_type.has_flag(.generic) {
610 node.typ = ast.new_type(idx).set_flag(.generic)
611 } else {
612 node.typ = ast.new_type(idx)
613 }
614 }
615 node.elem_type = elem_type
616 } else if node.is_fixed && node.exprs.len == 1 && node.elem_type != ast.void_type {
617 // `[50]u8`
618 sym := c.table.sym(node.typ)
619 if sym.info !is ast.ArrayFixed
620 || c.array_fixed_has_unresolved_size(sym.info as ast.ArrayFixed) {
621 mut size_expr := node.exprs[0]
622 node.typ = c.eval_array_fixed_sizes(mut size_expr, 0, node.elem_type)
623 if node.is_option {
624 node.typ = node.typ.set_flag(.option)
625 }
626 node.elem_type = (c.table.sym(node.typ).info as ast.ArrayFixed).elem_type
627 }
628 if node.has_init {
629 c.check_array_init_default_expr(mut node)
630 }
631 }
632 return array_init_result_type(node)
633}
634
635fn (mut c Checker) check_array_init_default_expr(mut node ast.ArrayInit) {
636 mut init_expr := node.init_expr
637 mut expected_elem_type := node.elem_type
638 if node.elem_type.has_flag(.generic) && c.table.cur_fn != unsafe { nil } {
639 generic_names := c.effective_fn_generic_names(c.table.cur_fn)
640 if generic_names.len > 0 && c.table.cur_concrete_types.len == generic_names.len {
641 expected_elem_type = c.table.unwrap_generic_type(node.elem_type, generic_names,
642 c.table.cur_concrete_types)
643 }
644 }
645 c.expected_type = expected_elem_type
646 init_typ := c.check_expr_option_or_result_call(init_expr, c.expr(mut init_expr))
647 node.init_type = init_typ
648 if !expected_elem_type.has_flag(.option) && init_typ.has_flag(.option) {
649 c.error('cannot use unwrapped Option as initializer', init_expr.pos())
650 }
651 if expected_elem_type.is_number() && init_typ.is_number() {
652 return
653 }
654 if c.table.type_kind(expected_elem_type) == .interface {
655 if c.type_implements(init_typ, expected_elem_type, init_expr.pos()) {
656 return
657 }
658 }
659 c.check_expected(init_typ, expected_elem_type) or { c.error(err.msg(), init_expr.pos()) }
660}
661
662fn (mut c Checker) check_array_init_para_type(para string, mut expr ast.Expr, pos token.Pos) {
663 sym := c.table.final_sym(c.unwrap_generic(c.expr(mut expr)))
664 $if new_int ? && x64 {
665 if sym.kind !in [.int, .int_literal, .i64, .i32, .i16, .i8] {
666 c.error('array ${para} needs to be an int/i64/i32/i16/i8', pos)
667 }
668 } $else {
669 if sym.kind !in [.int, .int_literal, .i32, .i16, .i8] {
670 c.error('array ${para} needs to be an int/i32/i16/i8', pos)
671 }
672 }
673 if expr is ast.IntegerLiteral {
674 lit := expr as ast.IntegerLiteral
675 if lit.val.int() < 0 {
676 c.error('array ${para} can not be negative', lit.pos)
677 }
678 }
679}
680
681// When the fixed array has multiple dimensions, it needs to be evaluated recursively.
682// `[const]int`, `[const][3]int`, `[3][const]int`, `[const + 1][3][const]int`...
683fn (mut c Checker) eval_array_fixed_sizes(mut size_expr ast.Expr, size int, elem_type ast.Type) ast.Type {
684 elem_sym := c.table.sym(elem_type)
685 elem_info := elem_sym.info
686
687 new_elem_typ := if elem_sym.kind == .array_fixed {
688 mut info := elem_info as ast.ArrayFixed
689 mut elem_size_expr := unsafe { info.size_expr }
690 c.eval_array_fixed_sizes(mut elem_size_expr, info.size, info.elem_type)
691 } else {
692 elem_type
693 }
694
695 mut fixed_size := i64(size)
696 if fixed_size <= 0 {
697 c.expr(mut size_expr)
698 match mut size_expr {
699 ast.IntegerLiteral {
700 fixed_size = size_expr.val.int()
701 }
702 ast.ComptimeCall {
703 if size_expr.kind == .d {
704 size_expr.resolve_compile_value(c.pref.compile_values) or {
705 c.error(err.msg(), size_expr.pos)
706 }
707 if size_expr.result_type != ast.i64_type {
708 c.error('value from \$d() can only be positive integers when used as fixed size',
709 size_expr.pos)
710 }
711 fixed_size = size_expr.compile_value.int()
712 } else {
713 c.error('only \$d() can be used for fixed size arrays', size_expr.pos)
714 }
715 }
716 ast.CastExpr {
717 if !size_expr.typ.is_pure_int() {
718 c.error('only integer types are allowed', size_expr.pos)
719 }
720 match mut size_expr.expr {
721 ast.IntegerLiteral {
722 fixed_size = size_expr.expr.val.int()
723 }
724 ast.FloatLiteral {
725 fixed_size = int(size_expr.expr.val.f64())
726 }
727 ast.EnumVal {
728 if val := c.table.find_enum_field_val(size_expr.expr.enum_name,
729 size_expr.expr.val)
730 {
731 fixed_size = val
732 }
733 }
734 else {}
735 }
736 }
737 ast.EnumVal {
738 c.error('${size_expr.enum_name}.${size_expr.val} has to be casted to integer to be used as size',
739 size_expr.pos)
740 }
741 ast.Ident {
742 if mut size_expr.obj is ast.ConstField {
743 if mut size_expr.obj.expr is ast.EnumVal {
744 c.error('${size_expr.obj.expr.enum_name}.${size_expr.obj.expr.val} has to be casted to integer to be used as size',
745 size_expr.pos)
746 }
747 if mut size_expr.obj.expr is ast.CastExpr {
748 if !size_expr.obj.expr.typ.is_pure_int() {
749 c.error('only integer types are allowed', size_expr.pos)
750 }
751 if size_expr.obj.expr.expr is ast.IntegerLiteral {
752 if comptime_value := c.eval_comptime_const_expr(size_expr.obj.expr.expr,
753 0)
754 {
755 fixed_size = comptime_value.i64() or { fixed_size }
756 }
757 }
758 if size_expr.obj.expr.expr is ast.InfixExpr {
759 if comptime_value := c.eval_comptime_const_expr(size_expr.obj.expr.expr,
760 0)
761 {
762 fixed_size = comptime_value.i64() or { fixed_size }
763 }
764 }
765 }
766 if comptime_value := c.eval_comptime_const_expr(size_expr.obj.expr, 0) {
767 fixed_size = comptime_value.i64() or { fixed_size }
768 }
769 } else {
770 c.error('non-constant array bound `${size_expr.name}`', size_expr.pos)
771 }
772 }
773 ast.InfixExpr {
774 if comptime_value := c.eval_comptime_const_expr(size_expr, 0) {
775 fixed_size = comptime_value.i64() or { fixed_size }
776 }
777 }
778 else {
779 c.error('fixed array size cannot use non-constant value', size_expr.pos())
780 }
781 }
782
783 if fixed_size <= 0 {
784 c.error('fixed size cannot be zero or negative (fixed_size: ${fixed_size})',
785 size_expr.pos())
786 }
787 }
788
789 idx := c.table.find_or_register_array_fixed(new_elem_typ, int(fixed_size), size_expr, false)
790 return if elem_type.has_flag(.generic) {
791 ast.new_type(idx).set_flag(.generic)
792 } else {
793 ast.new_type(idx)
794 }
795}
796
797fn (mut c Checker) array_fixed_has_unresolved_size(info &ast.ArrayFixed) bool {
798 if info.size <= 0 {
799 return true
800 }
801 mut elem_type := info.elem_type
802 mut elem_sym := c.table.sym(elem_type)
803 for {
804 if mut elem_sym.info is ast.ArrayFixed {
805 if elem_sym.info.size <= 0 {
806 return true
807 }
808 elem_type = elem_sym.info.elem_type
809 elem_sym = c.table.sym(elem_type)
810 } else {
811 break
812 }
813 }
814 return false
815}
816
817fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
818 if c.table.cur_fn != unsafe { nil } && c.table.cur_concrete_types.len > 0 && node.typ != 0
819 && c.expected_type != ast.void_type {
820 expected_map_type := c.expected_type.clear_option_and_result()
821 if c.table.sym(expected_map_type).kind == .map && node.typ != expected_map_type
822 && !expected_map_type.has_flag(.generic) {
823 node.typ = expected_map_type
824 node.key_type = 0
825 node.value_type = 0
826 }
827 }
828 // `map = {}`
829 if node.keys.len == 0 && node.vals.len == 0 && !node.has_update_expr && node.typ == 0 {
830 sym := c.table.sym(c.expected_type)
831 if sym.kind == .map {
832 info := sym.map_info()
833 node.typ = c.expected_type.clear_option_and_result()
834 node.key_type = info.key_type
835 node.value_type = info.value_type
836 return node.typ
837 } else if sym.info is ast.Struct {
838 msg := if sym.info.is_anon {
839 '`{}` cannot be used to initialize anonymous structs. Use `struct{}` instead.'
840 } else {
841 '`{}` can not be used for initialising empty structs any more. Use `${c.table.type_to_str(c.expected_type)}{}` instead.'
842 }
843 c.error(msg, node.pos)
844 if sym.info.is_anon {
845 return c.expected_type
846 }
847 } else {
848 c.error('invalid empty map initialisation syntax, use e.g. map[string]int{} instead',
849 node.pos)
850 }
851 return ast.void_type
852 }
853 // `x := map[string]string` - set in parser
854 if node.typ != 0 {
855 info := c.table.sym(node.typ).map_info()
856 start_errors := c.nr_errors
857 if node.typ.has_flag(.generic) {
858 c.table.used_features.comptime_syms[c.unwrap_generic(node.typ)] = true
859 }
860 if info.value_type != 0 {
861 if info.value_type.has_flag(.result) {
862 c.error('cannot use Result type as map value type', node.pos)
863 }
864 val_sym := c.table.sym(info.value_type)
865 if val_sym.kind == .struct {
866 val_info := val_sym.info as ast.Struct
867 if val_info.generic_types.len > 0 && val_info.concrete_types.len == 0
868 && !info.value_type.has_flag(.generic) {
869 if c.table.cur_concrete_types.len == 0 {
870 c.error('generic struct `${val_sym.name}` must specify type parameter, e.g. ${val_sym.name}[int]',
871 node.pos)
872 } else {
873 c.error('generic struct `${val_sym.name}` must specify type parameter, e.g. ${val_sym.name}[T]',
874 node.pos)
875 }
876 }
877 } else if val_sym.info is ast.FnType {
878 for param in val_sym.info.func.params {
879 if param.typ.has_flag(.result) {
880 c.error('result type arguments are not supported', node.pos)
881 }
882 }
883 }
884 }
885 c.ensure_type_exists(info.key_type, node.pos)
886 c.ensure_type_exists(info.value_type, node.pos)
887 node.key_type = info.key_type
888 node.value_type = info.value_type
889 if (c.table.sym(info.key_type).language == .v && info.key_type == ast.any_type)
890 || (c.table.sym(info.value_type).language == .v && info.value_type == ast.any_type) {
891 c.note('the `any` type is deprecated and will be removed soon - either use an empty interface, or a sum type',
892 node.pos)
893 c.error('cannot use type `any` here', node.pos)
894 }
895 needs_explicit_key_check := c.expected_type == ast.void_type
896 || c.expected_type.clear_option_and_result() != node.typ
897 if needs_explicit_key_check && c.nr_errors == start_errors && info.key_type != ast.void_type
898 && !info.key_type.has_flag(.generic) && !c.table.supports_map_key_type(info.key_type) {
899 c.error('map key type `${c.table.sym(info.key_type).name}` not supported', node.pos)
900 }
901 return node.typ
902 }
903
904 if (node.keys.len > 0 && node.vals.len > 0) || node.has_update_expr {
905 mut map_type := ast.void_type
906 start_errors := c.nr_errors
907 use_expected_type := c.expected_type != ast.void_type && !c.inside_const
908 && c.table.sym(c.expected_type).kind == .map && !(c.inside_fn_arg
909 && c.expected_type.has_flag(.generic))
910 if use_expected_type {
911 map_type = c.expected_type
912 }
913 if node.has_update_expr {
914 update_type := c.expr(mut node.update_expr)
915 if map_type != ast.void_type {
916 if update_type != map_type {
917 msg := c.expected_msg(update_type, map_type)
918 c.error('invalid map update: ${msg}', node.update_expr_pos)
919 }
920 } else if c.table.sym(update_type).kind != .map {
921 c.error('invalid map update: non-map type', node.update_expr_pos)
922 } else {
923 map_type = update_type
924 }
925 }
926
927 mut map_key_type := ast.void_type
928 mut map_val_type := ast.void_type
929 if map_type != ast.void_type {
930 sym := c.table.sym(map_type)
931 info := sym.map_info()
932 map_key_type = info.key_type
933 map_val_type = info.value_type
934 } else if node.keys.len > 0 {
935 // `{'age': 20}`
936 mut key_ := node.keys[0]
937 map_key_type = ast.mktyp(c.expr(mut key_))
938 if node.keys[0].is_auto_deref_var() {
939 map_key_type = map_key_type.deref()
940 }
941 mut val_ := node.vals[0]
942 map_val_type = ast.mktyp(c.expr(mut val_))
943 if node.vals[0].is_auto_deref_var() {
944 map_val_type = map_val_type.deref()
945 }
946 node.val_types << map_val_type
947 if node.keys.len == 1 && map_val_type == ast.none_type {
948 c.error('map value cannot be only `none`', node.vals[0].pos())
949 }
950 c.check_expr_option_or_result_call(key_, map_key_type)
951 c.check_expr_option_or_result_call(val_, map_val_type)
952 }
953 map_key_type = c.unwrap_generic(map_key_type)
954 map_val_type = c.unwrap_generic(map_val_type)
955 if c.nr_errors == start_errors && map_key_type != ast.void_type
956 && !map_key_type.has_flag(.generic) && !c.table.supports_map_key_type(map_key_type) {
957 c.error('map key type `${c.table.sym(map_key_type).name}` not supported', node.pos)
958 }
959
960 node.typ = ast.new_type(c.table.find_or_register_map(map_key_type, map_val_type))
961 node.key_type = map_key_type
962 node.value_type = map_val_type
963
964 map_value_sym := c.table.sym(map_val_type)
965 expecting_interface_map := map_value_sym.kind == .interface
966 mut same_key_type := true
967 for i, mut key in node.keys {
968 if i == 0 && map_type == ast.void_type {
969 continue // skip first key/value if we processed them above
970 }
971 mut val := node.vals[i]
972 c.expected_type = map_key_type
973 key_type := c.expr(mut key)
974 c.expected_type = map_val_type
975 c.set_expected_array_literal_type(mut val, map_val_type)
976 val_type := c.expr(mut val)
977 node.val_types << val_type
978 val_type_sym := c.table.sym(val_type)
979 c.check_expr_option_or_result_call(key, key_type)
980 c.check_expr_option_or_result_call(val, val_type)
981 if !c.check_types(key_type, map_key_type)
982 || (i == 0 && key_type.is_number() && map_key_type.is_number()
983 && map_key_type != ast.mktyp(key_type)) {
984 msg := c.expected_msg(key_type, map_key_type)
985 c.error('invalid map key: ${msg}', key.pos())
986 same_key_type = false
987 }
988 if expecting_interface_map {
989 if val_type == map_val_type {
990 continue
991 }
992 if val_type_sym.kind == .struct
993 && c.type_implements(val_type, map_val_type, val.pos()) {
994 node.vals[i] = ast.CastExpr{
995 expr: val
996 typname: c.table.get_type_name(map_val_type)
997 typ: map_val_type
998 expr_type: val_type
999 pos: val.pos()
1000 }
1001 continue
1002 } else {
1003 msg := c.expected_msg(val_type, map_val_type)
1004 c.error('invalid map value: ${msg}', val.pos())
1005 }
1006 }
1007 if val_type == ast.none_type && map_val_type.has_flag(.option) {
1008 continue
1009 }
1010 if !c.check_types(val_type, map_val_type)
1011 || map_val_type.has_flag(.option) != val_type.has_flag(.option)
1012 || (i == 0 && val_type.is_number() && map_val_type.is_number()
1013 && map_val_type != ast.mktyp(val_type)) {
1014 msg := c.expected_msg(val_type, map_val_type)
1015 c.error('invalid map value: ${msg}', val.pos())
1016 }
1017 }
1018 if same_key_type {
1019 for i in 1 .. node.keys.len {
1020 c.check_dup_keys(node, i)
1021 }
1022 }
1023 }
1024 return node.typ
1025}
1026
1027// check the element, and its children for ref uninitialized fields
1028fn (mut c Checker) check_elements_ref_fields_initialized(typ ast.Type, pos &token.Pos) {
1029 if typ == 0 || c.inside_const {
1030 return
1031 }
1032 sym := c.table.sym(typ)
1033 mut checked_types := []ast.Type{}
1034 c.do_check_elements_ref_fields_initialized(sym, mut checked_types, pos)
1035}
1036
1037// Recursively check the element, and its children for ref uninitialized fields
1038fn (mut c Checker) do_check_elements_ref_fields_initialized(sym &ast.TypeSymbol, mut checked_types []ast.Type,
1039 pos &token.Pos) {
1040 if sym.info is ast.Struct {
1041 linked_name := sym.name
1042 // For now, let's call this method and give a notice instead of an error.
1043 // After some time, we remove the check_ref_fields_initialized_note() method and
1044 // simply call check_ref_fields_initialized()
1045 c.check_ref_fields_initialized_note(sym, mut checked_types, linked_name, pos)
1046 return
1047 }
1048 match sym.info {
1049 ast.Array {
1050 elem_type := sym.info.elem_type
1051 if elem_type in checked_types {
1052 return
1053 }
1054 checked_types << elem_type
1055 elem_sym := c.table.sym(elem_type)
1056 c.do_check_elements_ref_fields_initialized(elem_sym, mut checked_types, pos)
1057 }
1058 ast.ArrayFixed {
1059 elem_type := sym.info.elem_type
1060 if elem_type in checked_types {
1061 return
1062 }
1063 checked_types << elem_type
1064 elem_sym := c.table.sym(elem_type)
1065 c.do_check_elements_ref_fields_initialized(elem_sym, mut checked_types, pos)
1066 }
1067 ast.Map {
1068 key_type := sym.info.key_type
1069 if key_type in checked_types {
1070 return
1071 }
1072 checked_types << key_type
1073 key_sym := c.table.sym(key_type)
1074 c.do_check_elements_ref_fields_initialized(key_sym, mut checked_types, pos)
1075 value_type := sym.info.value_type
1076 if value_type in checked_types {
1077 return
1078 }
1079 checked_types << value_type
1080 value_sym := c.table.sym(value_type)
1081 c.do_check_elements_ref_fields_initialized(value_sym, mut checked_types, pos)
1082 }
1083 ast.Alias {
1084 parent_type := sym.info.parent_type
1085 if parent_type in checked_types {
1086 return
1087 }
1088 checked_types << parent_type
1089 parent_sym := c.table.sym(parent_type)
1090 c.do_check_elements_ref_fields_initialized(parent_sym, mut checked_types, pos)
1091 }
1092 else {}
1093 }
1094}
1095
1096const err_ref_uninitialized = error('arrays of references need to be initialized right away')
1097const err_interface_uninitialized = error('arrays of interfaces need to be initialized right away')
1098const err_sumtype_uninitialized = error('arrays of sumtypes need to be initialized right away')
1099
1100// check the element, and its children for `ref/interface/sumtype` initialized
1101fn (mut c Checker) check_elements_initialized(typ ast.Type) ! {
1102 if typ == 0 || c.inside_unsafe {
1103 return
1104 }
1105 if typ.is_any_kind_of_pointer() {
1106 if !c.pref.translated && !c.file.is_translated {
1107 return err_ref_uninitialized
1108 } else {
1109 return
1110 }
1111 }
1112 sym := c.table.sym(typ)
1113 if sym.kind == .interface {
1114 return err_interface_uninitialized
1115 } else if sym.kind == .sum_type {
1116 return err_sumtype_uninitialized
1117 }
1118
1119 match sym.info {
1120 ast.Array {
1121 elem_type := sym.info.elem_type
1122 return c.check_elements_initialized(elem_type)
1123 }
1124 ast.ArrayFixed {
1125 elem_type := sym.info.elem_type
1126 if !c.is_builtin_mod {
1127 return c.check_elements_initialized(elem_type)
1128 }
1129 }
1130 ast.Map {
1131 value_type := sym.info.value_type
1132 if !c.is_builtin_mod {
1133 return c.check_elements_initialized(value_type)
1134 }
1135 }
1136 ast.Alias {
1137 parent_type := sym.info.parent_type
1138 return c.check_elements_initialized(parent_type)
1139 }
1140 else {}
1141 }
1142}
1143
1144fn (mut c Checker) check_append(mut node ast.InfixExpr, left_type ast.Type, right_type ast.Type,
1145 right_final_sym ast.TypeSymbol) ast.Type {
1146 if !node.is_stmt {
1147 c.error('array append cannot be used in an expression', node.pos)
1148 }
1149 mut right_sym := c.table.sym(right_type)
1150 mut left_sym := c.table.sym(left_type)
1151 if left_type.has_flag(.option) && node.left is ast.Ident && node.left.or_expr.kind == .absent {
1152 c.check_option_infix_expr(mut node, left_type, right_type, left_sym, right_sym)
1153 }
1154 right_pos := node.right.pos()
1155 // `array << elm`
1156 c.check_expr_option_or_result_call(node.right, right_type)
1157 node.auto_locked, _ = c.fail_if_immutable(mut node.left)
1158 left_value_type := c.table.value_type(c.unwrap_generic(left_type))
1159 left_value_sym := c.table.sym(c.unwrap_generic(left_value_type))
1160 if !left_value_type.has_flag(.option) && right_type.has_flag(.option) {
1161 c.error('unwrapped Option cannot be used in an infix expression', node.pos)
1162 }
1163
1164 right := node.right
1165 if right is ast.PrefixExpr && right.op == .amp {
1166 mut expr2 := right.right
1167 if mut expr2 is ast.Ident && !node.left.is_blank_ident() && expr2.obj is ast.ConstField {
1168 c.error('cannot have mutable reference to const `${expr2.name}`', expr2.pos)
1169 }
1170 }
1171 if left_value_sym.kind == .interface {
1172 if right is ast.ArrayInit && right.is_fixed {
1173 c.error('cannot append `${right_sym.name}` to `${left_sym.name}`', right_pos)
1174 return ast.void_type
1175 }
1176 right_is_interface_value := c.table.does_type_implement_interface(c.unwrap_generic(right_type),
1177 left_value_type)
1178 if right_is_interface_value {
1179 if !right_type.is_any_kind_of_pointer() && !c.inside_unsafe
1180 && right_sym.kind != .interface {
1181 c.mark_as_referenced(mut &node.right, true)
1182 }
1183 } else if right_final_sym.kind == .array {
1184 // []Animal << []Cat
1185 c.type_implements(c.table.value_type(right_type), left_value_type, right_pos)
1186 } else {
1187 // []Animal << Cat
1188 if c.type_implements(right_type, left_value_type, right_pos) {
1189 if !right_type.is_any_kind_of_pointer() && !c.inside_unsafe
1190 && right_sym.kind != .interface {
1191 c.mark_as_referenced(mut &node.right, true)
1192 }
1193 }
1194 }
1195 return ast.void_type
1196 } else if left_value_sym.kind == .sum_type {
1197 base_right_type := c.unwrap_generic(right_type)
1198 if c.check_types(base_right_type, left_value_type) {
1199 return ast.void_type
1200 }
1201 if right_sym.kind == .array {
1202 right_value_type := c.table.value_type(base_right_type)
1203 if c.check_types(right_value_type, left_value_type) {
1204 return ast.void_type
1205 }
1206 }
1207 c.error('cannot append `${right_sym.name}` to `${left_sym.name}`', right_pos)
1208 return ast.void_type
1209 }
1210 // []T << T or []T << []T
1211 unwrapped_right_type := c.unwrap_generic(right_type)
1212 if c.check_types(unwrapped_right_type, left_value_type) {
1213 // []&T << T is wrong: we check for that, !(T.is_ptr()) && ?(&T).is_ptr()
1214 if !(!unwrapped_right_type.is_ptr() && left_value_type.is_ptr()
1215 && left_value_type.share() == .mut_t) {
1216 return ast.void_type
1217 }
1218 } else if c.check_types(unwrapped_right_type, c.unwrap_generic(left_type)) {
1219 return ast.void_type
1220 }
1221 if left_value_type.has_flag(.option) && right_type == ast.none_type {
1222 return ast.void_type
1223 }
1224 c.error('cannot append `${right_sym.name}` to `${left_sym.name}`', right_pos)
1225 return ast.void_type
1226}
1227