v4 / vlib / v / checker / assign.v
1390 lines · 1365 sloc · 50.42 KB · 777460dfd3f7cf551cb57ac9a6f29831aa85f164
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 // Notice when a local variable shadows a function declaration (issue #22685).
675 // Skip when building tests: test files (and preludes loaded for them)
676 // commonly use short fixture fns like `fn a() {}` and shadow them
677 // freely in test bodies.
678 // Only consider functions declared in the same module as the
679 // variable; otherwise unrelated fns (esp. private builtin ones
680 // like `fn new_node()` in `builtin/sorted_map.v`) cause noisy
681 // false positives in user code and external modules.
682 if !c.pref.is_test {
683 qualified := if left.mod == 'builtin' {
684 left.name
685 } else {
686 '${left.mod}.${left.name}'
687 }
688 if fn_decl := c.table.find_fn(qualified) {
689 if fn_decl.mod == left.mod {
690 c.note('variable `${left.name}` shadows a function declaration',
691 left.pos)
692 }
693 }
694 }
695 }
696 if node.op == .assign && left_type.has_flag(.option) && right is ast.UnsafeExpr
697 && right.expr.is_nil() {
698 c.error('cannot assign `nil` to option value', right_pos)
699 }
700 }
701 }
702 ast.PrefixExpr {
703 // Do now allow `*x = y` outside `unsafe`
704 if left.op == .mul {
705 if !c.inside_unsafe && !c.pref.translated && !c.file.is_translated {
706 c.error('modifying variables via dereferencing can only be done in `unsafe` blocks',
707 node.pos)
708 } else if mut left.right is ast.Ident {
709 // mark `p` in `*p = val` as used:
710 if mut left.right.obj is ast.Var {
711 left.right.obj.is_used = true
712 }
713 }
714 } else if left.op == .amp {
715 c.error('cannot use a reference on the left side of `${node.op}`', left.pos)
716 } else {
717 c.error('cannot use `${left.op}` on the left of `${node.op}`', left.pos)
718 }
719 if is_decl {
720 c.error('non-name on the left side of `:=`', left.pos)
721 }
722 }
723 ast.SelectorExpr {
724 if mut left.expr is ast.IndexExpr {
725 if left.expr.is_index_operator {
726 c.error('cannot assign through overloaded index expressions, use `[]=` instead',
727 left.pos)
728 } else if left.expr.is_map {
729 left.expr.is_setter = true
730 }
731 }
732 if left_type in ast.unsigned_integer_type_idxs {
733 if mut right is ast.IntegerLiteral {
734 if right.val[0] == `-` {
735 c.error('cannot assign negative value to unsigned integer type',
736 right.pos)
737 }
738 }
739 }
740 if left_type.has_flag(.option) && right is ast.UnsafeExpr && right.expr.is_nil() {
741 c.error('cannot assign `nil` to option value', right_pos)
742 }
743 }
744 else {
745 if mut left is ast.IndexExpr {
746 // eprintln('>>> left.is_setter: ${left.is_setter:10} | left.is_map: ${left.is_map:10} | left.is_array: ${left.is_array:10}')
747 if (left.is_map || left.is_farray) && left.is_setter {
748 left.recursive_mapset_is_setter(true)
749 }
750 right_type = c.type_resolver.get_type_or_default(right, right_type)
751 }
752 if mut left is ast.InfixExpr {
753 c.error('cannot use infix expression on the left side of `${node.op}`',
754 left.pos)
755 }
756 if is_decl && !c.pref.is_vls {
757 c.error('non-name `${left}` on left side of `:=`', left.pos())
758 }
759
760 if node.op == .assign && (left.is_literal() || left is ast.StructInit) {
761 c.error('non-name literal value `${left}` on left side of `=`', left.pos())
762 }
763 }
764 }
765
766 if mut left is ast.IndexExpr {
767 if left.is_index_operator && node.op != .decl_assign {
768 receiver_name := c.table.sym(c.unwrap_generic(left.left_type)).name
769 if left.setter_arg_type == 0 {
770 c.error('index assignment requires a `[]=` overload on type `${receiver_name}`',
771 left.pos)
772 } else if !left.left.is_lvalue() {
773 c.error('cannot assign through overloaded index on a non-lvalue receiver',
774 left.pos)
775 }
776 if node.op == .assign {
777 left_type = left.setter_arg_type
778 }
779 }
780 }
781 left_type_unwrapped := c.unwrap_generic(ast.mktyp(left_type))
782 right_type_unwrapped := c.unwrap_generic(right_type)
783 if right_type_unwrapped == 0 {
784 // right type was a generic `T`
785 continue
786 }
787 if c.pref.translated || c.file.is_translated {
788 // TODO: fix this in C2V instead, for example cast enums to int before using `|` on them.
789 // TODO: replace all c.pref.translated checks with `$if !translated` for performance
790 continue
791 }
792 if left_type_unwrapped == 0 {
793 continue
794 }
795 left_sym := c.table.sym(left_type_unwrapped)
796 right_sym := c.table.sym(right_type_unwrapped)
797
798 if left_sym.kind == .array && !c.inside_unsafe && right_sym.kind == .array
799 && left is ast.Ident && !left.is_blank_ident() && right in [ast.Ident, ast.SelectorExpr]
800 && ((node.op == .decl_assign && left.is_mut) || node.op == .assign) {
801 // Do not allow direct array assignments outside unsafe.
802 // E.g.: `a2 = a1` wants `a2 = a1.clone()`, `a = val.arr_field` wants `a = val.arr_field.clone()`
803 mut_str := if node.op == .decl_assign { 'mut ' } else { '' }
804 c.error('use `${mut_str}array2 ${node.op.str()} array1.clone()` instead of `${mut_str}array2 ${node.op.str()} array1` (or use `unsafe`)',
805 node.pos)
806 }
807
808 // Do not allow auto (de)reference in PrefixExpr
809 // e.g. `*ptr1 = ptr2`
810 if mut left is ast.PrefixExpr && left.op == .mul {
811 if left_type.nr_muls() != right_type.nr_muls() && !left_type.is_voidptr()
812 && !right_type.is_voidptr() && right_type != ast.nil_type {
813 r := right_sym.str_with_correct_nr_muls(right_type.nr_muls())
814 l := left_sym.str_with_correct_nr_muls(left_type.nr_muls())
815 c.error('cannot use `${r}` (right side) as `${l}` (left side) in assignment',
816 node.pos)
817 }
818 }
819
820 if left_sym.kind == .array && right_sym.kind == .array {
821 right_info := right_sym.info as ast.Array
822 right_elem_type := c.table.unaliased_type(right_info.elem_type)
823 if node.op in [.decl_assign, .assign] {
824 // Do not allow `mut arr := [&immutable_object]`
825 if mut left is ast.Ident && right_elem_type.is_ptr() {
826 if left.is_mut() || (left.obj is ast.Var && left.obj.is_mut) {
827 if mut right is ast.ArrayInit && right.exprs.len > 0 {
828 elem_expr := right.exprs[0]
829 if elem_expr is ast.PrefixExpr && elem_expr.op == .amp {
830 r := elem_expr.right
831 if r is ast.Ident {
832 obj := r.obj
833 if obj is ast.Var && !obj.is_mut {
834 c.warn('cannot add a reference to an immutable object to a mutable array',
835 elem_expr.pos)
836 }
837 }
838 }
839 }
840 }
841 } else if mut left is ast.Ident && left.kind != .blank_ident {
842 mut should_clone_slice := false
843 right_notice_pos := right.pos()
844 right_expr := right
845 if right_expr is ast.IndexExpr {
846 should_clone_slice = right_expr.left is ast.Ident
847 && right_expr.index is ast.RangeExpr
848 && (right_expr.left.is_mut() || left.is_mut()) && !c.inside_unsafe
849 }
850 if should_clone_slice {
851 // `mut a := arr[..]` auto add clone() -> `mut a := arr[..].clone()`
852 c.add_error_detail_with_pos('To silence this notice, use either an explicit `a[..].clone()`,
853or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
854 right_notice_pos)
855 c.note('an implicit clone of the slice was done here', right_notice_pos)
856 mut cloned_right := ast.CallExpr{
857 name: 'clone'
858 kind: .clone
859 left: right
860 left_type: left_type
861 is_method: true
862 receiver_type: left_type
863 return_type: left_type
864 scope: c.fn_scope
865 is_return_used: true
866 }
867 right_type = c.expr(mut cloned_right)
868 right = cloned_right
869 node.right[i] = cloned_right
870 }
871 }
872 }
873 if node.op == .assign {
874 // `mut arr := [u8(1),2,3]`
875 // `arr = [u8(4),5,6]`
876 left_info := left_sym.info as ast.Array
877 left_elem_type := c.table.unaliased_type(left_info.elem_type)
878 if left_type_unwrapped.nr_muls() == right_type_unwrapped.nr_muls()
879 && left_info.nr_dims == right_info.nr_dims && left_elem_type == right_elem_type {
880 continue
881 }
882 }
883 }
884 right_is_lvalue := if right is ast.ComptimeSelector {
885 right.left.is_lvalue()
886 } else {
887 right.is_lvalue()
888 }
889 if left_sym.kind == .map && is_assign && right_sym.kind == .map && !c.inside_unsafe
890 && !left.is_blank_ident() && right_is_lvalue
891 && (!right_type.is_ptr() || (right is ast.Ident && assign_expr_is_auto_deref(right))) {
892 // Do not allow `a = b`
893 c.error('cannot copy map: call `move` or `clone` method (or use a reference)',
894 right.pos())
895 }
896 if is_assign && !c.inside_unsafe && !left.is_blank_ident()
897 && c.is_nocopy_struct(left_type_unwrapped) && c.is_nocopy_struct(right_type_unwrapped)
898 && right !is ast.StructInit {
899 c.error('cannot copy @[nocopy] struct: use a reference instead', right.pos())
900 }
901 if left_sym.kind == .function && right_sym.info is ast.FnType {
902 return_sym := c.table.sym(right_sym.info.func.return_type)
903 mut missing_fn_concrete_types := false
904 if right is ast.Ident {
905 ident := right as ast.Ident
906 if ident.kind == .function {
907 func, has_func := checker_table_fn_lookup(c.table, ident.name)
908 if has_func {
909 missing_fn_concrete_types = func.generic_names.len > 0
910 && ident.concrete_types.len == 0
911 }
912 }
913 }
914 if return_sym.kind == .placeholder {
915 c.error('unknown return type: cannot assign `${right}` as a function variable',
916 right.pos())
917 } else if !missing_fn_concrete_types && right !is ast.AnonFn
918 && c.type_has_unresolved_generic_parts(right_sym.info.func.return_type) {
919 c.error('cannot assign `${right}` as a generic function variable', right.pos())
920 }
921 }
922 if left_sym.kind == .array_fixed && !c.inside_unsafe && is_assign
923 && right_sym.kind == .array_fixed && left is ast.Ident && !left.is_blank_ident()
924 && right is ast.Ident {
925 if right_sym.info is ast.ArrayFixed {
926 if right_sym.info.elem_type.is_ptr() {
927 c.error('assignment from one fixed array to another with a pointer element type is prohibited outside of `unsafe`',
928 node.pos)
929 }
930 }
931 }
932 if left_type.is_any_kind_of_pointer() && !assign_expr_is_auto_deref(left) {
933 if !c.inside_unsafe && node.op !in [.assign, .decl_assign] {
934 // ptr op=
935 if !c.pref.translated && !c.file.is_translated {
936 c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos)
937 }
938 }
939 right_is_ptr := right_type.is_any_kind_of_pointer()
940 if !left_type.has_flag(.shared_f) && !right_is_ptr && node.op == .assign
941 && right_type_unwrapped.is_number() {
942 c.error('cannot assign to `${left}`: ' +
943 c.expected_msg(right_type_unwrapped, left_type_unwrapped), right.pos())
944 }
945 if !right_sym.is_number() && !left_type.has_flag(.shared_f)
946 && (right is ast.StructInit || !right_is_ptr) {
947 left_name := c.table.type_to_str(left_type_unwrapped)
948 mut rtype := right_type_unwrapped
949 if rtype.is_ptr() {
950 rtype = rtype.deref()
951 }
952 right_name := c.table.type_to_str(rtype)
953 if !(left_type.has_flag(.option) && right_type == ast.none_type) {
954 c.error('mismatched types `${left_name}` and `${right_name}`', node.pos)
955 }
956 }
957 }
958 if mut left is ast.Ident && left.info is ast.IdentVar {
959 if left.info.is_static {
960 if right_sym.kind == .map {
961 c.error('maps cannot be static', left.pos)
962 } else if !right.is_constant() {
963 c.error('cannot initialized static variable with non-constant value', left.pos)
964 }
965 }
966 }
967 // Single side check
968 match node.op {
969 .assign {} // No need to do single side check for =. But here put it first for speed.
970 .plus_assign, .minus_assign {
971 // allow literal values to auto deref var (e.g.`for mut v in values { v += 1.0 }`)
972 left_deref := if assign_expr_is_auto_deref(left) && left_type.is_ptr() {
973 left_type.deref()
974 } else {
975 left_type
976 }
977 if c.is_string_like_type(left_deref) {
978 if node.op != .plus_assign {
979 c.error('operator `${node.op}` not defined on left operand type `${left_sym.name}`',
980 left.pos())
981 }
982 if node.op == .plus_assign && !c.is_string_concat_type(right_type) {
983 c.error('invalid right operand: ${left_sym.name} ${node.op} ${right_sym.name}',
984 right.pos())
985 } else if node.op != .plus_assign && !c.is_string_like_type(right_type) {
986 c.error('invalid right operand: ${left_sym.name} ${node.op} ${right_sym.name}',
987 right.pos())
988 }
989 } else if !left_sym.is_number()
990 && left_sym.kind !in [.byteptr, .charptr, .struct, .alias] {
991 c.error('operator `${node.op}` not defined on left operand type `${left_sym.name}`',
992 left.pos())
993 } else if !right_sym.is_number()
994 && left_sym.kind !in [.byteptr, .charptr, .struct, .alias] {
995 c.error('invalid right operand: ${left_sym.name} ${node.op} ${right_sym.name}',
996 right.pos())
997 }
998 }
999 .mult_assign, .power_assign, .div_assign {
1000 if !left_sym.is_number() && !c.table.final_sym(left_type_unwrapped).is_int()
1001 && left_sym.kind !in [.struct, .alias] {
1002 c.error('operator ${node.op.str()} not defined on left operand type `${left_sym.name}`',
1003 left.pos())
1004 } else if !right_sym.is_number() && !c.table.final_sym(left_type_unwrapped).is_int()
1005 && left_sym.kind !in [.struct, .alias] {
1006 c.error('operator ${node.op.str()} not defined on right operand type `${right_sym.name}`',
1007 right.pos())
1008 }
1009 }
1010 .and_assign, .or_assign, .xor_assign {
1011 left_final_sym := c.table.final_sym(left_type_unwrapped)
1012 if left_final_sym.info is ast.Enum && left_final_sym.info.is_flag {
1013 // `@[flag]` tagged enums support compound bitwise assignment.
1014 } else if !left_sym.is_int() && !left_final_sym.is_int() {
1015 c.error('operator ${node.op.str()} not defined on left operand type `${left_sym.name}`',
1016 left.pos())
1017 } else if !right_sym.is_int() && !c.table.final_sym(right_type_unwrapped).is_int() {
1018 c.error('operator ${node.op.str()} not defined on right operand type `${right_sym.name}`',
1019 right.pos())
1020 }
1021 }
1022 .mod_assign, .left_shift_assign, .right_shift_assign {
1023 if !left_sym.is_int() && !c.table.final_sym(left_type_unwrapped).is_int() {
1024 c.error('operator ${node.op.str()} not defined on left operand type `${left_sym.name}`',
1025 left.pos())
1026 } else if !right_sym.is_int() && !c.table.final_sym(right_type_unwrapped).is_int() {
1027 c.error('operator ${node.op.str()} not defined on right operand type `${right_sym.name}`',
1028 right.pos())
1029 }
1030 }
1031 .boolean_and_assign, .boolean_or_assign {
1032 if c.table.final_sym(left_type_unwrapped).kind != .bool {
1033 c.error('operator ${node.op.str()} not defined on left operand type `${left_sym.name}`',
1034 left.pos())
1035 } else if c.table.final_sym(right_type_unwrapped).kind != .bool {
1036 c.error('operator ${node.op.str()} not defined on right operand type `${right_sym.name}`',
1037 right.pos())
1038 }
1039 }
1040 .unsigned_right_shift_assign {
1041 if node.left.len != 1 || node.right.len != 1 {
1042 c.error('unsupported operation: unable to lower expression for unsigned shift assignment.',
1043 node.pos)
1044 }
1045 mut modified_left_type := ast.void_type
1046 if !left_type.is_int() {
1047 c.error('invalid operation: shift on type `${c.table.sym(left_type).name}`',
1048 node.pos)
1049 } else if left_type.is_int_literal() {
1050 // int literal => i64
1051 modified_left_type = ast.u32_type
1052 } else if left_type.is_unsigned() {
1053 modified_left_type = left_type
1054 } else {
1055 // signed types => unsigned types
1056 unsigned_type := left_type.flip_signedness()
1057 if unsigned_type == ast.void_type {
1058 c.error('invalid operation: shift on type `${c.table.sym(left_type).name}`',
1059 node.pos)
1060 } else {
1061 modified_left_type = unsigned_type
1062 }
1063 }
1064 node = ast.AssignStmt{
1065 op: .assign
1066 pos: node.pos
1067 end_comments: node.end_comments
1068 left: node.left
1069 right: [
1070 ast.Expr(ast.InfixExpr{
1071 left: ast.CastExpr{
1072 expr: node.left[0]
1073 typ: modified_left_type
1074 typname: c.table.type_str(modified_left_type)
1075 expr_type: left_type
1076 pos: node.pos
1077 }
1078 op: .right_shift
1079 right: node.right[0]
1080 left_type: modified_left_type
1081 right_type: right_type
1082 pos: node.pos
1083 }),
1084 ]
1085 left_types: node.left_types
1086 right_types: node.right_types
1087 is_static: node.is_static
1088 is_simple: node.is_simple
1089 has_cross_var: node.has_cross_var
1090 }
1091 }
1092 else {}
1093 }
1094
1095 if node.op == .power_assign {
1096 c.markused_power_runtime_support()
1097 }
1098 if node.op in [.plus_assign, .minus_assign, .mod_assign, .mult_assign, .power_assign, .div_assign]
1099 && (left_sym.kind == .alias || (left_sym.kind == .struct && right_sym.kind == .struct)) {
1100 left_name := c.table.type_to_str(left_type_unwrapped)
1101 right_name := c.table.type_to_str(right_type_unwrapped)
1102 parent_sym := c.table.final_sym(left_type_unwrapped)
1103 if left_sym.kind == .alias && right_sym.kind != .alias {
1104 if !parent_sym.is_primitive() {
1105 c.error('mismatched types `${left_name}` and `${right_name}`', node.pos)
1106 }
1107 }
1108 extracted_op := match node.op {
1109 .plus_assign { '+' }
1110 .minus_assign { '-' }
1111 .div_assign { '/' }
1112 .mod_assign { '%' }
1113 .mult_assign { '*' }
1114 .power_assign { '**' }
1115 else { 'unknown op' }
1116 }
1117
1118 if left_sym.kind == .struct && (left_sym.info as ast.Struct).generic_types.len > 0 {
1119 continue
1120 }
1121 if method := left_sym.find_method_with_generic_parent(extracted_op) {
1122 c.mark_fn_decl_as_referenced(method.fkey())
1123 if method.return_type != left_type_unwrapped {
1124 c.error('operator `${extracted_op}` must return `${left_name}` to be used as an assignment operator',
1125 node.pos)
1126 }
1127 if right_sym.kind in [.alias, .struct]
1128 && !c.check_same_type_ignoring_pointers(left_type_unwrapped, right_type_unwrapped) {
1129 c.error('cannot assign to `${left}`: expected `${left_name}`, not `${right_name}`',
1130 right.pos())
1131 }
1132 } else {
1133 if method := parent_sym.find_method_with_generic_parent(extracted_op) {
1134 c.mark_fn_decl_as_referenced(method.fkey())
1135 if parent_sym.kind == .alias
1136 && (parent_sym.info as ast.Alias).parent_type != method.return_type {
1137 c.error('operator `${extracted_op}` must return `${left_name}` to be used as an assignment operator',
1138 node.pos)
1139 }
1140 if right_sym.kind in [.alias, .struct]
1141 && !c.check_same_type_ignoring_pointers(left_type_unwrapped, right_type_unwrapped) {
1142 c.error('cannot assign to `${left}`: expected `${left_name}`, not `${right_name}`',
1143 right.pos())
1144 }
1145 } else {
1146 if !parent_sym.is_primitive() {
1147 if left_name == right_name {
1148 c.error('undefined operation `${left_name}` ${extracted_op} `${right_name}`',
1149 node.pos)
1150 } else {
1151 c.error('mismatched types `${left_name}` and `${right_name}`', node.pos)
1152 }
1153 }
1154 }
1155 }
1156 }
1157 if !is_blank_ident && right_sym.kind != .placeholder && left_sym.kind != .interface
1158 && ((!right_type.has_flag(.generic) && !left_type.has_flag(.generic))
1159 || right_sym.kind != left_sym.kind) {
1160 // Disallow `array = voidptr` assign
1161 if left_sym.kind in [.array, .array_fixed]
1162 && (right_type_unwrapped.is_voidptr() || right.is_nil()) {
1163 left_str := c.table.type_to_str(left_type_unwrapped)
1164 right_str := c.table.type_to_str(right_type_unwrapped)
1165 c.error('cannot assign to `${left}`: expected `${left_str}`, not `${right_str}`',
1166 right.pos())
1167 }
1168 // Dual sides check (compatibility check)
1169 is_string_plus_assign := original_op == .plus_assign
1170 && c.is_string_like_type(left_type_unwrapped)
1171 && c.is_string_concat_type(right_type_unwrapped)
1172 assign_right_type := if
1173 original_op in [.left_shift_assign, .right_shift_assign, .unsigned_right_shift_assign]
1174 || is_string_plus_assign {
1175 left_type_unwrapped
1176 } else {
1177 right_type_unwrapped
1178 }
1179 if original_op == .assign
1180 && c.disallow_implicit_int_to_f32_assign(assign_right_type, left_type_unwrapped) {
1181 c.error('cannot assign to `${left}`: ${c.expected_msg(assign_right_type,
1182 left_type_unwrapped)}', right_pos)
1183 }
1184 c.check_expected(assign_right_type, left_type_unwrapped) or {
1185 if left.is_auto_deref_arg() && left_type.is_ptr() {
1186 left_deref := left_type.deref()
1187 right_deref := if right.is_pure_literal() {
1188 right.get_pure_type()
1189 } else if assign_expr_is_auto_deref(right) && right_type.is_ptr() {
1190 right_type.deref()
1191 } else {
1192 right_type
1193 }
1194 if left_deref.is_number() && right_deref.is_number() {
1195 continue
1196 }
1197 }
1198 // allow literal values to auto deref var (e.g.`for mut v in values { v = 1.0 }`)
1199 if assign_expr_is_auto_deref(left) || assign_expr_is_auto_deref(right) {
1200 left_deref := if assign_expr_is_auto_deref(left) && left_type.is_ptr() {
1201 left_type.deref()
1202 } else {
1203 left_type
1204 }
1205 right_deref := if right.is_pure_literal() {
1206 right.get_pure_type()
1207 } else if assign_expr_is_auto_deref(right) && right_type.is_ptr() {
1208 right_type.deref()
1209 } else {
1210 right_type
1211 }
1212 if c.check_types(right_deref, left_deref) {
1213 continue
1214 }
1215 }
1216 // allow for ptr += 2
1217 if left_type_unwrapped.is_ptr() && right_type_unwrapped.is_int()
1218 && node.op in [.plus_assign, .minus_assign] {
1219 if !c.inside_unsafe {
1220 c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos)
1221 }
1222 } else {
1223 if c.comptime.comptime_for_field_var != '' && left is ast.ComptimeSelector {
1224 field_type := c.unwrap_generic(c.comptime.comptime_for_field_type)
1225 field_sym := c.table.sym(field_type)
1226
1227 // allow `t.$(field.name) = 0` where `t.$(field.name)` is a enum
1228 if field_sym.kind == .enum && !right_type.is_int() {
1229 c.error('enums can only be assigned `int` values', right.pos())
1230 }
1231 // disallow invalid `t.$(field.name)` type assignment
1232 if !c.check_types(field_type, right_type) && !(c.inside_x_matches_type
1233 || field_sym.kind == .enum) {
1234 c.error('cannot assign to `${ast.Expr(left)}`: ${c.expected_msg(right_type,
1235 field_type)}', right.pos())
1236 }
1237 } else {
1238 if right_type_unwrapped != ast.void_type {
1239 if !var_option || (var_option && right_type_unwrapped != ast.none_type) {
1240 if left_sym.kind == .array_fixed && right_sym.kind == .array
1241 && right is ast.ArrayInit {
1242 c.add_error_detail('try adding `!` after the array literal, e.g.: `${left} = [...]!`')
1243 c.error('cannot assign to `${left}`: ${err.msg()}', right_pos)
1244 } else {
1245 c.error('cannot assign to `${left}`: ${err.msg()}', right_pos)
1246 }
1247 }
1248 }
1249 }
1250 }
1251 }
1252 }
1253 if left_sym.kind == .interface {
1254 if c.type_implements(right_type, left_type, right.pos()) {
1255 if !right_type.is_any_kind_of_pointer() && right_sym.kind != .interface
1256 && !c.inside_unsafe {
1257 c.mark_as_referenced(mut &node.right[i], true)
1258 }
1259 }
1260 }
1261 if left_sym.info is ast.Struct && !left_sym.info.is_anon && right is ast.StructInit
1262 && right.is_anon {
1263 c.error('cannot assign anonymous `struct` to a typed `struct`', right_pos)
1264 }
1265 if right_sym.kind == .alias && right_sym.name == 'byte' {
1266 c.error('byte is deprecated, use u8 instead', right.pos())
1267 }
1268 if original_op == .assign {
1269 c.update_option_assignment_smartcast(mut left, left_type, right, right_type)
1270 }
1271 }
1272 // this needs to run after the assign stmt left exprs have been run through checker
1273 // so that ident.obj is set
1274 // Check `x := &y` and `mut x := <-ch`
1275 if mut right_first is ast.PrefixExpr {
1276 mut right_node := right_first
1277 is_amp := right_first.op == .amp
1278 left_first := node.left[0]
1279 if left_first is ast.Ident {
1280 assigned_var := left_first
1281 mut is_shared := false
1282 if left_first.info is ast.IdentVar {
1283 is_shared = left_first.info.share == .shared_t
1284 }
1285 old_inside_ref_lit := c.inside_ref_lit
1286 c.inside_ref_lit = c.inside_ref_lit || right_node.op == .amp || is_shared
1287 c.expr(mut right_node.right)
1288 c.inside_ref_lit = old_inside_ref_lit
1289 if right_node.op == .amp {
1290 mut expr := right_node.right
1291 expr = expr.remove_par()
1292 if mut expr is ast.Ident {
1293 if mut expr.obj is ast.Var {
1294 v := expr.obj
1295 right_first_type = v.typ
1296 }
1297 if is_amp && !node.left[0].is_blank_ident() && expr.obj is ast.ConstField {
1298 c.error('cannot have mutable reference to const `${expr.name}`',
1299 right_node.pos)
1300 }
1301 if !c.inside_unsafe && assigned_var.is_mut() && !expr.is_mut() {
1302 c.error('`${expr.name}` is immutable, cannot have a mutable reference to it',
1303 right_node.pos)
1304 }
1305 }
1306 }
1307 if right_node.op == .arrow {
1308 if assigned_var.is_mut {
1309 right_sym := c.table.sym(right_first_type)
1310 if right_sym.kind == .chan {
1311 chan_info := right_sym.chan_info()
1312 if chan_info.elem_type.is_ptr() && !chan_info.is_mut {
1313 c.error('cannot have a mutable reference to object from `${right_sym.name}`',
1314 right_node.pos)
1315 }
1316 }
1317 }
1318 }
1319 }
1320 }
1321 if node.left_types.len != node.left.len {
1322 c.error('assign statement left type number mismatch', node.pos)
1323 }
1324}
1325
1326// change_flags_if_comptime_expr changes the flags of the left variable if the right expression is comptime/generic expr
1327fn (mut c Checker) change_flags_if_comptime_expr(mut left ast.Ident, right ast.Expr) {
1328 if mut left.obj is ast.Var {
1329 if right is ast.ComptimeSelector {
1330 left.obj.typ = c.comptime.comptime_for_field_type
1331 if right.or_block.kind == .propagate_option {
1332 left.obj.typ = left.obj.typ.clear_flag(.option)
1333 left.obj.ct_type_unwrapped = true
1334 }
1335 left.obj.ct_type_var = .field_var
1336 } else if right is ast.InfixExpr {
1337 right_ct_var := c.comptime.get_ct_type_var(right.left)
1338 if right_ct_var != .no_comptime {
1339 left.obj.ct_type_var = right_ct_var
1340 }
1341 } else if right is ast.StructInit && right.unresolved && right.typ.has_flag(.generic) {
1342 left.obj.ct_type_var = .generic_param
1343 } else if right is ast.IndexExpr && c.comptime.is_comptime(right) {
1344 right_ct_var := c.comptime.get_ct_type_var(right.left)
1345 if right_ct_var != .no_comptime {
1346 left.obj.ct_type_var = right_ct_var
1347 }
1348 } else if right is ast.Ident && right.obj is ast.Var && right.or_expr.kind == .absent {
1349 right_obj_var := right.obj as ast.Var
1350 if right_obj_var.ct_type_var != .no_comptime {
1351 ctyp := c.type_resolver.get_type(right)
1352 if ctyp != ast.void_type {
1353 left.obj.ct_type_var = right_obj_var.ct_type_var
1354 left.obj.typ = ctyp
1355 if ctyp.has_flag(.generic) && c.unwrap_generic(ctyp).has_flag(.option) {
1356 left.obj.typ = left.obj.typ.set_flag(.option)
1357 }
1358 }
1359 }
1360 } else if right is ast.DumpExpr && right.expr is ast.ComptimeSelector {
1361 left.obj.ct_type_var = .field_var
1362 left.obj.typ = c.comptime.comptime_for_field_type
1363 } else if right is ast.CallExpr {
1364 if right.left_type != 0 && c.table.type_kind(right.left_type) == .array
1365 && right.name == 'map' && right.args.len > 0 && right.args[0].expr is ast.AsCast
1366 && right.args[0].expr.typ.has_flag(.generic) {
1367 left.obj.ct_type_var = .generic_var
1368 } else if left.obj.ct_type_var in [.generic_var, .no_comptime]
1369 && c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len != 0
1370 && !right.comptime_ret_val && c.type_resolver.is_generic_expr(right) {
1371 // mark variable as generic var because its type changes according to fn return generic resolution type
1372 left.obj.ct_type_var = .generic_var
1373 }
1374 } else if right is ast.PostfixExpr && right.op == .question {
1375 if right.expr is ast.Ident && right.expr.ct_expr {
1376 right_obj_var := right.expr.obj as ast.Var
1377 ctyp := c.type_resolver.get_type(right)
1378 if ctyp != ast.void_type {
1379 left.obj.ct_type_unwrapped = true
1380 left.obj.ct_type_var = right_obj_var.ct_type_var
1381 left.obj.typ = ctyp.clear_flag(.option)
1382 }
1383 } else if right.expr is ast.ComptimeSelector {
1384 left.obj.ct_type_unwrapped = true
1385 left.obj.ct_type_var = .field_var
1386 left.obj.typ = c.comptime.comptime_for_field_type.clear_flag(.option)
1387 }
1388 }
1389 }
1390}
1391