v2 / vlib / v / checker / infix.v
1570 lines · 1518 sloc · 56.24 KB · 288ce180560f3a715e74c3fdf14fcfbbbe1c953a
Raw
1module checker
2
3import v.ast
4import v.token
5
6fn (mut c Checker) markused_power_runtime_support() {
7 // C/JS backends lower `**` directly at codegen time, so there is no
8 // function usage to mark here.
9}
10
11fn infix_expr_allows_auto_deref(expr ast.Expr) bool {
12 return expr is ast.Ident && expr.is_auto_deref_var()
13}
14
15fn infix_expr_is_zero_integer_literal(expr ast.Expr) bool {
16 return expr is ast.IntegerLiteral && expr.val == '0'
17}
18
19fn infix_expr_is_nil_like(expr ast.Expr) bool {
20 return expr.is_nil() || (expr is ast.UnsafeExpr && expr.expr.is_nil())
21}
22
23fn (c &Checker) type_is_optionish(typ ast.Type, sym ast.TypeSymbol) bool {
24 return typ.has_flag(.option)
25 || (sym.kind == .alias && sym.info is ast.Alias && sym.info.parent_type.has_flag(.option))
26}
27
28fn (c &Checker) is_string_like_type(typ ast.Type) bool {
29 return !typ.has_option_or_result() && typ.clear_flags() == ast.string_type
30}
31
32fn (c &Checker) is_char_or_rune_like_type(typ ast.Type) bool {
33 return !typ.has_option_or_result() && typ.clear_flags() in [ast.char_type, ast.rune_type]
34}
35
36fn (c &Checker) is_string_concat_type(typ ast.Type) bool {
37 return c.is_string_like_type(typ) || c.is_char_or_rune_like_type(typ)
38}
39
40fn (c &Checker) is_string_concat_pair(left ast.Type, right ast.Type) bool {
41 return c.is_string_concat_type(left) && c.is_string_concat_type(right)
42 && (c.is_string_like_type(left) || c.is_string_like_type(right))
43}
44
45fn has_matching_reference_operator_overload(sym &ast.TypeSymbol, op string, receiver_type ast.Type, operand_type ast.Type) bool {
46 method := sym.find_method_with_generic_parent(op) or { return false }
47 return method.params.len == 2 && method.params[0].typ == receiver_type
48 && method.params[1].typ == operand_type
49}
50
51fn (mut c Checker) int_literal_needs_promotion(expr ast.Expr, promoted_type ast.Type) bool {
52 base_type := promoted_type.clear_flags()
53 if base_type !in ast.int_promoted_type_idxs {
54 return false
55 }
56 value := c.eval_comptime_const_expr(expr, 0) or { return false }
57 size, _ := c.table.type_size(base_type.idx_type())
58 bit_size := size * 8
59 if bit_size == 0 {
60 return false
61 }
62 if base_type.is_signed() {
63 signed_value := value.i64() or { return true }
64 max_signed := if bit_size >= 64 {
65 max_i64
66 } else {
67 i64((u64(1) << (bit_size - 1)) - 1)
68 }
69 min_signed := if bit_size >= 64 {
70 min_i64
71 } else {
72 -max_signed - 1
73 }
74 return signed_value < min_signed || signed_value > max_signed
75 }
76 unsigned_value := value.u64() or { return true }
77 max_unsigned := if bit_size >= 64 {
78 max_u64
79 } else {
80 (u64(1) << bit_size) - 1
81 }
82 return unsigned_value > max_unsigned
83}
84
85fn (mut c Checker) adjust_infix_int_literal_promotion(left ast.Expr, right ast.Expr, left_type ast.Type,
86 right_type ast.Type, promoted_type ast.Type) ast.Type {
87 if promoted_type.clear_flags() !in ast.int_promoted_type_idxs {
88 return promoted_type
89 }
90 if left_type == ast.int_literal_type && c.int_literal_needs_promotion(left, promoted_type) {
91 return ast.int_type
92 }
93 if right_type == ast.int_literal_type && c.int_literal_needs_promotion(right, promoted_type) {
94 return ast.int_type
95 }
96 return promoted_type
97}
98
99fn (c &Checker) alias_supports_ordered_comparison(sym ast.TypeSymbol, op token.Kind) bool {
100 if sym.kind != .alias {
101 return false
102 }
103 if sym.has_method_with_generic_parent(op.str()) {
104 return true
105 }
106 return op in [.gt, .ge, .le] && sym.has_method_with_generic_parent('<')
107}
108
109fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
110 former_expected_type := c.expected_type
111 defer {
112 c.expected_type = former_expected_type
113 }
114 // In bool contexts like `assert` and `return`, short enum literals on the left
115 // need the right operand type first, so `.a == x` resolves `.a` correctly.
116 mut check_right_type_first_for_left_short_enum := false
117 if node.op in [.eq, .ne] && node.left is ast.EnumVal {
118 left_enum := node.left as ast.EnumVal
119 if left_enum.enum_name.len == 0 {
120 if node.right is ast.EnumVal {
121 right_enum := node.right as ast.EnumVal
122 check_right_type_first_for_left_short_enum = right_enum.enum_name.len > 0
123 } else {
124 check_right_type_first_for_left_short_enum = true
125 }
126 }
127 }
128 mut right_type := ast.void_type
129 if check_right_type_first_for_left_short_enum {
130 right_type = c.expr(mut node.right)
131 if right_type == ast.no_type {
132 node.right_type = right_type
133 return ast.void_type
134 }
135 node.right_type = right_type
136 c.expected_type = right_type
137 }
138 mut left_type := c.expr(mut node.left)
139 if left_type == ast.no_type {
140 node.left_type = left_type
141 return ast.void_type
142 }
143 left_type = c.maybe_wrap_index_expr_smartcast(mut node.left, left_type)
144 mut left_sym := c.table.sym(left_type)
145 node.left_type = left_type
146 c.expected_type = left_type
147
148 if left_sym.kind == .chan {
149 chan_info := left_sym.chan_info()
150 c.expected_type = chan_info.elem_type
151 }
152
153 if !node.left_ct_expr && !node.left.is_literal() {
154 node.left_ct_expr = c.comptime.is_comptime(node.left)
155 }
156 if !node.right_ct_expr && !node.right.is_literal() {
157 node.right_ct_expr = c.comptime.is_comptime(node.right)
158 }
159
160 // `if n is ast.Ident && n.is_mut { ... }`
161 // Walk the left side of && chains to find `is` checks for smartcasting.
162 // NOTE: Uses a regular loop with explicit casts instead of
163 // `for mut left_node is ast.InfixExpr` to avoid a codegen bug where
164 // reassignment inside such a loop overwrites the pointed-to InfixExpr
165 // struct instead of reassigning the Expr variable.
166 if !c.inside_sql && node.op == .and {
167 mut left_expr := node.left
168 for {
169 if left_expr !is ast.InfixExpr {
170 break
171 }
172 mut left_infix := unsafe { &(left_expr as ast.InfixExpr) }
173 if left_infix.op == .and && left_infix.right is ast.InfixExpr {
174 mut right_infix := unsafe { &(left_infix.right as ast.InfixExpr) }
175 if right_infix.op == .key_is {
176 // search last `n is ast.Ident` in the left
177 from_type := c.expr(mut right_infix.left)
178 to_type := c.expr(mut right_infix.right)
179 c.autocast_in_if_conds(mut node.right, right_infix.left, from_type, to_type)
180 }
181 }
182 if left_infix.op == .key_is {
183 // search `n is ast.Ident`
184 from_type := c.expr(mut left_infix.left)
185 to_type := c.expr(mut left_infix.right)
186 c.autocast_in_if_conds(mut node.right, left_infix.left, from_type, to_type)
187 break
188 } else if left_infix.op == .and {
189 if left_infix.left is ast.InfixExpr {
190 left_expr = left_infix.left
191 } else {
192 break
193 }
194 } else {
195 break
196 }
197 }
198 }
199
200 if node.op == .key_is {
201 c.inside_x_is_type = true
202 }
203 // `arr << if n > 0 { 10 } else { 11 }` set the right c.expected_type
204 if node.op == .left_shift && c.table.sym(left_type).kind == .array {
205 if left_type.has_flag(.option) {
206 c.error('cannot push to Option array that was not unwrapped first', node.left.pos())
207 }
208 if mut node.right is ast.IfExpr {
209 if node.right.is_expr && node.right.branches.len > 0 {
210 mut last_stmt := node.right.branches[0].stmts.last()
211 if mut last_stmt is ast.ExprStmt {
212 expr_typ := c.expr(mut last_stmt.expr)
213 info := c.table.sym(left_type).array_info()
214 if expr_typ == info.elem_type {
215 c.expected_type = info.elem_type
216 }
217 }
218 }
219 } else if mut node.right is ast.ArrayInit {
220 left_value_type := c.table.value_type(c.unwrap_generic(left_type))
221 if node.right.is_fixed
222 && c.table.final_sym(c.unwrap_generic(left_value_type)).kind == .interface {
223 c.expected_type = ast.void_type
224 } else if node.right.exprs.len == 0 && node.right.elem_type == ast.void_type {
225 // handle arr << [] where [] is empty
226 info := c.table.sym(left_type).array_info()
227 node.right.elem_type = info.elem_type
228 c.expected_type = info.elem_type
229 }
230 }
231 }
232 if !check_right_type_first_for_left_short_enum {
233 right_type = c.expr(mut node.right)
234 if right_type == ast.no_type {
235 node.right_type = right_type
236 if node.op in [.key_is, .not_is] {
237 node.promoted_type = ast.bool_type
238 return ast.bool_type
239 }
240 return ast.void_type
241 }
242 }
243 right_type = c.maybe_wrap_index_expr_smartcast(mut node.right, right_type)
244 if node.op in [.eq, .ne] {
245 left_type = c.maybe_wrap_option_compare_smartcast(mut node.left, left_type, node.right,
246 right_type)
247 node.left_type = left_type
248 left_sym = c.table.sym(left_type)
249 right_type = c.maybe_wrap_option_compare_smartcast(mut node.right, right_type, node.left,
250 left_type)
251 }
252 if node.op == .key_is {
253 c.inside_x_is_type = false
254 }
255 if node.op == .amp && left_type.is_bool() && right_type.is_bool() && right_type.is_ptr() {
256 pos := node.pos.extend(node.right.pos())
257 c.error('the right expression should be separated from the `&&` by a space', pos)
258 node.promoted_type = ast.bool_type
259 return ast.bool_type
260 }
261 node.right_type = right_type
262 if !left_type.has_flag(.option) && left_type.is_number() && !left_type.is_ptr()
263 && right_type in [ast.int_literal_type, ast.float_literal_type] {
264 node.right_type = left_type
265 if left_type in [ast.f32_type_idx, ast.f64_type_idx] && right_type == ast.float_literal_type {
266 defer(fn) {
267 node.right = ast.CastExpr{
268 expr: node.right
269 typ: left_type
270 typname: c.table.get_type_name(left_type)
271 expr_type: right_type
272 pos: node.right.pos()
273 }
274 }
275 }
276 }
277 if right_type.is_number() && !right_type.is_ptr()
278 && left_type in [ast.int_literal_type, ast.float_literal_type] {
279 node.left_type = right_type
280 if right_type in [ast.f32_type_idx, ast.f64_type_idx] && left_type == ast.float_literal_type {
281 defer(fn) {
282 node.left = ast.CastExpr{
283 expr: node.left
284 typ: right_type
285 typname: c.table.get_type_name(right_type)
286 expr_type: left_type
287 }
288 }
289 }
290 }
291 mut right_sym := c.table.sym(right_type)
292 right_final_sym := c.table.final_sym(c.unwrap_generic(right_type))
293 left_final_sym := c.table.final_sym(c.unwrap_generic(left_type))
294 left_pos := node.left.pos()
295 right_pos := node.right.pos()
296 left_right_pos := left_pos.extend(right_pos)
297 if left_sym.kind == .none && right_sym.kind == .none {
298 c.invalid_operator_error(node.op, left_type, right_type, left_right_pos)
299 }
300 if left_sym.kind == .multi_return && right_sym.kind == .multi_return {
301 c.error('invalid number of operand for `${node.op}`. Only one allowed on each side.',
302 left_right_pos)
303 }
304 if left_type.is_any_kind_of_pointer() && !left_type.has_flag(.shared_f)
305 && !node.left.is_auto_deref_var()
306 && node.op in [.plus, .minus, .mul, .power, .div, .mod, .xor, .amp, .pipe] {
307 if !c.pref.translated && ((right_type.is_any_kind_of_pointer() && node.op != .minus)
308 || (!right_type.is_any_kind_of_pointer() && node.op !in [.plus, .minus])) {
309 if _ := left_sym.find_method(node.op.str()) {
310 if left_sym.kind in [.alias, .struct] {
311 // allow an explicit operator override `fn (x &AliasType) OP (y &AliasType) &AliasType {`
312 // or `fn (x &Struct) OP (y &Struct) &Struct {`
313 } else {
314 c.invalid_operator_error(node.op, left_type, right_type, left_right_pos)
315 }
316 } else {
317 c.invalid_operator_error(node.op, left_type, right_type, left_right_pos)
318 }
319 } else if node.op in [.plus, .minus] {
320 if !c.inside_unsafe && !node.left.is_auto_deref_var() && !node.right.is_auto_deref_var() {
321 if !c.pref.translated && !c.file.is_translated {
322 c.warn('pointer arithmetic is only allowed in `unsafe` blocks', left_right_pos)
323 }
324 }
325 if (left_type == ast.voidptr_type || left_type == ast.nil_type) && !c.pref.translated {
326 c.error('`${node.op}` cannot be used with `voidptr`', left_pos)
327 }
328 }
329 }
330 mut return_type := left_type
331 if node.op == .plus && c.is_string_concat_pair(left_type, right_type) {
332 return_type = ast.string_type
333 }
334 left_is_explicit_ptr := left_type.is_any_kind_of_pointer() && !node.left.is_auto_deref_var()
335 && left_final_sym.kind != .voidptr
336 right_is_explicit_ptr := right_type.is_any_kind_of_pointer() && !node.right.is_auto_deref_var()
337 && right_final_sym.kind != .voidptr
338
339 if node.op != .key_is {
340 match mut node.left {
341 ast.Ident, ast.SelectorExpr {
342 // mut foo != none is allowed for unwrapping option
343 if !(node.op == .ne && node.right is ast.None) {
344 if node.left.is_mut {
345 c.error('the `mut` keyword is invalid here', node.left.mut_pos)
346 }
347 }
348 }
349 else {}
350 }
351 }
352 match mut node.right {
353 ast.Ident, ast.SelectorExpr {
354 if node.right.is_mut {
355 c.error('the `mut` keyword is invalid here', node.right.mut_pos)
356 }
357 }
358 else {}
359 }
360
361 eq_ne := node.op in [.eq, .ne]
362 // Single side check
363 // Place these branches according to ops' usage frequency to accelerate.
364 // TODO: First branch includes ops where single side check is not needed, or needed but hasn't been implemented.
365 // TODO: Some of the checks are not single side. Should find a better way to organize them.
366 match node.op {
367 // .eq, .ne, .gt, .lt, .ge, .le, .and, .logical_or, .dot, .key_as, .right_shift {}
368 .eq, .ne {
369 if node.left is ast.CallExpr && node.left.or_block.stmts.len > 0 {
370 c.check_expr_option_or_result_call(node.left, left_type)
371 }
372 if node.right is ast.CallExpr && node.right.or_block.stmts.len > 0 {
373 c.check_expr_option_or_result_call(node.right, right_type)
374 }
375 if left_type in ast.integer_type_idxs && right_type in ast.integer_type_idxs {
376 is_left_type_signed := left_type in ast.signed_integer_type_idxs
377 is_right_type_signed := right_type in ast.signed_integer_type_idxs
378 if !is_left_type_signed && mut node.right is ast.IntegerLiteral {
379 if node.right.val.int() < 0 && left_type in ast.int_promoted_type_idxs {
380 lt := c.table.sym(left_type).name
381 c.error('`${lt}` cannot be compared with negative value', node.right.pos)
382 }
383 } else if !is_right_type_signed && mut node.left is ast.IntegerLiteral {
384 if node.left.val.int() < 0 && right_type in ast.int_promoted_type_idxs {
385 rt := c.table.sym(right_type).name
386 c.error('negative value cannot be compared with `${rt}`', node.left.pos)
387 }
388 } else if is_left_type_signed != is_right_type_signed
389 && left_type != ast.int_literal_type_idx
390 && right_type != ast.int_literal_type_idx {
391 ls, _ := c.table.type_size(left_type)
392 rs, _ := c.table.type_size(right_type)
393 // prevent e.g. `u32 == i16` but not `u16 == i32` as max_u16 fits in i32
394 // TODO: u32 == i32, change < to <=
395 if !c.pref.translated && ((is_left_type_signed && ls < rs)
396 || (is_right_type_signed && rs < ls)) {
397 lt := c.table.sym(left_type).name
398 rt := c.table.sym(right_type).name
399 c.error('`${lt}` cannot be compared with `${rt}`', node.pos)
400 }
401 }
402 }
403
404 c.check_option_infix_expr(mut node, left_type, right_type, left_sym, right_sym)
405
406 // In SQL, `field == nil`/`field != nil` is lowered to NULL comparisons.
407 if !c.inside_sql {
408 // Do not allow comparing nil to non-pointers
409 if node.left.is_nil() {
410 mut final_type := right_type
411 if mut right_sym.info is ast.Alias
412 && right_sym.info.parent_type.is_any_kind_of_pointer() {
413 final_type = right_sym.info.parent_type
414 }
415 if !final_type.is_any_kind_of_pointer() && (right_final_sym.kind != .function
416 || (right_final_sym.language != .c && right_final_sym.kind == .placeholder))
417 && !right_final_sym.is_heap() {
418 rt := c.table.sym(right_type).name
419 c.error('cannot compare with `nil` because `${rt}` is not a pointer',
420 node.pos)
421 }
422 }
423
424 if node.right.is_nil() {
425 mut final_type := left_type
426 if mut left_sym.info is ast.Alias
427 && left_sym.info.parent_type.is_any_kind_of_pointer() {
428 final_type = left_sym.info.parent_type
429 }
430 if !final_type.is_any_kind_of_pointer() && (left_final_sym.kind != .function
431 || (left_final_sym.language != .c && left_final_sym.kind == .placeholder))
432 && !left_final_sym.is_heap() {
433 lt := c.table.sym(left_type).name
434 c.error('cannot compare with `nil` because `${lt}` is not a pointer',
435 node.pos)
436 }
437 }
438 }
439 }
440 .key_in, .not_in {
441 if left_type.has_flag(.option) || left_type.has_flag(.result) {
442 option_or_result := if left_type.has_flag(.option) { 'Option' } else { 'Result' }
443 c.error('unwrapped ${option_or_result} cannot be used with `${node.op.str()}`',
444 left_pos)
445 }
446 match right_final_sym.kind {
447 .array {
448 if left_sym.kind !in [.sum_type, .interface] {
449 elem_type := right_final_sym.array_info().elem_type
450 if node.left.is_auto_deref_var() && left_type.is_ptr() {
451 left_type = left_type.deref()
452 }
453 c.check_expected(left_type, elem_type) or {
454 c.error('left operand to `${node.op}` does not match the array element type: ${err.msg()}',
455 left_right_pos)
456 }
457 if mut node.right is ast.ArrayInit {
458 c.check_duplicated_items(node.right)
459 }
460 } else {
461 if mut node.right is ast.ArrayInit {
462 for i, typ in node.right.expr_types {
463 c.ensure_type_exists(typ, node.right.exprs[i].pos())
464 }
465 } else {
466 elem_type := right_final_sym.array_info().elem_type
467 if node.left.is_auto_deref_var() && left_type.is_ptr() {
468 left_type = left_type.deref()
469 }
470 c.check_expected(left_type, elem_type) or {
471 c.error('left operand to `${node.op}` does not match the array element type: ${err.msg()}',
472 left_right_pos)
473 }
474 }
475 }
476 }
477 .map {
478 map_info := right_final_sym.map_info()
479 if !c.check_map_key_type(left_type, map_info.key_type) {
480 c.error('left operand to `${node.op}` does not match the map key type: ${c.map_key_expected_msg(left_type,
481 map_info.key_type, node.left, '')}', left_right_pos)
482 }
483 node.left_type = map_info.key_type
484 }
485 .array_fixed {
486 if left_sym.kind !in [.sum_type, .interface] {
487 elem_type := right_final_sym.array_fixed_info().elem_type
488 c.check_expected(left_type, elem_type) or {
489 c.error('left operand to `${node.op}` does not match the fixed array element type: ${err.msg()}',
490 left_right_pos)
491 }
492 }
493 }
494 else {
495 if mut node.right is ast.RangeExpr {
496 if !left_final_sym.is_number() && left_final_sym.kind != .rune {
497 c.error('`${left_final_sym.name}` is an invalid type for range expression',
498 node.pos)
499 }
500 } else {
501 c.error('`${node.op.str()}` can only be used with arrays and maps',
502 node.pos)
503 }
504 }
505 }
506
507 node.promoted_type = ast.bool_type
508 return ast.bool_type
509 }
510 .plus, .minus, .mul, .power, .div, .mod, .xor, .amp, .pipe {
511 // binary operators that expect matching types
512 if node.op == .power {
513 c.markused_power_runtime_support()
514 }
515 unwrapped_left_type := c.unwrap_generic(left_type)
516 left_sym = c.table.sym(unwrapped_left_type)
517 unwrapped_right_type := c.unwrap_generic(right_type)
518 right_sym = c.table.sym(unwrapped_right_type)
519 if mut right_sym.info is ast.Alias && (right_sym.info.language != .c
520 && c.mod == c.table.type_to_str(unwrapped_right_type).split('.')[0]
521 && (right_final_sym.is_primitive() || right_final_sym.kind == .enum)) {
522 right_sym = unsafe { right_final_sym }
523 }
524 if mut left_sym.info is ast.Alias && (left_sym.info.language != .c
525 && c.mod == c.table.type_to_str(unwrapped_left_type).split('.')[0]
526 && (left_final_sym.is_primitive() || left_final_sym.kind == .enum)) {
527 left_sym = unsafe { left_final_sym }
528 }
529 op_str := node.op.str()
530 if c.pref.translated && node.op in [.plus, .minus, .mul]
531 && unwrapped_left_type.is_any_kind_of_pointer()
532 && unwrapped_right_type.is_any_kind_of_pointer() {
533 return_type = left_type
534 } else if !c.pref.translated && left_sym.info is ast.Alias
535 && !left_final_sym.is_primitive() {
536 if left_sym.has_method(op_str) {
537 if method := left_sym.find_method(op_str) {
538 return_type = method.return_type
539 } else {
540 return_type = left_type
541 }
542 } else if left_final_sym.has_method_with_generic_parent(op_str) {
543 if method := left_final_sym.find_method_with_generic_parent(op_str) {
544 return_type = method.return_type
545 } else {
546 return_type = left_type
547 }
548 } else {
549 left_name := c.table.type_to_str(unwrapped_left_type)
550 right_name := c.table.type_to_str(unwrapped_right_type)
551 if left_name == right_name {
552 c.error('undefined operation `${left_name}` ${op_str} `${right_name}`',
553 left_right_pos)
554 } else {
555 c.error('mismatched types `${left_name}` and `${right_name}`',
556 left_right_pos)
557 }
558 }
559 } else if !c.pref.translated && right_sym.info is ast.Alias
560 && !right_final_sym.is_primitive() {
561 if right_sym.has_method(op_str) {
562 if method := right_sym.find_method(op_str) {
563 return_type = method.return_type
564 } else {
565 return_type = right_type
566 }
567 } else if right_final_sym.has_method_with_generic_parent(op_str) {
568 if method := right_final_sym.find_method_with_generic_parent(op_str) {
569 return_type = method.return_type
570 } else {
571 return_type = right_type
572 }
573 } else if left_sym.has_method(op_str) {
574 if method := left_sym.find_method(op_str) {
575 return_type = method.return_type
576 } else {
577 return_type = left_type
578 }
579 } else if left_final_sym.has_method_with_generic_parent(op_str) {
580 if method := left_final_sym.find_method_with_generic_parent(op_str) {
581 return_type = method.return_type
582 } else {
583 return_type = left_type
584 }
585 } else {
586 left_name := c.table.type_to_str(unwrapped_left_type)
587 right_name := c.table.type_to_str(unwrapped_right_type)
588 if left_name == right_name {
589 c.error('undefined operation `${left_name}` ${op_str} `${right_name}`',
590 left_right_pos)
591 } else {
592 c.error('mismatched types `${left_name}` and `${right_name}`',
593 left_right_pos)
594 }
595 }
596 }
597
598 if ((unwrapped_left_type.is_ptr() && !node.left.is_auto_deref_var())
599 || (unwrapped_right_type.is_ptr() && !node.right.is_auto_deref_var()))
600 && node.op !in [.plus, .minus] {
601 c.error('infix `${node.op}` is not defined for pointer values', left_right_pos)
602 }
603
604 if !c.pref.translated && !left_is_explicit_ptr
605 && left_sym.kind in [.array, .array_fixed, .map, .struct] {
606 if left_sym.has_method_with_generic_parent(op_str) {
607 if method := left_sym.find_method_with_generic_parent(op_str) {
608 return_type = method.return_type
609 left_info := left_sym.info
610 if left_info is ast.Struct {
611 if left_info.concrete_types.len > 0 {
612 c.table.register_fn_concrete_types(method.fkey(),
613 left_info.concrete_types)
614 }
615 }
616 } else {
617 return_type = left_type
618 }
619 } else {
620 left_name := c.table.type_to_str(unwrapped_left_type)
621 right_name := c.table.type_to_str(unwrapped_right_type)
622 if left_name == right_name {
623 c.error('undefined operation `${left_name}` ${op_str} `${right_name}`',
624 left_right_pos)
625 } else {
626 c.error('mismatched types `${left_name}` and `${right_name}`',
627 left_right_pos)
628 }
629 }
630 } else if !c.pref.translated && !right_is_explicit_ptr
631 && right_sym.kind in [.array, .array_fixed, .map, .struct] {
632 if right_sym.has_method_with_generic_parent(op_str) {
633 if method := right_sym.find_method_with_generic_parent(op_str) {
634 return_type = method.return_type
635 right_info := right_sym.info
636 if right_info is ast.Struct {
637 if right_info.concrete_types.len > 0 {
638 c.table.register_fn_concrete_types(method.fkey(),
639 right_info.concrete_types)
640 }
641 }
642 } else {
643 return_type = right_type
644 }
645 } else {
646 left_name := c.table.type_to_str(unwrapped_left_type)
647 right_name := c.table.type_to_str(unwrapped_right_type)
648 if left_name == right_name {
649 c.error('undefined operation `${left_name}` ${op_str} `${right_name}`',
650 left_right_pos)
651 } else {
652 c.error('mismatched types `${left_name}` and `${right_name}`',
653 left_right_pos)
654 }
655 }
656 } else if node.left.is_auto_deref_var() || node.right.is_auto_deref_var() {
657 deref_left_type := if node.left.is_auto_deref_var() && unwrapped_left_type.is_ptr() {
658 unwrapped_left_type.deref()
659 } else {
660 unwrapped_left_type
661 }
662 deref_right_type := if node.right.is_auto_deref_var()
663 && unwrapped_right_type.is_ptr() {
664 unwrapped_right_type.deref()
665 } else {
666 unwrapped_right_type
667 }
668 left_name := c.table.type_to_str(ast.mktyp(deref_left_type))
669 right_name := c.table.type_to_str(ast.mktyp(deref_right_type))
670 if left_name != right_name {
671 c.error('mismatched types `${left_name}` and `${right_name}`', left_right_pos)
672 }
673 } else {
674 unaliased_left_type := c.table.unalias_num_type(unwrapped_left_type)
675 unalias_right_type := c.table.unalias_num_type(unwrapped_right_type)
676 mut promoted_type := ast.void_type
677 if node.op == .plus
678 && c.is_string_concat_pair(unaliased_left_type, unalias_right_type) {
679 promoted_type = ast.string_type
680 } else {
681 promoted_type = c.promote_keeping_aliases(unaliased_left_type,
682 unalias_right_type, left_sym.kind, right_sym.kind)
683 promoted_type = c.adjust_infix_int_literal_promotion(node.left, node.right,
684 unaliased_left_type, unalias_right_type, promoted_type)
685 // subtract pointers is allowed in unsafe block
686 is_allowed_pointer_arithmetic := left_type.is_any_kind_of_pointer()
687 && right_type.is_any_kind_of_pointer() && node.op == .minus
688 if is_allowed_pointer_arithmetic {
689 promoted_type = ast.int_type
690 }
691 if promoted_type.idx() == ast.void_type_idx {
692 left_name := c.table.type_to_str(unwrapped_left_type)
693 right_name := c.table.type_to_str(unwrapped_right_type)
694 c.error('mismatched types `${left_name}` and `${right_name}`',
695 left_right_pos)
696 } else if promoted_type.has_option_or_result() {
697 s := c.table.type_to_str(promoted_type)
698 c.error('`${node.op}` cannot be used with `${s}`', node.pos)
699 } else if promoted_type.is_float() {
700 if node.op in [.mod, .xor, .amp, .pipe] {
701 side := if unwrapped_left_type == promoted_type {
702 'left'
703 } else {
704 'right'
705 }
706 pos := if unwrapped_left_type == promoted_type {
707 left_pos
708 } else {
709 right_pos
710 }
711 name := if unwrapped_left_type == promoted_type {
712 left_sym.name
713 } else {
714 right_sym.name
715 }
716 if node.op == .mod {
717 c.error('float modulo not allowed, use math.fmod() instead', pos)
718 } else {
719 c.error('${side} type of `${op_str}` cannot be non-integer type `${name}`',
720 pos)
721 }
722 }
723 }
724 if node.op in [.div, .mod] {
725 c.check_div_mod_by_zero(node.right, node.op)
726 }
727 }
728
729 left_sym = c.table.sym(unwrapped_left_type)
730 right_sym = c.table.sym(unwrapped_right_type)
731 if left_sym.info is ast.Alias && left_final_sym.is_primitive() {
732 if left_sym.has_method(op_str) {
733 if method := left_sym.find_method(op_str) {
734 return_type = method.return_type
735 }
736 }
737 } else if right_sym.info is ast.Alias && right_final_sym.is_primitive() {
738 if right_sym.has_method(op_str) {
739 if method := right_sym.find_method(op_str) {
740 return_type = method.return_type
741 }
742 }
743 }
744 exact_left_sym := c.table.sym(unwrapped_left_type)
745 exact_right_sym := c.table.sym(unwrapped_right_type)
746 has_operator_overload := exact_left_sym.has_method_with_generic_parent(op_str)
747 || left_final_sym.has_method_with_generic_parent(op_str)
748 || exact_right_sym.has_method_with_generic_parent(op_str)
749 || right_final_sym.has_method_with_generic_parent(op_str)
750 if has_operator_overload && exact_left_sym.kind in [.alias, .struct]
751 && exact_right_sym.kind in [.alias, .struct]
752 && !c.check_same_type_ignoring_pointers(unwrapped_left_type, unwrapped_right_type) {
753 c.error('infix expr: cannot use `${exact_right_sym.name}` (right expression) as `${exact_left_sym.name}`',
754 left_right_pos)
755 }
756 return_sym := c.table.sym(return_type)
757 if return_sym.info !is ast.Alias {
758 return_type = promoted_type
759 }
760 }
761 }
762 .gt, .lt, .ge, .le {
763 unwrapped_left_type := c.unwrap_generic(left_type)
764 left_sym = c.table.sym(unwrapped_left_type)
765 if left_sym.kind == .alias && !c.alias_supports_ordered_comparison(left_sym, node.op) {
766 left_sym = c.table.final_sym(unwrapped_left_type)
767 }
768 unwrapped_right_type := c.unwrap_generic(right_type)
769 right_sym = c.table.sym(unwrapped_right_type)
770 if right_sym.kind == .alias && !c.alias_supports_ordered_comparison(right_sym, node.op) {
771 right_sym = c.table.final_sym(unwrapped_right_type)
772 }
773 if left_sym.kind in [.array, .array_fixed] && right_sym.kind in [.array, .array_fixed] {
774 c.error('only `==` and `!=` are defined on arrays', node.pos)
775 } else if left_sym.kind == .function || right_sym.kind == .function {
776 left_name := c.table.type_to_str(unwrapped_left_type)
777 right_name := c.table.type_to_str(unwrapped_right_type)
778 if left_sym.kind == .function && right_sym.kind == .function
779 && left_name == right_name {
780 c.error('undefined operation `${left_name}` ${node.op.str()} `${right_name}`',
781 left_right_pos)
782 } else {
783 c.error('mismatched types `${left_name}` and `${right_name}`', left_right_pos)
784 }
785 } else if left_sym.info is ast.Struct && left_sym.info.generic_types.len > 0 {
786 node.promoted_type = ast.bool_type
787 return ast.bool_type
788 } else if left_sym.kind == .struct && right_sym.kind == .struct && node.op in [.eq, .lt] {
789 if !(left_sym.has_method(node.op.str()) && right_sym.has_method(node.op.str())) {
790 left_name := c.table.type_to_str(unwrapped_left_type)
791 right_name := c.table.type_to_str(unwrapped_right_type)
792 if left_name == right_name {
793 if !(node.op == .lt && c.pref.translated) {
794 // Allow `&Foo < &Foo` in translated code.
795 // TODO: maybe in unsafe as well?
796 c.error('undefined operation `${left_name}` ${node.op.str()} `${right_name}`',
797 left_right_pos)
798 }
799 } else {
800 c.error('mismatched types `${left_name}` and `${right_name}`',
801 left_right_pos)
802 }
803 }
804 }
805 if left_sym.kind == .struct && right_sym.kind == .struct {
806 if !left_sym.has_method('<') && node.op in [.ge, .le] {
807 c.error('cannot use `${node.op}` as `<` operator method is not defined',
808 left_right_pos)
809 } else if !left_sym.has_method('<') && node.op == .gt {
810 c.error('cannot use `>` as `<=` operator method is not defined', left_right_pos)
811 }
812 } else if left_type.has_flag(.generic) && right_type.has_flag(.generic) {
813 // Try to unwrap the generic type to make sure that
814 // the below check works as expected
815 left_gen_type := c.unwrap_generic(left_type)
816 gen_sym := c.table.sym(left_gen_type)
817 need_overload := gen_sym.kind in [.struct, .interface]
818 if need_overload && !gen_sym.has_method_with_generic_parent('<')
819 && node.op in [.ge, .le] {
820 c.error('cannot use `${node.op}` as `<` operator method is not defined',
821 left_right_pos)
822 } else if need_overload && !gen_sym.has_method_with_generic_parent('<')
823 && node.op == .gt {
824 c.error('cannot use `>` as `<=` operator method is not defined', left_right_pos)
825 }
826 } else if left_type in ast.integer_type_idxs && right_type in ast.integer_type_idxs {
827 is_left_type_signed := left_type in ast.signed_integer_type_idxs
828 || left_type == ast.int_literal_type_idx
829 is_right_type_signed := right_type in ast.signed_integer_type_idxs
830 || right_type == ast.int_literal_type_idx
831 if is_left_type_signed != is_right_type_signed {
832 if is_right_type_signed {
833 if mut node.right is ast.IntegerLiteral {
834 if node.right.val.int() < 0 {
835 c.error('unsigned integer cannot be compared with negative value',
836 node.right.pos)
837 }
838 }
839 } else if is_left_type_signed {
840 if mut node.left is ast.IntegerLiteral {
841 if node.left.val.int() < 0 {
842 c.error('unsigned integer cannot be compared with negative value',
843 node.left.pos)
844 }
845 }
846 }
847 }
848 } else {
849 c.check_option_infix_expr(mut node, left_type, right_type, left_sym, right_sym)
850 }
851 if node.left.is_nil() || node.right.is_nil() {
852 c.error('cannot use `${node.op.str()}` with `nil`', node.pos)
853 }
854 }
855 .key_like {
856 node.promoted_type = ast.bool_type
857
858 return c.check_like_operator(node)
859 }
860 .key_ilike {
861 node.promoted_type = ast.bool_type
862
863 return c.check_like_operator(node)
864 }
865 .left_shift {
866 if left_final_sym.kind == .array
867 || c.table.sym(c.unwrap_generic(left_type)).kind == .array {
868 return c.check_append(mut node, left_type, right_type, right_final_sym)
869 } else {
870 node.promoted_type = c.check_shift(mut node, left_type, right_type)
871 return node.promoted_type
872 }
873 }
874 .right_shift {
875 node.promoted_type = c.check_shift(mut node, left_type, right_type)
876 return node.promoted_type
877 }
878 .unsigned_right_shift {
879 mut modified_left_type := 0
880 if !left_type.is_int() {
881 c.error('invalid operation: shift on type `${c.table.sym(left_type).name}`',
882 left_pos)
883 modified_left_type = ast.void_type
884 } else if left_type.is_int_literal() {
885 // int literal => i64
886 modified_left_type = ast.u32_type
887 } else if left_type.is_unsigned() {
888 modified_left_type = left_type
889 } else {
890 // signed type can't convert to an unsigned type
891 unsigned_type := left_type.flip_signedness()
892 if unsigned_type != ast.void_type {
893 modified_left_type = unsigned_type
894 }
895 }
896 if modified_left_type == 0 {
897 return ast.void_type
898 }
899 node = ast.InfixExpr{
900 left: ast.CastExpr{
901 expr: node.left
902 typ: modified_left_type
903 typname: c.table.type_str(modified_left_type)
904 expr_type: left_type
905 pos: node.pos
906 }
907 left_type: left_type
908 op: .right_shift
909 right: node.right
910 right_type: right_type
911 is_stmt: false
912 pos: node.pos
913 auto_locked: node.auto_locked
914 or_block: node.or_block
915 }
916 node.promoted_type = c.check_shift(mut node, left_type, right_type)
917 return node.promoted_type
918 }
919 .key_is, .not_is {
920 right_expr := node.right
921 mut typ := match right_expr {
922 ast.TypeNode {
923 if right_expr.typ.has_flag(.generic) {
924 c.unwrap_generic(right_expr.typ)
925 } else {
926 right_expr.typ
927 }
928 }
929 ast.None {
930 ast.none_type_idx
931 }
932 ast.Ident {
933 if right_expr.name == c.comptime.comptime_for_variant_var {
934 c.type_resolver.get_ct_type_or_default('${c.comptime.comptime_for_variant_var}.typ',
935 ast.void_type)
936 } else {
937 c.error('invalid type `${right_expr}`', right_expr.pos)
938 ast.no_type
939 }
940 }
941 else {
942 c.error('invalid type `${right_expr}`', right_expr.pos())
943 ast.no_type
944 }
945 }
946
947 if typ != ast.no_type {
948 $if trace_ci_fixes ? {
949 source_path := if node.pos.file_idx >= 0
950 && node.pos.file_idx < c.table.filelist.len {
951 c.table.filelist[node.pos.file_idx]
952 } else {
953 c.file.path
954 }
955 if source_path.contains('decode_sumtype.v')
956 && node.pos.line_nr + 1 in [12, 111, 138, 215] {
957 right_kind := match right_expr {
958 ast.Ident { 'ident:${right_expr.name}' }
959 ast.TypeNode { 'typenode:${c.table.type_to_str(right_expr.typ)}' }
960 ast.None { 'none' }
961 else { typeof(right_expr).name }
962 }
963
964 eprintln('infix is left=${node.left} left_type=${c.table.type_to_str(left_type)} right_kind=${right_kind} right_type=${c.table.type_to_str(typ)} variant_var=${c.comptime.comptime_for_variant_var} file=${c.file.path} source=${source_path} line=${
965 node.pos.line_nr + 1}')
966 }
967 }
968 resolved_typ := c.unwrap_generic(typ)
969 typ_sym := c.table.final_sym(resolved_typ)
970 op := node.op.str()
971 if left_type.has_flag(.option) && !c.inside_sql {
972 c.error('${node.left} is an Optional, it needs to be unwrapped first',
973 node.left.pos())
974 }
975 if typ_sym.kind == .placeholder {
976 c.error('${op}: type `${typ_sym.name}` does not exist', right_expr.pos())
977 }
978 if mut left_sym.info is ast.Aggregate {
979 parent_left_type := left_sym.info.sum_type
980 left_sym = c.table.sym(parent_left_type)
981 }
982 if c.inside_sql {
983 if typ != ast.none_type_idx {
984 c.error('`${op}` can only be used to test for none in sql', node.pos)
985 }
986 } else if left_final_sym.kind !in [.interface, .sum_type]
987 && !c.comptime.is_comptime(node.left) && !c.is_orig_sumtype(node.left) {
988 c.error('`${op}` can only be used with interfaces and sum types', node.pos) // can be used in sql too, but keep err simple
989 } else if mut left_sym.info is ast.SumType {
990 variant_typ := if left_type.nr_muls() > 0
991 && typ.nr_muls() <= left_type.nr_muls() {
992 typ.set_nr_muls(0)
993 } else {
994 typ
995 }
996 if variant_typ !in left_sym.info.variants
997 && c.unwrap_generic(variant_typ) !in left_sym.info.variants {
998 c.error('`${left_sym.name}` has no variant `${typ_sym.name}`', right_pos)
999 }
1000 } else if c.is_orig_sumtype(node.left) {
1001 // Variable is smartcast but original type is a sum type;
1002 // allow the `is` check using the original type's variants.
1003 if node.left is ast.Ident && node.left.obj is ast.Var {
1004 orig_t := (node.left.obj as ast.Var).orig_type
1005 orig_sym := c.table.sym(orig_t)
1006 if orig_sym.info is ast.SumType {
1007 if typ !in orig_sym.info.variants
1008 && c.unwrap_generic(typ) !in orig_sym.info.variants {
1009 c.error('`${orig_sym.name}` has no variant `${typ_sym.name}`',
1010 right_pos)
1011 }
1012 }
1013 }
1014 } else if left_sym.info is ast.Interface {
1015 if typ_sym.kind != .interface && !c.type_implements(typ, left_type, right_pos) {
1016 c.error("`${typ_sym.name}` doesn't implement interface `${left_sym.name}`",
1017 right_pos)
1018 }
1019 }
1020 }
1021 node.promoted_type = ast.bool_type
1022 return ast.bool_type
1023 }
1024 .arrow { // `chan <- elem`
1025 if left_sym.kind == .chan {
1026 chan_info := left_sym.chan_info()
1027 mut elem_type := chan_info.elem_type
1028 mut got_type := right_type
1029 if c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0
1030 && c.table.cur_fn.generic_names.len == c.table.cur_concrete_types.len {
1031 if c.needs_unwrap_generic_type(got_type) {
1032 got_type = c.table.unwrap_generic_type(got_type,
1033 c.table.cur_fn.generic_names, c.table.cur_concrete_types)
1034 }
1035 if c.needs_unwrap_generic_type(elem_type) {
1036 elem_type = c.table.unwrap_generic_type(elem_type,
1037 c.table.cur_fn.generic_names, c.table.cur_concrete_types)
1038 }
1039 }
1040 if !c.check_types(got_type, elem_type) {
1041 c.error('cannot push `${c.table.type_to_str(got_type)}` on `${left_sym.name}`',
1042 right_pos)
1043 }
1044 if chan_info.is_mut {
1045 // TODO: The error message of the following could be more specific...
1046 c.fail_if_immutable(mut node.right)
1047 }
1048 if elem_type.is_ptr() && !got_type.is_ptr() {
1049 c.error('cannot push non-reference `${right_sym.name}` on `${left_sym.name}`',
1050 right_pos)
1051 } else if got_type.is_ptr() != elem_type.is_ptr() {
1052 c.error('cannot push `${c.table.type_to_str(got_type)}` on `${left_sym.name}`',
1053 right_pos)
1054 }
1055 c.stmts_ending_with_expression(mut node.or_block.stmts, c.expected_or_type)
1056 } else {
1057 c.error('cannot push on non-channel `${left_sym.name}`', left_pos)
1058 }
1059 return ast.void_type
1060 }
1061 .and, .logical_or {
1062 if !c.pref.translated && !c.file.is_translated {
1063 // TODO Bring back once I split void into void and bad
1064 // if left_final_sym.kind !in [.bool, .void] {
1065 if left_final_sym.kind != .bool {
1066 c.error('left operand for `${node.op}` is not a boolean', node.left.pos())
1067 }
1068 // if right_final_sym.kind !in [.bool, .void] {
1069 if right_final_sym.kind != .bool {
1070 c.error('right operand for `${node.op}` is not a boolean', node.right.pos())
1071 }
1072 }
1073 if mut node.left is ast.InfixExpr {
1074 if node.left.op != node.op && node.left.op in [.logical_or, .and] {
1075 // for example: `(a && b) || c` instead of `a && b || c`
1076 c.error('ambiguous boolean expression. use `()` to ensure correct order of operations',
1077 node.pos)
1078 }
1079 }
1080 }
1081 else {}
1082 }
1083
1084 // Do an ambiguous expression check for << >> and &, since they all have the same precedence (unlike in C)
1085 if !c.is_builtin_mod && node.op in [.amp, .left_shift, .right_shift] {
1086 if mut node.left is ast.InfixExpr {
1087 if node.left.op != node.op && node.left.op in [.amp, .left_shift, .right_shift] {
1088 // for example: `(a << b) & c` instead of `a << b & c`
1089 c.note('ambiguous expression. use `()` to ensure correct order of operations',
1090 node.pos)
1091 }
1092 }
1093 }
1094 // TODO: Absorb this block into the above single side check block to accelerate.
1095 // Skip operator restriction checks for generic parameters that were resolved to
1096 // bool/string by recheck_concrete_type — the generic function itself allows any T.
1097 is_generic_resolved := c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0
1098 && c.table.cur_concrete_types.len > 0 && (node.left_type in c.table.cur_concrete_types
1099 || node.right_type in c.table.cur_concrete_types)
1100 if left_type == ast.bool_type && node.op !in [.eq, .ne, .logical_or, .and]
1101 && !is_generic_resolved {
1102 c.error('bool types only have the following operators defined: `==`, `!=`, `||`, and `&&`',
1103 node.pos)
1104 } else if left_type == ast.string_type && node.op !in [.plus, .eq, .ne, .lt, .gt, .le, .ge]
1105 && !is_generic_resolved {
1106 // TODO: broken !in
1107 c.error('string types only have the following operators defined: `==`, `!=`, `<`, `>`, `<=`, `>=`, and `+`',
1108 node.pos)
1109 } else if !eq_ne && mut left_sym.info is ast.Enum && mut right_sym.info is ast.Enum {
1110 if left_sym.info.is_flag && right_sym.info.is_flag {
1111 // `@[flag]` tagged enums are a special case that allow also `|` and `&` binary operators
1112 if node.op !in [.pipe, .amp, .xor, .bit_not] {
1113 c.error('only `==`, `!=`, `|`, `&`, `^` and `~` are defined on `@[flag]` tagged `enum`, use an explicit cast to `int` if needed',
1114 node.pos)
1115 }
1116 } else if !c.pref.translated && !c.file.is_translated && !left_type.has_flag(.generic)
1117 && !right_type.has_flag(.generic) && !is_generic_resolved {
1118 // Regular enums
1119 c.error('only `==` and `!=` are defined on `enum`, use an explicit cast to `int` if needed',
1120 node.pos)
1121 }
1122 }
1123 // sum types can't have any infix operation except of `is`, `eq`, `ne`.
1124 // `is` is checked before and doesn't reach this.
1125 if c.table.type_kind(left_type) == .sum_type && !eq_ne {
1126 c.error('cannot use operator `${node.op}` with `${left_sym.name}`', node.pos)
1127 } else if c.table.type_kind(right_type) == .sum_type && !eq_ne {
1128 c.error('cannot use operator `${node.op}` with `${right_sym.name}`', node.pos)
1129 }
1130 // TODO: move this to symmetric_check? Right now it would break `return 0` for `fn()?int `
1131 if node.left !in [ast.Ident, ast.IndexExpr, ast.SelectorExpr, ast.ComptimeSelector]
1132 || node.op in [.eq, .ne] {
1133 c.check_option_infix_expr(mut node, left_type, right_type, left_sym, right_sym)
1134 }
1135
1136 left_is_result := left_type.has_flag(.result)
1137 right_is_result := right_type.has_flag(.result)
1138 if left_is_result || right_is_result {
1139 opt_infix_pos := if left_is_result { left_pos } else { right_pos }
1140 c.error('unwrapped Result cannot be used in an infix expression', opt_infix_pos)
1141 }
1142 if c.inside_sql && node.op in [.eq, .ne] && (node.left.is_nil() || node.right.is_nil()) {
1143 node.promoted_type = ast.bool_type
1144 return ast.bool_type
1145 }
1146
1147 // Dual sides check (compatibility check)
1148 if node.left !is ast.ComptimeCall && node.right !is ast.ComptimeCall {
1149 if left_type.has_flag(.generic) {
1150 left_type = c.unwrap_generic(left_type)
1151 left_sym = c.table.sym(left_type)
1152 }
1153 if right_type.has_flag(.generic) {
1154 right_type = c.unwrap_generic(right_type)
1155 right_sym = c.table.sym(right_type)
1156 }
1157 is_string_concat := node.op == .plus && c.is_string_concat_pair(left_type, right_type)
1158 types_match := is_string_concat || (c.symmetric_check(left_type, right_type)
1159 && c.symmetric_check(right_type, left_type))
1160 left_allows_auto_deref := infix_expr_allows_auto_deref(node.left)
1161 right_allows_auto_deref := infix_expr_allows_auto_deref(node.right)
1162 unalias_left_type := c.table.unaliased_type(left_type)
1163 unalias_right_type := c.table.unaliased_type(right_type)
1164 left_is_any_kind_of_pointer := left_type.is_any_kind_of_pointer()
1165 || unalias_left_type.is_any_kind_of_pointer()
1166 right_is_any_kind_of_pointer := right_type.is_any_kind_of_pointer()
1167 || unalias_right_type.is_any_kind_of_pointer()
1168 allows_cstring_byte_compare :=
1169 (unalias_right_type in ast.byteptr_types && unalias_left_type == ast.u8_type)
1170 || (unalias_right_type in ast.charptr_types && unalias_left_type == ast.char_type)
1171 pointer_value_mismatch := left_is_any_kind_of_pointer != right_is_any_kind_of_pointer
1172 mut types_match_after_deref := false
1173 mut deref_left_type := left_type
1174 mut deref_right_type := right_type
1175 if (!types_match || pointer_value_mismatch)
1176 && (left_allows_auto_deref || right_allows_auto_deref) {
1177 deref_left_type = if left_allows_auto_deref && left_type.is_ptr() {
1178 left_type.deref()
1179 } else {
1180 left_type
1181 }
1182 deref_right_type = if right_allows_auto_deref && right_type.is_ptr() {
1183 right_type.deref()
1184 } else {
1185 right_type
1186 }
1187 types_match_after_deref = c.symmetric_check(deref_left_type, deref_right_type)
1188 && c.symmetric_check(deref_right_type, deref_left_type)
1189 }
1190 if node.op in [.eq, .ne] && right_is_any_kind_of_pointer && !left_is_any_kind_of_pointer
1191 && !allows_cstring_byte_compare && !infix_expr_is_zero_integer_literal(node.left)
1192 && !infix_expr_is_nil_like(node.left) && !infix_expr_is_nil_like(node.right)
1193 && !c.file.path.ends_with('.c.v') && left_sym.language == .v && right_sym.language == .v
1194 && !types_match_after_deref && !c.pref.translated && !c.file.is_translated
1195 && !c.inside_unsafe {
1196 error_left_name := if left_allows_auto_deref {
1197 c.table.type_to_str(deref_left_type)
1198 } else {
1199 c.table.type_to_str(left_type)
1200 }
1201 error_right_name := if right_allows_auto_deref {
1202 c.table.type_to_str(deref_right_type)
1203 } else {
1204 c.table.type_to_str(right_type)
1205 }
1206 sugg := if left_type in ast.integer_type_idxs || right_type in ast.integer_type_idxs {
1207 ' (you can use it inside an `unsafe` block)'
1208 } else {
1209 ''
1210 }
1211 c.error('infix expr: cannot use `${error_right_name}` (right expression) as `${error_left_name}`${sugg}',
1212 left_right_pos)
1213 }
1214 if !types_match && !types_match_after_deref && !c.pref.translated && !c.file.is_translated {
1215 // for type-unresolved consts
1216 if left_type == ast.void_type || right_type == ast.void_type {
1217 return ast.void_type
1218 }
1219 if left_type.nr_muls() > 0 && right_type.is_int() {
1220 // pointer arithmetic is fine, it is checked in other places
1221 node.promoted_type = return_type
1222 return return_type
1223 }
1224
1225 left_is_option := left_type.has_flag(.option) || (left_sym.kind == .alias
1226 && (left_sym.info as ast.Alias).parent_type.has_flag(.option))
1227 right_is_option := right_type.has_flag(.option)
1228 || (right_sym.kind == .alias
1229 && (right_sym.info as ast.Alias).parent_type.has_flag(.option))
1230 if (node.right is ast.None && left_is_option)
1231 || (node.left is ast.None && right_is_option) {
1232 return ast.bool_type
1233 }
1234 error_left_sym := if node.left.is_auto_deref_var() {
1235 c.table.sym(deref_left_type)
1236 } else {
1237 left_sym
1238 }
1239 error_right_sym := if node.right.is_auto_deref_var() {
1240 c.table.sym(deref_right_type)
1241 } else {
1242 right_sym
1243 }
1244 c.error('infix expr: cannot use `${error_right_sym.name}` (right expression) as `${error_left_sym.name}`',
1245 left_right_pos)
1246 } else if left_type.is_ptr() {
1247 for_ptr_op := left_is_explicit_ptr || c.table.type_is_for_pointer_arithmetic(left_type)
1248 if left_sym.language == .v && !c.pref.translated && !c.inside_unsafe && !for_ptr_op
1249 && right_type.is_int() {
1250 sugg := ' (you can use it inside an `unsafe` block)'
1251 c.error('infix expr: cannot use `${right_sym.name}` (right expression) as `${left_sym.name}` ${sugg}',
1252 left_right_pos)
1253 }
1254 }
1255 }
1256 if node.op == .plus && c.pref.warn_about_allocs
1257 && c.is_string_concat_pair(left_type, right_type) {
1258 c.warn_alloc('string concatenation', node.pos)
1259 }
1260 /*
1261 if (node.left is ast.InfixExpr && node.left.op == .inc) ||
1262 (node.right is ast.InfixExpr && node.right.op == .inc) {
1263 c.warn('`++` and `--` are statements, not expressions', node.pos)
1264 }
1265 */
1266 node.promoted_type = if node.op.is_relational() { ast.bool_type } else { return_type }
1267 return node.promoted_type
1268}
1269
1270fn (mut c Checker) check_div_mod_by_zero(expr ast.Expr, op_kind token.Kind) {
1271 match expr {
1272 ast.FloatLiteral {
1273 if expr.val.f64() == 0.0 {
1274 oper := if op_kind == .div { 'division' } else { 'modulo' }
1275 c.error('${oper} by zero', expr.pos)
1276 }
1277 }
1278 ast.IntegerLiteral {
1279 if expr.val.int() == 0 {
1280 oper := if op_kind == .div { 'division' } else { 'modulo' }
1281 c.error('${oper} by zero', expr.pos)
1282 }
1283 }
1284 ast.CastExpr {
1285 c.check_div_mod_by_zero(expr.expr, op_kind)
1286 }
1287 else {}
1288 }
1289}
1290
1291fn (mut c Checker) check_duplicated_items(node &ast.ArrayInit) {
1292 mut unique_items := []string{cap: node.exprs.len}
1293 for item in node.exprs {
1294 item_str := item.str()
1295 if item_str in unique_items {
1296 c.note('item `${item_str}` is duplicated in the list', item.pos())
1297 } else {
1298 unique_items << item_str
1299 }
1300 }
1301}
1302
1303fn (mut c Checker) check_like_operator(node &ast.InfixExpr) ast.Type {
1304 if node.left !is ast.Ident || !node.left_type.is_string() {
1305 c.error('the left operand of the `like` operator must be an identifier with a string type',
1306 node.left.pos())
1307 }
1308
1309 if !node.right_type.is_string() {
1310 c.error('the right operand of the `like` operator must be a string type', node.right.pos())
1311 }
1312
1313 return node.promoted_type
1314}
1315
1316fn (mut c Checker) invalid_operator_error(op token.Kind, left_type ast.Type, right_type ast.Type, pos token.Pos) {
1317 left_name := c.table.type_to_str(left_type)
1318 right_name := c.table.type_to_str(right_type)
1319 c.error('invalid operator `${op}` to `${left_name}` and `${right_name}`', pos)
1320}
1321
1322// `if node is ast.Ident && node.is_mut { ... }` -> `if node is ast.Ident && (node as ast.Ident).is_mut { ... }`
1323fn (mut c Checker) maybe_wrap_index_expr_smartcast(mut expr ast.Expr, expr_type ast.Type) ast.Type {
1324 if isnil(c.fn_scope) || expr_type in [ast.no_type, ast.void_type] {
1325 return expr_type
1326 }
1327 expr0 := expr
1328 if expr0 is ast.IndexExpr {
1329 index_expr := expr0
1330 scope := c.fn_scope.innermost(index_expr.pos.pos)
1331 expr_key := smartcast_index_expr_scope_key(index_expr)
1332 if var := scope.find_var(expr_key) {
1333 if var.smartcasts.len > 0 {
1334 cast_type := c.exposed_smartcast_type(var.orig_type, var.smartcasts.last(),
1335 var.is_mut)
1336 if cast_type != expr_type {
1337 expr = ast.Expr(ast.AsCast{
1338 expr: ast.Expr(index_expr)
1339 typ: cast_type
1340 expr_type: expr_type
1341 pos: index_expr.pos
1342 })
1343 }
1344 return cast_type
1345 }
1346 }
1347 }
1348 return expr_type
1349}
1350
1351fn (c &Checker) smartcast_expr_original_option_type(expr ast.Expr) ast.Type {
1352 match expr {
1353 ast.Ident {
1354 if expr.obj is ast.Var {
1355 var := expr.obj as ast.Var
1356 if var.smartcasts.len > 0 && var.orig_type.has_flag(.option) {
1357 return var.orig_type
1358 }
1359 }
1360 }
1361 ast.SelectorExpr {
1362 if expr.expr_type != 0 {
1363 expr_str := smartcast_selector_expr_str(expr)
1364 scope_field := expr.scope.find_struct_field(expr_str, expr.expr_type,
1365 expr.field_name)
1366 if scope_field != unsafe { nil } && scope_field.smartcasts.len > 0
1367 && scope_field.orig_type.has_flag(.option) {
1368 return scope_field.orig_type
1369 }
1370 }
1371 }
1372 ast.IndexExpr {
1373 if !isnil(c.fn_scope) {
1374 scope := c.fn_scope.innermost(expr.pos.pos)
1375 expr_key := smartcast_index_expr_scope_key(expr)
1376 if var := scope.find_var(expr_key) {
1377 if var.smartcasts.len > 0 && var.orig_type.has_flag(.option) {
1378 return var.orig_type
1379 }
1380 }
1381 }
1382 }
1383 else {}
1384 }
1385
1386 return ast.no_type
1387}
1388
1389fn (mut c Checker) maybe_wrap_option_compare_smartcast(mut expr ast.Expr, expr_type ast.Type, other_expr ast.Expr, other_type ast.Type) ast.Type {
1390 if expr_type.has_flag(.option) || expr_type.has_flag(.result) {
1391 return expr_type
1392 }
1393 other_sym := c.table.sym(other_type)
1394 other_is_optionish := c.type_is_optionish(other_type, other_sym) || other_expr is ast.None
1395 || other_sym.kind == .none
1396 if !other_is_optionish {
1397 return expr_type
1398 }
1399 orig_option_type := c.smartcast_expr_original_option_type(expr)
1400 if orig_option_type == ast.no_type {
1401 return expr_type
1402 }
1403 expr = ast.Expr(ast.AsCast{
1404 expr: expr
1405 typ: orig_option_type
1406 expr_type: expr_type
1407 pos: expr.pos()
1408 })
1409 return orig_option_type
1410}
1411
1412fn (mut c Checker) autocast_in_if_conds(mut right ast.Expr, from_expr ast.Expr, from_type ast.Type, to_type ast.Type) {
1413 if '${right}' == from_expr.str() {
1414 right = ast.AsCast{
1415 typ: to_type
1416 expr: from_expr
1417 expr_type: from_type
1418 }
1419 return
1420 }
1421
1422 match mut right {
1423 ast.SelectorExpr {
1424 if right.expr.str() == from_expr.str() {
1425 right.expr = ast.ParExpr{
1426 expr: ast.AsCast{
1427 typ: to_type
1428 expr: from_expr
1429 expr_type: from_type
1430 }
1431 }
1432 } else {
1433 c.autocast_in_if_conds(mut right.expr, from_expr, from_type, to_type)
1434 }
1435 }
1436 ast.ParExpr {
1437 c.autocast_in_if_conds(mut right.expr, from_expr, from_type, to_type)
1438 }
1439 ast.AsCast {
1440 if right.typ != to_type {
1441 c.autocast_in_if_conds(mut right.expr, from_expr, from_type, to_type)
1442 }
1443 }
1444 ast.PrefixExpr {
1445 c.autocast_in_if_conds(mut right.right, from_expr, from_type, to_type)
1446 }
1447 ast.CallExpr {
1448 if right.left.str() == from_expr.str()
1449 && c.table.sym(to_type).has_method_with_generic_parent(right.name) {
1450 right.left = ast.ParExpr{
1451 expr: ast.AsCast{
1452 typ: to_type
1453 expr: from_expr
1454 expr_type: from_type
1455 }
1456 }
1457 }
1458 if right.left !is ast.Ident {
1459 c.autocast_in_if_conds(mut right.left, from_expr, from_type, to_type)
1460 }
1461 for mut arg in right.args {
1462 c.autocast_in_if_conds(mut arg.expr, from_expr, from_type, to_type)
1463 }
1464 }
1465 ast.InfixExpr {
1466 c.autocast_in_if_conds(mut right.left, from_expr, from_type, to_type)
1467 c.autocast_in_if_conds(mut right.right, from_expr, from_type, to_type)
1468 }
1469 ast.IndexExpr {
1470 c.autocast_in_if_conds(mut right.left, from_expr, from_type, to_type)
1471 c.autocast_in_if_conds(mut right.index, from_expr, from_type, to_type)
1472 }
1473 ast.RangeExpr {
1474 c.autocast_in_if_conds(mut right.low, from_expr, from_type, to_type)
1475 c.autocast_in_if_conds(mut right.high, from_expr, from_type, to_type)
1476 }
1477 ast.StringInterLiteral {
1478 for mut expr in right.exprs {
1479 c.autocast_in_if_conds(mut expr, from_expr, from_type, to_type)
1480 }
1481 }
1482 ast.UnsafeExpr {
1483 c.autocast_in_if_conds(mut right.expr, from_expr, from_type, to_type)
1484 }
1485 else {}
1486 }
1487}
1488
1489fn (mut c Checker) check_sort_external_variable_access(node ast.Expr) bool {
1490 match node {
1491 ast.InfixExpr {
1492 if !c.check_sort_external_variable_access(node.left) {
1493 return false
1494 }
1495 if !c.check_sort_external_variable_access(node.right) {
1496 return false
1497 }
1498 }
1499 ast.Ident {
1500 if node.name !in ['a', 'b'] {
1501 c.error('can not access external variable `${node.name}`', node.pos)
1502 return false
1503 }
1504 }
1505 ast.CallExpr {
1506 return c.check_sort_external_variable_access(node.left)
1507 }
1508 ast.SelectorExpr {
1509 return c.check_sort_external_variable_access(node.expr)
1510 }
1511 ast.IndexExpr {
1512 if !c.check_sort_external_variable_access(node.left) {
1513 return false
1514 }
1515 if !c.check_sort_external_variable_access(node.index) {
1516 return false
1517 }
1518 }
1519 else {
1520 return true
1521 }
1522 }
1523
1524 return true
1525}
1526
1527fn (c &Checker) option_payload_can_compare_to_nil(typ ast.Type, sym ast.TypeSymbol) bool {
1528 mut option_type := typ
1529 if sym.kind == .alias && sym.info is ast.Alias && sym.info.parent_type.has_flag(.option) {
1530 option_type = sym.info.parent_type
1531 }
1532 return option_type.clear_option_and_result().is_any_kind_of_pointer()
1533}
1534
1535fn (mut c Checker) check_option_infix_expr(mut node ast.InfixExpr, left_type ast.Type, right_type ast.Type, left_sym ast.TypeSymbol, right_sym ast.TypeSymbol) {
1536 // SQL expressions can compare optional values directly, but anon fn bodies in SQL
1537 // should keep regular option checks.
1538 if c.inside_sql && !c.inside_anon_fn {
1539 return
1540 }
1541 left_is_option := left_type.has_flag(.option)
1542 || (left_sym.kind == .alias && (left_sym.info as ast.Alias).parent_type.has_flag(.option))
1543 right_is_option := right_type.has_flag(.option)
1544 || (right_sym.kind == .alias && (right_sym.info as ast.Alias).parent_type.has_flag(.option))
1545 if left_is_option && node.right.is_nil()
1546 && c.option_payload_can_compare_to_nil(left_type, left_sym) {
1547 node.right = ast.None{}
1548 node.right_type = ast.none_type
1549 return
1550 }
1551 if (node.left is ast.None && right_is_option)
1552 || (node.right is ast.None && left_is_option)
1553 || (left_sym.kind == .none || right_sym.kind == .none) {
1554 return
1555 }
1556 if left_is_option || right_is_option {
1557 pos, opt, nopt := if left_is_option {
1558 node.left.pos(), left_sym.name, right_sym.name
1559 } else {
1560 node.right.pos(), right_sym.name, left_sym.name
1561 }
1562 if left_is_option && right_is_option {
1563 if node.op !in [.eq, .ne] {
1564 c.error('`?${opt}` cannot be used as `${nopt}`, unwrap the option first', pos)
1565 }
1566 return
1567 }
1568 c.error('`?${opt}` cannot be used as `${nopt}`, unwrap the option first', pos)
1569 }
1570}
1571