v2 / vlib / v / checker / assign.v
1364 lines · 1339 sloc · 49.46 KB · a75b9622292f36a85c5da0926c1f8a1e1623e4ae
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
6
7fn checker_table_fn_lookup(table &ast.Table, name string) (ast.Fn, bool) {
8 if name !in table.fns {
9 return ast.Fn{}, false
10 }
11 return unsafe { table.fns[name] }, true
12}
13
14@[inline]
15fn (mut c Checker) is_nocopy_struct(typ_ ast.Type) bool {
16 mut typ := c.unwrap_generic(typ_).clear_option_and_result()
17 if typ == 0 || typ.is_ptr() {
18 return false
19 }
20 mut sym := c.table.final_sym(typ)
21 if sym.kind == .generic_inst && sym.info is ast.GenericInst {
22 sym = c.table.sym(ast.new_type(sym.info.parent_idx))
23 }
24 return sym.info is ast.Struct && sym.info.attrs.contains('nocopy')
25}
26
27fn assign_expr_is_auto_deref(expr ast.Expr) bool {
28 return expr.is_auto_deref_var()
29}
30
31fn (c &Checker) auto_deref_source_type_is_pointer(expr ast.Expr) bool {
32 if expr !is ast.Ident || c.table.cur_fn == unsafe { nil } || !expr.is_auto_deref_var() {
33 return false
34 }
35 ident := expr as ast.Ident
36 for param in c.table.cur_fn.params {
37 if param.name == ident.name {
38 source_typ := if param.orig_typ != 0 { param.orig_typ } else { param.typ }
39 return source_typ.is_any_kind_of_pointer()
40 }
41 }
42 return false
43}
44
45fn (mut c Checker) smartcasted_assign_lhs_type(expr ast.Expr, fallback_type ast.Type) ast.Type {
46 match expr {
47 ast.Ident {
48 if expr.obj is ast.Var && expr.obj.smartcasts.len > 0 {
49 if expr.obj.orig_type.has_flag(.option) {
50 return expr.obj.orig_type
51 }
52 if expr.obj.is_mut && expr.obj.orig_type != 0 {
53 orig_sym := c.table.final_sym(expr.obj.orig_type)
54 if orig_sym.kind == .sum_type {
55 return expr.obj.orig_type
56 }
57 }
58 return c.exposed_smartcast_type(expr.obj.orig_type, expr.obj.smartcasts.last(),
59 expr.obj.is_mut)
60 }
61 }
62 ast.SelectorExpr {
63 if expr.expr_type != 0 {
64 scope_field := expr.scope.find_struct_field(smartcast_selector_expr_str(expr),
65 expr.expr_type, expr.field_name)
66 if scope_field != unsafe { nil } && scope_field.smartcasts.len > 0 {
67 if scope_field.orig_type.has_flag(.option) {
68 return scope_field.orig_type
69 }
70 return c.exposed_smartcast_type(scope_field.orig_type,
71 scope_field.smartcasts.last(), scope_field.is_mut)
72 }
73 }
74 }
75 else {}
76 }
77
78 return fallback_type
79}
80
81fn (mut c Checker) reset_option_assignment_smartcast(mut expr ast.Ident, left_type ast.Type) {
82 if expr.scope == unsafe { nil } {
83 return
84 }
85 if var := expr.scope.find_var(expr.name) {
86 expr.scope.objects[expr.name] = ast.Var{
87 ...var
88 typ: left_type
89 pos: var.pos
90 orig_type: ast.no_type
91 smartcasts: []ast.Type{}
92 is_assignment_smartcast: false
93 is_unwrapped: false
94 }
95 }
96}
97
98fn (mut c Checker) update_option_assignment_smartcast(mut expr ast.Expr, left_type ast.Type, right ast.Expr, right_type ast.Type) {
99 if !left_type.has_flag(.option) {
100 return
101 }
102 match mut expr {
103 ast.Ident {
104 mut original_pos := expr.pos
105 if var := expr.scope.find_var(expr.name) {
106 original_pos = var.pos
107 }
108 if right_type == ast.none_type || right_type == ast.nil_type
109 || right_type.has_flag(.option) || right.is_nil()
110 || (right is ast.UnsafeExpr && right.expr.is_nil()) {
111 c.reset_option_assignment_smartcast(mut expr, left_type)
112 return
113 }
114 c.smartcast(mut expr, left_type, left_type.clear_flag(.option), mut expr.scope, false,
115 true, false, true)
116 if mut scope_var := expr.scope.find_var(expr.name) {
117 scope_var.is_assignment_smartcast = true
118 scope_var.pos = original_pos
119 }
120 }
121 else {}
122 }
123}
124
125@[inline]
126fn (c &Checker) disallow_implicit_int_to_f32_assign(got ast.Type, expected ast.Type) bool {
127 got_type := c.table.unalias_num_type(got).clear_flags()
128 expected_type := c.table.unalias_num_type(expected).clear_flags()
129 return expected_type == ast.f32_type
130 && got_type in [ast.i32_type, ast.int_type, ast.i64_type, ast.isize_type, ast.u32_type, ast.u64_type, ast.usize_type]
131}
132
133// TODO: 980 line function
134fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
135 prev_inside_assign := c.inside_assign
136 c.inside_assign = true
137 if node.attr.name != '' {
138 c.assign_stmt_attr = node.attr.name
139 } else {
140 c.assign_stmt_attr = ''
141 }
142 c.expected_type = ast.none_type // TODO: a hack to make `x := if ... work`
143 defer {
144 c.expected_type = ast.void_type
145 c.inside_assign = prev_inside_assign
146 }
147 is_decl := node.op == .decl_assign
148 original_op := node.op
149 mut right_first := node.right[0]
150 node.left_types = []
151 mut right_len := node.right.len
152 mut right_first_type := ast.void_type
153 old_recheck := c.inside_recheck
154
155 // check if we are rechecking an already checked expression on generic rechecking
156 c.inside_recheck = old_recheck || node.right_types.len > 0
157 defer {
158 c.inside_recheck = old_recheck
159 }
160 for i, mut right in node.right {
161 if right in [ast.ArrayInit, ast.CallExpr, ast.ComptimeCall, ast.DumpExpr, ast.IfExpr,
162 ast.LockExpr, ast.MapInit, ast.MatchExpr, ast.ParExpr, ast.SelectorExpr, ast.StructInit] {
163 if right in [ast.ArrayInit, ast.IfExpr, ast.MapInit, ast.MatchExpr, ast.StructInit]
164 && node.left.len == node.right.len && !is_decl
165 && node.left[i] in [ast.Ident, ast.IndexExpr, ast.SelectorExpr]
166 && !node.left[i].is_blank_ident() {
167 mut expr := node.left[i]
168 old_is_index_assign := c.is_index_assign
169 if expr is ast.IndexExpr {
170 c.is_index_assign = true
171 }
172 c.expected_type = c.expr(mut expr)
173 c.is_index_assign = old_is_index_assign
174 }
175 if is_decl && node.left[i] is ast.Ident && (node.left[i] as ast.Ident).is_mut()
176 && right is ast.StructInit && (right as ast.StructInit).is_anon {
177 c.anon_struct_should_be_mut = true
178 }
179 mut right_type := c.expr(mut right)
180 c.anon_struct_should_be_mut = false
181 if right in [ast.CallExpr, ast.IfExpr, ast.LockExpr, ast.MatchExpr, ast.DumpExpr] {
182 c.fail_if_unreadable(right, right_type, 'right-hand side of assignment')
183 }
184 if i == 0 {
185 right_first_type = right_type
186 node.right_types = [
187 c.check_expr_option_or_result_call(right, right_first_type),
188 ]
189 }
190 if right_type != 0 {
191 right_type_sym := c.table.sym(right_type)
192 // fixed array returns an struct, but when assigning it must be the array type
193 if right_type_sym.info is ast.ArrayFixed {
194 right_type = c.cast_fixed_array_ret(right_type, right_type_sym)
195 }
196 if right_type_sym.kind == .multi_return {
197 if node.right.len > 1 {
198 c.error('cannot use multi-value ${right_type_sym.name} in single-value context',
199 right.pos())
200 }
201 node.right_types = right_type_sym.mr_info().types.map(c.cast_fixed_array_ret(it,
202 c.table.sym(it)))
203 right_len = node.right_types.len
204 }
205 }
206 if right_type == ast.void_type {
207 right_len = 0
208 if mut right is ast.IfExpr {
209 last_branch := right.branches.last()
210 last_stmts := last_branch.stmts.filter(it is ast.ExprStmt)
211 if last_stmts.any((it as ast.ExprStmt).typ.has_flag(.generic)) {
212 right_len = last_branch.stmts.len
213 node.right_types = last_stmts.map((it as ast.ExprStmt).typ)
214 }
215 }
216 }
217 } else if mut right is ast.InfixExpr {
218 if right.op == .arrow {
219 c.error('cannot use `<-` on the right-hand side of an assignment, as it does not return any values',
220 right.pos)
221 } else if c.inside_recheck {
222 if i < node.right_types.len {
223 c.expected_type = node.right_types[i]
224 }
225 mut right_type := c.expr(mut right)
226 if right_type != 0 {
227 right_type_sym := c.table.sym(right_type)
228 // fixed array returns an struct, but when assigning it must be the array type
229 if right_type_sym.info is ast.ArrayFixed {
230 right_type = c.cast_fixed_array_ret(right_type, right_type_sym)
231 }
232 }
233 if i == 0 {
234 right_first_type = right_type
235 node.right_types = [
236 c.check_expr_option_or_result_call(right, right_first_type),
237 ]
238 }
239 }
240 }
241 if mut right is ast.Ident {
242 if right.is_mut {
243 c.error('unexpected `mut` on right-hand side of assignment', right.mut_pos)
244 }
245 }
246 if is_decl && mut right is ast.None {
247 c.error('cannot assign a `none` value to a variable', right.pos)
248 }
249 // Handle `left_name := unsafe { none }`
250 if mut right is ast.UnsafeExpr && right.expr is ast.None {
251 c.error('cannot use `none` in `unsafe` blocks', right.expr.pos)
252 }
253 if mut right is ast.AnonFn {
254 if right.decl.generic_names.len > 0 && (right.inherited_vars.len == 0
255 || !c.generic_anon_fn_can_use_current_context(right.decl.generic_names)) {
256 c.error('cannot assign generic function to a variable', right.decl.pos)
257 }
258 }
259 }
260 if node.left.len != right_len {
261 if right_len == 0 && right_first_type == ast.void_type {
262 match right_first {
263 ast.ArrayInit, ast.MapInit, ast.StructInit {
264 if is_decl {
265 for i, mut left in node.left {
266 node.left_types << ast.void_type
267 if mut left is ast.Ident {
268 if mut left.info is ast.IdentVar {
269 left.info.typ = ast.void_type
270 if mut left.obj is ast.Var {
271 left.obj.typ = ast.void_type
272 }
273 }
274 }
275 if i < node.right_types.len && node.right_types[i] == 0 {
276 node.right_types[i] = ast.void_type
277 }
278 }
279 }
280 return
281 }
282 else {}
283 }
284 }
285 if mut right_first is ast.CallExpr {
286 if node.left_types.len > 0 && node.left_types[0] == ast.void_type {
287 // If it's a void type, it's an unknown variable, already had an error earlier.
288 return
289 }
290 str_variables := if node.left.len == 1 { 'variable' } else { 'variables' }
291 str_values := if right_len == 1 { 'value' } else { 'values' }
292 c.error('assignment mismatch: ${node.left.len} ${str_variables} but `${right_first.get_name()}()` returns ${right_len} ${str_values}',
293 node.pos)
294 } else if mut right_first is ast.ParExpr {
295 mut right_next := right_first
296 for {
297 if mut right_next.expr is ast.CallExpr {
298 if right_next.expr.return_type == ast.void_type {
299 c.error('assignment mismatch: expected ${node.left.len} value(s) but `${right_next.expr.get_name()}()` returns ${right_len} value(s)',
300 node.pos)
301 }
302 break
303 } else if mut right_next.expr is ast.ParExpr {
304 right_next = right_next.expr
305 } else {
306 break
307 }
308 }
309 } else {
310 str_variables := if node.left.len == 1 { 'variable' } else { 'variables' }
311 str_values := if right_len == 1 { 'value' } else { 'values' }
312 c.error('assignment mismatch: ${node.left.len} ${str_variables} ${right_len} ${str_values}',
313 node.pos)
314 }
315 return
316 }
317 for i, mut left in node.left {
318 if !is_decl {
319 if left is ast.Ident {
320 ident := left as ast.Ident
321 c.clear_assert_autocast(ident.scope, ident.name)
322 }
323 }
324 if mut left is ast.CallExpr {
325 // ban `foo() = 10`
326 if c.pref.is_vls {
327 // in `vls` mode, code is incomplete, eval left also
328 c.expr(mut left)
329 } else {
330 c.error('cannot call function `${left.name}()` on the left side of an assignment',
331 left.pos)
332 }
333 } else if mut left is ast.PrefixExpr {
334 // ban `*foo() = 10`
335 if left.right is ast.CallExpr && left.op == .mul {
336 c.error('cannot dereference a function call on the left side of an assignment, use a temporary variable',
337 left.pos)
338 }
339 } else if mut left is ast.Ident && node.op == .decl_assign {
340 if left.name in c.global_names {
341 c.note('the global variable named `${left.name}` already exists', left.pos)
342 }
343 }
344 is_blank_ident := left.is_blank_ident()
345 mut left_type := ast.void_type
346 mut var_option := false
347 mut is_shared_re_assign := false
348 if !is_decl && !is_blank_ident {
349 if left in [ast.Ident, ast.SelectorExpr] {
350 c.prevent_sum_type_unwrapping_once = true
351 }
352 if left is ast.IndexExpr {
353 c.is_index_assign = true
354 }
355 left_type = c.expr(mut left)
356 if left is ast.IndexExpr && left.index is ast.RangeExpr && !left.is_index_operator {
357 c.error('cannot reassign using range expression on the left side of an assignment',
358 left.pos)
359 }
360 left_type = c.smartcasted_assign_lhs_type(left, left_type)
361 c.is_index_assign = false
362 c.expected_type = c.unwrap_generic(left_type)
363 is_shared_re_assign = left is ast.Ident && left.info is ast.IdentVar
364 && ((left.info as ast.IdentVar).share == .shared_t || left_type.has_flag(.shared_f))
365 }
366
367 if c.comptime.comptime_for_field_var != '' && mut left is ast.ComptimeSelector {
368 if c.comptime.has_different_types && node.right[i].is_literal()
369 && !c.comptime.inside_comptime_if {
370 c.error('mismatched types: check field type with \$if to avoid this problem',
371 node.right[i].pos())
372 }
373 left_type = c.comptime.comptime_for_field_type
374 c.expected_type = c.unwrap_generic(left_type)
375 }
376 if node.right_types.len < node.left.len { // first type or multi return types added above
377 old_inside_ref_lit := c.inside_ref_lit
378 if mut left is ast.Ident && left.info is ast.IdentVar {
379 c.inside_ref_lit = c.inside_ref_lit || left.info.share == .shared_t
380 }
381 c.inside_decl_rhs = is_decl
382 mut expr := node.right[i]
383 if left is ast.Ident && left.is_mut() && expr is ast.StructInit && expr.is_anon {
384 c.anon_struct_should_be_mut = true
385 defer(fn) {
386 c.anon_struct_should_be_mut = false
387 }
388 }
389 right_type := c.expr(mut expr)
390 c.inside_decl_rhs = false
391 c.inside_ref_lit = old_inside_ref_lit
392 if node.right_types.len == i {
393 node.right_types << c.check_expr_option_or_result_call(node.right[i], right_type)
394 }
395 } else if c.inside_recheck && i < node.right.len {
396 // Generic rechecks reuse the same AST nodes, so cached rhs types for
397 // identifiers/selectors can be stale across concrete instantiations.
398 needs_rhs_recheck := c.comptime.has_comptime_expr(node.right[i])
399 || node.right[i] in [ast.Ident, ast.SelectorExpr, ast.IndexExpr, ast.ComptimeSelector, ast.PrefixExpr, ast.CastExpr, ast.UnsafeExpr]
400 if needs_rhs_recheck {
401 mut expr := mut node.right[i]
402 right_type := c.expr(mut expr)
403 node.right_types[i] = c.check_expr_option_or_result_call(node.right[i], right_type)
404 }
405 }
406 mut right := if i < node.right.len { node.right[i] } else { node.right[0] }
407 mut right_type := node.right_types[i]
408 right_pos := right.pos()
409 left_pos := left.pos()
410 if mut right is ast.Ident {
411 // resolve shared right variable
412 if right_type.has_flag(.shared_f) {
413 if c.fail_if_unreadable(right, right_type, 'right-hand side of assignment') {
414 return
415 }
416 }
417 right_sym := c.table.sym(right_type)
418 if right_sym.info is ast.Struct {
419 if right_sym.info.generic_types.len > 0 {
420 obj := right.scope.find_ptr(right.name)
421 if obj != unsafe { nil } {
422 match obj {
423 ast.ConstField {
424 right_type = obj.typ
425 }
426 ast.GlobalField {
427 right_type = obj.typ
428 }
429 ast.Var {
430 right_type = obj.typ
431 }
432 else {}
433 }
434 }
435 }
436 }
437 if right.or_expr.kind in [.propagate_option, .block] {
438 right_type = right_type.clear_flag(.option)
439 }
440 } else if right is ast.ComptimeSelector {
441 if !(right as ast.ComptimeSelector).is_method {
442 right_type = c.comptime.comptime_for_field_type
443 }
444 }
445 if is_decl || is_shared_re_assign {
446 // check generic struct init and return unwrap generic struct type
447 if mut right is ast.StructInit {
448 c.expr(mut right)
449 if right.typ.has_flag(.generic) {
450 right_type = right.typ
451 }
452 } else if mut right is ast.PrefixExpr {
453 if right.op == .amp && right.right is ast.StructInit {
454 right_type = c.expr(mut right)
455 } else if right.op == .arrow {
456 right_type = c.expr(mut right)
457 right_type = c.cast_fixed_array_ret(right_type, c.table.sym(right_type))
458 }
459 } else if mut right is ast.Ident {
460 if right.kind == .function {
461 c.expr(mut right)
462 }
463 }
464 if assign_expr_is_auto_deref(right) && right_type.is_ptr()
465 && !c.auto_deref_source_type_is_pointer(right) {
466 left_type = ast.mktyp(right_type.deref())
467 } else {
468 left_type = ast.mktyp(right_type)
469 }
470 if left_type == ast.int_type {
471 if mut right is ast.IntegerLiteral {
472 val := right.val.i64()
473 if overflows_i32(val) {
474 c.error('overflow in implicit type `int`, use explicit type casting instead',
475 right.pos)
476 }
477 }
478 }
479 } else {
480 // Make sure the variable is mutable
481 c.fail_if_immutable(mut left)
482
483 if !is_blank_ident && !left_type.has_flag(.option) && right_type.has_flag(.option) {
484 c.error('cannot assign an Option value to a non-option variable', right.pos())
485 }
486 // left_type = c.expr(left)
487 // if right is ast.None && !left_type.has_flag(.option) {
488 // println(left_type)
489 // c.error('cannot assign a `none` value to a non-option variable', right.pos())
490 // }
491 }
492 if !c.inside_unsafe && !is_blank_ident && node.op in [.decl_assign, .assign]
493 && left is ast.Ident && left.is_mut() {
494 // check if right-side is a immutable reference
495 c.fail_if_immutable_to_mutable(left_type, right_type, right)
496 }
497 if mut left is ast.Ident && left.info is ast.IdentVar && right is ast.Ident
498 && right.name in c.global_names {
499 ident_var_info := left.info as ast.IdentVar
500 if ident_var_info.share == .shared_t {
501 c.error('cannot assign global variable to shared variable', right_pos)
502 }
503 }
504 if right_type.is_ptr() && left_type.is_ptr() {
505 if mut right is ast.Ident {
506 c.fail_if_stack_struct_action_outside_unsafe(mut right, 'assigned')
507 }
508 }
509 // Do not allow `a := 0; b := 0; a = &b`
510 if !is_decl && left is ast.Ident && !is_blank_ident && !left_type.is_any_kind_of_pointer()
511 && right_type.is_any_kind_of_pointer() && !right_type.has_flag(.shared_f) {
512 left_sym := c.table.sym(left_type)
513 if left_sym.kind !in [.function, .array] {
514 c.warn(
515 'cannot assign a reference to a value (this will be an error soon) left=${c.table.type_str(left_type)} ${left_type.is_ptr()} ' +
516 'right=${c.table.type_str(right_type)} ${right_type.is_any_kind_of_pointer()} ptr=${right_type.is_ptr()}',
517 node.pos)
518 }
519 }
520 node.left_types << left_type
521
522 if right is ast.StructInit {
523 right_sym := c.table.sym(right_type)
524 c.check_any_type(right_type, right_sym, right_pos)
525 }
526
527 if left is ast.ParExpr && is_decl {
528 c.error('parentheses are not supported on the left side of `:=`', left_pos)
529 }
530 left = left.remove_par()
531 is_assign := node.op in [.assign, .decl_assign]
532 match mut left {
533 ast.Ident {
534 if (is_decl || left.kind == .blank_ident) && left_type.is_ptr()
535 && right is ast.PrefixExpr {
536 prefix_right := right as ast.PrefixExpr
537 if prefix_right.right_type == ast.int_literal_type_idx
538 && prefix_right.right is ast.Ident {
539 ident_right := prefix_right.right as ast.Ident
540 if ident_right.obj is ast.ConstField {
541 const_name := ident_right.name.all_after_last('.')
542 const_val := (ident_right.obj as ast.ConstField).expr
543 c.add_error_detail('Specify the type for the constant value. Example:')
544 c.add_error_detail(' `const ${const_name} = int(${const_val})`')
545 c.error('cannot assign a pointer to a constant with an integer literal value',
546 ident_right.pos)
547 }
548 }
549 }
550 if left.kind == .blank_ident {
551 if !is_decl && mut right is ast.None {
552 c.error('cannot assign a `none` value to blank `_` identifier', right.pos)
553 }
554 left_type = right_type
555 node.left_types[i] = right_type
556 if !is_assign {
557 c.error('cannot modify blank `_` identifier', left.pos)
558 }
559 } else if left.info !is ast.IdentVar {
560 c.error('cannot assign to ${left.kind} `${left.name}`', left.pos)
561 } else {
562 if is_decl {
563 c.check_valid_snake_case(left.name, 'variable name', left.pos)
564 if reserved_type_names_chk.matches(left.name) {
565 c.error('invalid use of reserved type `${left.name}` as a variable name',
566 left.pos)
567 }
568 }
569 if (is_decl || is_shared_re_assign) && right is ast.Nil && !c.inside_unsafe {
570 // `x := unsafe { nil }` is allowed,
571 // as well as:
572 // `unsafe {
573 // x := nil
574 // println(x)
575 // }`
576 c.error('use of untyped nil in assignment (use `unsafe` | ${c.inside_unsafe})',
577 right_pos)
578 }
579 mut ident_var_info := left.info as ast.IdentVar
580 if ident_var_info.share == .shared_t || is_shared_re_assign {
581 left_type = left_type.set_flag(.shared_f)
582 if is_decl || is_shared_re_assign {
583 if left_type.nr_muls() > 1 {
584 c.error('shared cannot be multi level reference', left.pos)
585 }
586 left_type = left_type.set_nr_muls(1)
587 }
588 } else if left_type.has_flag(.shared_f) {
589 left_type = left_type.clear_flag(.shared_f)
590 if left_type.is_ptr() {
591 left_type = left_type.deref()
592 }
593 }
594 if ident_var_info.share == .atomic_t {
595 left_type = left_type.set_flag(.atomic_f)
596 }
597 if ident_var_info.is_option {
598 var_option = true
599 }
600 node.left_types[i] = left_type
601 ident_var_info.typ = left_type
602 left.info = ident_var_info
603 if left_type != 0 {
604 match mut left.obj {
605 ast.Var {
606 left.obj.typ = left_type
607 if is_decl && node.left.len == node.right.len && i < node.right.len {
608 left.obj.expr = node.right[i]
609 }
610 if is_decl && left.obj.generic_typ == 0
611 && (left_type.has_flag(.generic)
612 || c.type_has_unresolved_generic_parts(left_type)) {
613 left.obj.generic_typ = left_type
614 if left.scope != unsafe { nil } {
615 if mut scope_var := left.scope.find_var(left.name) {
616 scope_var.generic_typ = left_type
617 }
618 }
619 }
620 if left.obj.is_auto_deref {
621 left.obj.is_used = true
622 }
623 if !left_type.is_ptr() {
624 if c.table.sym(left_type).is_heap() {
625 left.obj.is_auto_heap = true
626 }
627 }
628 if left_type in ast.unsigned_integer_type_idxs {
629 if mut right is ast.IntegerLiteral {
630 if right.val[0] == `-` {
631 c.error('cannot assign negative value to unsigned integer type',
632 right.pos)
633 }
634 }
635 }
636 // flag the variable as comptime/generic related on its declaration
637 if is_decl {
638 c.change_flags_if_comptime_expr(mut left, right)
639 if left.scope != unsafe { nil } {
640 left.scope.update_var_type(left.name, left.obj.typ)
641 if node.left.len == node.right.len && i < node.right.len {
642 if mut scope_var := left.scope.find_var(left.name) {
643 scope_var.expr = node.right[i]
644 }
645 }
646 }
647 }
648 }
649 ast.GlobalField {
650 left.obj.typ = left_type
651 }
652 else {}
653 }
654 }
655 if is_decl {
656 full_name := '${left.mod}.${left.name}'
657 scope_obj := c.file.global_scope.find_ptr(full_name)
658 if scope_obj != unsafe { nil } {
659 match scope_obj {
660 ast.ConstField {
661 c.warn('duplicate of a const name `${full_name}`', left.pos)
662 }
663 else {}
664 }
665 }
666 if left.name == left.mod && left.name != 'main' {
667 c.error('duplicate of a module name `${left.name}`', left.pos)
668 }
669 // Check if variable name is already registered as imported module symbol
670 if c.check_import_sym_conflict(left.name) {
671 c.error('duplicate of an import symbol `${left.name}`', left.pos)
672 }
673 c.check_module_name_conflict(left.name, left.pos)
674 }
675 if node.op == .assign && left_type.has_flag(.option) && right is ast.UnsafeExpr
676 && right.expr.is_nil() {
677 c.error('cannot assign `nil` to option value', right_pos)
678 }
679 }
680 }
681 ast.PrefixExpr {
682 // Do now allow `*x = y` outside `unsafe`
683 if left.op == .mul {
684 if !c.inside_unsafe && !c.pref.translated && !c.file.is_translated {
685 c.error('modifying variables via dereferencing can only be done in `unsafe` blocks',
686 node.pos)
687 } else if mut left.right is ast.Ident {
688 // mark `p` in `*p = val` as used:
689 if mut left.right.obj is ast.Var {
690 left.right.obj.is_used = true
691 }
692 }
693 } else if left.op == .amp {
694 c.error('cannot use a reference on the left side of `${node.op}`', left.pos)
695 } else {
696 c.error('cannot use `${left.op}` on the left of `${node.op}`', left.pos)
697 }
698 if is_decl {
699 c.error('non-name on the left side of `:=`', left.pos)
700 }
701 }
702 ast.SelectorExpr {
703 if mut left.expr is ast.IndexExpr {
704 if left.expr.is_index_operator {
705 c.error('cannot assign through overloaded index expressions, use `[]=` instead',
706 left.pos)
707 } else if left.expr.is_map {
708 left.expr.is_setter = true
709 }
710 }
711 if left_type in ast.unsigned_integer_type_idxs {
712 if mut right is ast.IntegerLiteral {
713 if right.val[0] == `-` {
714 c.error('cannot assign negative value to unsigned integer type',
715 right.pos)
716 }
717 }
718 }
719 if left_type.has_flag(.option) && right is ast.UnsafeExpr && right.expr.is_nil() {
720 c.error('cannot assign `nil` to option value', right_pos)
721 }
722 }
723 else {
724 if mut left is ast.IndexExpr {
725 // eprintln('>>> left.is_setter: ${left.is_setter:10} | left.is_map: ${left.is_map:10} | left.is_array: ${left.is_array:10}')
726 if (left.is_map || left.is_farray) && left.is_setter {
727 left.recursive_mapset_is_setter(true)
728 }
729 right_type = c.type_resolver.get_type_or_default(right, right_type)
730 }
731 if mut left is ast.InfixExpr {
732 c.error('cannot use infix expression on the left side of `${node.op}`',
733 left.pos)
734 }
735 if is_decl && !c.pref.is_vls {
736 c.error('non-name `${left}` on left side of `:=`', left.pos())
737 }
738
739 if node.op == .assign && (left.is_literal() || left is ast.StructInit) {
740 c.error('non-name literal value `${left}` on left side of `=`', left.pos())
741 }
742 }
743 }
744
745 if mut left is ast.IndexExpr {
746 if left.is_index_operator && node.op != .decl_assign {
747 receiver_name := c.table.sym(c.unwrap_generic(left.left_type)).name
748 if left.setter_arg_type == 0 {
749 c.error('index assignment requires a `[]=` overload on type `${receiver_name}`',
750 left.pos)
751 } else if !left.left.is_lvalue() {
752 c.error('cannot assign through overloaded index on a non-lvalue receiver',
753 left.pos)
754 }
755 if node.op == .assign {
756 left_type = left.setter_arg_type
757 }
758 }
759 }
760 left_type_unwrapped := c.unwrap_generic(ast.mktyp(left_type))
761 right_type_unwrapped := c.unwrap_generic(right_type)
762 if right_type_unwrapped == 0 {
763 // right type was a generic `T`
764 continue
765 }
766 if c.pref.translated || c.file.is_translated {
767 // TODO: fix this in C2V instead, for example cast enums to int before using `|` on them.
768 // TODO: replace all c.pref.translated checks with `$if !translated` for performance
769 continue
770 }
771 if left_type_unwrapped == 0 {
772 continue
773 }
774 left_sym := c.table.sym(left_type_unwrapped)
775 right_sym := c.table.sym(right_type_unwrapped)
776
777 if left_sym.kind == .array && !c.inside_unsafe && right_sym.kind == .array
778 && left is ast.Ident && !left.is_blank_ident() && right in [ast.Ident, ast.SelectorExpr]
779 && ((node.op == .decl_assign && left.is_mut) || node.op == .assign) {
780 // Do not allow direct array assignments outside unsafe.
781 // E.g.: `a2 = a1` wants `a2 = a1.clone()`, `a = val.arr_field` wants `a = val.arr_field.clone()`
782 mut_str := if node.op == .decl_assign { 'mut ' } else { '' }
783 c.error('use `${mut_str}array2 ${node.op.str()} array1.clone()` instead of `${mut_str}array2 ${node.op.str()} array1` (or use `unsafe`)',
784 node.pos)
785 }
786
787 // Do not allow auto (de)reference in PrefixExpr
788 // e.g. `*ptr1 = ptr2`
789 if mut left is ast.PrefixExpr && left.op == .mul {
790 if left_type.nr_muls() != right_type.nr_muls() && !left_type.is_voidptr()
791 && !right_type.is_voidptr() && right_type != ast.nil_type {
792 r := right_sym.str_with_correct_nr_muls(right_type.nr_muls())
793 l := left_sym.str_with_correct_nr_muls(left_type.nr_muls())
794 c.error('cannot use `${r}` (right side) as `${l}` (left side) in assignment',
795 node.pos)
796 }
797 }
798
799 if left_sym.kind == .array && right_sym.kind == .array {
800 right_info := right_sym.info as ast.Array
801 right_elem_type := c.table.unaliased_type(right_info.elem_type)
802 if node.op in [.decl_assign, .assign] {
803 // Do not allow `mut arr := [&immutable_object]`
804 if mut left is ast.Ident && right_elem_type.is_ptr() {
805 if left.is_mut() || (left.obj is ast.Var && left.obj.is_mut) {
806 if mut right is ast.ArrayInit && right.exprs.len > 0 {
807 elem_expr := right.exprs[0]
808 if elem_expr is ast.PrefixExpr && elem_expr.op == .amp {
809 r := elem_expr.right
810 if r is ast.Ident {
811 obj := r.obj
812 if obj is ast.Var && !obj.is_mut {
813 c.warn('cannot add a reference to an immutable object to a mutable array',
814 elem_expr.pos)
815 }
816 }
817 }
818 }
819 }
820 } else if mut left is ast.Ident && left.kind != .blank_ident {
821 mut should_clone_slice := false
822 right_notice_pos := right.pos()
823 right_expr := right
824 if right_expr is ast.IndexExpr {
825 should_clone_slice = right_expr.left is ast.Ident
826 && right_expr.index is ast.RangeExpr
827 && (right_expr.left.is_mut() || left.is_mut()) && !c.inside_unsafe
828 }
829 if should_clone_slice {
830 // `mut a := arr[..]` auto add clone() -> `mut a := arr[..].clone()`
831 c.add_error_detail_with_pos('To silence this notice, use either an explicit `a[..].clone()`,
832or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
833 right_notice_pos)
834 c.note('an implicit clone of the slice was done here', right_notice_pos)
835 mut cloned_right := ast.CallExpr{
836 name: 'clone'
837 kind: .clone
838 left: right
839 left_type: left_type
840 is_method: true
841 receiver_type: left_type
842 return_type: left_type
843 scope: c.fn_scope
844 is_return_used: true
845 }
846 right_type = c.expr(mut cloned_right)
847 right = cloned_right
848 node.right[i] = cloned_right
849 }
850 }
851 }
852 if node.op == .assign {
853 // `mut arr := [u8(1),2,3]`
854 // `arr = [u8(4),5,6]`
855 left_info := left_sym.info as ast.Array
856 left_elem_type := c.table.unaliased_type(left_info.elem_type)
857 if left_type_unwrapped.nr_muls() == right_type_unwrapped.nr_muls()
858 && left_info.nr_dims == right_info.nr_dims && left_elem_type == right_elem_type {
859 continue
860 }
861 }
862 }
863 if left_sym.kind == .map && is_assign && right_sym.kind == .map && !c.inside_unsafe
864 && !left.is_blank_ident() && right.is_lvalue() && right !is ast.ComptimeSelector
865 && (!right_type.is_ptr() || (right is ast.Ident && assign_expr_is_auto_deref(right))) {
866 // Do not allow `a = b`
867 c.error('cannot copy map: call `move` or `clone` method (or use a reference)',
868 right.pos())
869 }
870 if is_assign && !c.inside_unsafe && !left.is_blank_ident()
871 && c.is_nocopy_struct(left_type_unwrapped) && c.is_nocopy_struct(right_type_unwrapped)
872 && right !is ast.StructInit {
873 c.error('cannot copy @[nocopy] struct: use a reference instead', right.pos())
874 }
875 if left_sym.kind == .function && right_sym.info is ast.FnType {
876 return_sym := c.table.sym(right_sym.info.func.return_type)
877 mut missing_fn_concrete_types := false
878 if right is ast.Ident {
879 ident := right as ast.Ident
880 if ident.kind == .function {
881 func, has_func := checker_table_fn_lookup(c.table, ident.name)
882 if has_func {
883 missing_fn_concrete_types = func.generic_names.len > 0
884 && ident.concrete_types.len == 0
885 }
886 }
887 }
888 if return_sym.kind == .placeholder {
889 c.error('unknown return type: cannot assign `${right}` as a function variable',
890 right.pos())
891 } else if !missing_fn_concrete_types && right !is ast.AnonFn
892 && c.type_has_unresolved_generic_parts(right_sym.info.func.return_type) {
893 c.error('cannot assign `${right}` as a generic function variable', right.pos())
894 }
895 }
896 if left_sym.kind == .array_fixed && !c.inside_unsafe && is_assign
897 && right_sym.kind == .array_fixed && left is ast.Ident && !left.is_blank_ident()
898 && right is ast.Ident {
899 if right_sym.info is ast.ArrayFixed {
900 if right_sym.info.elem_type.is_ptr() {
901 c.error('assignment from one fixed array to another with a pointer element type is prohibited outside of `unsafe`',
902 node.pos)
903 }
904 }
905 }
906 if left_type.is_any_kind_of_pointer() && !assign_expr_is_auto_deref(left) {
907 if !c.inside_unsafe && node.op !in [.assign, .decl_assign] {
908 // ptr op=
909 if !c.pref.translated && !c.file.is_translated {
910 c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos)
911 }
912 }
913 right_is_ptr := right_type.is_any_kind_of_pointer()
914 if !left_type.has_flag(.shared_f) && !right_is_ptr && node.op == .assign
915 && right_type_unwrapped.is_number() {
916 c.error('cannot assign to `${left}`: ' +
917 c.expected_msg(right_type_unwrapped, left_type_unwrapped), right.pos())
918 }
919 if !right_sym.is_number() && !left_type.has_flag(.shared_f)
920 && (right is ast.StructInit || !right_is_ptr) {
921 left_name := c.table.type_to_str(left_type_unwrapped)
922 mut rtype := right_type_unwrapped
923 if rtype.is_ptr() {
924 rtype = rtype.deref()
925 }
926 right_name := c.table.type_to_str(rtype)
927 if !(left_type.has_flag(.option) && right_type == ast.none_type) {
928 c.error('mismatched types `${left_name}` and `${right_name}`', node.pos)
929 }
930 }
931 }
932 if mut left is ast.Ident && left.info is ast.IdentVar {
933 if left.info.is_static {
934 if right_sym.kind == .map {
935 c.error('maps cannot be static', left.pos)
936 } else if !right.is_constant() {
937 c.error('cannot initialized static variable with non-constant value', left.pos)
938 }
939 }
940 }
941 // Single side check
942 match node.op {
943 .assign {} // No need to do single side check for =. But here put it first for speed.
944 .plus_assign, .minus_assign {
945 // allow literal values to auto deref var (e.g.`for mut v in values { v += 1.0 }`)
946 left_deref := if assign_expr_is_auto_deref(left) && left_type.is_ptr() {
947 left_type.deref()
948 } else {
949 left_type
950 }
951 if c.is_string_like_type(left_deref) {
952 if node.op != .plus_assign {
953 c.error('operator `${node.op}` not defined on left operand type `${left_sym.name}`',
954 left.pos())
955 }
956 if node.op == .plus_assign && !c.is_string_concat_type(right_type) {
957 c.error('invalid right operand: ${left_sym.name} ${node.op} ${right_sym.name}',
958 right.pos())
959 } else if node.op != .plus_assign && !c.is_string_like_type(right_type) {
960 c.error('invalid right operand: ${left_sym.name} ${node.op} ${right_sym.name}',
961 right.pos())
962 }
963 } else if !left_sym.is_number()
964 && left_sym.kind !in [.byteptr, .charptr, .struct, .alias] {
965 c.error('operator `${node.op}` not defined on left operand type `${left_sym.name}`',
966 left.pos())
967 } else if !right_sym.is_number()
968 && left_sym.kind !in [.byteptr, .charptr, .struct, .alias] {
969 c.error('invalid right operand: ${left_sym.name} ${node.op} ${right_sym.name}',
970 right.pos())
971 }
972 }
973 .mult_assign, .power_assign, .div_assign {
974 if !left_sym.is_number() && !c.table.final_sym(left_type_unwrapped).is_int()
975 && left_sym.kind !in [.struct, .alias] {
976 c.error('operator ${node.op.str()} not defined on left operand type `${left_sym.name}`',
977 left.pos())
978 } else if !right_sym.is_number() && !c.table.final_sym(left_type_unwrapped).is_int()
979 && left_sym.kind !in [.struct, .alias] {
980 c.error('operator ${node.op.str()} not defined on right operand type `${right_sym.name}`',
981 right.pos())
982 }
983 }
984 .and_assign, .or_assign, .xor_assign {
985 left_final_sym := c.table.final_sym(left_type_unwrapped)
986 if left_final_sym.info is ast.Enum && left_final_sym.info.is_flag {
987 // `@[flag]` tagged enums support compound bitwise assignment.
988 } else if !left_sym.is_int() && !left_final_sym.is_int() {
989 c.error('operator ${node.op.str()} not defined on left operand type `${left_sym.name}`',
990 left.pos())
991 } else if !right_sym.is_int() && !c.table.final_sym(right_type_unwrapped).is_int() {
992 c.error('operator ${node.op.str()} not defined on right operand type `${right_sym.name}`',
993 right.pos())
994 }
995 }
996 .mod_assign, .left_shift_assign, .right_shift_assign {
997 if !left_sym.is_int() && !c.table.final_sym(left_type_unwrapped).is_int() {
998 c.error('operator ${node.op.str()} not defined on left operand type `${left_sym.name}`',
999 left.pos())
1000 } else if !right_sym.is_int() && !c.table.final_sym(right_type_unwrapped).is_int() {
1001 c.error('operator ${node.op.str()} not defined on right operand type `${right_sym.name}`',
1002 right.pos())
1003 }
1004 }
1005 .boolean_and_assign, .boolean_or_assign {
1006 if c.table.final_sym(left_type_unwrapped).kind != .bool {
1007 c.error('operator ${node.op.str()} not defined on left operand type `${left_sym.name}`',
1008 left.pos())
1009 } else if c.table.final_sym(right_type_unwrapped).kind != .bool {
1010 c.error('operator ${node.op.str()} not defined on right operand type `${right_sym.name}`',
1011 right.pos())
1012 }
1013 }
1014 .unsigned_right_shift_assign {
1015 if node.left.len != 1 || node.right.len != 1 {
1016 c.error('unsupported operation: unable to lower expression for unsigned shift assignment.',
1017 node.pos)
1018 }
1019 mut modified_left_type := ast.void_type
1020 if !left_type.is_int() {
1021 c.error('invalid operation: shift on type `${c.table.sym(left_type).name}`',
1022 node.pos)
1023 } else if left_type.is_int_literal() {
1024 // int literal => i64
1025 modified_left_type = ast.u32_type
1026 } else if left_type.is_unsigned() {
1027 modified_left_type = left_type
1028 } else {
1029 // signed types => unsigned types
1030 unsigned_type := left_type.flip_signedness()
1031 if unsigned_type == ast.void_type {
1032 c.error('invalid operation: shift on type `${c.table.sym(left_type).name}`',
1033 node.pos)
1034 } else {
1035 modified_left_type = unsigned_type
1036 }
1037 }
1038 node = ast.AssignStmt{
1039 op: .assign
1040 pos: node.pos
1041 end_comments: node.end_comments
1042 left: node.left
1043 right: [
1044 ast.Expr(ast.InfixExpr{
1045 left: ast.CastExpr{
1046 expr: node.left[0]
1047 typ: modified_left_type
1048 typname: c.table.type_str(modified_left_type)
1049 expr_type: left_type
1050 pos: node.pos
1051 }
1052 op: .right_shift
1053 right: node.right[0]
1054 left_type: modified_left_type
1055 right_type: right_type
1056 pos: node.pos
1057 }),
1058 ]
1059 left_types: node.left_types
1060 right_types: node.right_types
1061 is_static: node.is_static
1062 is_simple: node.is_simple
1063 has_cross_var: node.has_cross_var
1064 }
1065 }
1066 else {}
1067 }
1068
1069 if node.op == .power_assign {
1070 c.markused_power_runtime_support()
1071 }
1072 if node.op in [.plus_assign, .minus_assign, .mod_assign, .mult_assign, .power_assign, .div_assign]
1073 && (left_sym.kind == .alias || (left_sym.kind == .struct && right_sym.kind == .struct)) {
1074 left_name := c.table.type_to_str(left_type_unwrapped)
1075 right_name := c.table.type_to_str(right_type_unwrapped)
1076 parent_sym := c.table.final_sym(left_type_unwrapped)
1077 if left_sym.kind == .alias && right_sym.kind != .alias {
1078 if !parent_sym.is_primitive() {
1079 c.error('mismatched types `${left_name}` and `${right_name}`', node.pos)
1080 }
1081 }
1082 extracted_op := match node.op {
1083 .plus_assign { '+' }
1084 .minus_assign { '-' }
1085 .div_assign { '/' }
1086 .mod_assign { '%' }
1087 .mult_assign { '*' }
1088 .power_assign { '**' }
1089 else { 'unknown op' }
1090 }
1091
1092 if left_sym.kind == .struct && (left_sym.info as ast.Struct).generic_types.len > 0 {
1093 continue
1094 }
1095 if method := left_sym.find_method_with_generic_parent(extracted_op) {
1096 c.mark_fn_decl_as_referenced(method.fkey())
1097 if method.return_type != left_type_unwrapped {
1098 c.error('operator `${extracted_op}` must return `${left_name}` to be used as an assignment operator',
1099 node.pos)
1100 }
1101 if right_sym.kind in [.alias, .struct]
1102 && !c.check_same_type_ignoring_pointers(left_type_unwrapped, right_type_unwrapped) {
1103 c.error('cannot assign to `${left}`: expected `${left_name}`, not `${right_name}`',
1104 right.pos())
1105 }
1106 } else {
1107 if method := parent_sym.find_method_with_generic_parent(extracted_op) {
1108 c.mark_fn_decl_as_referenced(method.fkey())
1109 if parent_sym.kind == .alias
1110 && (parent_sym.info as ast.Alias).parent_type != method.return_type {
1111 c.error('operator `${extracted_op}` must return `${left_name}` to be used as an assignment operator',
1112 node.pos)
1113 }
1114 if right_sym.kind in [.alias, .struct]
1115 && !c.check_same_type_ignoring_pointers(left_type_unwrapped, right_type_unwrapped) {
1116 c.error('cannot assign to `${left}`: expected `${left_name}`, not `${right_name}`',
1117 right.pos())
1118 }
1119 } else {
1120 if !parent_sym.is_primitive() {
1121 if left_name == right_name {
1122 c.error('undefined operation `${left_name}` ${extracted_op} `${right_name}`',
1123 node.pos)
1124 } else {
1125 c.error('mismatched types `${left_name}` and `${right_name}`', node.pos)
1126 }
1127 }
1128 }
1129 }
1130 }
1131 if !is_blank_ident && right_sym.kind != .placeholder && left_sym.kind != .interface
1132 && ((!right_type.has_flag(.generic) && !left_type.has_flag(.generic))
1133 || right_sym.kind != left_sym.kind) {
1134 // Disallow `array = voidptr` assign
1135 if left_sym.kind in [.array, .array_fixed]
1136 && (right_type_unwrapped.is_voidptr() || right.is_nil()) {
1137 left_str := c.table.type_to_str(left_type_unwrapped)
1138 right_str := c.table.type_to_str(right_type_unwrapped)
1139 c.error('cannot assign to `${left}`: expected `${left_str}`, not `${right_str}`',
1140 right.pos())
1141 }
1142 // Dual sides check (compatibility check)
1143 is_string_plus_assign := original_op == .plus_assign
1144 && c.is_string_like_type(left_type_unwrapped)
1145 && c.is_string_concat_type(right_type_unwrapped)
1146 assign_right_type := if
1147 original_op in [.left_shift_assign, .right_shift_assign, .unsigned_right_shift_assign]
1148 || is_string_plus_assign {
1149 left_type_unwrapped
1150 } else {
1151 right_type_unwrapped
1152 }
1153 if original_op == .assign
1154 && c.disallow_implicit_int_to_f32_assign(assign_right_type, left_type_unwrapped) {
1155 c.error('cannot assign to `${left}`: ${c.expected_msg(assign_right_type,
1156 left_type_unwrapped)}', right_pos)
1157 }
1158 c.check_expected(assign_right_type, left_type_unwrapped) or {
1159 if left.is_auto_deref_arg() && left_type.is_ptr() {
1160 left_deref := left_type.deref()
1161 right_deref := if right.is_pure_literal() {
1162 right.get_pure_type()
1163 } else if assign_expr_is_auto_deref(right) && right_type.is_ptr() {
1164 right_type.deref()
1165 } else {
1166 right_type
1167 }
1168 if left_deref.is_number() && right_deref.is_number() {
1169 continue
1170 }
1171 }
1172 // allow literal values to auto deref var (e.g.`for mut v in values { v = 1.0 }`)
1173 if assign_expr_is_auto_deref(left) || assign_expr_is_auto_deref(right) {
1174 left_deref := if assign_expr_is_auto_deref(left) && left_type.is_ptr() {
1175 left_type.deref()
1176 } else {
1177 left_type
1178 }
1179 right_deref := if right.is_pure_literal() {
1180 right.get_pure_type()
1181 } else if assign_expr_is_auto_deref(right) && right_type.is_ptr() {
1182 right_type.deref()
1183 } else {
1184 right_type
1185 }
1186 if c.check_types(right_deref, left_deref) {
1187 continue
1188 }
1189 }
1190 // allow for ptr += 2
1191 if left_type_unwrapped.is_ptr() && right_type_unwrapped.is_int()
1192 && node.op in [.plus_assign, .minus_assign] {
1193 if !c.inside_unsafe {
1194 c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos)
1195 }
1196 } else {
1197 if c.comptime.comptime_for_field_var != '' && left is ast.ComptimeSelector {
1198 field_type := c.unwrap_generic(c.comptime.comptime_for_field_type)
1199 field_sym := c.table.sym(field_type)
1200
1201 // allow `t.$(field.name) = 0` where `t.$(field.name)` is a enum
1202 if field_sym.kind == .enum && !right_type.is_int() {
1203 c.error('enums can only be assigned `int` values', right.pos())
1204 }
1205 // disallow invalid `t.$(field.name)` type assignment
1206 if !c.check_types(field_type, right_type) && !(c.inside_x_matches_type
1207 || field_sym.kind == .enum) {
1208 c.error('cannot assign to `${ast.Expr(left)}`: ${c.expected_msg(right_type,
1209 field_type)}', right.pos())
1210 }
1211 } else {
1212 if right_type_unwrapped != ast.void_type {
1213 if !var_option || (var_option && right_type_unwrapped != ast.none_type) {
1214 if left_sym.kind == .array_fixed && right_sym.kind == .array
1215 && right is ast.ArrayInit {
1216 c.add_error_detail('try adding `!` after the array literal, e.g.: `${left} = [...]!`')
1217 c.error('cannot assign to `${left}`: ${err.msg()}', right_pos)
1218 } else {
1219 c.error('cannot assign to `${left}`: ${err.msg()}', right_pos)
1220 }
1221 }
1222 }
1223 }
1224 }
1225 }
1226 }
1227 if left_sym.kind == .interface {
1228 if c.type_implements(right_type, left_type, right.pos()) {
1229 if !right_type.is_any_kind_of_pointer() && right_sym.kind != .interface
1230 && !c.inside_unsafe {
1231 c.mark_as_referenced(mut &node.right[i], true)
1232 }
1233 }
1234 }
1235 if left_sym.info is ast.Struct && !left_sym.info.is_anon && right is ast.StructInit
1236 && right.is_anon {
1237 c.error('cannot assign anonymous `struct` to a typed `struct`', right_pos)
1238 }
1239 if right_sym.kind == .alias && right_sym.name == 'byte' {
1240 c.error('byte is deprecated, use u8 instead', right.pos())
1241 }
1242 if original_op == .assign {
1243 c.update_option_assignment_smartcast(mut left, left_type, right, right_type)
1244 }
1245 }
1246 // this needs to run after the assign stmt left exprs have been run through checker
1247 // so that ident.obj is set
1248 // Check `x := &y` and `mut x := <-ch`
1249 if mut right_first is ast.PrefixExpr {
1250 mut right_node := right_first
1251 is_amp := right_first.op == .amp
1252 left_first := node.left[0]
1253 if left_first is ast.Ident {
1254 assigned_var := left_first
1255 mut is_shared := false
1256 if left_first.info is ast.IdentVar {
1257 is_shared = left_first.info.share == .shared_t
1258 }
1259 old_inside_ref_lit := c.inside_ref_lit
1260 c.inside_ref_lit = c.inside_ref_lit || right_node.op == .amp || is_shared
1261 c.expr(mut right_node.right)
1262 c.inside_ref_lit = old_inside_ref_lit
1263 if right_node.op == .amp {
1264 mut expr := right_node.right
1265 expr = expr.remove_par()
1266 if mut expr is ast.Ident {
1267 if mut expr.obj is ast.Var {
1268 v := expr.obj
1269 right_first_type = v.typ
1270 }
1271 if is_amp && !node.left[0].is_blank_ident() && expr.obj is ast.ConstField {
1272 c.error('cannot have mutable reference to const `${expr.name}`',
1273 right_node.pos)
1274 }
1275 if !c.inside_unsafe && assigned_var.is_mut() && !expr.is_mut() {
1276 c.error('`${expr.name}` is immutable, cannot have a mutable reference to it',
1277 right_node.pos)
1278 }
1279 }
1280 }
1281 if right_node.op == .arrow {
1282 if assigned_var.is_mut {
1283 right_sym := c.table.sym(right_first_type)
1284 if right_sym.kind == .chan {
1285 chan_info := right_sym.chan_info()
1286 if chan_info.elem_type.is_ptr() && !chan_info.is_mut {
1287 c.error('cannot have a mutable reference to object from `${right_sym.name}`',
1288 right_node.pos)
1289 }
1290 }
1291 }
1292 }
1293 }
1294 }
1295 if node.left_types.len != node.left.len {
1296 c.error('assign statement left type number mismatch', node.pos)
1297 }
1298}
1299
1300// change_flags_if_comptime_expr changes the flags of the left variable if the right expression is comptime/generic expr
1301fn (mut c Checker) change_flags_if_comptime_expr(mut left ast.Ident, right ast.Expr) {
1302 if mut left.obj is ast.Var {
1303 if right is ast.ComptimeSelector {
1304 left.obj.typ = c.comptime.comptime_for_field_type
1305 if right.or_block.kind == .propagate_option {
1306 left.obj.typ = left.obj.typ.clear_flag(.option)
1307 left.obj.ct_type_unwrapped = true
1308 }
1309 left.obj.ct_type_var = .field_var
1310 } else if right is ast.InfixExpr {
1311 right_ct_var := c.comptime.get_ct_type_var(right.left)
1312 if right_ct_var != .no_comptime {
1313 left.obj.ct_type_var = right_ct_var
1314 }
1315 } else if right is ast.StructInit && right.unresolved && right.typ.has_flag(.generic) {
1316 left.obj.ct_type_var = .generic_param
1317 } else if right is ast.IndexExpr && c.comptime.is_comptime(right) {
1318 right_ct_var := c.comptime.get_ct_type_var(right.left)
1319 if right_ct_var != .no_comptime {
1320 left.obj.ct_type_var = right_ct_var
1321 }
1322 } else if right is ast.Ident && right.obj is ast.Var && right.or_expr.kind == .absent {
1323 right_obj_var := right.obj as ast.Var
1324 if right_obj_var.ct_type_var != .no_comptime {
1325 ctyp := c.type_resolver.get_type(right)
1326 if ctyp != ast.void_type {
1327 left.obj.ct_type_var = right_obj_var.ct_type_var
1328 left.obj.typ = ctyp
1329 if ctyp.has_flag(.generic) && c.unwrap_generic(ctyp).has_flag(.option) {
1330 left.obj.typ = left.obj.typ.set_flag(.option)
1331 }
1332 }
1333 }
1334 } else if right is ast.DumpExpr && right.expr is ast.ComptimeSelector {
1335 left.obj.ct_type_var = .field_var
1336 left.obj.typ = c.comptime.comptime_for_field_type
1337 } else if right is ast.CallExpr {
1338 if right.left_type != 0 && c.table.type_kind(right.left_type) == .array
1339 && right.name == 'map' && right.args.len > 0 && right.args[0].expr is ast.AsCast
1340 && right.args[0].expr.typ.has_flag(.generic) {
1341 left.obj.ct_type_var = .generic_var
1342 } else if left.obj.ct_type_var in [.generic_var, .no_comptime]
1343 && c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len != 0
1344 && !right.comptime_ret_val && c.type_resolver.is_generic_expr(right) {
1345 // mark variable as generic var because its type changes according to fn return generic resolution type
1346 left.obj.ct_type_var = .generic_var
1347 }
1348 } else if right is ast.PostfixExpr && right.op == .question {
1349 if right.expr is ast.Ident && right.expr.ct_expr {
1350 right_obj_var := right.expr.obj as ast.Var
1351 ctyp := c.type_resolver.get_type(right)
1352 if ctyp != ast.void_type {
1353 left.obj.ct_type_unwrapped = true
1354 left.obj.ct_type_var = right_obj_var.ct_type_var
1355 left.obj.typ = ctyp.clear_flag(.option)
1356 }
1357 } else if right.expr is ast.ComptimeSelector {
1358 left.obj.ct_type_unwrapped = true
1359 left.obj.ct_type_var = .field_var
1360 left.obj.typ = c.comptime.comptime_for_field_type.clear_flag(.option)
1361 }
1362 }
1363 }
1364}
1365