checker: simplify assign_stmt & add better checks

pull/4680/head
joe-conigliaro 2020-05-02 19:45:08 +10:00
parent 06d533b0c1
commit fd925fbd05
No known key found for this signature in database
GPG Key ID: C12F7136C08206F1
1 changed files with 50 additions and 77 deletions

View File

@ -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) {
c.expected_type = table.none_type // TODO a hack to make `x := if ... work`
// check variablename for beginning with capital letter 'Abc'
for ident in assign_stmt.left {
if assign_stmt.right[0] is ast.CallExpr {
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
if is_decl && util.contains_capital(ident.name) {
c.error('variable names cannot contain uppercase letters, use snake_case instead',
@ -1030,83 +1059,27 @@ pub fn (mut c Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
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) }
if assign_stmt.op == .decl_assign {
c.var_decl_name = ident.name
}
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
mut ident_var_info := ident.var_info()
// c.assigned_var_name = ident.name
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)
}
}
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 {
c.var_decl_name = ident.name
}
mut ident_var_info := ident.var_info()
// 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 {
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[i], val_type, true)
ident_var_info.typ = val_type
ident.info = ident_var_info
assign_stmt.left[i] = ident
scope.update_var_type(ident.name, val_type)
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 = ''