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 {
match stmt {
ast.ConstDecl {
if it.is_pub {
c.warn('const $no_pub_in_main_warning', it.pos)
if stmt.is_pub {
c.warn('const $no_pub_in_main_warning', stmt.pos)
}
}
ast.ConstField {
if it.is_pub {
c.warn('const field `$it.name` $no_pub_in_main_warning', it.pos)
if stmt.is_pub {
c.warn('const field `$stmt.name` $no_pub_in_main_warning', stmt.pos)
}
}
ast.EnumDecl {
if it.is_pub {
c.warn('enum `$it.name` $no_pub_in_main_warning', it.pos)
if stmt.is_pub {
c.warn('enum `$stmt.name` $no_pub_in_main_warning', stmt.pos)
}
}
ast.FnDecl {
if it.name == 'main' {
if stmt.name == 'main' {
has_main_fn = true
if it.is_pub {
c.error('function `main` cannot be declared public', it.pos)
if stmt.is_pub {
c.error('function `main` cannot be declared public', stmt.pos)
}
if it.args.len > 0 {
c.error('function `main` cannot have arguments', it.pos)
if stmt.args.len > 0 {
c.error('function `main` cannot have arguments', stmt.pos)
}
if it.return_type != table.void_type {
c.error('function `main` cannot return values', it.pos)
if stmt.return_type != table.void_type {
c.error('function `main` cannot return values', stmt.pos)
}
} else {
if it.is_pub && !it.is_method {
c.warn('function `$it.name` $no_pub_in_main_warning', it.pos)
if stmt.is_pub && !stmt.is_method {
c.warn('function `$stmt.name` $no_pub_in_main_warning', stmt.pos)
}
}
if it.ctdefine.len > 0 {
if it.return_type != table.void_type {
c.error('only functions that do NOT return values can have `[if ${it.ctdefine}]` tags',
it.pos)
if stmt.ctdefine.len > 0 {
if stmt.return_type != table.void_type {
c.error('only functions that do NOT return values can have `[if $stmt.ctdefine]` tags',
stmt.pos)
}
}
}
ast.StructDecl {
if it.is_pub {
c.warn('struct `$it.name` $no_pub_in_main_warning', it.pos)
if stmt.is_pub {
c.warn('struct `$stmt.name` $no_pub_in_main_warning', stmt.pos)
}
}
ast.TypeDecl {
// type_decl := stmt as ast.TypeDecl
if it is ast.AliasTypeDecl {
alias_decl := it as ast.AliasTypeDecl
if stmt is ast.AliasTypeDecl {
alias_decl := stmt as ast.AliasTypeDecl
if alias_decl.is_pub {
c.warn('type alias `$alias_decl.name` $no_pub_in_main_warning', alias_decl.pos)
}
} else if it is ast.SumTypeDecl {
sum_decl := it as ast.SumTypeDecl
} else if stmt is ast.SumTypeDecl {
sum_decl := stmt as ast.SumTypeDecl
if sum_decl.is_pub {
c.warn('sum type `$sum_decl.name` $no_pub_in_main_warning', sum_decl.pos)
}
} else if it is ast.FnTypeDecl {
fn_decl := it as ast.FnTypeDecl
} else if stmt is ast.FnTypeDecl {
fn_decl := stmt as ast.FnTypeDecl
if fn_decl.is_pub {
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 {
// TODO Replace `c.file.mod.name != 'time'` by `it.language != .v` once available
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 {
c.error("type `$typ_sym.name` doesn't exist", it.pos)
c.error("type `$typ_sym.name` doesn't exist", node.pos)
}
}
ast.FnTypeDecl {
c.check_valid_pascal_case(it.name, 'fn type', it.pos)
typ_sym := c.table.get_type_symbol(it.typ)
c.check_valid_pascal_case(node.name, 'fn type', node.pos)
typ_sym := c.table.get_type_symbol(node.typ)
fn_typ_info := typ_sym.info as table.FnType
fn_info := fn_typ_info.func
ret_sym := c.table.get_type_symbol(fn_info.return_type)
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 {
arg_sym := c.table.get_type_symbol(arg.typ)
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 {
c.check_valid_pascal_case(it.name, 'sum type', it.pos)
for typ in it.sub_types {
c.check_valid_pascal_case(node.name, 'sum type', node.pos)
for typ in node.sub_types {
typ_sym := c.table.get_type_symbol(typ)
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) {
field_expr_type_sym := c.table.get_type_symbol(field_expr_type)
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())
}
}
@ -404,7 +404,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
continue
}
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)
}
}
@ -498,7 +498,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
if infix_expr.op == .mod {
c.error('float modulo not allowed, use math.fmod() instead', pos)
} 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)
}
}
@ -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
typ_sym := c.table.get_type_symbol(type_expr.typ)
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 {
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
}
ast.Ident {
scope := c.file.scope.innermost(it.pos.pos)
if v := scope.find_var(it.name) {
scope := c.file.scope.innermost(expr.pos.pos)
if v := scope.find_var(expr.name) {
if !v.is_mut && !v.typ.is_ptr() {
c.error('`$it.name` is immutable, declare it with `mut` to make it mutable',
it.pos)
c.error('`$expr.name` is immutable, declare it with `mut` to make it mutable',
expr.pos)
}
v.is_changed = true
} else if it.name in c.const_names {
c.error('cannot modify constant `$it.name`', it.pos)
} else if expr.name in c.const_names {
c.error('cannot modify constant `$expr.name`', expr.pos)
}
}
ast.IndexExpr {
c.fail_if_immutable(it.left)
c.fail_if_immutable(expr.left)
}
ast.ParExpr {
c.fail_if_immutable(it.expr)
c.fail_if_immutable(expr.expr)
}
ast.PrefixExpr {
c.fail_if_immutable(it.right)
c.fail_if_immutable(expr.right)
}
ast.SelectorExpr {
// retrieve table.Field
if it.expr_type == 0 {
c.error('0 type in SelectorExpr', it.pos)
if expr.expr_type == 0 {
c.error('0 type in SelectorExpr', expr.pos)
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 {
.struct_ {
struct_info := typ_sym.info as table.Struct
field_info := struct_info.find_field(it.field_name) or {
type_str := c.table.type_to_str(it.expr_type)
c.error('unknown field `${type_str}.$it.field_name`', it.pos)
field_info := struct_info.find_field(expr.field_name) or {
type_str := c.table.type_to_str(expr.expr_type)
c.error('unknown field `${type_str}.$expr.field_name`', expr.pos)
return
}
if !field_info.is_mut {
type_str := c.table.type_to_str(it.expr_type)
c.error('field `$it.field_name` of struct `${type_str}` is immutable',
it.pos)
type_str := c.table.type_to_str(expr.expr_type)
c.error('field `$expr.field_name` of struct `$type_str` is immutable',
expr.pos)
}
c.fail_if_immutable(it.expr)
c.fail_if_immutable(expr.expr)
}
.array, .string {
// This should only happen in `builtin`
// 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.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 {
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) {
if or_expr.kind == .propagate {
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)
}
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 {
ast.ExprStmt {
it.typ = c.expr(it.expr)
type_fits := c.check_types(it.typ, ret_type)
is_panic_or_exit := is_expr_panic_or_exit(it.expr)
last_stmt.typ = c.expr(last_stmt.expr)
type_fits := c.check_types(last_stmt.typ, ret_type)
is_panic_or_exit := is_expr_panic_or_exit(last_stmt.expr)
if type_fits || is_panic_or_exit {
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
c.error('wrong return type `$type_name` in the `or {}` block, expected `$expected_type_name`',
it.pos)
last_stmt.pos)
return
}
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',
it.tok.position())
last_stmt.tok.position())
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 {
match expr {
ast.CallExpr { return it.name in ['panic', 'exit'] }
ast.CallExpr { return expr.name in ['panic', 'exit'] }
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
match left {
ast.Ident {
if it.kind == .blank_ident {
if left.kind == .blank_ident {
left_type = right_type
assign_stmt.left_types[i] = right_type
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 {
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 ident_var_info := it.var_info()
mut ident_var_info := left.var_info()
ident_var_info.typ = left_type
it.info = ident_var_info
scope.update_var_type(it.name, left_type)
left.info = ident_var_info
scope.update_var_type(left.name, left_type)
}
}
ast.PrefixExpr {
// 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',
assign_stmt.pos)
}
@ -1409,19 +1409,19 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
}
.mult_assign, .div_assign {
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())
} 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())
}
}
.and_assign, .or_assign, .xor_assign, .mod_assign, .left_shift_assign, .right_shift_assign {
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())
} 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())
}
}
@ -1429,7 +1429,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
}
// Dual sides check (compatibility check)
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())
}
}
@ -1588,36 +1588,36 @@ fn (mut c Checker) stmt(node ast.Stmt) {
// c.expected_type = table.void_type
match mut node {
ast.AssertStmt {
assert_type := c.expr(it.expr)
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',
it.pos)
c.error('assert can be used only with `bool` expressions, but found `$atype_name` instead',
node.pos)
}
}
// ast.Attr {}
ast.AssignStmt {
c.assign_stmt(mut it)
c.assign_stmt(mut node)
}
ast.Block {
c.stmts(it.stmts)
c.stmts(node.stmts)
}
ast.BranchStmt {
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 {
// c.expr(it.cond)
c.stmts(it.stmts)
if it.has_else {
c.stmts(it.else_stmts)
c.stmts(node.stmts)
if node.has_else {
c.stmts(node.else_stmts)
}
}
ast.ConstDecl {
mut field_names := []string{}
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
if field.name in c.const_names {
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 done_fields := []int{}
for i, field in it.fields {
for i, field in node.fields {
c.const_decl = field.name
c.const_deps << field.name
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 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 {
needs_order = true
x := field_order[j]
@ -1650,60 +1650,60 @@ fn (mut c Checker) stmt(node ast.Stmt) {
if needs_order {
mut ordered_fields := []ast.ConstField{}
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 {
c.stmts(it.stmts)
c.stmts(node.stmts)
}
ast.EnumDecl {
c.enum_decl(it)
c.enum_decl(node)
}
ast.ExprStmt {
it.typ = c.expr(it.expr)
node.typ = c.expr(node.expr)
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 .-.
// it.typ = c.check_expr_opt_call(it.expr, table.void_type)
}
ast.FnDecl {
c.fn_decl(it)
c.fn_decl(node)
}
ast.ForCStmt {
c.in_for_count++
c.stmt(it.init)
c.expr(it.cond)
c.stmt(it.inc)
c.stmt(node.init)
c.expr(node.cond)
c.stmt(node.inc)
// c.expr(it.inc)
c.stmts(it.stmts)
c.stmts(node.stmts)
c.in_for_count--
}
ast.ForInStmt {
c.in_for_count++
typ := c.expr(it.cond)
typ := c.expr(node.cond)
typ_idx := typ.idx()
if it.is_range {
high_type_idx := c.expr(it.high).idx()
if node.is_range {
high_type_idx := c.expr(node.high).idx()
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 {
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 {
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 {
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 {
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)
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' +
'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 {
.map { sym.map_info().key_type }
else { table.int_type }
@ -1817,85 +1817,85 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
match mut node {
ast.AnonFn {
keep_fn := c.cur_fn
c.cur_fn = &it.decl
c.stmts(it.decl.stmts)
c.cur_fn = &node.decl
c.stmts(node.decl.stmts)
c.cur_fn = keep_fn
return it.typ
return node.typ
}
ast.ArrayInit {
return c.array_init(mut it)
return c.array_init(mut node)
}
ast.AsCast {
it.expr_type = c.expr(it.expr)
expr_type_sym := c.table.get_type_symbol(it.expr_type)
type_sym := c.table.get_type_symbol(it.typ)
node.expr_type = c.expr(node.expr)
expr_type_sym := c.table.get_type_symbol(node.expr_type)
type_sym := c.table.get_type_symbol(node.typ)
if expr_type_sym.kind == .sum_type {
info := expr_type_sym.info as table.SumType
if it.typ !in info.variants {
c.error('cannot cast `$expr_type_sym.name` to `$type_sym.name`', it.pos)
if node.typ !in info.variants {
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)
}
} 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
}
ast.Assoc {
scope := c.file.scope.innermost(it.pos.pos)
v := scope.find_var(it.var_name) or {
scope := c.file.scope.innermost(node.pos.pos)
v := scope.find_var(node.var_name) or {
panic(err)
}
for i, _ in it.fields {
c.expr(it.exprs[i])
for i, _ in node.fields {
c.expr(node.exprs[i])
}
it.typ = v.typ
node.typ = v.typ
return v.typ
}
ast.BoolLiteral {
return table.bool_type
}
ast.CastExpr {
it.expr_type = c.expr(it.expr)
sym := c.table.get_type_symbol(it.expr_type)
if it.typ == table.string_type && !(sym.kind in [.byte, .byteptr] || (sym.kind ==
node.expr_type = c.expr(node.expr)
sym := c.table.get_type_symbol(node.expr_type)
if node.typ == table.string_type && !(sym.kind in [.byte, .byteptr] || (sym.kind ==
.array && sym.name == 'array_byte')) {
type_name := c.table.type_to_str(it.expr_type)
c.error('cannot cast type `$type_name` to string, use `x.str()` instead', it.pos)
type_name := c.table.type_to_str(node.expr_type)
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'
if it.expr is ast.StringLiteral {
str_lit := it.expr as ast.StringLiteral
if node.expr is ast.StringLiteral {
str_lit := node.expr as ast.StringLiteral
if str_lit.val.len == 1 {
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 {
c.expr(it.arg)
if node.has_arg {
c.expr(node.arg)
}
it.typname = c.table.get_type_symbol(it.typ).name
return it.typ
node.typname = c.table.get_type_symbol(node.typ).name
return node.typ
}
ast.CallExpr {
return c.call_expr(mut it)
return c.call_expr(mut node)
}
ast.CharLiteral {
return table.byte_type
}
ast.ComptimeCall {
it.sym = c.table.get_type_symbol(c.unwrap_generic(c.expr(it.left)))
if it.is_vweb {
node.sym = c.table.get_type_symbol(c.unwrap_generic(c.expr(node.left)))
if node.is_vweb {
x := *c.pref
xx := {
x |
is_vweb: true
} // TODO assoc parser bug
mut c2 := new_checker(c.table, xx)
c2.check(it.vweb_tmpl)
c2.check(node.vweb_tmpl)
c.warnings << c2.warnings
c.errors << c2.errors
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
}
ast.ConcatExpr {
return c.concat_expr(mut it)
return c.concat_expr(mut node)
}
ast.EnumVal {
return c.enum_val(mut it)
return c.enum_val(mut node)
}
ast.FloatLiteral {
return table.any_flt_type
}
ast.Ident {
// c.checked_ident = it.name
res := c.ident(mut it)
res := c.ident(mut node)
// c.checked_ident = ''
return res
}
ast.IfExpr {
return c.if_expr(mut it)
return c.if_expr(mut node)
}
ast.IfGuardExpr {
it.expr_type = c.expr(it.expr)
node.expr_type = c.expr(node.expr)
return table.bool_type
}
ast.IndexExpr {
return c.index_expr(mut it)
return c.index_expr(mut node)
}
ast.InfixExpr {
return c.infix_expr(mut it)
return c.infix_expr(mut node)
}
ast.IntegerLiteral {
return table.any_int_type
}
ast.MapInit {
return c.map_init(mut it)
return c.map_init(mut node)
}
ast.MatchExpr {
return c.match_expr(mut it)
return c.match_expr(mut node)
}
ast.PostfixExpr {
return c.postfix_expr(it)
return c.postfix_expr(node)
}
ast.PrefixExpr {
right_type := c.expr(it.right)
right_type := c.expr(node.right)
// 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()
}
if it.op == .mul && right_type.is_ptr() {
if node.op == .mul && right_type.is_ptr() {
return right_type.deref()
}
if it.op == .bit_not && !right_type.is_int() {
c.error('operator ~ only defined on int types', it.pos)
if node.op == .bit_not && !right_type.is_int() {
c.error('operator ~ only defined on int types', node.pos)
}
if it.op == .not && right_type != table.bool_type_idx {
c.error('! operator can only be used with bool types', it.pos)
if node.op == .not && right_type != table.bool_type_idx {
c.error('! operator can only be used with bool types', node.pos)
}
return right_type
}
@ -1968,47 +1968,47 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
return table.void_type
}
ast.ParExpr {
return c.expr(it.expr)
return c.expr(node.expr)
}
ast.RangeExpr {
// never happens
return table.void_type
}
ast.SelectorExpr {
return c.selector_expr(mut it)
return c.selector_expr(mut node)
}
ast.SizeOf {
return table.u32_type
}
ast.SqlExpr {
return c.sql_expr(it)
return c.sql_expr(node)
}
ast.StringLiteral {
if it.language == .c {
if node.language == .c {
return table.byteptr_type
}
return table.string_type
}
ast.StringInterLiteral {
return c.string_inter_lit(mut it)
return c.string_inter_lit(mut node)
}
ast.StructInit {
return c.struct_init(mut it)
return c.struct_init(mut node)
}
ast.Type {
return it.typ
return node.typ
}
ast.TypeOf {
it.expr_type = c.expr(it.expr)
node.expr_type = c.expr(node.expr)
return table.string_type
}
ast.Likely {
ltype := c.expr(it.expr)
ltype := c.expr(node.expr)
if !c.check_types(ltype, table.bool_type) {
ltype_sym := c.table.get_type_symbol(ltype)
lname := if it.is_likely { '_likely_' } else { '_unlikely_' }
c.error('`${lname}()` expects a boolean expression, instead it got `${ltype_sym.name}`',
it.pos)
lname := if node.is_likely { '_likely_' } else { '_unlikely_' }
c.error('`${lname}()` expects a boolean expression, instead it got `$ltype_sym.name`',
node.pos)
}
return table.bool_type
}
@ -2051,21 +2051,21 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
ast.GlobalDecl {
ident.kind = .global
ident.info = ast.IdentVar{
typ: it.typ
typ: obj.typ
}
return it.typ
return obj.typ
}
ast.Var {
mut typ := it.typ
mut typ := obj.typ
if typ == 0 {
if it.expr is ast.Ident {
inner_ident := it.expr as ast.Ident
if obj.expr is ast.Ident {
inner_ident := obj.expr as ast.Ident
if inner_ident.kind == .unresolved {
c.error('unresolved variable: `$ident.name`', ident.pos)
return table.void_type
}
}
typ = c.expr(it.expr)
typ = c.expr(obj.expr)
}
is_optional := typ.has_flag(.optional)
ident.kind = .variable
@ -2080,7 +2080,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
// typ = c.cur_generic_type
// }
// } else {
it.typ = typ
obj.typ = typ
// unwrap optional (`println(x)`)
if is_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) {
match obj {
ast.ConstField {
mut typ := it.typ
mut typ := obj.typ
if typ == 0 {
typ = c.expr(it.expr)
typ = c.expr(obj.expr)
}
ident.name = name
ident.kind = .constant
ident.info = ast.IdentVar{
typ: typ
}
it.typ = typ
obj.typ = typ
return typ
}
else {}
@ -2224,8 +2224,8 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
for expr in branch.exprs {
mut key := ''
match expr {
ast.Type { key = c.table.type_to_str(it.typ) }
ast.EnumVal { key = it.val }
ast.Type { key = c.table.type_to_str(expr.typ) }
ast.EnumVal { key = expr.val }
else { key = expr.str() }
}
val := if key in branch_exprs { branch_exprs[key] } else { 0 }