checker: use the new match syntax

pull/5417/head
Alexander Medvednikov 2020-06-18 20:38:59 +02:00
parent 78b32892ac
commit 5ddb129bc2
1 changed files with 193 additions and 193 deletions

View File

@ -126,63 +126,63 @@ fn (mut c Checker) check_file_in_main(file ast.File) bool {
for stmt in file.stmts { for stmt in file.stmts {
match stmt { match stmt {
ast.ConstDecl { ast.ConstDecl {
if it.is_pub { if stmt.is_pub {
c.warn('const $no_pub_in_main_warning', it.pos) c.warn('const $no_pub_in_main_warning', stmt.pos)
} }
} }
ast.ConstField { ast.ConstField {
if it.is_pub { if stmt.is_pub {
c.warn('const field `$it.name` $no_pub_in_main_warning', it.pos) c.warn('const field `$stmt.name` $no_pub_in_main_warning', stmt.pos)
} }
} }
ast.EnumDecl { ast.EnumDecl {
if it.is_pub { if stmt.is_pub {
c.warn('enum `$it.name` $no_pub_in_main_warning', it.pos) c.warn('enum `$stmt.name` $no_pub_in_main_warning', stmt.pos)
} }
} }
ast.FnDecl { ast.FnDecl {
if it.name == 'main' { if stmt.name == 'main' {
has_main_fn = true has_main_fn = true
if it.is_pub { if stmt.is_pub {
c.error('function `main` cannot be declared public', it.pos) c.error('function `main` cannot be declared public', stmt.pos)
} }
if it.args.len > 0 { if stmt.args.len > 0 {
c.error('function `main` cannot have arguments', it.pos) c.error('function `main` cannot have arguments', stmt.pos)
} }
if it.return_type != table.void_type { if stmt.return_type != table.void_type {
c.error('function `main` cannot return values', it.pos) c.error('function `main` cannot return values', stmt.pos)
} }
} else { } else {
if it.is_pub && !it.is_method { if stmt.is_pub && !stmt.is_method {
c.warn('function `$it.name` $no_pub_in_main_warning', it.pos) c.warn('function `$stmt.name` $no_pub_in_main_warning', stmt.pos)
} }
} }
if it.ctdefine.len > 0 { if stmt.ctdefine.len > 0 {
if it.return_type != table.void_type { if stmt.return_type != table.void_type {
c.error('only functions that do NOT return values can have `[if ${it.ctdefine}]` tags', c.error('only functions that do NOT return values can have `[if $stmt.ctdefine]` tags',
it.pos) stmt.pos)
} }
} }
} }
ast.StructDecl { ast.StructDecl {
if it.is_pub { if stmt.is_pub {
c.warn('struct `$it.name` $no_pub_in_main_warning', it.pos) c.warn('struct `$stmt.name` $no_pub_in_main_warning', stmt.pos)
} }
} }
ast.TypeDecl { ast.TypeDecl {
// type_decl := stmt as ast.TypeDecl // type_decl := stmt as ast.TypeDecl
if it is ast.AliasTypeDecl { if stmt is ast.AliasTypeDecl {
alias_decl := it as ast.AliasTypeDecl alias_decl := stmt as ast.AliasTypeDecl
if alias_decl.is_pub { if alias_decl.is_pub {
c.warn('type alias `$alias_decl.name` $no_pub_in_main_warning', alias_decl.pos) c.warn('type alias `$alias_decl.name` $no_pub_in_main_warning', alias_decl.pos)
} }
} else if it is ast.SumTypeDecl { } else if stmt is ast.SumTypeDecl {
sum_decl := it as ast.SumTypeDecl sum_decl := stmt as ast.SumTypeDecl
if sum_decl.is_pub { if sum_decl.is_pub {
c.warn('sum type `$sum_decl.name` $no_pub_in_main_warning', sum_decl.pos) c.warn('sum type `$sum_decl.name` $no_pub_in_main_warning', sum_decl.pos)
} }
} else if it is ast.FnTypeDecl { } else if stmt is ast.FnTypeDecl {
fn_decl := it as ast.FnTypeDecl fn_decl := stmt as ast.FnTypeDecl
if fn_decl.is_pub { if fn_decl.is_pub {
c.warn('type alias `$fn_decl.name` $no_pub_in_main_warning', fn_decl.pos) c.warn('type alias `$fn_decl.name` $no_pub_in_main_warning', fn_decl.pos)
} }
@ -223,35 +223,35 @@ pub fn (mut c Checker) type_decl(node ast.TypeDecl) {
ast.AliasTypeDecl { ast.AliasTypeDecl {
// TODO Replace `c.file.mod.name != 'time'` by `it.language != .v` once available // TODO Replace `c.file.mod.name != 'time'` by `it.language != .v` once available
if c.file.mod.name != 'time' { if c.file.mod.name != 'time' {
c.check_valid_pascal_case(it.name, 'type alias', it.pos) c.check_valid_pascal_case(node.name, 'type alias', node.pos)
} }
typ_sym := c.table.get_type_symbol(it.parent_type) typ_sym := c.table.get_type_symbol(node.parent_type)
if typ_sym.kind == .placeholder { if typ_sym.kind == .placeholder {
c.error("type `$typ_sym.name` doesn't exist", it.pos) c.error("type `$typ_sym.name` doesn't exist", node.pos)
} }
} }
ast.FnTypeDecl { ast.FnTypeDecl {
c.check_valid_pascal_case(it.name, 'fn type', it.pos) c.check_valid_pascal_case(node.name, 'fn type', node.pos)
typ_sym := c.table.get_type_symbol(it.typ) typ_sym := c.table.get_type_symbol(node.typ)
fn_typ_info := typ_sym.info as table.FnType fn_typ_info := typ_sym.info as table.FnType
fn_info := fn_typ_info.func fn_info := fn_typ_info.func
ret_sym := c.table.get_type_symbol(fn_info.return_type) ret_sym := c.table.get_type_symbol(fn_info.return_type)
if ret_sym.kind == .placeholder { if ret_sym.kind == .placeholder {
c.error("type `$ret_sym.name` doesn't exist", it.pos) c.error("type `$ret_sym.name` doesn't exist", node.pos)
} }
for arg in fn_info.args { for arg in fn_info.args {
arg_sym := c.table.get_type_symbol(arg.typ) arg_sym := c.table.get_type_symbol(arg.typ)
if arg_sym.kind == .placeholder { if arg_sym.kind == .placeholder {
c.error("type `$arg_sym.name` doesn't exist", it.pos) c.error("type `$arg_sym.name` doesn't exist", node.pos)
} }
} }
} }
ast.SumTypeDecl { ast.SumTypeDecl {
c.check_valid_pascal_case(it.name, 'sum type', it.pos) c.check_valid_pascal_case(node.name, 'sum type', node.pos)
for typ in it.sub_types { for typ in node.sub_types {
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
if typ_sym.kind == .placeholder { if typ_sym.kind == .placeholder {
c.error("type `$typ_sym.name` doesn't exist", it.pos) c.error("type `$typ_sym.name` doesn't exist", node.pos)
} }
} }
} }
@ -301,7 +301,7 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
if !c.check_types(field_expr_type, field.typ) { if !c.check_types(field_expr_type, field.typ) {
field_expr_type_sym := c.table.get_type_symbol(field_expr_type) field_expr_type_sym := c.table.get_type_symbol(field_expr_type)
field_type_sym := c.table.get_type_symbol(field.typ) field_type_sym := c.table.get_type_symbol(field.typ)
c.error('default expression for field `${field.name}` ' + 'has type `${field_expr_type_sym.name}`, but should be `${field_type_sym.name}`', c.error('default expression for field `$field.name` ' + 'has type `$field_expr_type_sym.name`, but should be `$field_type_sym.name`',
field.default_expr.position()) field.default_expr.position())
} }
} }
@ -404,7 +404,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
continue continue
} }
if field.typ.is_ptr() { if field.typ.is_ptr() {
c.warn('reference field `${type_sym.name}.${field.name}` must be initialized', c.warn('reference field `${type_sym.name}.$field.name` must be initialized',
struct_init.pos) struct_init.pos)
} }
} }
@ -498,7 +498,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
if infix_expr.op == .mod { if infix_expr.op == .mod {
c.error('float modulo not allowed, use math.fmod() instead', pos) c.error('float modulo not allowed, use math.fmod() instead', pos)
} else { } else {
c.error('$side type of `${infix_expr.op.str()}` cannot be non-integer type $name', c.error('$side type of `$infix_expr.op.str()` cannot be non-integer type $name',
pos) pos)
} }
} }
@ -553,7 +553,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
type_expr := infix_expr.right as ast.Type type_expr := infix_expr.right as ast.Type
typ_sym := c.table.get_type_symbol(type_expr.typ) typ_sym := c.table.get_type_symbol(type_expr.typ)
if typ_sym.kind == .placeholder { if typ_sym.kind == .placeholder {
c.error('$infix_expr.op.str(): type `${typ_sym.name}` does not exist', type_expr.pos) c.error('$infix_expr.op.str(): type `$typ_sym.name` does not exist', type_expr.pos)
} }
if left.kind != .interface_ && left.kind != .sum_type { if left.kind != .interface_ && left.kind != .sum_type {
c.error('`$infix_expr.op.str()` can only be used with interfaces and sum types', c.error('`$infix_expr.op.str()` can only be used with interfaces and sum types',
@ -607,58 +607,58 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) {
return return
} }
ast.Ident { ast.Ident {
scope := c.file.scope.innermost(it.pos.pos) scope := c.file.scope.innermost(expr.pos.pos)
if v := scope.find_var(it.name) { if v := scope.find_var(expr.name) {
if !v.is_mut && !v.typ.is_ptr() { if !v.is_mut && !v.typ.is_ptr() {
c.error('`$it.name` is immutable, declare it with `mut` to make it mutable', c.error('`$expr.name` is immutable, declare it with `mut` to make it mutable',
it.pos) expr.pos)
} }
v.is_changed = true v.is_changed = true
} else if it.name in c.const_names { } else if expr.name in c.const_names {
c.error('cannot modify constant `$it.name`', it.pos) c.error('cannot modify constant `$expr.name`', expr.pos)
} }
} }
ast.IndexExpr { ast.IndexExpr {
c.fail_if_immutable(it.left) c.fail_if_immutable(expr.left)
} }
ast.ParExpr { ast.ParExpr {
c.fail_if_immutable(it.expr) c.fail_if_immutable(expr.expr)
} }
ast.PrefixExpr { ast.PrefixExpr {
c.fail_if_immutable(it.right) c.fail_if_immutable(expr.right)
} }
ast.SelectorExpr { ast.SelectorExpr {
// retrieve table.Field // retrieve table.Field
if it.expr_type == 0 { if expr.expr_type == 0 {
c.error('0 type in SelectorExpr', it.pos) c.error('0 type in SelectorExpr', expr.pos)
return return
} }
typ_sym := c.table.get_type_symbol(c.unwrap_generic(it.expr_type)) typ_sym := c.table.get_type_symbol(c.unwrap_generic(expr.expr_type))
match typ_sym.kind { match typ_sym.kind {
.struct_ { .struct_ {
struct_info := typ_sym.info as table.Struct struct_info := typ_sym.info as table.Struct
field_info := struct_info.find_field(it.field_name) or { field_info := struct_info.find_field(expr.field_name) or {
type_str := c.table.type_to_str(it.expr_type) type_str := c.table.type_to_str(expr.expr_type)
c.error('unknown field `${type_str}.$it.field_name`', it.pos) c.error('unknown field `${type_str}.$expr.field_name`', expr.pos)
return return
} }
if !field_info.is_mut { if !field_info.is_mut {
type_str := c.table.type_to_str(it.expr_type) type_str := c.table.type_to_str(expr.expr_type)
c.error('field `$it.field_name` of struct `${type_str}` is immutable', c.error('field `$expr.field_name` of struct `$type_str` is immutable',
it.pos) expr.pos)
} }
c.fail_if_immutable(it.expr) c.fail_if_immutable(expr.expr)
} }
.array, .string { .array, .string {
// This should only happen in `builtin` // This should only happen in `builtin`
// TODO Remove `crypto.rand` when possible (see vlib/crypto/rand/rand.v, // TODO Remove `crypto.rand` when possible (see vlib/crypto/rand/rand.v,
// if `c_array_to_bytes_tmp` doesn't exist, then it's safe to remove it) // if `c_array_to_bytes_tmp` doesn't exist, then it's safe to remove it)
if c.file.mod.name !in ['builtin', 'crypto.rand'] { if c.file.mod.name !in ['builtin', 'crypto.rand'] {
c.error('`$typ_sym.kind` can not be modified', it.pos) c.error('`$typ_sym.kind` can not be modified', expr.pos)
} }
} }
else { else {
c.error('unexpected symbol `${typ_sym.kind}`', it.pos) c.error('unexpected symbol `$typ_sym.kind`', expr.pos)
} }
} }
} }
@ -1109,7 +1109,7 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t
pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type) { pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type) {
if or_expr.kind == .propagate { if or_expr.kind == .propagate {
if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main' { if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main' {
c.error('to propagate the optional call, `${c.cur_fn.name}` must itself return an optional', c.error('to propagate the optional call, `$c.cur_fn.name` must itself return an optional',
or_expr.pos) or_expr.pos)
} }
return return
@ -1134,22 +1134,22 @@ pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type
} }
match last_stmt { match last_stmt {
ast.ExprStmt { ast.ExprStmt {
it.typ = c.expr(it.expr) last_stmt.typ = c.expr(last_stmt.expr)
type_fits := c.check_types(it.typ, ret_type) type_fits := c.check_types(last_stmt.typ, ret_type)
is_panic_or_exit := is_expr_panic_or_exit(it.expr) is_panic_or_exit := is_expr_panic_or_exit(last_stmt.expr)
if type_fits || is_panic_or_exit { if type_fits || is_panic_or_exit {
return return
} }
type_name := c.table.get_type_symbol(it.typ).name type_name := c.table.get_type_symbol(last_stmt.typ).name
expected_type_name := c.table.get_type_symbol(ret_type).name expected_type_name := c.table.get_type_symbol(ret_type).name
c.error('wrong return type `$type_name` in the `or {}` block, expected `$expected_type_name`', c.error('wrong return type `$type_name` in the `or {}` block, expected `$expected_type_name`',
it.pos) last_stmt.pos)
return return
} }
ast.BranchStmt { ast.BranchStmt {
if it.tok.kind !in [.key_continue, .key_break] { if last_stmt.tok.kind !in [.key_continue, .key_break] {
c.error('only break/continue is allowed as a branch statement in the end of an `or {}` block', c.error('only break/continue is allowed as a branch statement in the end of an `or {}` block',
it.tok.position()) last_stmt.tok.position())
return return
} }
} }
@ -1161,7 +1161,7 @@ pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type
fn is_expr_panic_or_exit(expr ast.Expr) bool { fn is_expr_panic_or_exit(expr ast.Expr) bool {
match expr { match expr {
ast.CallExpr { return it.name in ['panic', 'exit'] } ast.CallExpr { return expr.name in ['panic', 'exit'] }
else { return false } else { return false }
} }
} }
@ -1350,26 +1350,26 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
assign_stmt.left_types << left_type assign_stmt.left_types << left_type
match left { match left {
ast.Ident { ast.Ident {
if it.kind == .blank_ident { if left.kind == .blank_ident {
left_type = right_type left_type = right_type
assign_stmt.left_types[i] = right_type assign_stmt.left_types[i] = right_type
if assign_stmt.op !in [.assign, .decl_assign] { if assign_stmt.op !in [.assign, .decl_assign] {
c.error('cannot modify blank `_` identifier', it.pos) c.error('cannot modify blank `_` identifier', left.pos)
} }
} else { } else {
if is_decl { if is_decl {
c.check_valid_snake_case(it.name, 'variable name', it.pos) c.check_valid_snake_case(left.name, 'variable name', left.pos)
} }
mut scope := c.file.scope.innermost(assign_stmt.pos.pos) mut scope := c.file.scope.innermost(assign_stmt.pos.pos)
mut ident_var_info := it.var_info() mut ident_var_info := left.var_info()
ident_var_info.typ = left_type ident_var_info.typ = left_type
it.info = ident_var_info left.info = ident_var_info
scope.update_var_type(it.name, left_type) scope.update_var_type(left.name, left_type)
} }
} }
ast.PrefixExpr { ast.PrefixExpr {
// Do now allow `*x = y` outside `unsafe` // Do now allow `*x = y` outside `unsafe`
if it.op == .mul && !c.inside_unsafe { if left.op == .mul && !c.inside_unsafe {
c.error('modifying variables via deferencing can only be done in `unsafe` blocks', c.error('modifying variables via deferencing can only be done in `unsafe` blocks',
assign_stmt.pos) assign_stmt.pos)
} }
@ -1409,19 +1409,19 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
} }
.mult_assign, .div_assign { .mult_assign, .div_assign {
if !left_sym.is_number() { if !left_sym.is_number() {
c.error('operator ${assign_stmt.op.str()} not defined on left operand type `$left_sym.name`', c.error('operator $assign_stmt.op.str() not defined on left operand type `$left_sym.name`',
left.position()) left.position())
} else if !right_sym.is_number() { } else if !right_sym.is_number() {
c.error('operator ${assign_stmt.op.str()} not defined on right operand type `$right_sym.name`', c.error('operator $assign_stmt.op.str() not defined on right operand type `$right_sym.name`',
right.position()) right.position())
} }
} }
.and_assign, .or_assign, .xor_assign, .mod_assign, .left_shift_assign, .right_shift_assign { .and_assign, .or_assign, .xor_assign, .mod_assign, .left_shift_assign, .right_shift_assign {
if !left_sym.is_int() { if !left_sym.is_int() {
c.error('operator ${assign_stmt.op.str()} not defined on left operand type `$left_sym.name`', c.error('operator $assign_stmt.op.str() not defined on left operand type `$left_sym.name`',
left.position()) left.position())
} else if !right_sym.is_int() { } else if !right_sym.is_int() {
c.error('operator ${assign_stmt.op.str()} not defined on right operand type `$right_sym.name`', c.error('operator $assign_stmt.op.str() not defined on right operand type `$right_sym.name`',
right.position()) right.position())
} }
} }
@ -1429,7 +1429,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
} }
// Dual sides check (compatibility check) // Dual sides check (compatibility check)
if !is_blank_ident && !c.check_types(right_type_unwrapped, left_type_unwrapped) { if !is_blank_ident && !c.check_types(right_type_unwrapped, left_type_unwrapped) {
c.error('cannot assign `$right_sym.name` to `${left.str()}` of type `$left_sym.name`', c.error('cannot assign `$right_sym.name` to `$left.str()` of type `$left_sym.name`',
right.position()) right.position())
} }
} }
@ -1588,36 +1588,36 @@ 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 {
assert_type := c.expr(it.expr) assert_type := c.expr(node.expr)
if assert_type != table.bool_type_idx { if assert_type != table.bool_type_idx {
atype_name := c.table.get_type_symbol(assert_type).name 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', c.error('assert can be used only with `bool` expressions, but found `$atype_name` instead',
it.pos) node.pos)
} }
} }
// ast.Attr {} // ast.Attr {}
ast.AssignStmt { ast.AssignStmt {
c.assign_stmt(mut it) c.assign_stmt(mut node)
} }
ast.Block { ast.Block {
c.stmts(it.stmts) c.stmts(node.stmts)
} }
ast.BranchStmt { ast.BranchStmt {
if c.in_for_count == 0 { if c.in_for_count == 0 {
c.error('$it.tok.lit statement not within a loop', it.tok.position()) c.error('$node.tok.lit statement not within a loop', node.tok.position())
} }
} }
ast.CompIf { ast.CompIf {
// c.expr(it.cond) // c.expr(it.cond)
c.stmts(it.stmts) c.stmts(node.stmts)
if it.has_else { if node.has_else {
c.stmts(it.else_stmts) c.stmts(node.else_stmts)
} }
} }
ast.ConstDecl { ast.ConstDecl {
mut field_names := []string{} mut field_names := []string{}
mut field_order := []int{} mut field_order := []int{}
for i, field in it.fields { for i, field in node.fields {
// TODO Check const name once the syntax is decided // TODO Check const name once the syntax is decided
if field.name in c.const_names { if field.name in c.const_names {
c.error('field name `$field.name` duplicate', field.pos) c.error('field name `$field.name` duplicate', field.pos)
@ -1628,13 +1628,13 @@ fn (mut c Checker) stmt(node ast.Stmt) {
} }
mut needs_order := false mut needs_order := false
mut done_fields := []int{} mut done_fields := []int{}
for i, field in it.fields { for i, field in node.fields {
c.const_decl = field.name c.const_decl = field.name
c.const_deps << field.name c.const_deps << field.name
typ := c.expr(field.expr) typ := c.expr(field.expr)
it.fields[i].typ = c.table.mktyp(typ) node.fields[i].typ = c.table.mktyp(typ)
for cd in c.const_deps { for cd in c.const_deps {
for j, f in it.fields { for j, f in node.fields {
if j != i && cd in field_names && cd == f.name && j !in done_fields { if j != i && cd in field_names && cd == f.name && j !in done_fields {
needs_order = true needs_order = true
x := field_order[j] x := field_order[j]
@ -1650,60 +1650,60 @@ fn (mut c Checker) stmt(node ast.Stmt) {
if needs_order { if needs_order {
mut ordered_fields := []ast.ConstField{} mut ordered_fields := []ast.ConstField{}
for order in field_order { for order in field_order {
ordered_fields << it.fields[order] ordered_fields << node.fields[order]
} }
it.fields = ordered_fields node.fields = ordered_fields
} }
} }
ast.DeferStmt { ast.DeferStmt {
c.stmts(it.stmts) c.stmts(node.stmts)
} }
ast.EnumDecl { ast.EnumDecl {
c.enum_decl(it) c.enum_decl(node)
} }
ast.ExprStmt { ast.ExprStmt {
it.typ = c.expr(it.expr) node.typ = c.expr(node.expr)
c.expected_type = table.void_type c.expected_type = table.void_type
c.check_expr_opt_call(it.expr, table.void_type) c.check_expr_opt_call(node.expr, table.void_type)
// TODO This should work, even if it's prolly useless .-. // TODO This should work, even if it's prolly useless .-.
// it.typ = c.check_expr_opt_call(it.expr, table.void_type) // it.typ = c.check_expr_opt_call(it.expr, table.void_type)
} }
ast.FnDecl { ast.FnDecl {
c.fn_decl(it) c.fn_decl(node)
} }
ast.ForCStmt { ast.ForCStmt {
c.in_for_count++ c.in_for_count++
c.stmt(it.init) c.stmt(node.init)
c.expr(it.cond) c.expr(node.cond)
c.stmt(it.inc) c.stmt(node.inc)
// c.expr(it.inc) // c.expr(it.inc)
c.stmts(it.stmts) c.stmts(node.stmts)
c.in_for_count-- c.in_for_count--
} }
ast.ForInStmt { ast.ForInStmt {
c.in_for_count++ c.in_for_count++
typ := c.expr(it.cond) typ := c.expr(node.cond)
typ_idx := typ.idx() typ_idx := typ.idx()
if it.is_range { if node.is_range {
high_type_idx := c.expr(it.high).idx() high_type_idx := c.expr(node.high).idx()
if typ_idx in table.integer_type_idxs && high_type_idx !in table.integer_type_idxs { if typ_idx in table.integer_type_idxs && high_type_idx !in table.integer_type_idxs {
c.error('range types do not match', it.cond.position()) 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 { } 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', it.cond.position()) 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 { } else if typ_idx == table.bool_type_idx || high_type_idx == table.bool_type_idx {
c.error('range type can not be bool', it.cond.position()) 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 { } else if typ_idx == table.string_type_idx || high_type_idx == table.string_type_idx {
c.error('range type can not be string', it.cond.position()) c.error('range type can not be string', node.cond.position())
} }
c.expr(it.high) c.expr(node.high)
} else { } else {
mut scope := c.file.scope.innermost(it.pos.pos) mut scope := c.file.scope.innermost(node.pos.pos)
sym := c.table.get_type_symbol(typ) sym := c.table.get_type_symbol(typ)
if sym.kind == .map && !(it.key_var.len > 0 && it.val_var.len > 0) { 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' + 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', it.pos) 'use `_` if you do not need the variable', node.pos)
} }
if it.key_var.len > 0 { if node.key_var.len > 0 {
key_type := match sym.kind { key_type := match sym.kind {
.map { sym.map_info().key_type } .map { sym.map_info().key_type }
else { table.int_type } else { table.int_type }
@ -1817,85 +1817,85 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
match mut node { match mut node {
ast.AnonFn { ast.AnonFn {
keep_fn := c.cur_fn keep_fn := c.cur_fn
c.cur_fn = &it.decl c.cur_fn = &node.decl
c.stmts(it.decl.stmts) c.stmts(node.decl.stmts)
c.cur_fn = keep_fn c.cur_fn = keep_fn
return it.typ return node.typ
} }
ast.ArrayInit { ast.ArrayInit {
return c.array_init(mut it) return c.array_init(mut node)
} }
ast.AsCast { ast.AsCast {
it.expr_type = c.expr(it.expr) node.expr_type = c.expr(node.expr)
expr_type_sym := c.table.get_type_symbol(it.expr_type) expr_type_sym := c.table.get_type_symbol(node.expr_type)
type_sym := c.table.get_type_symbol(it.typ) type_sym := c.table.get_type_symbol(node.typ)
if expr_type_sym.kind == .sum_type { if expr_type_sym.kind == .sum_type {
info := expr_type_sym.info as table.SumType info := expr_type_sym.info as table.SumType
if it.typ !in info.variants { if node.typ !in info.variants {
c.error('cannot cast `$expr_type_sym.name` to `$type_sym.name`', it.pos) c.error('cannot cast `$expr_type_sym.name` to `$type_sym.name`', node.pos)
// c.error('only $info.variants can be casted to `$typ`', it.pos) // c.error('only $info.variants can be casted to `$typ`', it.pos)
} }
} else { } else {
// //
c.error('cannot cast non sum type `$type_sym.name` using `as`', it.pos) c.error('cannot cast non sum type `$type_sym.name` using `as`', node.pos)
} }
return it.typ.to_ptr() return node.typ.to_ptr()
// return it.typ // return it.typ
} }
ast.Assoc { ast.Assoc {
scope := c.file.scope.innermost(it.pos.pos) scope := c.file.scope.innermost(node.pos.pos)
v := scope.find_var(it.var_name) or { v := scope.find_var(node.var_name) or {
panic(err) panic(err)
} }
for i, _ in it.fields { for i, _ in node.fields {
c.expr(it.exprs[i]) c.expr(node.exprs[i])
} }
it.typ = v.typ node.typ = v.typ
return v.typ return v.typ
} }
ast.BoolLiteral { ast.BoolLiteral {
return table.bool_type return table.bool_type
} }
ast.CastExpr { ast.CastExpr {
it.expr_type = c.expr(it.expr) node.expr_type = c.expr(node.expr)
sym := c.table.get_type_symbol(it.expr_type) sym := c.table.get_type_symbol(node.expr_type)
if it.typ == table.string_type && !(sym.kind in [.byte, .byteptr] || (sym.kind == if node.typ == table.string_type && !(sym.kind in [.byte, .byteptr] || (sym.kind ==
.array && sym.name == 'array_byte')) { .array && sym.name == 'array_byte')) {
type_name := c.table.type_to_str(it.expr_type) type_name := c.table.type_to_str(node.expr_type)
c.error('cannot cast type `$type_name` to string, use `x.str()` instead', it.pos) c.error('cannot cast type `$type_name` to string, use `x.str()` instead', node.pos)
} }
if it.expr_type == table.string_type { if node.expr_type == table.string_type {
mut error_msg := 'cannot cast a string' mut error_msg := 'cannot cast a string'
if it.expr is ast.StringLiteral { if node.expr is ast.StringLiteral {
str_lit := it.expr as ast.StringLiteral str_lit := node.expr as ast.StringLiteral
if str_lit.val.len == 1 { if str_lit.val.len == 1 {
error_msg += ", for denoting characters use `$str_lit.val` instead of '$str_lit.val'" error_msg += ", for denoting characters use `$str_lit.val` instead of '$str_lit.val'"
} }
} }
c.error(error_msg, it.pos) c.error(error_msg, node.pos)
} }
if it.has_arg { if node.has_arg {
c.expr(it.arg) c.expr(node.arg)
} }
it.typname = c.table.get_type_symbol(it.typ).name node.typname = c.table.get_type_symbol(node.typ).name
return it.typ return node.typ
} }
ast.CallExpr { ast.CallExpr {
return c.call_expr(mut it) return c.call_expr(mut node)
} }
ast.CharLiteral { ast.CharLiteral {
return table.byte_type return table.byte_type
} }
ast.ComptimeCall { ast.ComptimeCall {
it.sym = c.table.get_type_symbol(c.unwrap_generic(c.expr(it.left))) node.sym = c.table.get_type_symbol(c.unwrap_generic(c.expr(node.left)))
if it.is_vweb { if node.is_vweb {
x := *c.pref x := *c.pref
xx := { xx := {
x | x |
is_vweb: true is_vweb: true
} // TODO assoc parser bug } // TODO assoc parser bug
mut c2 := new_checker(c.table, xx) mut c2 := new_checker(c.table, xx)
c2.check(it.vweb_tmpl) c2.check(node.vweb_tmpl)
c.warnings << c2.warnings c.warnings << c2.warnings
c.errors << c2.errors c.errors << c2.errors
c.nr_warnings += c2.nr_warnings c.nr_warnings += c2.nr_warnings
@ -1904,59 +1904,59 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
return table.void_type return table.void_type
} }
ast.ConcatExpr { ast.ConcatExpr {
return c.concat_expr(mut it) return c.concat_expr(mut node)
} }
ast.EnumVal { ast.EnumVal {
return c.enum_val(mut it) return c.enum_val(mut node)
} }
ast.FloatLiteral { ast.FloatLiteral {
return table.any_flt_type return table.any_flt_type
} }
ast.Ident { ast.Ident {
// c.checked_ident = it.name // c.checked_ident = it.name
res := c.ident(mut it) res := c.ident(mut node)
// c.checked_ident = '' // c.checked_ident = ''
return res return res
} }
ast.IfExpr { ast.IfExpr {
return c.if_expr(mut it) return c.if_expr(mut node)
} }
ast.IfGuardExpr { ast.IfGuardExpr {
it.expr_type = c.expr(it.expr) node.expr_type = c.expr(node.expr)
return table.bool_type return table.bool_type
} }
ast.IndexExpr { ast.IndexExpr {
return c.index_expr(mut it) return c.index_expr(mut node)
} }
ast.InfixExpr { ast.InfixExpr {
return c.infix_expr(mut it) return c.infix_expr(mut node)
} }
ast.IntegerLiteral { ast.IntegerLiteral {
return table.any_int_type return table.any_int_type
} }
ast.MapInit { ast.MapInit {
return c.map_init(mut it) return c.map_init(mut node)
} }
ast.MatchExpr { ast.MatchExpr {
return c.match_expr(mut it) return c.match_expr(mut node)
} }
ast.PostfixExpr { ast.PostfixExpr {
return c.postfix_expr(it) return c.postfix_expr(node)
} }
ast.PrefixExpr { ast.PrefixExpr {
right_type := c.expr(it.right) right_type := c.expr(node.right)
// TODO: testing ref/deref strategy // TODO: testing ref/deref strategy
if it.op == .amp && !right_type.is_ptr() { if node.op == .amp && !right_type.is_ptr() {
return right_type.to_ptr() return right_type.to_ptr()
} }
if it.op == .mul && right_type.is_ptr() { if node.op == .mul && right_type.is_ptr() {
return right_type.deref() return right_type.deref()
} }
if it.op == .bit_not && !right_type.is_int() { if node.op == .bit_not && !right_type.is_int() {
c.error('operator ~ only defined on int types', it.pos) c.error('operator ~ only defined on int types', node.pos)
} }
if it.op == .not && right_type != table.bool_type_idx { if node.op == .not && right_type != table.bool_type_idx {
c.error('! operator can only be used with bool types', it.pos) c.error('! operator can only be used with bool types', node.pos)
} }
return right_type return right_type
} }
@ -1968,47 +1968,47 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
return table.void_type return table.void_type
} }
ast.ParExpr { ast.ParExpr {
return c.expr(it.expr) return c.expr(node.expr)
} }
ast.RangeExpr { ast.RangeExpr {
// never happens // never happens
return table.void_type return table.void_type
} }
ast.SelectorExpr { ast.SelectorExpr {
return c.selector_expr(mut it) return c.selector_expr(mut node)
} }
ast.SizeOf { ast.SizeOf {
return table.u32_type return table.u32_type
} }
ast.SqlExpr { ast.SqlExpr {
return c.sql_expr(it) return c.sql_expr(node)
} }
ast.StringLiteral { ast.StringLiteral {
if it.language == .c { if node.language == .c {
return table.byteptr_type return table.byteptr_type
} }
return table.string_type return table.string_type
} }
ast.StringInterLiteral { ast.StringInterLiteral {
return c.string_inter_lit(mut it) return c.string_inter_lit(mut node)
} }
ast.StructInit { ast.StructInit {
return c.struct_init(mut it) return c.struct_init(mut node)
} }
ast.Type { ast.Type {
return it.typ return node.typ
} }
ast.TypeOf { ast.TypeOf {
it.expr_type = c.expr(it.expr) node.expr_type = c.expr(node.expr)
return table.string_type return table.string_type
} }
ast.Likely { ast.Likely {
ltype := c.expr(it.expr) ltype := c.expr(node.expr)
if !c.check_types(ltype, table.bool_type) { if !c.check_types(ltype, table.bool_type) {
ltype_sym := c.table.get_type_symbol(ltype) ltype_sym := c.table.get_type_symbol(ltype)
lname := if it.is_likely { '_likely_' } else { '_unlikely_' } lname := if node.is_likely { '_likely_' } else { '_unlikely_' }
c.error('`${lname}()` expects a boolean expression, instead it got `${ltype_sym.name}`', c.error('`${lname}()` expects a boolean expression, instead it got `$ltype_sym.name`',
it.pos) node.pos)
} }
return table.bool_type return table.bool_type
} }
@ -2051,21 +2051,21 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
ast.GlobalDecl { ast.GlobalDecl {
ident.kind = .global ident.kind = .global
ident.info = ast.IdentVar{ ident.info = ast.IdentVar{
typ: it.typ typ: obj.typ
} }
return it.typ return obj.typ
} }
ast.Var { ast.Var {
mut typ := it.typ mut typ := obj.typ
if typ == 0 { if typ == 0 {
if it.expr is ast.Ident { if obj.expr is ast.Ident {
inner_ident := it.expr as ast.Ident inner_ident := obj.expr as ast.Ident
if inner_ident.kind == .unresolved { if inner_ident.kind == .unresolved {
c.error('unresolved variable: `$ident.name`', ident.pos) c.error('unresolved variable: `$ident.name`', ident.pos)
return table.void_type return table.void_type
} }
} }
typ = c.expr(it.expr) typ = c.expr(obj.expr)
} }
is_optional := typ.has_flag(.optional) is_optional := typ.has_flag(.optional)
ident.kind = .variable ident.kind = .variable
@ -2080,7 +2080,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
// typ = c.cur_generic_type // typ = c.cur_generic_type
// } // }
// } else { // } else {
it.typ = typ obj.typ = typ
// unwrap optional (`println(x)`) // unwrap optional (`println(x)`)
if is_optional { if is_optional {
return typ.clear_flag(.optional) return typ.clear_flag(.optional)
@ -2098,16 +2098,16 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
if obj := c.file.global_scope.find(name) { if obj := c.file.global_scope.find(name) {
match obj { match obj {
ast.ConstField { ast.ConstField {
mut typ := it.typ mut typ := obj.typ
if typ == 0 { if typ == 0 {
typ = c.expr(it.expr) typ = c.expr(obj.expr)
} }
ident.name = name ident.name = name
ident.kind = .constant ident.kind = .constant
ident.info = ast.IdentVar{ ident.info = ast.IdentVar{
typ: typ typ: typ
} }
it.typ = typ obj.typ = typ
return typ return typ
} }
else {} else {}
@ -2224,8 +2224,8 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
for expr in branch.exprs { for expr in branch.exprs {
mut key := '' mut key := ''
match expr { match expr {
ast.Type { key = c.table.type_to_str(it.typ) } ast.Type { key = c.table.type_to_str(expr.typ) }
ast.EnumVal { key = it.val } ast.EnumVal { key = expr.val }
else { key = expr.str() } else { key = expr.str() }
} }
val := if key in branch_exprs { branch_exprs[key] } else { 0 } val := if key in branch_exprs { branch_exprs[key] } else { 0 }