all: use the new types with old syntax (#6922)
							parent
							
								
									8be9bdacd1
								
							
						
					
					
						commit
						aa6303f0b2
					
				| 
						 | 
				
			
			@ -7,7 +7,7 @@ import v.token
 | 
			
		|||
import v.table
 | 
			
		||||
import v.errors
 | 
			
		||||
 | 
			
		||||
pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl | UnionSumTypeDecl
 | 
			
		||||
pub __type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl | UnionSumTypeDecl
 | 
			
		||||
 | 
			
		||||
pub __type Expr = AnonFn | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral | CTempVar |
 | 
			
		||||
	CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ConcatExpr | EnumVal |
 | 
			
		||||
| 
						 | 
				
			
			@ -16,14 +16,14 @@ pub __type Expr = AnonFn | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral | C
 | 
			
		|||
	RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral |
 | 
			
		||||
	StructInit | Type | TypeOf | UnsafeExpr
 | 
			
		||||
 | 
			
		||||
pub type Stmt = AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | DeferStmt |
 | 
			
		||||
	EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt |
 | 
			
		||||
	GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | SqlStmt |
 | 
			
		||||
	StructDecl | TypeDecl
 | 
			
		||||
pub __type Stmt = AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl |
 | 
			
		||||
	DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl |
 | 
			
		||||
	GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return |
 | 
			
		||||
	SqlStmt | StructDecl | TypeDecl
 | 
			
		||||
 | 
			
		||||
// NB: when you add a new Expr or Stmt type with a .pos field, remember to update
 | 
			
		||||
// the .position() token.Position methods too.
 | 
			
		||||
pub type ScopeObject = ConstField | GlobalField | Var
 | 
			
		||||
pub __type ScopeObject = ConstField | GlobalField | Var
 | 
			
		||||
 | 
			
		||||
pub struct Type {
 | 
			
		||||
pub:
 | 
			
		||||
| 
						 | 
				
			
			@ -430,7 +430,7 @@ pub mut:
 | 
			
		|||
	share       table.ShareType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub type IdentInfo = IdentFn | IdentVar
 | 
			
		||||
pub __type IdentInfo = IdentFn | IdentVar
 | 
			
		||||
 | 
			
		||||
pub enum IdentKind {
 | 
			
		||||
	unresolved
 | 
			
		||||
| 
						 | 
				
			
			@ -457,9 +457,9 @@ pub mut:
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
pub fn (i &Ident) var_info() IdentVar {
 | 
			
		||||
	match i.info as info {
 | 
			
		||||
	match union mut i.info {
 | 
			
		||||
		IdentVar {
 | 
			
		||||
			return *info
 | 
			
		||||
			return i.info
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			// return IdentVar{}
 | 
			
		||||
| 
						 | 
				
			
			@ -1123,7 +1123,7 @@ pub fn (expr Expr) is_expr() bool {
 | 
			
		|||
 | 
			
		||||
// check if stmt can be an expression in C
 | 
			
		||||
pub fn (stmt Stmt) check_c_expr() ? {
 | 
			
		||||
	match stmt {
 | 
			
		||||
	match union stmt {
 | 
			
		||||
		AssignStmt {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -1148,10 +1148,10 @@ pub:
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
pub fn (stmt Stmt) position() token.Position {
 | 
			
		||||
	match stmt {
 | 
			
		||||
	match union stmt {
 | 
			
		||||
		AssertStmt, AssignStmt, Block, BranchStmt, CompFor, ConstDecl, DeferStmt, EnumDecl, ExprStmt, FnDecl, ForCStmt, ForInStmt, ForStmt, GotoLabel, GotoStmt, Import, Return, StructDecl, GlobalDecl, HashStmt, InterfaceDecl, Module, SqlStmt { return stmt.pos }
 | 
			
		||||
		GoStmt { return stmt.call_expr.position() }
 | 
			
		||||
		TypeDecl { match stmt {
 | 
			
		||||
		TypeDecl { match union stmt {
 | 
			
		||||
				AliasTypeDecl, FnTypeDecl, SumTypeDecl, UnionSumTypeDecl { return stmt.pos }
 | 
			
		||||
			} }
 | 
			
		||||
		// Please, do NOT use else{} here.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,8 +73,8 @@ pub fn (s &Scope) is_known(name string) bool {
 | 
			
		|||
 | 
			
		||||
pub fn (s &Scope) find_var(name string) ?&Var {
 | 
			
		||||
	if obj := s.find(name) {
 | 
			
		||||
		match obj {
 | 
			
		||||
			Var { return obj }
 | 
			
		||||
		match union obj {
 | 
			
		||||
			Var { return &obj }
 | 
			
		||||
			else {}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -83,8 +83,8 @@ pub fn (s &Scope) find_var(name string) ?&Var {
 | 
			
		|||
 | 
			
		||||
pub fn (s &Scope) find_const(name string) ?&ConstField {
 | 
			
		||||
	if obj := s.find(name) {
 | 
			
		||||
		match obj {
 | 
			
		||||
			ConstField { return obj }
 | 
			
		||||
		match union obj {
 | 
			
		||||
			ConstField { return &obj }
 | 
			
		||||
			else {}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -100,12 +100,13 @@ pub fn (s &Scope) known_var(name string) bool {
 | 
			
		|||
 | 
			
		||||
pub fn (mut s Scope) update_var_type(name string, typ table.Type) {
 | 
			
		||||
	s.end_pos = s.end_pos // TODO mut bug
 | 
			
		||||
	match mut s.objects[name] {
 | 
			
		||||
	mut obj := s.objects[name]
 | 
			
		||||
	match union mut obj {
 | 
			
		||||
		Var {
 | 
			
		||||
			if it.typ == typ {
 | 
			
		||||
			if obj.typ == typ {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			it.typ = typ
 | 
			
		||||
			obj.typ = typ
 | 
			
		||||
		}
 | 
			
		||||
		else {}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -181,7 +182,7 @@ pub fn (sc &Scope) show(depth int, max_depth int) string {
 | 
			
		|||
	}
 | 
			
		||||
	out += '$indent# $sc.start_pos - $sc.end_pos\n'
 | 
			
		||||
	for _, obj in sc.objects {
 | 
			
		||||
		match obj {
 | 
			
		||||
		match union obj {
 | 
			
		||||
			ConstField { out += '$indent  * const: $obj.name - $obj.typ\n' }
 | 
			
		||||
			Var { out += '$indent  * var: $obj.name - $obj.typ\n' }
 | 
			
		||||
			else {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -302,7 +302,7 @@ pub fn (node &BranchStmt) str() string {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
pub fn (node Stmt) str() string {
 | 
			
		||||
	match node {
 | 
			
		||||
	match union node {
 | 
			
		||||
		AssignStmt {
 | 
			
		||||
			mut out := ''
 | 
			
		||||
			for i, left in node.left {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ pub fn (b &Builder) generic_struct_insts_to_concrete() {
 | 
			
		|||
		if typ.kind == .generic_struct_inst {
 | 
			
		||||
			info := typ.info as table.GenericStructInst
 | 
			
		||||
			parent := b.table.types[info.parent_idx]
 | 
			
		||||
			mut parent_info := *(parent.info as table.Struct)
 | 
			
		||||
			mut parent_info := parent.info as table.Struct
 | 
			
		||||
			mut fields := parent_info.fields.clone()
 | 
			
		||||
			for i, _ in fields {
 | 
			
		||||
				mut field := fields[i]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,7 +95,7 @@ pub fn (mut c Checker) check(ast_file &ast.File) {
 | 
			
		|||
 | 
			
		||||
pub fn (mut c Checker) check_scope_vars(sc &ast.Scope) {
 | 
			
		||||
	for _, obj in sc.objects {
 | 
			
		||||
		match obj {
 | 
			
		||||
		match union obj {
 | 
			
		||||
			ast.Var {
 | 
			
		||||
				if !c.pref.is_repl {
 | 
			
		||||
					if !obj.is_used && obj.name[0] != `_` {
 | 
			
		||||
| 
						 | 
				
			
			@ -178,7 +178,7 @@ const (
 | 
			
		|||
fn (mut c Checker) check_file_in_main(file ast.File) bool {
 | 
			
		||||
	mut has_main_fn := false
 | 
			
		||||
	for stmt in file.stmts {
 | 
			
		||||
		match stmt {
 | 
			
		||||
		match union stmt {
 | 
			
		||||
			ast.ConstDecl {
 | 
			
		||||
				if stmt.is_pub {
 | 
			
		||||
					c.warn('const $no_pub_in_main_warning', stmt.pos)
 | 
			
		||||
| 
						 | 
				
			
			@ -278,7 +278,7 @@ fn (mut c Checker) check_valid_pascal_case(name string, identifier string, pos t
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
pub fn (mut c Checker) type_decl(node ast.TypeDecl) {
 | 
			
		||||
	match node {
 | 
			
		||||
	match union node {
 | 
			
		||||
		ast.AliasTypeDecl {
 | 
			
		||||
			// TODO Replace `c.file.mod.name != 'time'` by `it.language != .v` once available
 | 
			
		||||
			if c.file.mod.name != 'time' && c.file.mod.name != 'builtin' {
 | 
			
		||||
| 
						 | 
				
			
			@ -347,21 +347,22 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
 | 
			
		|||
	if decl.language == .v && !c.is_builtin_mod {
 | 
			
		||||
		c.check_valid_pascal_case(decl.name, 'struct name', decl.pos)
 | 
			
		||||
	}
 | 
			
		||||
	struct_sym := c.table.find_type(decl.name) or {
 | 
			
		||||
	mut struct_sym := c.table.find_type(decl.name) or {
 | 
			
		||||
		table.TypeSymbol{}
 | 
			
		||||
	}
 | 
			
		||||
	mut struct_info := struct_sym.info as table.Struct
 | 
			
		||||
	if mut struct_sym.info is table.Struct {
 | 
			
		||||
		for i, field in decl.fields {
 | 
			
		||||
			if decl.language == .v && !field.is_embed {
 | 
			
		||||
				c.check_valid_snake_case(field.name, 'field name', field.pos)
 | 
			
		||||
			}
 | 
			
		||||
			sym := c.table.get_type_symbol(field.typ)
 | 
			
		||||
			if field.is_embed {
 | 
			
		||||
			if sym.info is table.Struct as sym_info {
 | 
			
		||||
				for embed_field in sym_info.fields {
 | 
			
		||||
					already_exists := struct_info.fields.filter(it.name == embed_field.name).len > 0
 | 
			
		||||
				if mut sym.info is table.Struct {
 | 
			
		||||
					for embed_field in sym.info.fields {
 | 
			
		||||
						already_exists := struct_sym.info.fields.filter(it.name == embed_field.name).len >
 | 
			
		||||
							0
 | 
			
		||||
						if !already_exists {
 | 
			
		||||
						struct_info.fields << {
 | 
			
		||||
							struct_sym.info.fields << {
 | 
			
		||||
								embed_field |
 | 
			
		||||
								embed_alias_for: field.name
 | 
			
		||||
							}
 | 
			
		||||
| 
						 | 
				
			
			@ -410,7 +411,8 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
 | 
			
		|||
				c.expected_type = field.typ
 | 
			
		||||
				field_expr_type := c.expr(field.default_expr)
 | 
			
		||||
				c.check_expected(field_expr_type, field.typ) or {
 | 
			
		||||
				c.error('incompatible initializer for field `$field.name`: $err', field.default_expr.position())
 | 
			
		||||
					c.error('incompatible initializer for field `$field.name`: $err',
 | 
			
		||||
						field.default_expr.position())
 | 
			
		||||
				}
 | 
			
		||||
				// Check for unnecessary inits like ` = 0` and ` = ''`
 | 
			
		||||
				if field.typ.is_ptr() {
 | 
			
		||||
| 
						 | 
				
			
			@ -434,6 +436,7 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
 | 
			
		||||
| 
						 | 
				
			
			@ -938,9 +941,8 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Position) {
 | 
			
		|||
				return '', pos
 | 
			
		||||
			}
 | 
			
		||||
			mut typ_sym := c.table.get_type_symbol(c.unwrap_generic(expr.expr_type))
 | 
			
		||||
			if typ_sym.kind == .alias {
 | 
			
		||||
				alias_info := typ_sym.info as table.Alias
 | 
			
		||||
				typ_sym = c.table.get_type_symbol(alias_info.parent_type)
 | 
			
		||||
			if mut typ_sym.info is table.Alias {
 | 
			
		||||
				typ_sym = c.table.get_type_symbol(typ_sym.info.parent_type)
 | 
			
		||||
			}
 | 
			
		||||
			match typ_sym.kind {
 | 
			
		||||
				.struct_ {
 | 
			
		||||
| 
						 | 
				
			
			@ -1148,8 +1150,8 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
 | 
			
		|||
			arg_sym := c.table.get_type_symbol(arg_type)
 | 
			
		||||
			// FIXME: match expr failed for now
 | 
			
		||||
			mut ret_type := 0
 | 
			
		||||
			match arg_sym.info as info {
 | 
			
		||||
				table.FnType { ret_type = info.func.return_type }
 | 
			
		||||
			match union mut arg_sym.info {
 | 
			
		||||
				table.FnType { ret_type = arg_sym.info.func.return_type }
 | 
			
		||||
				else { ret_type = arg_type }
 | 
			
		||||
			}
 | 
			
		||||
			call_expr.return_type = c.table.find_or_register_array(ret_type, 1, c.mod)
 | 
			
		||||
| 
						 | 
				
			
			@ -1616,7 +1618,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
 | 
			
		|||
 | 
			
		||||
fn (mut c Checker) type_implements(typ table.Type, inter_typ table.Type, pos token.Position) bool {
 | 
			
		||||
	typ_sym := c.table.get_type_symbol(typ)
 | 
			
		||||
	inter_sym := c.table.get_type_symbol(inter_typ)
 | 
			
		||||
	mut inter_sym := c.table.get_type_symbol(inter_typ)
 | 
			
		||||
	styp := c.table.type_to_str(typ)
 | 
			
		||||
	for imethod in inter_sym.methods {
 | 
			
		||||
		if method := typ_sym.find_method(imethod.name) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1632,9 +1634,10 @@ fn (mut c Checker) type_implements(typ table.Type, inter_typ table.Type, pos tok
 | 
			
		|||
		}
 | 
			
		||||
		c.error("`$styp` doesn't implement method `$imethod.name`", pos)
 | 
			
		||||
	}
 | 
			
		||||
	mut inter_info := inter_sym.info as table.Interface
 | 
			
		||||
	if typ !in inter_info.types && typ_sym.kind != .interface_ {
 | 
			
		||||
		inter_info.types << typ
 | 
			
		||||
	if mut inter_sym.info is table.Interface {
 | 
			
		||||
		if typ !in inter_sym.info.types && typ_sym.kind != .interface_ {
 | 
			
		||||
			inter_sym.info.types << typ
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1686,7 +1689,7 @@ pub fn (mut c Checker) check_or_expr(or_expr ast.OrExpr, ret_type table.Type, ex
 | 
			
		|||
	}
 | 
			
		||||
	last_stmt := or_expr.stmts[stmts_len - 1]
 | 
			
		||||
	if ret_type != table.void_type {
 | 
			
		||||
		match last_stmt {
 | 
			
		||||
		match union last_stmt {
 | 
			
		||||
			ast.ExprStmt {
 | 
			
		||||
				last_stmt_typ := c.expr(last_stmt.expr)
 | 
			
		||||
				type_fits := c.check_types(last_stmt_typ, ret_type)
 | 
			
		||||
| 
						 | 
				
			
			@ -1721,7 +1724,7 @@ pub fn (mut c Checker) check_or_expr(or_expr ast.OrExpr, ret_type table.Type, ex
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		match last_stmt {
 | 
			
		||||
		match union last_stmt {
 | 
			
		||||
			ast.ExprStmt {
 | 
			
		||||
				if last_stmt.typ == table.void_type {
 | 
			
		||||
					return
 | 
			
		||||
| 
						 | 
				
			
			@ -2141,9 +2144,9 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
 | 
			
		|||
					ident_var_info.typ = left_type
 | 
			
		||||
					left.info = ident_var_info
 | 
			
		||||
					if left_type != 0 {
 | 
			
		||||
						match mut left.obj as v {
 | 
			
		||||
							ast.Var { v.typ = left_type }
 | 
			
		||||
							ast.GlobalField { v.typ = left_type }
 | 
			
		||||
						match union mut left.obj {
 | 
			
		||||
							ast.Var { left.obj.typ = left_type }
 | 
			
		||||
							ast.GlobalField { left.obj.typ = left_type }
 | 
			
		||||
							else {}
 | 
			
		||||
						}
 | 
			
		||||
						/*
 | 
			
		||||
| 
						 | 
				
			
			@ -2444,7 +2447,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
 | 
			
		|||
		eprintln('checking file: ${c.file.path:-30} | stmt pos: ${stmt_pos.str():-45} | stmt')
 | 
			
		||||
	}
 | 
			
		||||
	// c.expected_type = table.void_type
 | 
			
		||||
	match mut node {
 | 
			
		||||
	match union mut node {
 | 
			
		||||
		ast.AssertStmt {
 | 
			
		||||
			cur_exp_typ := c.expected_type
 | 
			
		||||
			assert_type := c.expr(node.expr)
 | 
			
		||||
| 
						 | 
				
			
			@ -3071,9 +3074,9 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) table.Type {
 | 
			
		|||
			c.error('cannot cast `$from_type_sym.source_name` to `$to_type_sym.source_name`',
 | 
			
		||||
				node.pos)
 | 
			
		||||
		}
 | 
			
		||||
	} else if to_type_sym.info is table.Alias as alias_info {
 | 
			
		||||
		if !c.check_types(node.expr_type, alias_info.parent_type) {
 | 
			
		||||
			parent_type_sym := c.table.get_type_symbol(alias_info.parent_type)
 | 
			
		||||
	} else if mut to_type_sym.info is table.Alias {
 | 
			
		||||
		if !c.check_types(node.expr_type, to_type_sym.info.parent_type) {
 | 
			
		||||
			parent_type_sym := c.table.get_type_symbol(to_type_sym.info.parent_type)
 | 
			
		||||
			c.error('cannot convert type `$from_type_sym.source_name` to `$to_type_sym.source_name` (alias to `$parent_type_sym.source_name`)',
 | 
			
		||||
				node.pos)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -3217,14 +3220,14 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
 | 
			
		|||
			c.error('`mut` not allowed with `=` (use `:=` to declare a variable)', ident.pos)
 | 
			
		||||
		}
 | 
			
		||||
		start_scope := c.file.scope.innermost(ident.pos.pos)
 | 
			
		||||
		if obj1 := start_scope.find(ident.name) {
 | 
			
		||||
			match mut obj1 as obj {
 | 
			
		||||
		if obj := start_scope.find(ident.name) {
 | 
			
		||||
			match union mut obj {
 | 
			
		||||
				ast.GlobalField {
 | 
			
		||||
					ident.kind = .global
 | 
			
		||||
					ident.info = ast.IdentVar{
 | 
			
		||||
						typ: obj.typ
 | 
			
		||||
					}
 | 
			
		||||
					ident.obj = obj1
 | 
			
		||||
					ident.obj = obj
 | 
			
		||||
					return obj.typ
 | 
			
		||||
				}
 | 
			
		||||
				ast.Var {
 | 
			
		||||
| 
						 | 
				
			
			@ -3269,7 +3272,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
 | 
			
		|||
					if !is_sum_type_cast {
 | 
			
		||||
						obj.typ = typ
 | 
			
		||||
					}
 | 
			
		||||
					ident.obj = obj1
 | 
			
		||||
					ident.obj = obj
 | 
			
		||||
					// unwrap optional (`println(x)`)
 | 
			
		||||
					if is_optional {
 | 
			
		||||
						return typ.clear_flag(.optional)
 | 
			
		||||
| 
						 | 
				
			
			@ -3284,8 +3287,8 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
 | 
			
		|||
		if !name.contains('.') && ident.mod != 'builtin' {
 | 
			
		||||
			name = '${ident.mod}.$ident.name'
 | 
			
		||||
		}
 | 
			
		||||
		if obj1 := c.file.global_scope.find(name) {
 | 
			
		||||
			match mut obj1 as obj {
 | 
			
		||||
		if obj := c.file.global_scope.find(name) {
 | 
			
		||||
			match union mut obj {
 | 
			
		||||
				ast.ConstField {
 | 
			
		||||
					mut typ := obj.typ
 | 
			
		||||
					if typ == 0 {
 | 
			
		||||
| 
						 | 
				
			
			@ -3297,7 +3300,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
 | 
			
		|||
						typ: typ
 | 
			
		||||
					}
 | 
			
		||||
					obj.typ = typ
 | 
			
		||||
					ident.obj = obj1
 | 
			
		||||
					ident.obj = obj
 | 
			
		||||
					return typ
 | 
			
		||||
				}
 | 
			
		||||
				else {}
 | 
			
		||||
| 
						 | 
				
			
			@ -3398,7 +3401,8 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
 | 
			
		|||
		}
 | 
			
		||||
		// If the last statement is an expression, return its type
 | 
			
		||||
		if branch.stmts.len > 0 {
 | 
			
		||||
			match mut branch.stmts[branch.stmts.len - 1] as stmt {
 | 
			
		||||
			mut stmt := branch.stmts[branch.stmts.len - 1]
 | 
			
		||||
			match union mut stmt {
 | 
			
		||||
				ast.ExprStmt {
 | 
			
		||||
					ret_type = c.expr(stmt.expr)
 | 
			
		||||
					stmt.typ = ret_type
 | 
			
		||||
| 
						 | 
				
			
			@ -3513,8 +3517,8 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
 | 
			
		|||
				// c.type_implements(expr_type, c.expected_type, expr.position())
 | 
			
		||||
				expr_pos := expr.position()
 | 
			
		||||
				c.type_implements(expr_type, c.expected_type, expr_pos)
 | 
			
		||||
			} else if cond_type_sym.info is table.UnionSumType as info {
 | 
			
		||||
				if expr_type !in info.variants {
 | 
			
		||||
			} else if mut cond_type_sym.info is table.UnionSumType {
 | 
			
		||||
				if expr_type !in cond_type_sym.info.variants {
 | 
			
		||||
					expr_str := c.table.type_to_str(expr_type)
 | 
			
		||||
					expect_str := c.table.type_to_str(c.expected_type)
 | 
			
		||||
					c.error('`$expect_str` has no variant `$expr_str`', expr.position())
 | 
			
		||||
| 
						 | 
				
			
			@ -3616,9 +3620,9 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
 | 
			
		|||
	// by listing all variants or values
 | 
			
		||||
	mut is_exhaustive := true
 | 
			
		||||
	mut unhandled := []string{}
 | 
			
		||||
	match type_sym.info as info {
 | 
			
		||||
	match union mut type_sym.info {
 | 
			
		||||
		table.SumType {
 | 
			
		||||
			for v in info.variants {
 | 
			
		||||
			for v in type_sym.info.variants {
 | 
			
		||||
				v_str := c.table.type_to_str(v)
 | 
			
		||||
				if v_str !in branch_exprs {
 | 
			
		||||
					is_exhaustive = false
 | 
			
		||||
| 
						 | 
				
			
			@ -3627,7 +3631,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
		table.UnionSumType {
 | 
			
		||||
			for v in info.variants {
 | 
			
		||||
			for v in type_sym.info.variants {
 | 
			
		||||
				v_str := c.table.type_to_str(v)
 | 
			
		||||
				if v_str !in branch_exprs {
 | 
			
		||||
					is_exhaustive = false
 | 
			
		||||
| 
						 | 
				
			
			@ -3637,7 +3641,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
 | 
			
		|||
		}
 | 
			
		||||
		//
 | 
			
		||||
		table.Enum {
 | 
			
		||||
			for v in info.vals {
 | 
			
		||||
			for v in type_sym.info.vals {
 | 
			
		||||
				if v !in branch_exprs {
 | 
			
		||||
					is_exhaustive = false
 | 
			
		||||
					unhandled << '`.$v`'
 | 
			
		||||
| 
						 | 
				
			
			@ -3690,27 +3694,27 @@ pub fn (mut c Checker) select_expr(mut node ast.SelectExpr) table.Type {
 | 
			
		|||
	node.expected_type = c.expected_type
 | 
			
		||||
	for branch in node.branches {
 | 
			
		||||
		c.stmt(branch.stmt)
 | 
			
		||||
		match branch.stmt as stmt {
 | 
			
		||||
		match union branch.stmt {
 | 
			
		||||
			ast.ExprStmt {
 | 
			
		||||
				if branch.is_timeout {
 | 
			
		||||
					if !stmt.typ.is_int() {
 | 
			
		||||
						tsym := c.table.get_type_symbol(stmt.typ)
 | 
			
		||||
					if !branch.stmt.typ.is_int() {
 | 
			
		||||
						tsym := c.table.get_type_symbol(branch.stmt.typ)
 | 
			
		||||
						c.error('invalid type `$tsym.name` for timeout - expected integer type aka `time.Duration`',
 | 
			
		||||
							stmt.pos)
 | 
			
		||||
							branch.stmt.pos)
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					if stmt.expr is ast.InfixExpr {
 | 
			
		||||
						if stmt.expr.left !is ast.Ident &&
 | 
			
		||||
							stmt.expr.left !is ast.SelectorExpr && stmt.expr.left !is ast.IndexExpr {
 | 
			
		||||
							c.error('channel in `select` key must be predefined', stmt.expr.left.position())
 | 
			
		||||
					if branch.stmt.expr is ast.InfixExpr {
 | 
			
		||||
						if branch.stmt.expr.left !is ast.Ident &&
 | 
			
		||||
							branch.stmt.expr.left !is ast.SelectorExpr && branch.stmt.expr.left !is ast.IndexExpr {
 | 
			
		||||
							c.error('channel in `select` key must be predefined', branch.stmt.expr.left.position())
 | 
			
		||||
						}
 | 
			
		||||
					} else {
 | 
			
		||||
						c.error('invalid expression for `select` key', stmt.expr.position())
 | 
			
		||||
						c.error('invalid expression for `select` key', branch.stmt.expr.position())
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			ast.AssignStmt {
 | 
			
		||||
				expr := stmt.right[0]
 | 
			
		||||
				expr := branch.stmt.right[0]
 | 
			
		||||
				match union expr {
 | 
			
		||||
					ast.PrefixExpr {
 | 
			
		||||
						if expr.right !is ast.Ident &&
 | 
			
		||||
| 
						 | 
				
			
			@ -3723,7 +3727,7 @@ pub fn (mut c Checker) select_expr(mut node ast.SelectExpr) table.Type {
 | 
			
		|||
						}
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						c.error('`<-` receive expression expected', stmt.right[0].position())
 | 
			
		||||
						c.error('`<-` receive expression expected', branch.stmt.right[0].position())
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -3742,8 +3746,8 @@ pub fn (mut c Checker) lock_expr(mut node ast.LockExpr) table.Type {
 | 
			
		|||
	for i in 0 .. node.lockeds.len {
 | 
			
		||||
		c.ident(mut node.lockeds[i])
 | 
			
		||||
		id := node.lockeds[i]
 | 
			
		||||
		if id.obj is ast.Var as v {
 | 
			
		||||
			if v.typ.share() != .shared_t {
 | 
			
		||||
		if mut id.obj is ast.Var {
 | 
			
		||||
			if id.obj.typ.share() != .shared_t {
 | 
			
		||||
				c.error('`$id.name` must be declared `shared` to be locked', id.pos)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -122,7 +122,7 @@ pub fn (mut d Doc) stmt(stmt ast.Stmt, filename string) ?DocNode {
 | 
			
		|||
	if node.name.len == 0 && node.comment.len == 0 && node.content.len == 0 {
 | 
			
		||||
		return error('empty stmt')
 | 
			
		||||
	}
 | 
			
		||||
	match stmt {
 | 
			
		||||
	match union stmt {
 | 
			
		||||
		ast.ConstDecl {
 | 
			
		||||
			node.kind = .const_group
 | 
			
		||||
			node.parent_name = 'Constants'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,7 +77,7 @@ fn (mut d Doc) convert_pos(filename string, pos token.Position) DocPos {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
pub fn (mut d Doc) stmt_signature(stmt ast.Stmt) string {
 | 
			
		||||
	match stmt {
 | 
			
		||||
	match union stmt {
 | 
			
		||||
		ast.Module {
 | 
			
		||||
			return 'module $stmt.name'
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -93,9 +93,9 @@ pub fn (mut d Doc) stmt_signature(stmt ast.Stmt) string {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
pub fn (d Doc) stmt_name(stmt ast.Stmt) string {
 | 
			
		||||
	match stmt {
 | 
			
		||||
	match union stmt {
 | 
			
		||||
		ast.FnDecl, ast.StructDecl, ast.EnumDecl, ast.InterfaceDecl { return stmt.name }
 | 
			
		||||
		ast.TypeDecl { match stmt {
 | 
			
		||||
		ast.TypeDecl { match union stmt {
 | 
			
		||||
				ast.SumTypeDecl, ast.FnTypeDecl, ast.AliasTypeDecl, ast.UnionSumTypeDecl { return stmt.name }
 | 
			
		||||
			} }
 | 
			
		||||
		ast.ConstDecl { return '' } // leave it blank
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ import v.checker
 | 
			
		|||
import v.table
 | 
			
		||||
import v.pref
 | 
			
		||||
 | 
			
		||||
pub type Object = int | string
 | 
			
		||||
pub __type Object = int | string
 | 
			
		||||
 | 
			
		||||
pub struct Eval {
 | 
			
		||||
mut:
 | 
			
		||||
| 
						 | 
				
			
			@ -33,14 +33,14 @@ pub fn (mut e Eval) eval(file ast.File, table &table.Table) string {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
fn print_object(o Object) {
 | 
			
		||||
	match o {
 | 
			
		||||
	match union o {
 | 
			
		||||
		int { println(o) }
 | 
			
		||||
		else { println('unknown object') }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn (o Object) str() string {
 | 
			
		||||
	match o {
 | 
			
		||||
	match union o {
 | 
			
		||||
		int { return o.str() }
 | 
			
		||||
		else { println('unknown object') }
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -245,7 +245,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
 | 
			
		|||
	if f.is_debug {
 | 
			
		||||
		eprintln('stmt: ${node.position():-42} | node: ${typeof(node):-20}')
 | 
			
		||||
	}
 | 
			
		||||
	match node {
 | 
			
		||||
	match union node {
 | 
			
		||||
		ast.AssignStmt {
 | 
			
		||||
			f.comments(node.comments, {})
 | 
			
		||||
			for i, left in node.left {
 | 
			
		||||
| 
						 | 
				
			
			@ -480,18 +480,18 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
 | 
			
		|||
			f.writeln('}')
 | 
			
		||||
		}
 | 
			
		||||
		ast.StructDecl {
 | 
			
		||||
			f.struct_decl(it)
 | 
			
		||||
			f.struct_decl(node)
 | 
			
		||||
		}
 | 
			
		||||
		ast.TypeDecl {
 | 
			
		||||
			// already handled in f.imports
 | 
			
		||||
			f.type_decl(it)
 | 
			
		||||
			f.type_decl(node)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn (mut f Fmt) type_decl(node ast.TypeDecl) {
 | 
			
		||||
	mut comments := []ast.Comment{}
 | 
			
		||||
	match node {
 | 
			
		||||
	match union node {
 | 
			
		||||
		ast.AliasTypeDecl {
 | 
			
		||||
			if node.is_pub {
 | 
			
		||||
				f.write('pub ')
 | 
			
		||||
| 
						 | 
				
			
			@ -962,8 +962,8 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
 | 
			
		|||
						f.write('> ')
 | 
			
		||||
					}
 | 
			
		||||
					f.single_line_if = true
 | 
			
		||||
					match branch.stmt as stmt {
 | 
			
		||||
						ast.ExprStmt { f.expr(stmt.expr) }
 | 
			
		||||
					match branch.stmt {
 | 
			
		||||
						ast.ExprStmt { f.expr(branch.stmt.expr) }
 | 
			
		||||
						else { f.stmt(branch.stmt) }
 | 
			
		||||
					}
 | 
			
		||||
					f.single_line_if = false
 | 
			
		||||
| 
						 | 
				
			
			@ -1691,7 +1691,7 @@ fn (mut f Fmt) write_language_prefix(lang table.Language) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
fn stmt_is_single_line(stmt ast.Stmt) bool {
 | 
			
		||||
	match stmt {
 | 
			
		||||
	match union stmt {
 | 
			
		||||
		ast.ExprStmt { return expr_is_single_line(stmt.expr) }
 | 
			
		||||
		ast.Return { return true }
 | 
			
		||||
		ast.AssignStmt { return true }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,9 +10,9 @@ import v.util
 | 
			
		|||
fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string {
 | 
			
		||||
	mut sym := g.table.get_type_symbol(g.unwrap_generic(typ))
 | 
			
		||||
	mut str_fn_name := styp_to_str_fn_name(styp)
 | 
			
		||||
	if sym.info is table.Alias as sym_info {
 | 
			
		||||
		if sym_info.is_import {
 | 
			
		||||
			sym = g.table.get_type_symbol((sym.info as table.Alias).parent_type)
 | 
			
		||||
	if mut sym.info is table.Alias {
 | 
			
		||||
		if sym.info.is_import {
 | 
			
		||||
			sym = g.table.get_type_symbol(sym.info.parent_type)
 | 
			
		||||
			str_fn_name = styp_to_str_fn_name(sym.name.replace('.', '__'))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -47,37 +47,37 @@ fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string {
 | 
			
		|||
			eprintln('> gen_str_for_type_with_styp: |typ: ${typ:5}, ${sym.name:20}|has_str: ${sym_has_str_method:5}|expects_ptr: ${str_method_expects_ptr:5}|nr_args: ${str_nr_args:1}|fn_name: ${str_fn_name:20}')
 | 
			
		||||
		}
 | 
			
		||||
		g.str_types << already_generated_key
 | 
			
		||||
		match sym.info as sym_info {
 | 
			
		||||
		match union mut sym.info {
 | 
			
		||||
			table.Alias {
 | 
			
		||||
				if sym_info.is_import {
 | 
			
		||||
				if sym.info.is_import {
 | 
			
		||||
					g.gen_str_default(sym, styp, str_fn_name)
 | 
			
		||||
				} else {
 | 
			
		||||
					g.gen_str_for_alias(sym_info, styp, str_fn_name)
 | 
			
		||||
					g.gen_str_for_alias(sym.info, styp, str_fn_name)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			table.Array {
 | 
			
		||||
				g.gen_str_for_array(it, styp, str_fn_name)
 | 
			
		||||
				g.gen_str_for_array(sym.info, styp, str_fn_name)
 | 
			
		||||
			}
 | 
			
		||||
			table.ArrayFixed {
 | 
			
		||||
				g.gen_str_for_array_fixed(it, styp, str_fn_name)
 | 
			
		||||
				g.gen_str_for_array_fixed(sym.info, styp, str_fn_name)
 | 
			
		||||
			}
 | 
			
		||||
			table.Enum {
 | 
			
		||||
				g.gen_str_for_enum(it, styp, str_fn_name)
 | 
			
		||||
				g.gen_str_for_enum(sym.info, styp, str_fn_name)
 | 
			
		||||
			}
 | 
			
		||||
			table.Struct {
 | 
			
		||||
				g.gen_str_for_struct(it, styp, str_fn_name)
 | 
			
		||||
				g.gen_str_for_struct(sym.info, styp, str_fn_name)
 | 
			
		||||
			}
 | 
			
		||||
			table.Map {
 | 
			
		||||
				g.gen_str_for_map(it, styp, str_fn_name)
 | 
			
		||||
				g.gen_str_for_map(sym.info, styp, str_fn_name)
 | 
			
		||||
			}
 | 
			
		||||
			table.MultiReturn {
 | 
			
		||||
				g.gen_str_for_multi_return(it, styp, str_fn_name)
 | 
			
		||||
				g.gen_str_for_multi_return(sym.info, styp, str_fn_name)
 | 
			
		||||
			}
 | 
			
		||||
			table.SumType {
 | 
			
		||||
				g.gen_str_for_sum_type(it, styp, str_fn_name)
 | 
			
		||||
				g.gen_str_for_sum_type(sym.info, styp, str_fn_name)
 | 
			
		||||
			}
 | 
			
		||||
			table.UnionSumType {
 | 
			
		||||
				g.gen_str_for_union_sum_type(it, styp, str_fn_name)
 | 
			
		||||
				g.gen_str_for_union_sum_type(sym.info, styp, str_fn_name)
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				verror("could not generate string method $str_fn_name for type \'$styp\'")
 | 
			
		||||
| 
						 | 
				
			
			@ -120,9 +120,9 @@ fn (mut g Gen) gen_str_for_alias(info table.Alias, styp string, str_fn_name stri
 | 
			
		|||
fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name string) {
 | 
			
		||||
	mut typ := info.elem_type
 | 
			
		||||
	mut sym := g.table.get_type_symbol(info.elem_type)
 | 
			
		||||
	if sym.info is table.Alias as alias_info {
 | 
			
		||||
		typ = alias_info.parent_type
 | 
			
		||||
		sym = g.table.get_type_symbol(alias_info.parent_type)
 | 
			
		||||
	if mut sym.info is table.Alias {
 | 
			
		||||
		typ = sym.info.parent_type
 | 
			
		||||
		sym = g.table.get_type_symbol(typ)
 | 
			
		||||
	}
 | 
			
		||||
	field_styp := g.typ(typ)
 | 
			
		||||
	is_elem_ptr := typ.is_ptr()
 | 
			
		||||
| 
						 | 
				
			
			@ -188,9 +188,9 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name stri
 | 
			
		|||
fn (mut g Gen) gen_str_for_array_fixed(info table.ArrayFixed, styp string, str_fn_name string) {
 | 
			
		||||
	mut typ := info.elem_type
 | 
			
		||||
	mut sym := g.table.get_type_symbol(info.elem_type)
 | 
			
		||||
	if sym.info is table.Alias as alias_info {
 | 
			
		||||
		typ = alias_info.parent_type
 | 
			
		||||
		sym = g.table.get_type_symbol(alias_info.parent_type)
 | 
			
		||||
	if mut sym.info is table.Alias {
 | 
			
		||||
		typ = sym.info.parent_type
 | 
			
		||||
		sym = g.table.get_type_symbol(typ)
 | 
			
		||||
	}
 | 
			
		||||
	field_styp := g.typ(typ)
 | 
			
		||||
	is_elem_ptr := typ.is_ptr()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -801,7 +801,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
 | 
			
		|||
	}
 | 
			
		||||
	// println('cgen.stmt()')
 | 
			
		||||
	// g.writeln('//// stmt start')
 | 
			
		||||
	match node {
 | 
			
		||||
	match union node {
 | 
			
		||||
		ast.AssertStmt {
 | 
			
		||||
			g.write_v_source_line_info(node.pos)
 | 
			
		||||
			g.gen_assert_stmt(node)
 | 
			
		||||
| 
						 | 
				
			
			@ -843,7 +843,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
 | 
			
		|||
			g.comp_for(node)
 | 
			
		||||
		}
 | 
			
		||||
		ast.DeferStmt {
 | 
			
		||||
			mut defer_stmt := *node
 | 
			
		||||
			mut defer_stmt := node
 | 
			
		||||
			defer_stmt.ifdef = g.defer_ifdef
 | 
			
		||||
			g.defer_stmts << defer_stmt
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -914,7 +914,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
			keep_fn_decl := g.fn_decl
 | 
			
		||||
			g.fn_decl = node
 | 
			
		||||
			g.fn_decl = &node
 | 
			
		||||
			if node.name == 'main.main' {
 | 
			
		||||
				g.has_main = true
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -2098,25 +2098,24 @@ fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int
 | 
			
		|||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for _, obj in scope.objects {
 | 
			
		||||
		match obj {
 | 
			
		||||
		match union obj {
 | 
			
		||||
			ast.Var {
 | 
			
		||||
				g.writeln('// var $obj.name pos=$obj.pos.pos')
 | 
			
		||||
				// if var.typ == 0 {
 | 
			
		||||
				// // TODO why 0?
 | 
			
		||||
				// continue
 | 
			
		||||
				// }
 | 
			
		||||
				v := *obj
 | 
			
		||||
				// if v.pos.pos > end_pos {
 | 
			
		||||
				if v.pos.pos > end_pos || (v.pos.pos < start_pos && v.pos.line_nr == line_nr) {
 | 
			
		||||
				if obj.pos.pos > end_pos || (obj.pos.pos < start_pos && obj.pos.line_nr == line_nr) {
 | 
			
		||||
					// Do not free vars that were declared after this scope
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				is_optional := v.typ.has_flag(.optional)
 | 
			
		||||
				is_optional := obj.typ.has_flag(.optional)
 | 
			
		||||
				if is_optional {
 | 
			
		||||
					// TODO: free optionals
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				g.autofree_variable(v)
 | 
			
		||||
				g.autofree_variable(obj)
 | 
			
		||||
			}
 | 
			
		||||
			else {}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -2573,8 +2572,8 @@ fn (mut g Gen) expr(node ast.Expr) {
 | 
			
		|||
								if i != 0 {
 | 
			
		||||
									sum_type_deref_field += ').'
 | 
			
		||||
								}
 | 
			
		||||
								if cast_sym.info is table.Aggregate as sym_info {
 | 
			
		||||
									sum_type_deref_field += '_${sym_info.types[g.aggregate_type_idx]}'
 | 
			
		||||
								if mut cast_sym.info is table.Aggregate {
 | 
			
		||||
									sum_type_deref_field += '_${cast_sym.info.types[g.aggregate_type_idx]}'
 | 
			
		||||
								} else {
 | 
			
		||||
									sum_type_deref_field += '_$typ'
 | 
			
		||||
								}
 | 
			
		||||
| 
						 | 
				
			
			@ -3253,10 +3252,10 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
 | 
			
		|||
			exception_branch = j
 | 
			
		||||
			timeout_expr = (branch.stmt as ast.ExprStmt).expr
 | 
			
		||||
		} else {
 | 
			
		||||
			match branch.stmt as stmt {
 | 
			
		||||
			match union branch.stmt {
 | 
			
		||||
				ast.ExprStmt {
 | 
			
		||||
					// send expression
 | 
			
		||||
					expr := stmt.expr as ast.InfixExpr
 | 
			
		||||
					expr := branch.stmt.expr as ast.InfixExpr
 | 
			
		||||
					channels << expr.left
 | 
			
		||||
					if expr.right is ast.Ident ||
 | 
			
		||||
						expr.right is ast.IndexExpr || expr.right is ast.SelectorExpr || expr.right is ast.StructInit {
 | 
			
		||||
| 
						 | 
				
			
			@ -3275,15 +3274,16 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
 | 
			
		|||
					is_push << true
 | 
			
		||||
				}
 | 
			
		||||
				ast.AssignStmt {
 | 
			
		||||
					rec_expr := stmt.right[0] as ast.PrefixExpr
 | 
			
		||||
					rec_expr := branch.stmt.right[0] as ast.PrefixExpr
 | 
			
		||||
					channels << rec_expr.right
 | 
			
		||||
					is_push << false
 | 
			
		||||
					// create tmp unless the object with *exactly* the type we need exists already
 | 
			
		||||
					if stmt.op == .decl_assign || stmt.right_types[0] != stmt.left_types[0] {
 | 
			
		||||
					if branch.stmt.op == .decl_assign ||
 | 
			
		||||
						branch.stmt.right_types[0] != branch.stmt.left_types[0] {
 | 
			
		||||
						tmp_obj := g.new_tmp_var()
 | 
			
		||||
						tmp_objs << tmp_obj
 | 
			
		||||
						el_stype := g.typ(stmt.right_types[0])
 | 
			
		||||
						elem_types << if stmt.op == .decl_assign {
 | 
			
		||||
						el_stype := g.typ(branch.stmt.right_types[0])
 | 
			
		||||
						elem_types << if branch.stmt.op == .decl_assign {
 | 
			
		||||
							el_stype + ' '
 | 
			
		||||
						} else {
 | 
			
		||||
							''
 | 
			
		||||
| 
						 | 
				
			
			@ -3293,7 +3293,7 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
 | 
			
		|||
						tmp_objs << ''
 | 
			
		||||
						elem_types << ''
 | 
			
		||||
					}
 | 
			
		||||
					objs << stmt.left[0]
 | 
			
		||||
					objs << branch.stmt.left[0]
 | 
			
		||||
				}
 | 
			
		||||
				else {}
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -3418,8 +3418,8 @@ fn (mut g Gen) ident(node ast.Ident) {
 | 
			
		|||
						if i == 0 {
 | 
			
		||||
							g.write(name)
 | 
			
		||||
						}
 | 
			
		||||
						if cast_sym.info is table.Aggregate as sym_info {
 | 
			
		||||
							g.write('._${sym_info.types[g.aggregate_type_idx]}')
 | 
			
		||||
						if mut cast_sym.info is table.Aggregate {
 | 
			
		||||
							g.write('._${cast_sym.info.types[g.aggregate_type_idx]}')
 | 
			
		||||
						} else {
 | 
			
		||||
							g.write('._$typ')
 | 
			
		||||
						}
 | 
			
		||||
| 
						 | 
				
			
			@ -3447,16 +3447,17 @@ fn (mut g Gen) should_write_asterisk_due_to_match_sumtype(expr ast.Expr) bool {
 | 
			
		|||
fn (mut g Gen) match_sumtype_has_no_struct_and_contains(node ast.Ident) bool {
 | 
			
		||||
	for i, expr in g.match_sumtype_exprs {
 | 
			
		||||
		if expr is ast.Ident && node.name == (expr as ast.Ident).name {
 | 
			
		||||
			match g.match_sumtype_syms[i].info as sumtype {
 | 
			
		||||
			info := g.match_sumtype_syms[i].info
 | 
			
		||||
			match union info {
 | 
			
		||||
				table.SumType {
 | 
			
		||||
					for typ in sumtype.variants {
 | 
			
		||||
					for typ in info.variants {
 | 
			
		||||
						if g.table.get_type_symbol(typ).kind == .struct_ {
 | 
			
		||||
							return false
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				table.UnionSumType {
 | 
			
		||||
					for typ in sumtype.variants {
 | 
			
		||||
					for typ in info.variants {
 | 
			
		||||
						if g.table.get_type_symbol(typ).kind == .struct_ {
 | 
			
		||||
							return false
 | 
			
		||||
						}
 | 
			
		||||
| 
						 | 
				
			
			@ -3500,9 +3501,11 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
 | 
			
		|||
	// easier to use a temp var, than do C tricks with commas, introduce special vars etc
 | 
			
		||||
	// (as it used to be done).
 | 
			
		||||
	// Always use this in -autofree, since ?: can have tmp expressions that have to be freed.
 | 
			
		||||
	first_branch := node.branches[0]
 | 
			
		||||
	needs_tmp_var := node.is_expr &&
 | 
			
		||||
		(g.pref.autofree || (g.pref.experimental &&
 | 
			
		||||
		(node.branches[0].stmts.len > 1 || node.branches[0].stmts[0] is ast.IfExpr)))
 | 
			
		||||
		(first_branch.stmts.len > 1 || (first_branch.stmts[0] is ast.ExprStmt &&
 | 
			
		||||
		(first_branch.stmts[0] as ast.ExprStmt).expr is ast.IfExpr))))
 | 
			
		||||
	/*
 | 
			
		||||
	needs_tmp_var := node.is_expr &&
 | 
			
		||||
		(g.pref.autofree || g.pref.experimental) &&
 | 
			
		||||
| 
						 | 
				
			
			@ -4224,8 +4227,8 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
 | 
			
		|||
	mut initialized := false
 | 
			
		||||
	for i, field in struct_init.fields {
 | 
			
		||||
		inited_fields[field.name] = i
 | 
			
		||||
		if sym.info is table.Struct as struct_info {
 | 
			
		||||
			equal_fields := struct_info.fields.filter(it.name == field.name)
 | 
			
		||||
		if mut sym.info is table.Struct {
 | 
			
		||||
			equal_fields := sym.info.fields.filter(it.name == field.name)
 | 
			
		||||
			if equal_fields.len == 0 {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -4276,8 +4279,8 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
 | 
			
		|||
		// g.zero_struct_fields(info, inited_fields)
 | 
			
		||||
		// nr_fields = info.fields.len
 | 
			
		||||
		for field in info.fields {
 | 
			
		||||
			if sym.info is table.Struct as struct_info {
 | 
			
		||||
				equal_fields := struct_info.fields.filter(it.name == field.name)
 | 
			
		||||
			if mut sym.info is table.Struct {
 | 
			
		||||
				equal_fields := sym.info.fields.filter(it.name == field.name)
 | 
			
		||||
				if equal_fields.len == 0 {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -4590,9 +4593,9 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
 | 
			
		|||
		}
 | 
			
		||||
		// sym := g.table.get_type_symbol(typ)
 | 
			
		||||
		mut name := util.no_dots(typ.name)
 | 
			
		||||
		match typ.info as info {
 | 
			
		||||
		match union mut typ.info {
 | 
			
		||||
			table.Struct {
 | 
			
		||||
				if info.generic_types.len > 0 {
 | 
			
		||||
				if typ.info.generic_types.len > 0 {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				// TODO: yuck
 | 
			
		||||
| 
						 | 
				
			
			@ -4602,13 +4605,13 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
 | 
			
		|||
				}
 | 
			
		||||
				// TODO avoid buffer manip
 | 
			
		||||
				start_pos := g.type_definitions.len
 | 
			
		||||
				if info.is_union {
 | 
			
		||||
				if typ.info.is_union {
 | 
			
		||||
					g.type_definitions.writeln('union $name {')
 | 
			
		||||
				} else {
 | 
			
		||||
					g.type_definitions.writeln('struct $name {')
 | 
			
		||||
				}
 | 
			
		||||
				if info.fields.len > 0 {
 | 
			
		||||
					for field in info.fields.filter(it.embed_alias_for == '') {
 | 
			
		||||
				if typ.info.fields.len > 0 {
 | 
			
		||||
					for field in typ.info.fields.filter(it.embed_alias_for == '') {
 | 
			
		||||
						// Some of these structs may want to contain
 | 
			
		||||
						// optionals that may not be defined at this point
 | 
			
		||||
						// if this is the case then we are going to
 | 
			
		||||
| 
						 | 
				
			
			@ -4642,7 +4645,7 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
 | 
			
		|||
			table.SumType {
 | 
			
		||||
				g.type_definitions.writeln('')
 | 
			
		||||
				g.type_definitions.writeln('// Sum type $name = ')
 | 
			
		||||
				for sv in it.variants {
 | 
			
		||||
				for sv in typ.info.variants {
 | 
			
		||||
					g.type_definitions.writeln('//          | ${sv:4d} = ${g.typ(sv):-20s}')
 | 
			
		||||
				}
 | 
			
		||||
				g.type_definitions.writeln('typedef struct {')
 | 
			
		||||
| 
						 | 
				
			
			@ -4655,12 +4658,12 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
 | 
			
		|||
				g.typedefs.writeln('typedef struct $name $name;')
 | 
			
		||||
				g.type_definitions.writeln('')
 | 
			
		||||
				g.type_definitions.writeln('// Union sum type $name = ')
 | 
			
		||||
				for variant in it.variants {
 | 
			
		||||
				for variant in typ.info.variants {
 | 
			
		||||
					g.type_definitions.writeln('//          | ${variant:4d} = ${g.typ(variant.idx()):-20s}')
 | 
			
		||||
				}
 | 
			
		||||
				g.type_definitions.writeln('struct $name {')
 | 
			
		||||
				g.type_definitions.writeln('    union {')
 | 
			
		||||
				for variant in it.variants {
 | 
			
		||||
				for variant in typ.info.variants {
 | 
			
		||||
					g.type_definitions.writeln('        ${g.typ(variant.to_ptr())} _$variant.idx();')
 | 
			
		||||
				}
 | 
			
		||||
				g.type_definitions.writeln('    };')
 | 
			
		||||
| 
						 | 
				
			
			@ -4702,19 +4705,18 @@ fn (g &Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
 | 
			
		|||
		}
 | 
			
		||||
		// create list of deps
 | 
			
		||||
		mut field_deps := []string{}
 | 
			
		||||
		match t.info {
 | 
			
		||||
		match union mut t.info {
 | 
			
		||||
			table.ArrayFixed {
 | 
			
		||||
				dep := g.table.get_type_symbol(it.elem_type).name
 | 
			
		||||
				dep := g.table.get_type_symbol(t.info.elem_type).name
 | 
			
		||||
				if dep in type_names {
 | 
			
		||||
					field_deps << dep
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			table.Struct {
 | 
			
		||||
				info := t.info as table.Struct
 | 
			
		||||
				// if info.is_interface {
 | 
			
		||||
				// continue
 | 
			
		||||
				// }
 | 
			
		||||
				for field in info.fields {
 | 
			
		||||
				for field in t.info.fields {
 | 
			
		||||
					dep := g.table.get_type_symbol(field.typ).name
 | 
			
		||||
					// skip if not in types list or already in deps
 | 
			
		||||
					if dep !in type_names || dep in field_deps || field.typ.is_ptr() {
 | 
			
		||||
| 
						 | 
				
			
			@ -4747,11 +4749,11 @@ fn (g &Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
 | 
			
		|||
fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
 | 
			
		||||
	mut typ := etype
 | 
			
		||||
	mut sym := g.table.get_type_symbol(typ)
 | 
			
		||||
	if sym.info is table.Alias as alias_info {
 | 
			
		||||
		parent_sym := g.table.get_type_symbol(alias_info.parent_type)
 | 
			
		||||
	if mut sym.info is table.Alias {
 | 
			
		||||
		parent_sym := g.table.get_type_symbol(sym.info.parent_type)
 | 
			
		||||
		if parent_sym.has_method('str') {
 | 
			
		||||
			typ = sym.info.parent_type
 | 
			
		||||
			sym = parent_sym
 | 
			
		||||
			typ = alias_info.parent_type
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -549,9 +549,9 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
 | 
			
		|||
			g.checker_bug('print arg.typ is 0', node.pos)
 | 
			
		||||
		}
 | 
			
		||||
		mut sym := g.table.get_type_symbol(typ)
 | 
			
		||||
		if sym.info is table.Alias as alias_info {
 | 
			
		||||
			typ = alias_info.parent_type
 | 
			
		||||
			sym = g.table.get_type_symbol(alias_info.parent_type)
 | 
			
		||||
		if mut sym.info is table.Alias {
 | 
			
		||||
			typ = sym.info.parent_type
 | 
			
		||||
			sym = g.table.get_type_symbol(typ)
 | 
			
		||||
		}
 | 
			
		||||
		// check if alias parent also not a string
 | 
			
		||||
		if typ != table.string_type {
 | 
			
		||||
| 
						 | 
				
			
			@ -685,7 +685,7 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) {
 | 
			
		|||
			// instead of `string t = ...`, and we need to mark this variable as unused,
 | 
			
		||||
			// so that it's freed after the call. (Used tmp arg vars are not freed to avoid double frees).
 | 
			
		||||
			if x := scope.find(t) {
 | 
			
		||||
				match mut x {
 | 
			
		||||
				match union mut x {
 | 
			
		||||
					ast.Var { x.is_used = false }
 | 
			
		||||
					else {}
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -740,27 +740,26 @@ fn (mut g Gen) autofree_call_postgen(node_pos int) {
 | 
			
		|||
	// g.write('/* postgen */')
 | 
			
		||||
	scope := g.file.scope.innermost(node_pos)
 | 
			
		||||
	for _, obj in scope.objects {
 | 
			
		||||
		match mut obj {
 | 
			
		||||
		match union mut obj {
 | 
			
		||||
			ast.Var {
 | 
			
		||||
				// if var.typ == 0 {
 | 
			
		||||
				// // TODO why 0?
 | 
			
		||||
				// continue
 | 
			
		||||
				// }
 | 
			
		||||
				v := *obj
 | 
			
		||||
				is_optional := v.typ.has_flag(.optional)
 | 
			
		||||
				is_optional := obj.typ.has_flag(.optional)
 | 
			
		||||
				if is_optional {
 | 
			
		||||
					// TODO: free optionals
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if !v.is_autofree_tmp {
 | 
			
		||||
				if !obj.is_autofree_tmp {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if v.is_used {
 | 
			
		||||
				if obj.is_used {
 | 
			
		||||
					// this means this tmp expr var has already been freed
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				obj.is_used = true
 | 
			
		||||
				g.autofree_variable(v)
 | 
			
		||||
				g.autofree_variable(obj)
 | 
			
		||||
				// g.nr_vars_to_free--
 | 
			
		||||
			}
 | 
			
		||||
			else {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -164,7 +164,7 @@ pub fn (mut g JsGen) push_pub_var(s string) {
 | 
			
		|||
 | 
			
		||||
pub fn (mut g JsGen) find_class_methods(stmts []ast.Stmt) {
 | 
			
		||||
	for stmt in stmts {
 | 
			
		||||
		match stmt {
 | 
			
		||||
		match union stmt {
 | 
			
		||||
			ast.FnDecl {
 | 
			
		||||
				if stmt.is_method {
 | 
			
		||||
					// Found struct method, store it to be generated along with the class.
 | 
			
		||||
| 
						 | 
				
			
			@ -437,7 +437,7 @@ fn (mut g JsGen) stmts(stmts []ast.Stmt) {
 | 
			
		|||
 | 
			
		||||
fn (mut g JsGen) stmt(node ast.Stmt) {
 | 
			
		||||
	g.stmt_start_pos = g.out.len
 | 
			
		||||
	match node {
 | 
			
		||||
	match union node {
 | 
			
		||||
		ast.AssertStmt {
 | 
			
		||||
			g.gen_assert_stmt(node)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -456,7 +456,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
 | 
			
		|||
			g.gen_const_decl(node)
 | 
			
		||||
		}
 | 
			
		||||
		ast.DeferStmt {
 | 
			
		||||
			g.defer_stmts << *node
 | 
			
		||||
			g.defer_stmts << node
 | 
			
		||||
		}
 | 
			
		||||
		ast.EnumDecl {
 | 
			
		||||
			g.gen_enum_decl(node)
 | 
			
		||||
| 
						 | 
				
			
			@ -466,7 +466,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
 | 
			
		|||
			g.gen_expr_stmt(node)
 | 
			
		||||
		}
 | 
			
		||||
		ast.FnDecl {
 | 
			
		||||
			g.fn_decl = node
 | 
			
		||||
			g.fn_decl = &node
 | 
			
		||||
			g.gen_fn_decl(node)
 | 
			
		||||
		}
 | 
			
		||||
		ast.ForCStmt {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -603,7 +603,7 @@ pub fn (mut g Gen) call_fn(node ast.CallExpr) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
fn (mut g Gen) stmt(node ast.Stmt) {
 | 
			
		||||
	match node {
 | 
			
		||||
	match union node {
 | 
			
		||||
		ast.AssignStmt {
 | 
			
		||||
			g.assign_stmt(node)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -103,7 +103,7 @@ fn (mut p Parser) vweb() ast.ComptimeCall {
 | 
			
		|||
					if obj is ast.Var {
 | 
			
		||||
						mut v := obj
 | 
			
		||||
						v.pos = stmt.body_pos
 | 
			
		||||
						tmpl_scope.register(v.name, *v)
 | 
			
		||||
						tmpl_scope.register(v.name, v)
 | 
			
		||||
						// set the controller action var to used
 | 
			
		||||
						// if its unused in the template it will warn
 | 
			
		||||
						v.is_used = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -443,12 +443,12 @@ fn (mut p Parser) select_expr() ast.SelectExpr {
 | 
			
		|||
			}
 | 
			
		||||
			p.inside_match = false
 | 
			
		||||
			p.inside_select = false
 | 
			
		||||
			match stmt {
 | 
			
		||||
			match union mut stmt {
 | 
			
		||||
				ast.ExprStmt {
 | 
			
		||||
					if !stmt.is_expr {
 | 
			
		||||
						p.error_with_pos('select: invalid expression', stmt.pos)
 | 
			
		||||
					} else {
 | 
			
		||||
						match union stmt.expr {
 | 
			
		||||
						match union mut stmt.expr {
 | 
			
		||||
							ast.InfixExpr {
 | 
			
		||||
								if stmt.expr.op != .arrow {
 | 
			
		||||
									p.error_with_pos('select key: `<-` operator expected',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -608,18 +608,18 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
 | 
			
		|||
					p.next()
 | 
			
		||||
					if p.tok.kind == .key_for {
 | 
			
		||||
						mut stmt := p.stmt(is_top_level)
 | 
			
		||||
						match mut stmt {
 | 
			
		||||
						match union mut stmt {
 | 
			
		||||
							ast.ForStmt {
 | 
			
		||||
								stmt.label = name
 | 
			
		||||
								return *stmt
 | 
			
		||||
								return stmt
 | 
			
		||||
							}
 | 
			
		||||
							ast.ForInStmt {
 | 
			
		||||
								stmt.label = name
 | 
			
		||||
								return *stmt
 | 
			
		||||
								return stmt
 | 
			
		||||
							}
 | 
			
		||||
							ast.ForCStmt {
 | 
			
		||||
								stmt.label = name
 | 
			
		||||
								return *stmt
 | 
			
		||||
								return stmt
 | 
			
		||||
							}
 | 
			
		||||
							else {
 | 
			
		||||
								assert false
 | 
			
		||||
| 
						 | 
				
			
			@ -2139,7 +2139,7 @@ fn (mut p Parser) rewind_scanner_to_current_token_in_new_mode() {
 | 
			
		|||
 | 
			
		||||
pub fn (mut p Parser) mark_var_as_used(varname string) bool {
 | 
			
		||||
	if obj := p.scope.find(varname) {
 | 
			
		||||
		match mut obj {
 | 
			
		||||
		match union mut obj {
 | 
			
		||||
			ast.Var {
 | 
			
		||||
				obj.is_used = true
 | 
			
		||||
				return true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -263,12 +263,12 @@ pub fn (t &Table) struct_find_field(s &TypeSymbol, name string) ?Field {
 | 
			
		|||
	// println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
 | 
			
		||||
	mut ts := s
 | 
			
		||||
	for {
 | 
			
		||||
		if ts.info is Struct as struct_info {
 | 
			
		||||
			if field := struct_info.find_field(name) {
 | 
			
		||||
		if mut ts.info is Struct {
 | 
			
		||||
			if field := ts.info.find_field(name) {
 | 
			
		||||
				return field
 | 
			
		||||
			}
 | 
			
		||||
		} else if ts.info is Aggregate as agg_info {
 | 
			
		||||
			if field := agg_info.find_field(name) {
 | 
			
		||||
		} else if mut ts.info is Aggregate {
 | 
			
		||||
			if field := ts.info.find_field(name) {
 | 
			
		||||
				return field
 | 
			
		||||
			}
 | 
			
		||||
			field := t.register_aggregate_field(mut ts, name) or {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,8 +15,8 @@ import strings
 | 
			
		|||
 | 
			
		||||
pub type Type = int
 | 
			
		||||
 | 
			
		||||
pub type TypeInfo = Aggregate | Alias | Array | ArrayFixed | Chan | Enum | FnType | GenericStructInst |
 | 
			
		||||
	Interface | Map | MultiReturn | Struct | SumType | UnionSumType
 | 
			
		||||
pub __type TypeInfo = Aggregate | Alias | Array | ArrayFixed | Chan | Enum | FnType |
 | 
			
		||||
	GenericStructInst | Interface | Map | MultiReturn | Struct | SumType | UnionSumType
 | 
			
		||||
 | 
			
		||||
pub enum Language {
 | 
			
		||||
	v
 | 
			
		||||
| 
						 | 
				
			
			@ -421,56 +421,56 @@ pub fn (t &TypeSymbol) str() string {
 | 
			
		|||
 | 
			
		||||
[inline]
 | 
			
		||||
pub fn (t &TypeSymbol) enum_info() Enum {
 | 
			
		||||
	match t.info {
 | 
			
		||||
		Enum { return *it }
 | 
			
		||||
	match union mut t.info {
 | 
			
		||||
		Enum { return t.info }
 | 
			
		||||
		else { panic('TypeSymbol.enum_info(): no enum info for type: $t.name') }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[inline]
 | 
			
		||||
pub fn (t &TypeSymbol) mr_info() MultiReturn {
 | 
			
		||||
	match t.info {
 | 
			
		||||
		MultiReturn { return *it }
 | 
			
		||||
	match union mut t.info {
 | 
			
		||||
		MultiReturn { return t.info }
 | 
			
		||||
		else { panic('TypeSymbol.mr_info(): no multi return info for type: $t.name') }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[inline]
 | 
			
		||||
pub fn (t &TypeSymbol) array_info() Array {
 | 
			
		||||
	match t.info {
 | 
			
		||||
		Array { return *it }
 | 
			
		||||
	match union mut t.info {
 | 
			
		||||
		Array { return t.info }
 | 
			
		||||
		else { panic('TypeSymbol.array_info(): no array info for type: $t.name') }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[inline]
 | 
			
		||||
pub fn (t &TypeSymbol) array_fixed_info() ArrayFixed {
 | 
			
		||||
	match t.info {
 | 
			
		||||
		ArrayFixed { return *it }
 | 
			
		||||
	match union mut t.info {
 | 
			
		||||
		ArrayFixed { return t.info }
 | 
			
		||||
		else { panic('TypeSymbol.array_fixed(): no array fixed info for type: $t.name') }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[inline]
 | 
			
		||||
pub fn (t &TypeSymbol) chan_info() Chan {
 | 
			
		||||
	match t.info {
 | 
			
		||||
		Chan { return *it }
 | 
			
		||||
	match union mut t.info {
 | 
			
		||||
		Chan { return t.info }
 | 
			
		||||
		else { panic('TypeSymbol.chan_info(): no chan info for type: $t.name') }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[inline]
 | 
			
		||||
pub fn (t &TypeSymbol) map_info() Map {
 | 
			
		||||
	match t.info {
 | 
			
		||||
		Map { return *it }
 | 
			
		||||
	match union mut t.info {
 | 
			
		||||
		Map { return t.info }
 | 
			
		||||
		else { panic('TypeSymbol.map_info(): no map info for type: $t.name') }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[inline]
 | 
			
		||||
pub fn (t &TypeSymbol) struct_info() Struct {
 | 
			
		||||
	match t.info {
 | 
			
		||||
		Struct { return *it }
 | 
			
		||||
	match union mut t.info {
 | 
			
		||||
		Struct { return t.info }
 | 
			
		||||
		else { panic('TypeSymbol.struct_info(): no struct info for type: $t.name') }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -790,7 +790,7 @@ pub:
 | 
			
		|||
// NB: FExpr here is a actually an ast.Expr .
 | 
			
		||||
// It should always be used by casting to ast.Expr, using ast.fe2ex()/ast.ex2fe()
 | 
			
		||||
// That hack is needed to break an import cycle between v.ast and v.table .
 | 
			
		||||
pub type FExpr = byteptr | voidptr
 | 
			
		||||
pub __type FExpr = byteptr | voidptr
 | 
			
		||||
 | 
			
		||||
pub struct Field {
 | 
			
		||||
pub:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ import v.util
 | 
			
		|||
import v.pref
 | 
			
		||||
 | 
			
		||||
// `Any` is a sum type that lists the possible types to be decoded and used.
 | 
			
		||||
pub type Any = string | int | i64 | f32 | f64 | any_int | any_float | bool | Null | []Any | map[string]Any
 | 
			
		||||
pub __type Any = string | int | i64 | f32 | f64 | any_int | any_float | bool | Null | []Any | map[string]Any
 | 
			
		||||
// `Null` struct is a simple representation of the `null` value in JSON.
 | 
			
		||||
pub struct Null {}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,21 +51,20 @@ pub fn (flds []Any) str() string {
 | 
			
		|||
 | 
			
		||||
// String representation of the `Any` type.
 | 
			
		||||
pub fn (f Any) str() string {
 | 
			
		||||
	match f {
 | 
			
		||||
		string { return *f }
 | 
			
		||||
		int { return (*f).str() }
 | 
			
		||||
		i64 { return (*f).str() }
 | 
			
		||||
		f32 { return (*f).str() }
 | 
			
		||||
		f64 { return (*f).str() }
 | 
			
		||||
		any_int {	return (*f).str() }
 | 
			
		||||
		any_float {	return (*f).str() }
 | 
			
		||||
		bool { return (*f).str() }
 | 
			
		||||
		map[string]Any { return (*f).str() }
 | 
			
		||||
	match union f {
 | 
			
		||||
		string { return f }
 | 
			
		||||
		int { return f.str() }
 | 
			
		||||
		i64 { return f.str() }
 | 
			
		||||
		f32 { return f.str() }
 | 
			
		||||
		f64 { return f.str() }
 | 
			
		||||
		any_int { return f.str() }
 | 
			
		||||
		any_float {	return f.str() }
 | 
			
		||||
		bool { return f.str() }
 | 
			
		||||
		map[string]Any { return f.str() }
 | 
			
		||||
		Null { return 'null' }
 | 
			
		||||
		else {
 | 
			
		||||
			if f is []Any {
 | 
			
		||||
				arr := f
 | 
			
		||||
				return (*arr).str()
 | 
			
		||||
				return f.str()
 | 
			
		||||
			}
 | 
			
		||||
			return ''
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,11 +66,10 @@ pub fn null() Null {
 | 
			
		|||
// Use `Any` as a map.
 | 
			
		||||
pub fn (f Any) as_map() map[string]Any {
 | 
			
		||||
	if f is map[string]Any {
 | 
			
		||||
		return *f
 | 
			
		||||
		return f
 | 
			
		||||
	} else if f is []Any {
 | 
			
		||||
		mut mp := map[string]Any
 | 
			
		||||
		arr := f
 | 
			
		||||
		for i, fi in arr {
 | 
			
		||||
		for i, fi in f {
 | 
			
		||||
			mp['$i'] = fi
 | 
			
		||||
		}
 | 
			
		||||
		return mp
 | 
			
		||||
| 
						 | 
				
			
			@ -80,9 +79,9 @@ pub fn (f Any) as_map() map[string]Any {
 | 
			
		|||
 | 
			
		||||
// Use `Any` as an integer.
 | 
			
		||||
pub fn (f Any) int() int {
 | 
			
		||||
	match f {
 | 
			
		||||
		int  { return *f }
 | 
			
		||||
		i64  { return int(*f) }
 | 
			
		||||
	match union f {
 | 
			
		||||
		int  { return f }
 | 
			
		||||
		i64  { return int(f) }
 | 
			
		||||
		f64  { return f.str().int() }
 | 
			
		||||
		f32  { return f.str().int() }
 | 
			
		||||
		bool { return int(f) }
 | 
			
		||||
| 
						 | 
				
			
			@ -92,9 +91,9 @@ pub fn (f Any) int() int {
 | 
			
		|||
 | 
			
		||||
// Use `Any` as a 64-bit integer.
 | 
			
		||||
pub fn (f Any) i64() i64 {
 | 
			
		||||
	match f {
 | 
			
		||||
		int  { return *f }
 | 
			
		||||
		i64  { return int(*f) }
 | 
			
		||||
	match union f {
 | 
			
		||||
		int  { return f }
 | 
			
		||||
		i64  { return int(f) }
 | 
			
		||||
		f64  { return f.str().i64() }
 | 
			
		||||
		f32  { return f.str().i64() }
 | 
			
		||||
		bool { return int(f) }
 | 
			
		||||
| 
						 | 
				
			
			@ -104,33 +103,32 @@ pub fn (f Any) i64() i64 {
 | 
			
		|||
 | 
			
		||||
// Use `Any` as a 32-bit float.
 | 
			
		||||
pub fn (f Any) f32() f32 {
 | 
			
		||||
	match f {
 | 
			
		||||
		int { return *f }
 | 
			
		||||
		i64 { return (*f).str().f32() }
 | 
			
		||||
		f64 { return (*f).str().f32() }
 | 
			
		||||
		f32 { return *f }
 | 
			
		||||
	match union f {
 | 
			
		||||
		int { return f }
 | 
			
		||||
		i64 { return f.str().f32() }
 | 
			
		||||
		f64 { return f.str().f32() }
 | 
			
		||||
		f32 { return f }
 | 
			
		||||
		else { return 0.0 }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Use `Any` as a float.
 | 
			
		||||
pub fn (f Any) f64() f64 {
 | 
			
		||||
	match f {
 | 
			
		||||
		int { return *f }
 | 
			
		||||
		i64 { return *f }
 | 
			
		||||
		f64 { return *f }
 | 
			
		||||
		f32 { return (*f).str().f64() }
 | 
			
		||||
	match union f {
 | 
			
		||||
		int { return f }
 | 
			
		||||
		i64 { return f }
 | 
			
		||||
		f64 { return f }
 | 
			
		||||
		f32 { return f.str().f64() }
 | 
			
		||||
		else { return 0.0 }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
// Use `Any` as an array.
 | 
			
		||||
pub fn (f Any) arr() []Any {
 | 
			
		||||
	if f is []Any {
 | 
			
		||||
		return *f
 | 
			
		||||
		return f
 | 
			
		||||
	} else if f is map[string]Any {
 | 
			
		||||
		mut arr := []Any{}
 | 
			
		||||
		mp := *f
 | 
			
		||||
		for _, v in mp {
 | 
			
		||||
		for _, v in f {
 | 
			
		||||
			arr << v
 | 
			
		||||
		}
 | 
			
		||||
		return arr
 | 
			
		||||
| 
						 | 
				
			
			@ -140,9 +138,9 @@ pub fn (f Any) arr() []Any {
 | 
			
		|||
 | 
			
		||||
// Use `Any` as a bool
 | 
			
		||||
pub fn (f Any) bool() bool {
 | 
			
		||||
	match f {
 | 
			
		||||
		bool { return *f }
 | 
			
		||||
		string { return (*f).bool() }
 | 
			
		||||
	match union f {
 | 
			
		||||
		bool { return f }
 | 
			
		||||
		string { return f.bool() }
 | 
			
		||||
		else { return false }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue