table: allow type hold 8 flags at once

pull/5210/head
joe-conigliaro 2020-06-04 22:38:54 +10:00
parent 2230cbae01
commit edd56bc080
No known key found for this signature in database
GPG Key ID: C12F7136C08206F1
7 changed files with 58 additions and 54 deletions

View File

@ -19,7 +19,7 @@ pub fn (c &Checker) check_basic(got, expected table.Type) bool {
// and the other is not, is this correct behaviour? // and the other is not, is this correct behaviour?
return true return true
} }
if got_idx == table.none_type_idx && expected.flag_is(.optional) { if got_idx == table.none_type_idx && expected.has_flag(.optional) {
return true return true
} }
// allow pointers to be initialized with 0. TODO: use none instead // allow pointers to be initialized with 0. TODO: use none instead

View File

@ -826,7 +826,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
c.expected_type = exp_arg_typ c.expected_type = exp_arg_typ
got_arg_typ := c.expr(arg.expr) got_arg_typ := c.expr(arg.expr)
call_expr.args[i].typ = got_arg_typ call_expr.args[i].typ = got_arg_typ
if method.is_variadic && got_arg_typ.flag_is(.variadic) && call_expr.args.len - if method.is_variadic && got_arg_typ.has_flag(.variadic) && call_expr.args.len -
1 > i { 1 > i {
c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos) c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos)
} }
@ -1027,7 +1027,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
call_expr.args[i].typ = typ call_expr.args[i].typ = typ
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
arg_typ_sym := c.table.get_type_symbol(arg.typ) arg_typ_sym := c.table.get_type_symbol(arg.typ)
if f.is_variadic && typ.flag_is(.variadic) && call_expr.args.len - 1 > i { if f.is_variadic && typ.has_flag(.variadic) && call_expr.args.len - 1 > i {
c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos) c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos)
} }
if arg.is_mut && !call_arg.is_mut { if arg.is_mut && !call_arg.is_mut {
@ -1100,7 +1100,7 @@ fn (mut c Checker) type_implements(typ, inter_typ table.Type, pos token.Position
pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) table.Type { pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) table.Type {
if expr is ast.CallExpr { if expr is ast.CallExpr {
call_expr := expr as ast.CallExpr call_expr := expr as ast.CallExpr
if call_expr.return_type.flag_is(.optional) { if call_expr.return_type.has_flag(.optional) {
if call_expr.or_block.kind == .absent { if call_expr.or_block.kind == .absent {
if ret_type != table.void_type { if ret_type != table.void_type {
c.error('${call_expr.name}() returns an option, but you missed to add an `or {}` block to it', c.error('${call_expr.name}() returns an option, but you missed to add an `or {}` block to it',
@ -1110,7 +1110,7 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t
c.check_or_expr(call_expr.or_block, ret_type) c.check_or_expr(call_expr.or_block, ret_type)
} }
// remove optional flag // remove optional flag
return ret_type.set_flag(.unset) return ret_type.clear_flag(.optional)
} else if call_expr.or_block.kind == .block { } else if call_expr.or_block.kind == .block {
c.error('unexpected `or` block, the function `$call_expr.name` does not return an optional', c.error('unexpected `or` block, the function `$call_expr.name` does not return an optional',
call_expr.pos) call_expr.pos)
@ -1124,7 +1124,7 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t
pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type) { pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type) {
if or_expr.kind == .propagate { if or_expr.kind == .propagate {
if !c.cur_fn.return_type.flag_is(.optional) && c.cur_fn.name != 'main' { if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main' {
c.error('to propagate the optional call, `${c.cur_fn.name}` must itself return an optional', c.error('to propagate the optional call, `${c.cur_fn.name}` must itself return an optional',
or_expr.pos) or_expr.pos)
} }
@ -1193,7 +1193,7 @@ pub fn (mut c Checker) selector_expr(mut selector_expr ast.SelectorExpr) table.T
sym := c.table.get_type_symbol(c.unwrap_generic(typ)) sym := c.table.get_type_symbol(c.unwrap_generic(typ))
field_name := selector_expr.field_name field_name := selector_expr.field_name
// variadic // variadic
if typ.flag_is(.variadic) { if typ.has_flag(.variadic) {
if field_name == 'len' { if field_name == 'len' {
return table.int_type return table.int_type
} }
@ -1228,7 +1228,7 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
} }
expected_type := c.expected_type expected_type := c.expected_type
expected_type_sym := c.table.get_type_symbol(expected_type) expected_type_sym := c.table.get_type_symbol(expected_type)
exp_is_optional := expected_type.flag_is(.optional) exp_is_optional := expected_type.has_flag(.optional)
mut expected_types := [expected_type] mut expected_types := [expected_type]
if expected_type_sym.kind == .multi_return { if expected_type_sym.kind == .multi_return {
mr_info := expected_type_sym.info as table.MultiReturn mr_info := expected_type_sym.info as table.MultiReturn
@ -1258,8 +1258,8 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
} }
for i, exp_type in expected_types { for i, exp_type in expected_types {
got_typ := got_types[i] got_typ := got_types[i]
if got_typ.flag_is(.optional) && if got_typ.has_flag(.optional) &&
(!exp_type.flag_is(.optional) || c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) { (!exp_type.has_flag(.optional) || c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) {
pos := return_stmt.exprs[i].position() pos := return_stmt.exprs[i].position()
c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument', pos) c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument', pos)
} }
@ -1977,7 +1977,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
} }
typ = c.expr(it.expr) typ = c.expr(it.expr)
} }
is_optional := typ.flag_is(.optional) is_optional := typ.has_flag(.optional)
ident.kind = .variable ident.kind = .variable
ident.info = ast.IdentVar{ ident.info = ast.IdentVar{
typ: typ typ: typ
@ -1993,7 +1993,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
it.typ = typ it.typ = typ
// unwrap optional (`println(x)`) // unwrap optional (`println(x)`)
if is_optional { if is_optional {
return typ.set_flag(.unset) return typ.clear_flag(.optional)
} }
return typ return typ
} }

View File

@ -324,7 +324,7 @@ fn (g &Gen) typ(t table.Type) string {
// T => int etc // T => int etc
return g.typ(g.cur_generic_type) return g.typ(g.cur_generic_type)
} }
if t.flag_is(.optional) { if t.has_flag(.optional) {
// Register an optional if it's not registered yet // Register an optional if it's not registered yet
return g.register_optional(t) return g.register_optional(t)
} }
@ -844,7 +844,7 @@ fn (mut g Gen) for_in(it ast.ForInStmt) {
} }
g.stmts(it.stmts) g.stmts(it.stmts)
g.writeln('}') g.writeln('}')
} else if it.cond_type.flag_is(.variadic) { } else if it.cond_type.has_flag(.variadic) {
g.writeln('// FOR IN cond_type/variadic') g.writeln('// FOR IN cond_type/variadic')
i := if it.key_var in ['', '_'] { g.new_tmp_var() } else { it.key_var } i := if it.key_var in ['', '_'] { g.new_tmp_var() } else { it.key_var }
styp := g.typ(it.cond_type) styp := g.typ(it.cond_type)
@ -901,7 +901,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type, expected_type table.Type)
got_deref_type := got_type.deref() got_deref_type := got_type.deref()
deref_sym := g.table.get_type_symbol(got_deref_type) deref_sym := g.table.get_type_symbol(got_deref_type)
deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx] deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx]
got_is_opt := got_type.flag_is(.optional) got_is_opt := got_type.has_flag(.optional)
if deref_will_match || got_is_opt { if deref_will_match || got_is_opt {
g.write('*') g.write('*')
} }
@ -1015,7 +1015,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
1 { 1 {
// multi return // multi return
// TODO Handle in if_expr // TODO Handle in if_expr
is_optional := return_type.flag_is(.optional) is_optional := return_type.has_flag(.optional)
mr_var_name := 'mr_$assign_stmt.pos.pos' mr_var_name := 'mr_$assign_stmt.pos.pos'
mr_styp := g.typ(return_type) mr_styp := g.typ(return_type)
g.write('$mr_styp $mr_var_name = ') g.write('$mr_styp $mr_var_name = ')
@ -1289,7 +1289,7 @@ fn (mut g Gen) autofree_scope_vars(pos int) string {
// continue // continue
// } // }
v := *it v := *it
is_optional := v.typ.flag_is(.optional) is_optional := v.typ.has_flag(.optional)
if is_optional { if is_optional {
// TODO: free optionals // TODO: free optionals
continue continue
@ -1644,7 +1644,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) {
} }
else {} else {}
} }
gen_or := is_call && return_type.flag_is(.optional) gen_or := is_call && return_type.has_flag(.optional)
tmp_opt := if gen_or { g.new_tmp_var() } else { '' } tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
if gen_or { if gen_or {
rstyp := g.typ(return_type) rstyp := g.typ(return_type)
@ -1662,7 +1662,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) {
} }
} else { } else {
g.is_assign_lhs = true g.is_assign_lhs = true
if node.right_type.flag_is(.optional) { if node.right_type.has_flag(.optional) {
g.right_is_opt = true g.right_is_opt = true
} }
mut str_add := false mut str_add := false
@ -1719,7 +1719,7 @@ fn (mut g Gen) assign_expr(node ast.AssignExpr) {
if gen_or { if gen_or {
// g.write('/*777 $tmp_opt*/') // g.write('/*777 $tmp_opt*/')
g.or_block(tmp_opt, or_block, return_type) g.or_block(tmp_opt, or_block, return_type)
unwrapped_type_str := g.typ(return_type.set_flag(.unset)) unwrapped_type_str := g.typ(return_type.clear_flag(.optional))
ident := node.left as ast.Ident ident := node.left as ast.Ident
if ident.kind != .blank_ident && ident.info is ast.IdentVar { if ident.kind != .blank_ident && ident.info is ast.IdentVar {
ident_var := ident.info as ast.IdentVar ident_var := ident.info as ast.IdentVar
@ -2207,7 +2207,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
if !is_range { if !is_range {
sym := g.table.get_type_symbol(node.left_type) sym := g.table.get_type_symbol(node.left_type)
left_is_ptr := node.left_type.is_ptr() left_is_ptr := node.left_type.is_ptr()
if node.left_type.flag_is(.variadic) { if node.left_type.has_flag(.variadic) {
g.expr(node.left) g.expr(node.left)
g.write('.args') g.write('.args')
g.write('[') g.write('[')
@ -2339,7 +2339,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
// got to do a correct check for multireturn // got to do a correct check for multireturn
sym := g.table.get_type_symbol(g.fn_decl.return_type) sym := g.table.get_type_symbol(g.fn_decl.return_type)
fn_return_is_multi := sym.kind == .multi_return fn_return_is_multi := sym.kind == .multi_return
fn_return_is_optional := g.fn_decl.return_type.flag_is(.optional) fn_return_is_optional := g.fn_decl.return_type.has_flag(.optional)
// handle promoting none/error/function returning 'Option' // handle promoting none/error/function returning 'Option'
if fn_return_is_optional { if fn_return_is_optional {
optional_none := node.exprs[0] is ast.None optional_none := node.exprs[0] is ast.None
@ -2418,7 +2418,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
// normal return // normal return
return_sym := g.table.get_type_symbol(node.types[0]) return_sym := g.table.get_type_symbol(node.types[0])
// `return opt_ok(expr)` for functions that expect an optional // `return opt_ok(expr)` for functions that expect an optional
if fn_return_is_optional && !node.types[0].flag_is(.optional) && return_sym.name != if fn_return_is_optional && !node.types[0].has_flag(.optional) && return_sym.name !=
'Option' { 'Option' {
styp := g.base_type(g.fn_decl.return_type) styp := g.base_type(g.fn_decl.return_type)
opt_type := g.typ(g.fn_decl.return_type) opt_type := g.typ(g.fn_decl.return_type)
@ -2631,7 +2631,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
// unions thould have exactly one explicit initializer // unions thould have exactly one explicit initializer
continue continue
} }
if field.typ.flag_is(.optional) { if field.typ.has_flag(.optional) {
// TODO handle/require optionals in inits // TODO handle/require optionals in inits
continue continue
} }
@ -2813,7 +2813,7 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
// if this is the case then we are going to // if this is the case then we are going to
// buffer manip out in front of the struct // buffer manip out in front of the struct
// write the optional in and then continue // write the optional in and then continue
if field.typ.flag_is(.optional) { if field.typ.has_flag(.optional) {
// Dont use g.typ() here becuase it will register // Dont use g.typ() here becuase it will register
// optional and we dont want that // optional and we dont want that
last_text := g.type_definitions.after(start_pos).clone() last_text := g.type_definitions.after(start_pos).clone()
@ -3102,7 +3102,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool { fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
sym := g.table.get_type_symbol(etype) sym := g.table.get_type_symbol(etype)
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
if etype.flag_is(.variadic) { if etype.has_flag(.variadic) {
str_fn_name := g.gen_str_for_type(etype) str_fn_name := g.gen_str_for_type(etype)
g.write('${str_fn_name}(') g.write('${str_fn_name}(')
g.expr(expr) g.expr(expr)
@ -3294,7 +3294,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type table.
expr_stmt := stmt as ast.ExprStmt expr_stmt := stmt as ast.ExprStmt
g.stmt_path_pos << g.out.len g.stmt_path_pos << g.out.len
g.write('*(${mr_styp}*) ${cvar_name}.data = ') g.write('*(${mr_styp}*) ${cvar_name}.data = ')
is_opt_call := expr_stmt.expr is ast.CallExpr && expr_stmt.typ.flag_is(.optional) is_opt_call := expr_stmt.expr is ast.CallExpr && expr_stmt.typ.has_flag(.optional)
if is_opt_call { if is_opt_call {
g.write('*(${mr_styp}*) ') g.write('*(${mr_styp}*) ')
} }
@ -3858,7 +3858,7 @@ fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string {
} }
} }
// if varg, generate str for varg // if varg, generate str for varg
if typ.flag_is(.variadic) { if typ.has_flag(.variadic) {
varg_already_generated_key := 'varg_$already_generated_key' varg_already_generated_key := 'varg_$already_generated_key'
if varg_already_generated_key !in g.str_types { if varg_already_generated_key !in g.str_types {
g.gen_str_for_varg(styp, str_fn_name, sym_has_str_method) g.gen_str_for_varg(styp, str_fn_name, sym_has_str_method)

View File

@ -430,7 +430,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
} }
g.expr(node.left) g.expr(node.left)
is_variadic := node.expected_arg_types.len > 0 && node.expected_arg_types[node.expected_arg_types.len - is_variadic := node.expected_arg_types.len > 0 && node.expected_arg_types[node.expected_arg_types.len -
1].flag_is(.variadic) 1].has_flag(.variadic)
if node.args.len > 0 || is_variadic { if node.args.len > 0 || is_variadic {
g.write(', ') g.write(', ')
} }
@ -523,7 +523,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
styp = styp.replace('*', '') styp = styp.replace('*', '')
} }
mut str_fn_name := g.gen_str_for_type_with_styp(typ, styp) mut str_fn_name := g.gen_str_for_type_with_styp(typ, styp)
if g.autofree && !typ.flag_is(.optional) { if g.autofree && !typ.has_flag(.optional) {
// Create a temporary variable so that the value can be freed // Create a temporary variable so that the value can be freed
tmp := g.new_tmp_var() tmp := g.new_tmp_var()
// tmps << tmp // tmps << tmp
@ -565,7 +565,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
g.write('*') g.write('*')
} }
g.expr(expr) g.expr(expr)
if !typ.flag_is(.variadic) && sym.kind == .struct_ && styp != 'ptr' && !sym.has_method('str') { if !typ.has_flag(.variadic) && sym.kind == .struct_ && styp != 'ptr' && !sym.has_method('str') {
g.write(', 0') // trailing 0 is initial struct indent count g.write(', 0') // trailing 0 is initial struct indent count
} }
} }
@ -599,8 +599,8 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
} }
fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) { fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
is_variadic := expected_types.len > 0 && expected_types[expected_types.len - 1].flag_is(.variadic) is_variadic := expected_types.len > 0 && expected_types[expected_types.len - 1].has_flag(.variadic)
is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.flag_is(.variadic) is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.has_flag(.variadic)
gen_vargs := is_variadic && !is_forwarding_varg gen_vargs := is_variadic && !is_forwarding_varg
for i, arg in args { for i, arg in args {
if gen_vargs && i == expected_types.len - 1 { if gen_vargs && i == expected_types.len - 1 {

View File

@ -908,7 +908,7 @@ fn (mut g JsGen) gen_for_in_stmt(it ast.ForInStmt) {
g.inside_loop = false g.inside_loop = false
g.stmts(it.stmts) g.stmts(it.stmts)
g.writeln('}') g.writeln('}')
} else if it.kind == .array || it.cond_type.flag_is(.variadic) { } else if it.kind == .array || it.cond_type.has_flag(.variadic) {
// `for num in nums {` // `for num in nums {`
i := if it.key_var == '' { g.new_tmp_var() } else { it.key_var } i := if it.key_var == '' { g.new_tmp_var() } else { it.key_var }
// styp := g.typ(it.val_type) // styp := g.typ(it.val_type)

View File

@ -36,8 +36,8 @@ pub mut:
is_public bool is_public bool
} }
// max of 8
pub enum TypeFlag { pub enum TypeFlag {
unset
optional optional
variadic variadic
generic generic
@ -99,29 +99,33 @@ pub fn (t Type) deref() Type {
return (((int(t) >> 24) & 0xff) << 24) | ((nr_muls - 1) << 16) | (u16(t) & 0xffff) return (((int(t) >> 24) & 0xff) << 24) | ((nr_muls - 1) << 16) | (u16(t) & 0xffff)
} }
// return the flag that is set on `t` // set `flag` on `t` and return `t`
[inline]
pub fn (t Type) flag() TypeFlag {
return (int(t) >> 24) & 0xff
}
// set the flag on `t` to `flag` and return it
[inline] [inline]
pub fn (t Type) set_flag(flag TypeFlag) Type { pub fn (t Type) set_flag(flag TypeFlag) Type {
return (int(flag) << 24) | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff) return ((((int(t) >> 24) & 0xff) | 1 << int(flag)) << 24) | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff)
} }
// return true if the flag set on `t` is `flag` // clear `flag` on `t` and return `t`
pub fn (t Type) clear_flag(flag TypeFlag) Type {
return (((((int(t) >> 24) & 0xff) & ~(1 << int(flag))) << 24) ) | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff)
}
// clear all flags
pub fn (t Type) clear_flags() Type {
return 0 | (((int(t) >> 16) & 0xff) << 16) | (u16(t) & 0xffff)
}
// return true if `flag` is set in `t`
[inline] [inline]
pub fn (t Type) flag_is(flag TypeFlag) bool { pub fn (t Type) has_flag(flag TypeFlag) bool {
return (int(t) >> 24) & 0xff == flag return (((int(t) >> 24) & 0xff) >> int(flag)) & 1 == 1
} }
// return new type with TypeSymbol idx set to `idx` // return new type with TypeSymbol idx set to `idx`
[inline] [inline]
pub fn new_type(idx int) Type { pub fn new_type(idx int) Type {
if idx < 1 || idx > 65536 { if idx < 1 || idx > 65535 {
panic('new_type_id: idx must be between 1 & 65536') panic('new_type_id: idx must be between 1 & 65535')
} }
return idx return idx
} }
@ -129,8 +133,8 @@ pub fn new_type(idx int) Type {
// return new type with TypeSymbol idx set to `idx` & nr_muls set to `nr_muls` // return new type with TypeSymbol idx set to `idx` & nr_muls set to `nr_muls`
[inline] [inline]
pub fn new_type_ptr(idx, nr_muls int) Type { pub fn new_type_ptr(idx, nr_muls int) Type {
if idx < 1 || idx > 65536 { if idx < 1 || idx > 65535 {
panic('new_type_ptr: idx must be between 1 & 65536') panic('new_type_ptr: idx must be between 1 & 65535')
} }
if nr_muls < 0 || nr_muls > 255 { if nr_muls < 0 || nr_muls > 255 {
panic('new_type_ptr: nr_muls must be between 0 & 255') panic('new_type_ptr: nr_muls must be between 0 & 255')
@ -673,7 +677,7 @@ pub fn (table &Table) type_to_str(t Type) string {
mut res := sym.name mut res := sym.name
if sym.kind == .multi_return { if sym.kind == .multi_return {
res = '(' res = '('
if t.flag_is(.optional) { if t.has_flag(.optional) {
res = '?' + res res = '?' + res
} }
mr_info := sym.info as MultiReturn mr_info := sym.info as MultiReturn
@ -706,7 +710,7 @@ pub fn (table &Table) type_to_str(t Type) string {
if nr_muls > 0 { if nr_muls > 0 {
res = strings.repeat(`&`, nr_muls) + res res = strings.repeat(`&`, nr_muls) + res
} }
if t.flag_is(.optional) { if t.has_flag(.optional) {
if sym.kind == .void { if sym.kind == .void {
res = '?' res = '?'
} else { } else {

View File

@ -417,9 +417,9 @@ pub fn (mut t Table) add_placeholder_type(name string) int {
[inline] [inline]
pub fn (t &Table) value_type(typ Type) Type { pub fn (t &Table) value_type(typ Type) Type {
typ_sym := t.get_type_symbol(typ) typ_sym := t.get_type_symbol(typ)
if typ.flag_is(.variadic) { if typ.has_flag(.variadic) {
// ...string => string // ...string => string
return typ.set_flag(.unset) return typ.clear_flag(.variadic)
} }
if typ_sym.kind == .array { if typ_sym.kind == .array {
// Check index type // Check index type