checker: extract long match branches in c.stmt(), into separate checker functions (#8666)
							parent
							
								
									f2ad6dd4d9
								
							
						
					
					
						commit
						4305ce1493
					
				| 
						 | 
					@ -3104,37 +3104,16 @@ fn (mut c Checker) stmt(node ast.Stmt) {
 | 
				
			||||||
	// c.expected_type = table.void_type
 | 
						// c.expected_type = table.void_type
 | 
				
			||||||
	match mut node {
 | 
						match mut node {
 | 
				
			||||||
		ast.AssertStmt {
 | 
							ast.AssertStmt {
 | 
				
			||||||
			cur_exp_typ := c.expected_type
 | 
								c.assert_stmt(node)
 | 
				
			||||||
			assert_type := c.expr(node.expr)
 | 
					 | 
				
			||||||
			if assert_type != table.bool_type_idx {
 | 
					 | 
				
			||||||
				atype_name := c.table.get_type_symbol(assert_type).name
 | 
					 | 
				
			||||||
				c.error('assert can be used only with `bool` expressions, but found `$atype_name` instead',
 | 
					 | 
				
			||||||
					node.pos)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			c.expected_type = cur_exp_typ
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.AssignStmt {
 | 
							ast.AssignStmt {
 | 
				
			||||||
			c.assign_stmt(mut node)
 | 
								c.assign_stmt(mut node)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.Block {
 | 
							ast.Block {
 | 
				
			||||||
			if node.is_unsafe {
 | 
								c.block(node)
 | 
				
			||||||
				assert !c.inside_unsafe
 | 
					 | 
				
			||||||
				c.inside_unsafe = true
 | 
					 | 
				
			||||||
				c.stmts(node.stmts)
 | 
					 | 
				
			||||||
				c.inside_unsafe = false
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				c.stmts(node.stmts)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.BranchStmt {
 | 
							ast.BranchStmt {
 | 
				
			||||||
			if c.in_for_count == 0 {
 | 
								c.branch_stmt(node)
 | 
				
			||||||
				c.error('$node.kind.str() statement not within a loop', node.pos)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if node.label.len > 0 {
 | 
					 | 
				
			||||||
				if node.label != c.loop_label {
 | 
					 | 
				
			||||||
					c.error('invalid label name `$node.label`', node.pos)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.CompFor {
 | 
							ast.CompFor {
 | 
				
			||||||
			// node.typ = c.expr(node.expr)
 | 
								// node.typ = c.expr(node.expr)
 | 
				
			||||||
| 
						 | 
					@ -3166,147 +3145,19 @@ fn (mut c Checker) stmt(node ast.Stmt) {
 | 
				
			||||||
			c.fn_decl(mut node)
 | 
								c.fn_decl(mut node)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.ForCStmt {
 | 
							ast.ForCStmt {
 | 
				
			||||||
			c.in_for_count++
 | 
								c.for_c_stmt(node)
 | 
				
			||||||
			prev_loop_label := c.loop_label
 | 
					 | 
				
			||||||
			c.stmt(node.init)
 | 
					 | 
				
			||||||
			c.expr(node.cond)
 | 
					 | 
				
			||||||
			c.stmt(node.inc)
 | 
					 | 
				
			||||||
			c.check_loop_label(node.label, node.pos)
 | 
					 | 
				
			||||||
			c.stmts(node.stmts)
 | 
					 | 
				
			||||||
			c.loop_label = prev_loop_label
 | 
					 | 
				
			||||||
			c.in_for_count--
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.ForInStmt {
 | 
							ast.ForInStmt {
 | 
				
			||||||
			c.in_for_count++
 | 
								c.for_in_stmt(mut node)
 | 
				
			||||||
			prev_loop_label := c.loop_label
 | 
					 | 
				
			||||||
			typ := c.expr(node.cond)
 | 
					 | 
				
			||||||
			typ_idx := typ.idx()
 | 
					 | 
				
			||||||
			if node.key_var.len > 0 && node.key_var != '_' {
 | 
					 | 
				
			||||||
				c.check_valid_snake_case(node.key_var, 'variable name', node.pos)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if node.val_var.len > 0 && node.val_var != '_' {
 | 
					 | 
				
			||||||
				c.check_valid_snake_case(node.val_var, 'variable name', node.pos)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if node.is_range {
 | 
					 | 
				
			||||||
				high_type := c.expr(node.high)
 | 
					 | 
				
			||||||
				high_type_idx := high_type.idx()
 | 
					 | 
				
			||||||
				if typ_idx in table.integer_type_idxs && high_type_idx !in table.integer_type_idxs {
 | 
					 | 
				
			||||||
					c.error('range types do not match', node.cond.position())
 | 
					 | 
				
			||||||
				} else if typ_idx in table.float_type_idxs || high_type_idx in table.float_type_idxs {
 | 
					 | 
				
			||||||
					c.error('range type can not be float', node.cond.position())
 | 
					 | 
				
			||||||
				} else if typ_idx == table.bool_type_idx || high_type_idx == table.bool_type_idx {
 | 
					 | 
				
			||||||
					c.error('range type can not be bool', node.cond.position())
 | 
					 | 
				
			||||||
				} else if typ_idx == table.string_type_idx || high_type_idx == table.string_type_idx {
 | 
					 | 
				
			||||||
					c.error('range type can not be string', node.cond.position())
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				sym := c.table.get_type_symbol(typ)
 | 
					 | 
				
			||||||
				if sym.kind == .struct_ {
 | 
					 | 
				
			||||||
					// iterators
 | 
					 | 
				
			||||||
					next_fn := sym.find_method('next') or {
 | 
					 | 
				
			||||||
						c.error('a struct must have a `next()` method to be an iterator',
 | 
					 | 
				
			||||||
							node.cond.position())
 | 
					 | 
				
			||||||
						return
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					if !next_fn.return_type.has_flag(.optional) {
 | 
					 | 
				
			||||||
						c.error('iterator method `next()` must return an optional', node.cond.position())
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					// the receiver
 | 
					 | 
				
			||||||
					if next_fn.params.len != 1 {
 | 
					 | 
				
			||||||
						c.error('iterator method `next()` must have 0 parameters', node.cond.position())
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					val_type := next_fn.return_type.clear_flag(.optional)
 | 
					 | 
				
			||||||
					node.cond_type = typ
 | 
					 | 
				
			||||||
					node.kind = sym.kind
 | 
					 | 
				
			||||||
					node.val_type = val_type
 | 
					 | 
				
			||||||
					node.scope.update_var_type(node.val_var, val_type)
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					if sym.kind == .map && !(node.key_var.len > 0 && node.val_var.len > 0) {
 | 
					 | 
				
			||||||
						c.error(
 | 
					 | 
				
			||||||
							'declare a key and a value variable when ranging a map: `for key, val in map {`\n' +
 | 
					 | 
				
			||||||
							'use `_` if you do not need the variable', node.pos)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					if node.key_var.len > 0 {
 | 
					 | 
				
			||||||
						key_type := match sym.kind {
 | 
					 | 
				
			||||||
							.map { sym.map_info().key_type }
 | 
					 | 
				
			||||||
							else { table.int_type }
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
						node.key_type = key_type
 | 
					 | 
				
			||||||
						node.scope.update_var_type(node.key_var, key_type)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					mut value_type := c.table.value_type(typ)
 | 
					 | 
				
			||||||
					if value_type == table.void_type || typ.has_flag(.optional) {
 | 
					 | 
				
			||||||
						if typ != table.void_type {
 | 
					 | 
				
			||||||
							c.error('for in: cannot index `${c.table.type_to_str(typ)}`',
 | 
					 | 
				
			||||||
								node.cond.position())
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					if node.val_is_mut {
 | 
					 | 
				
			||||||
						value_type = value_type.to_ptr()
 | 
					 | 
				
			||||||
						match node.cond {
 | 
					 | 
				
			||||||
							ast.Ident {
 | 
					 | 
				
			||||||
								if node.cond.obj is ast.Var {
 | 
					 | 
				
			||||||
									obj := node.cond.obj as ast.Var
 | 
					 | 
				
			||||||
									if !obj.is_mut {
 | 
					 | 
				
			||||||
										c.error('`$obj.name` is immutable, it cannot be changed',
 | 
					 | 
				
			||||||
											node.cond.pos)
 | 
					 | 
				
			||||||
									}
 | 
					 | 
				
			||||||
								}
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
							ast.ArrayInit {
 | 
					 | 
				
			||||||
								c.error('array literal is immutable, it cannot be changed',
 | 
					 | 
				
			||||||
									node.cond.pos)
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
							ast.MapInit {
 | 
					 | 
				
			||||||
								c.error('map literal is immutable, it cannot be changed',
 | 
					 | 
				
			||||||
									node.cond.pos)
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
							else {}
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					node.cond_type = typ
 | 
					 | 
				
			||||||
					node.kind = sym.kind
 | 
					 | 
				
			||||||
					node.val_type = value_type
 | 
					 | 
				
			||||||
					node.scope.update_var_type(node.val_var, value_type)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			c.check_loop_label(node.label, node.pos)
 | 
					 | 
				
			||||||
			if node.val_is_mut {
 | 
					 | 
				
			||||||
				c.for_in_mut_val_name = node.val_var
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			c.stmts(node.stmts)
 | 
					 | 
				
			||||||
			if node.val_is_mut {
 | 
					 | 
				
			||||||
				c.for_in_mut_val_name = ''
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			c.loop_label = prev_loop_label
 | 
					 | 
				
			||||||
			c.in_for_count--
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.ForStmt {
 | 
							ast.ForStmt {
 | 
				
			||||||
			c.for_stmt(mut node)
 | 
								c.for_stmt(mut node)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.GlobalDecl {
 | 
							ast.GlobalDecl {
 | 
				
			||||||
			for field in node.fields {
 | 
								c.global_decl(node)
 | 
				
			||||||
				c.check_valid_snake_case(field.name, 'global name', field.pos)
 | 
					 | 
				
			||||||
				if field.name in c.global_names {
 | 
					 | 
				
			||||||
					c.error('duplicate global `$field.name`', field.pos)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				c.global_names << field.name
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.GoStmt {
 | 
							ast.GoStmt {
 | 
				
			||||||
			c.call_expr(mut node.call_expr)
 | 
								c.go_stmt(mut node)
 | 
				
			||||||
			// Make sure there are no mutable arguments
 | 
					 | 
				
			||||||
			for arg in node.call_expr.args {
 | 
					 | 
				
			||||||
				if arg.is_mut && !arg.typ.is_ptr() {
 | 
					 | 
				
			||||||
					c.error('function in `go` statement cannot contain mutable non-reference arguments',
 | 
					 | 
				
			||||||
						arg.expr.position())
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if node.call_expr.is_method && node.call_expr.receiver_type.is_ptr()
 | 
					 | 
				
			||||||
				&& !node.call_expr.left_type.is_ptr() {
 | 
					 | 
				
			||||||
				c.error('method in `go` statement cannot have non-reference mutable receiver',
 | 
					 | 
				
			||||||
					node.call_expr.left.position())
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.GotoLabel {}
 | 
							ast.GotoLabel {}
 | 
				
			||||||
		ast.GotoStmt {
 | 
							ast.GotoStmt {
 | 
				
			||||||
| 
						 | 
					@ -3346,6 +3197,217 @@ fn (mut c Checker) stmt(node ast.Stmt) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut c Checker) assert_stmt(node ast.AssertStmt) {
 | 
				
			||||||
 | 
						cur_exp_typ := c.expected_type
 | 
				
			||||||
 | 
						assert_type := c.expr(node.expr)
 | 
				
			||||||
 | 
						if assert_type != table.bool_type_idx {
 | 
				
			||||||
 | 
							atype_name := c.table.get_type_symbol(assert_type).name
 | 
				
			||||||
 | 
							c.error('assert can be used only with `bool` expressions, but found `$atype_name` instead',
 | 
				
			||||||
 | 
								node.pos)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c.expected_type = cur_exp_typ
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut c Checker) block(node ast.Block) {
 | 
				
			||||||
 | 
						if node.is_unsafe {
 | 
				
			||||||
 | 
							assert !c.inside_unsafe
 | 
				
			||||||
 | 
							c.inside_unsafe = true
 | 
				
			||||||
 | 
							c.stmts(node.stmts)
 | 
				
			||||||
 | 
							c.inside_unsafe = false
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							c.stmts(node.stmts)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut c Checker) branch_stmt(node ast.BranchStmt) {
 | 
				
			||||||
 | 
						if c.in_for_count == 0 {
 | 
				
			||||||
 | 
							c.error('$node.kind.str() statement not within a loop', node.pos)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if node.label.len > 0 {
 | 
				
			||||||
 | 
							if node.label != c.loop_label {
 | 
				
			||||||
 | 
								c.error('invalid label name `$node.label`', node.pos)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut c Checker) for_c_stmt(node ast.ForCStmt) {
 | 
				
			||||||
 | 
						c.in_for_count++
 | 
				
			||||||
 | 
						prev_loop_label := c.loop_label
 | 
				
			||||||
 | 
						c.stmt(node.init)
 | 
				
			||||||
 | 
						c.expr(node.cond)
 | 
				
			||||||
 | 
						c.stmt(node.inc)
 | 
				
			||||||
 | 
						c.check_loop_label(node.label, node.pos)
 | 
				
			||||||
 | 
						c.stmts(node.stmts)
 | 
				
			||||||
 | 
						c.loop_label = prev_loop_label
 | 
				
			||||||
 | 
						c.in_for_count--
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
 | 
				
			||||||
 | 
						c.in_for_count++
 | 
				
			||||||
 | 
						prev_loop_label := c.loop_label
 | 
				
			||||||
 | 
						typ := c.expr(node.cond)
 | 
				
			||||||
 | 
						typ_idx := typ.idx()
 | 
				
			||||||
 | 
						if node.key_var.len > 0 && node.key_var != '_' {
 | 
				
			||||||
 | 
							c.check_valid_snake_case(node.key_var, 'variable name', node.pos)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if node.val_var.len > 0 && node.val_var != '_' {
 | 
				
			||||||
 | 
							c.check_valid_snake_case(node.val_var, 'variable name', node.pos)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if node.is_range {
 | 
				
			||||||
 | 
							high_type := c.expr(node.high)
 | 
				
			||||||
 | 
							high_type_idx := high_type.idx()
 | 
				
			||||||
 | 
							if typ_idx in table.integer_type_idxs && high_type_idx !in table.integer_type_idxs {
 | 
				
			||||||
 | 
								c.error('range types do not match', node.cond.position())
 | 
				
			||||||
 | 
							} else if typ_idx in table.float_type_idxs || high_type_idx in table.float_type_idxs {
 | 
				
			||||||
 | 
								c.error('range type can not be float', node.cond.position())
 | 
				
			||||||
 | 
							} else if typ_idx == table.bool_type_idx || high_type_idx == table.bool_type_idx {
 | 
				
			||||||
 | 
								c.error('range type can not be bool', node.cond.position())
 | 
				
			||||||
 | 
							} else if typ_idx == table.string_type_idx || high_type_idx == table.string_type_idx {
 | 
				
			||||||
 | 
								c.error('range type can not be string', node.cond.position())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							sym := c.table.get_type_symbol(typ)
 | 
				
			||||||
 | 
							if sym.kind == .struct_ {
 | 
				
			||||||
 | 
								// iterators
 | 
				
			||||||
 | 
								next_fn := sym.find_method('next') or {
 | 
				
			||||||
 | 
									c.error('a struct must have a `next()` method to be an iterator', node.cond.position())
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if !next_fn.return_type.has_flag(.optional) {
 | 
				
			||||||
 | 
									c.error('iterator method `next()` must return an optional', node.cond.position())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// the receiver
 | 
				
			||||||
 | 
								if next_fn.params.len != 1 {
 | 
				
			||||||
 | 
									c.error('iterator method `next()` must have 0 parameters', node.cond.position())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								val_type := next_fn.return_type.clear_flag(.optional)
 | 
				
			||||||
 | 
								node.cond_type = typ
 | 
				
			||||||
 | 
								node.kind = sym.kind
 | 
				
			||||||
 | 
								node.val_type = val_type
 | 
				
			||||||
 | 
								node.scope.update_var_type(node.val_var, val_type)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if sym.kind == .map && !(node.key_var.len > 0 && node.val_var.len > 0) {
 | 
				
			||||||
 | 
									c.error(
 | 
				
			||||||
 | 
										'declare a key and a value variable when ranging a map: `for key, val in map {`\n' +
 | 
				
			||||||
 | 
										'use `_` if you do not need the variable', node.pos)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if node.key_var.len > 0 {
 | 
				
			||||||
 | 
									key_type := match sym.kind {
 | 
				
			||||||
 | 
										.map { sym.map_info().key_type }
 | 
				
			||||||
 | 
										else { table.int_type }
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									node.key_type = key_type
 | 
				
			||||||
 | 
									node.scope.update_var_type(node.key_var, key_type)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								mut value_type := c.table.value_type(typ)
 | 
				
			||||||
 | 
								if value_type == table.void_type || typ.has_flag(.optional) {
 | 
				
			||||||
 | 
									if typ != table.void_type {
 | 
				
			||||||
 | 
										c.error('for in: cannot index `${c.table.type_to_str(typ)}`', node.cond.position())
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if node.val_is_mut {
 | 
				
			||||||
 | 
									value_type = value_type.to_ptr()
 | 
				
			||||||
 | 
									match node.cond {
 | 
				
			||||||
 | 
										ast.Ident {
 | 
				
			||||||
 | 
											if node.cond.obj is ast.Var {
 | 
				
			||||||
 | 
												obj := node.cond.obj as ast.Var
 | 
				
			||||||
 | 
												if !obj.is_mut {
 | 
				
			||||||
 | 
													c.error('`$obj.name` is immutable, it cannot be changed',
 | 
				
			||||||
 | 
														node.cond.pos)
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										ast.ArrayInit {
 | 
				
			||||||
 | 
											c.error('array literal is immutable, it cannot be changed', node.cond.pos)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										ast.MapInit {
 | 
				
			||||||
 | 
											c.error('map literal is immutable, it cannot be changed', node.cond.pos)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else {}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								node.cond_type = typ
 | 
				
			||||||
 | 
								node.kind = sym.kind
 | 
				
			||||||
 | 
								node.val_type = value_type
 | 
				
			||||||
 | 
								node.scope.update_var_type(node.val_var, value_type)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c.check_loop_label(node.label, node.pos)
 | 
				
			||||||
 | 
						if node.val_is_mut {
 | 
				
			||||||
 | 
							c.for_in_mut_val_name = node.val_var
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c.stmts(node.stmts)
 | 
				
			||||||
 | 
						if node.val_is_mut {
 | 
				
			||||||
 | 
							c.for_in_mut_val_name = ''
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c.loop_label = prev_loop_label
 | 
				
			||||||
 | 
						c.in_for_count--
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut c Checker) for_stmt(mut node ast.ForStmt) {
 | 
				
			||||||
 | 
						c.in_for_count++
 | 
				
			||||||
 | 
						prev_loop_label := c.loop_label
 | 
				
			||||||
 | 
						c.expected_type = table.bool_type
 | 
				
			||||||
 | 
						typ := c.expr(node.cond)
 | 
				
			||||||
 | 
						if !node.is_inf && typ.idx() != table.bool_type_idx && !c.pref.translated {
 | 
				
			||||||
 | 
							c.error('non-bool used as for condition', node.pos)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if node.cond is ast.InfixExpr {
 | 
				
			||||||
 | 
							infix := node.cond
 | 
				
			||||||
 | 
							if infix.op == .key_is {
 | 
				
			||||||
 | 
								if (infix.left is ast.Ident || infix.left is ast.SelectorExpr)
 | 
				
			||||||
 | 
									&& infix.right is ast.Type {
 | 
				
			||||||
 | 
									right_expr := infix.right as ast.Type
 | 
				
			||||||
 | 
									is_variable := if mut infix.left is ast.Ident {
 | 
				
			||||||
 | 
										infix.left.kind == .variable
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										true
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									left_type := c.expr(infix.left)
 | 
				
			||||||
 | 
									left_sym := c.table.get_type_symbol(left_type)
 | 
				
			||||||
 | 
									if is_variable {
 | 
				
			||||||
 | 
										if left_sym.kind == .sum_type {
 | 
				
			||||||
 | 
											c.smartcast_sumtype(infix.left, infix.left_type, right_expr.typ, mut
 | 
				
			||||||
 | 
												node.scope)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// TODO: update loop var type
 | 
				
			||||||
 | 
						// how does this work currenly?
 | 
				
			||||||
 | 
						c.check_loop_label(node.label, node.pos)
 | 
				
			||||||
 | 
						c.stmts(node.stmts)
 | 
				
			||||||
 | 
						c.loop_label = prev_loop_label
 | 
				
			||||||
 | 
						c.in_for_count--
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut c Checker) global_decl(node ast.GlobalDecl) {
 | 
				
			||||||
 | 
						for field in node.fields {
 | 
				
			||||||
 | 
							c.check_valid_snake_case(field.name, 'global name', field.pos)
 | 
				
			||||||
 | 
							if field.name in c.global_names {
 | 
				
			||||||
 | 
								c.error('duplicate global `$field.name`', field.pos)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							c.global_names << field.name
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut c Checker) go_stmt(mut node ast.GoStmt) {
 | 
				
			||||||
 | 
						c.call_expr(mut node.call_expr)
 | 
				
			||||||
 | 
						// Make sure there are no mutable arguments
 | 
				
			||||||
 | 
						for arg in node.call_expr.args {
 | 
				
			||||||
 | 
							if arg.is_mut && !arg.typ.is_ptr() {
 | 
				
			||||||
 | 
								c.error('function in `go` statement cannot contain mutable non-reference arguments',
 | 
				
			||||||
 | 
									arg.expr.position())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if node.call_expr.is_method && node.call_expr.receiver_type.is_ptr()
 | 
				
			||||||
 | 
							&& !node.call_expr.left_type.is_ptr() {
 | 
				
			||||||
 | 
							c.error('method in `go` statement cannot have non-reference mutable receiver',
 | 
				
			||||||
 | 
								node.call_expr.left.position())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
 | 
					fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
 | 
				
			||||||
	if c.skip_flags {
 | 
						if c.skip_flags {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
| 
						 | 
					@ -4659,44 +4721,6 @@ pub fn (mut c Checker) unsafe_expr(mut node ast.UnsafeExpr) table.Type {
 | 
				
			||||||
	return t
 | 
						return t
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (mut c Checker) for_stmt(mut node ast.ForStmt) {
 | 
					 | 
				
			||||||
	c.in_for_count++
 | 
					 | 
				
			||||||
	prev_loop_label := c.loop_label
 | 
					 | 
				
			||||||
	c.expected_type = table.bool_type
 | 
					 | 
				
			||||||
	typ := c.expr(node.cond)
 | 
					 | 
				
			||||||
	if !node.is_inf && typ.idx() != table.bool_type_idx && !c.pref.translated {
 | 
					 | 
				
			||||||
		c.error('non-bool used as for condition', node.pos)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if node.cond is ast.InfixExpr {
 | 
					 | 
				
			||||||
		infix := node.cond
 | 
					 | 
				
			||||||
		if infix.op == .key_is {
 | 
					 | 
				
			||||||
			if (infix.left is ast.Ident || infix.left is ast.SelectorExpr)
 | 
					 | 
				
			||||||
				&& infix.right is ast.Type {
 | 
					 | 
				
			||||||
				right_expr := infix.right as ast.Type
 | 
					 | 
				
			||||||
				is_variable := if mut infix.left is ast.Ident {
 | 
					 | 
				
			||||||
					infix.left.kind == .variable
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					true
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				left_type := c.expr(infix.left)
 | 
					 | 
				
			||||||
				left_sym := c.table.get_type_symbol(left_type)
 | 
					 | 
				
			||||||
				if is_variable {
 | 
					 | 
				
			||||||
					if left_sym.kind == .sum_type {
 | 
					 | 
				
			||||||
						c.smartcast_sumtype(infix.left, infix.left_type, right_expr.typ, mut
 | 
					 | 
				
			||||||
							node.scope)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// TODO: update loop var type
 | 
					 | 
				
			||||||
	// how does this work currenly?
 | 
					 | 
				
			||||||
	c.check_loop_label(node.label, node.pos)
 | 
					 | 
				
			||||||
	c.stmts(node.stmts)
 | 
					 | 
				
			||||||
	c.loop_label = prev_loop_label
 | 
					 | 
				
			||||||
	c.in_for_count--
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
 | 
					pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
 | 
				
			||||||
	if_kind := if node.is_comptime { '\$if' } else { 'if' }
 | 
						if_kind := if node.is_comptime { '\$if' } else { 'if' }
 | 
				
			||||||
	expr_required := c.expected_type != table.void_type
 | 
						expr_required := c.expected_type != table.void_type
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue