checker: simplify assign_stmt & add better checks
parent
06d533b0c1
commit
fd925fbd05
|
@ -1019,8 +1019,37 @@ pub fn (mut c Checker) enum_decl(decl ast.EnumDecl) {
|
||||||
|
|
||||||
pub fn (mut c Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
|
pub fn (mut c Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
|
||||||
c.expected_type = table.none_type // TODO a hack to make `x := if ... work`
|
c.expected_type = table.none_type // TODO a hack to make `x := if ... work`
|
||||||
// check variablename for beginning with capital letter 'Abc'
|
if assign_stmt.right[0] is ast.CallExpr {
|
||||||
for ident in assign_stmt.left {
|
call_expr := assign_stmt.right[0] as ast.CallExpr
|
||||||
|
right_type0 := c.expr(assign_stmt.right[0])
|
||||||
|
assign_stmt.right_types = [right_type0]
|
||||||
|
right_type_sym0 := c.table.get_type_symbol(right_type0)
|
||||||
|
mut right_len := if right_type0 == table.void_type { 0 } else { 1 }
|
||||||
|
if right_type_sym0.kind == .multi_return {
|
||||||
|
assign_stmt.right_types = right_type_sym0.mr_info().types
|
||||||
|
right_len = assign_stmt.right_types.len
|
||||||
|
}
|
||||||
|
if assign_stmt.left.len != right_len {
|
||||||
|
c.error('assignment mismatch: $assign_stmt.left.len variable(s) but `${call_expr.name}()` returns $right_len value(s)',
|
||||||
|
assign_stmt.pos)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if assign_stmt.left.len != assign_stmt.right.len {
|
||||||
|
c.error('assignment mismatch: $assign_stmt.left.len variable(s) $assign_stmt.right.len value(s)',
|
||||||
|
assign_stmt.pos)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mut scope := c.file.scope.innermost(assign_stmt.pos.pos)
|
||||||
|
for i, _ in assign_stmt.left {
|
||||||
|
mut ident := assign_stmt.left[i]
|
||||||
|
if assign_stmt.right_types.len < assign_stmt.right.len {
|
||||||
|
assign_stmt.right_types << c.expr(assign_stmt.right[i])
|
||||||
|
}
|
||||||
|
val_type := assign_stmt.right_types[i]
|
||||||
|
// check variable name for beginning with capital letter 'Abc'
|
||||||
is_decl := assign_stmt.op == .decl_assign
|
is_decl := assign_stmt.op == .decl_assign
|
||||||
if is_decl && util.contains_capital(ident.name) {
|
if is_decl && util.contains_capital(ident.name) {
|
||||||
c.error('variable names cannot contain uppercase letters, use snake_case instead',
|
c.error('variable names cannot contain uppercase letters, use snake_case instead',
|
||||||
|
@ -1030,67 +1059,11 @@ pub fn (mut c Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
|
||||||
c.error('variable names cannot start with `__`', ident.pos)
|
c.error('variable names cannot start with `__`', ident.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if assign_stmt.left.len > assign_stmt.right.len {
|
|
||||||
// multi return
|
|
||||||
match assign_stmt.right[0] {
|
|
||||||
ast.CallExpr {}
|
|
||||||
else { c.error('assign_stmt: expected call', assign_stmt.pos) }
|
|
||||||
}
|
|
||||||
right_type := c.expr(assign_stmt.right[0])
|
|
||||||
right_type_sym := c.table.get_type_symbol(right_type)
|
|
||||||
if right_type_sym.kind != .multi_return {
|
|
||||||
c.error('expression on the right does not return multiple values, while at least $assign_stmt.left.len are expected',
|
|
||||||
assign_stmt.pos)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mr_info := right_type_sym.mr_info()
|
|
||||||
if mr_info.types.len < assign_stmt.left.len {
|
|
||||||
c.error('right expression returns only $mr_info.types.len values, but left one expects $assign_stmt.left.len',
|
|
||||||
assign_stmt.pos)
|
|
||||||
}
|
|
||||||
mut scope := c.file.scope.innermost(assign_stmt.pos.pos)
|
|
||||||
for i, _ in assign_stmt.left {
|
|
||||||
mut ident := assign_stmt.left[i]
|
|
||||||
mut ident_var_info := ident.var_info()
|
|
||||||
if i >= mr_info.types.len {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val_type := mr_info.types[i]
|
|
||||||
if assign_stmt.op == .assign {
|
|
||||||
var_type := c.expr(ident)
|
|
||||||
assign_stmt.left_types << var_type
|
|
||||||
if !c.table.check(val_type, var_type) {
|
|
||||||
val_type_sym := c.table.get_type_symbol(val_type)
|
|
||||||
var_type_sym := c.table.get_type_symbol(var_type)
|
|
||||||
c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`',
|
|
||||||
assign_stmt.pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ident_var_info.typ = val_type
|
|
||||||
ident.info = ident_var_info
|
|
||||||
assign_stmt.left[i] = ident
|
|
||||||
assign_stmt.right_types << val_type
|
|
||||||
scope.update_var_type(ident.name, val_type)
|
|
||||||
}
|
|
||||||
c.check_expr_opt_call(assign_stmt.right[0], right_type, true)
|
|
||||||
} else {
|
|
||||||
// `a := 1` | `a,b := 1,2`
|
|
||||||
if assign_stmt.left.len != assign_stmt.right.len {
|
|
||||||
c.error('wrong number of vars', assign_stmt.pos)
|
|
||||||
}
|
|
||||||
mut scope := c.file.scope.innermost(assign_stmt.pos.pos)
|
|
||||||
for i, _ in assign_stmt.left {
|
|
||||||
mut ident := assign_stmt.left[i]
|
|
||||||
if assign_stmt.op == .decl_assign {
|
if assign_stmt.op == .decl_assign {
|
||||||
c.var_decl_name = ident.name
|
c.var_decl_name = ident.name
|
||||||
}
|
}
|
||||||
mut ident_var_info := ident.var_info()
|
mut ident_var_info := ident.var_info()
|
||||||
// c.assigned_var_name = ident.name
|
// c.assigned_var_name = ident.name
|
||||||
val_type := c.expr(assign_stmt.right[i])
|
|
||||||
if val_type == table.void_type {
|
|
||||||
c.error('expression does not return a value', assign_stmt.right[i].position())
|
|
||||||
}
|
|
||||||
if assign_stmt.op == .assign {
|
if assign_stmt.op == .assign {
|
||||||
var_type := c.expr(ident)
|
var_type := c.expr(ident)
|
||||||
assign_stmt.left_types << var_type
|
assign_stmt.left_types << var_type
|
||||||
|
@ -1104,9 +1077,9 @@ pub fn (mut c Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
|
||||||
ident_var_info.typ = val_type
|
ident_var_info.typ = val_type
|
||||||
ident.info = ident_var_info
|
ident.info = ident_var_info
|
||||||
assign_stmt.left[i] = ident
|
assign_stmt.left[i] = ident
|
||||||
assign_stmt.right_types << val_type
|
|
||||||
scope.update_var_type(ident.name, val_type)
|
scope.update_var_type(ident.name, val_type)
|
||||||
c.check_expr_opt_call(assign_stmt.right[i], val_type, true)
|
if i < assign_stmt.right.len { // only once for multi return
|
||||||
|
c.check_expr_opt_call(assign_stmt.right[i], assign_stmt.right_types[i], true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.var_decl_name = ''
|
c.var_decl_name = ''
|
||||||
|
|
Loading…
Reference in New Issue