Skip to content

Commit

Permalink
v: fix aliased type checking, add error for passing aliased int val…
Browse files Browse the repository at this point in the history
…ues to fns that accept `u8` (fix #18278) (#22572)
  • Loading branch information
felipensp authored Oct 19, 2024
1 parent 9ed3788 commit 67f2e93
Show file tree
Hide file tree
Showing 31 changed files with 163 additions and 118 deletions.
20 changes: 11 additions & 9 deletions .github/workflows/compare_pr_to_master.v
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import time
const compare_prod = '-prod' in os.args

fn gbranch() string {
return os.execute(r'git branch --list|grep ^\*').output.trim_space()
return os.execute(r'git branch --list|grep ^\*').output.trim_left('* ').trim_space()
}

fn gcommit() string {
return os.execute(r'git rev-parse --short=7 HEAD').output.trim_space()
return os.execute(r'git rev-parse --short=7 HEAD').output.trim_left('* ').trim_space()
}

fn r(cmd string) {
Expand Down Expand Up @@ -40,9 +40,10 @@ fn vcompare(vold string, vnew string) {

fn main() {
// The starting point, when this program should be started, is just after `gh pr checkout NUMBER`.

println('Current git branch: ${gbranch()}, commit: ${gcommit()}')
println(' Compiling new V executables from PR branch: ${gbranch()}, commit: ${gcommit()} ...')
pr_branch := gbranch()
println('Current git branch: ${pr_branch}, commit: ${gcommit()}')
println(' Compiling new V executables from PR branch: ${pr_branch}, commit: ${gcommit()} ...')
xtime('./v -g self')
xtime('./v -o vnew1 cmd/v')
xtime('./vnew1 -o vnew2 cmd/v')
xtime('./vnew2 -o vnew cmd/v')
Expand All @@ -52,8 +53,9 @@ fn main() {
}

r('git checkout master')

println(' Compiling old V executables from branch: ${gbranch()}, commit: ${gcommit()} ...')
master_branch := gbranch()
println(' Compiling old V executables from branch: ${master_branch}, commit: ${gcommit()} ...')
xtime('./v -g self')
xtime('./v -o vold1 cmd/v')
xtime('./vold1 -o vold2 cmd/v')
xtime('./vold2 -o vold cmd/v')
Expand All @@ -62,9 +64,9 @@ fn main() {
xtime('./vold -prod -o vold_prod cmd/v')
}

r('git switch -') // we are on the PR branch again
r('git checkout ${pr_branch}') // we are on the PR branch again

println(' Measuring at PR branch: ${gbranch()}, commit: ${gcommit()} ...')
println(' Measuring at PR branch: ${pr_branch}, commit: ${gcommit()} ...')
if compare_prod {
vcompare('./vold_prod', './vnew_prod')
} else {
Expand Down
2 changes: 1 addition & 1 deletion vlib/term/termios/termios_darwin.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,5 @@ pub fn set_state(fd int, new_state Termios) int {
// disable_echo disables echoing characters as they are typed,
// when that Termios state is later set with termios.set_state(fd,t)
pub fn (mut t Termios) disable_echo() {
t.c_lflag &= invert(C.ECHO)
t.c_lflag &= invert(usize(C.ECHO))
}
2 changes: 1 addition & 1 deletion vlib/term/ui/termios_nix.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fn get_termios() termios.Termios {
@[inline]
fn get_terminal_size() (u16, u16) {
winsz := C.winsize{}
termios.ioctl(0, termios.flag(C.TIOCGWINSZ), voidptr(&winsz))
termios.ioctl(0, u64(termios.flag(C.TIOCGWINSZ)), voidptr(&winsz))
return winsz.ws_row, winsz.ws_col
}

Expand Down
26 changes: 17 additions & 9 deletions vlib/v/ast/table.v
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,11 @@ pub fn (t &Table) resolve_common_sumtype_fields(mut sym TypeSymbol) {
sym.info = info
}

@[inline]
pub fn (t &Table) find_type(name string) Type {
return idx_to_type(t.type_idxs[name])
}

@[inline]
pub fn (t &Table) find_type_idx(name string) int {
return t.type_idxs[name]
Expand Down Expand Up @@ -1162,7 +1167,8 @@ pub fn (mut t Table) find_or_register_array_with_dims(elem_type Type, nr_dims in
if nr_dims == 1 {
return t.find_or_register_array(elem_type)
}
return t.find_or_register_array(t.find_or_register_array_with_dims(elem_type, nr_dims - 1))
return t.find_or_register_array(idx_to_type(t.find_or_register_array_with_dims(elem_type,
nr_dims - 1)))
}

pub fn (mut t Table) find_or_register_array_fixed(elem_type Type, size int, size_expr Expr, is_fn_ret bool) int {
Expand Down Expand Up @@ -1416,10 +1422,11 @@ pub fn (t &Table) is_interface_smartcast(var ScopeObject) bool {
pub fn (t &Table) known_type_names() []string {
mut res := []string{cap: t.type_idxs.len}
for _, idx in t.type_idxs {
typ := idx_to_type(idx)
// Skip `int_literal_type_idx` and `float_literal_type_idx` because they shouldn't be visible to the User.
if idx !in [0, int_literal_type_idx, float_literal_type_idx] && t.known_type_idx(idx)
&& t.sym(idx).kind != .function {
res << t.type_to_str(idx)
if idx !in [0, int_literal_type_idx, float_literal_type_idx] && t.known_type_idx(typ)
&& t.sym(typ).kind != .function {
res << t.type_to_str(typ)
}
}
return res
Expand Down Expand Up @@ -1449,6 +1456,7 @@ pub fn (mut t Table) complete_interface_check() {
util.timing_measure(@METHOD)
}
for tk, mut tsym in t.type_symbols {
tk_typ := idx_to_type(tk)
if tsym.kind != .struct {
continue
}
Expand All @@ -1460,11 +1468,11 @@ pub fn (mut t Table) complete_interface_check() {
if idecl.methods.len == 0 && idecl.fields.len == 0 && tsym.mod != t.sym(idecl.typ).mod {
continue
}
if t.does_type_implement_interface(tk, idecl.typ) {
if t.does_type_implement_interface(tk_typ, idecl.typ) {
$if trace_types_implementing_each_interface ? {
eprintln('>>> tsym.mod: ${tsym.mod} | tsym.name: ${tsym.name} | tk: ${tk} | idecl.name: ${idecl.name} | idecl.typ: ${idecl.typ}')
}
t.iface_types[idecl.name] << tk
t.iface_types[idecl.name] << tk_typ
}
}
}
Expand Down Expand Up @@ -1593,7 +1601,7 @@ pub fn (mut t Table) convert_generic_static_type_name(fn_name string, generic_na
valid_generic := util.is_generic_type_name(generic_name)
&& generic_name in generic_names
if valid_generic {
name_type := idx_to_type(t.find_type_idx(generic_name)).set_flag(.generic)
name_type := t.find_type(generic_name).set_flag(.generic)
if typ := t.convert_generic_type(name_type, generic_names, concrete_types) {
return '${t.type_to_str(typ)}${fn_name[index..]}'
}
Expand Down Expand Up @@ -2129,7 +2137,7 @@ pub fn (mut t Table) unwrap_generic_type_ex(typ Type, generic_names []string, co
info: info
is_pub: ts.is_pub
)
mut ts_copy := t.sym(new_idx)
mut ts_copy := t.sym(idx_to_type(new_idx))
for method in all_methods {
ts_copy.register_method(method)
}
Expand Down Expand Up @@ -2585,6 +2593,6 @@ pub fn (mut t Table) get_veb_result_type_idx() int {
return t.veb_res_idx_cache
}

t.veb_res_idx_cache = t.find_type_idx('veb.Result')
t.veb_res_idx_cache = t.find_type('veb.Result')
return t.veb_res_idx_cache
}
6 changes: 6 additions & 0 deletions vlib/v/ast/types.v
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,12 @@ pub fn (t Type) derive_add_muls(t_from Type) Type {
return Type((0xff000000 & t_from) | u16(t)).set_nr_muls(t.nr_muls() + t_from.nr_muls())
}

// return new type from its `idx`
@[inline]
pub fn (t Type) idx_type() Type {
return idx_to_type(t.idx())
}

// return new type with TypeSymbol idx set to `idx`
@[inline]
pub fn new_type(idx int) Type {
Expand Down
6 changes: 3 additions & 3 deletions vlib/v/checker/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -717,10 +717,10 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
modified_left_type := if !left_type.is_int() {
c.error('invalid operation: shift on type `${c.table.sym(left_type).name}`',
node.pos)
ast.void_type_idx
ast.void_type
} else if left_type.is_int_literal() {
// int literal => i64
ast.u32_type_idx
ast.u32_type
} else if left_type.is_unsigned() {
left_type
} else {
Expand All @@ -731,7 +731,7 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
// i64 => u64
// isize => usize
// i128 => u128 NOT IMPLEMENTED YET
left_type.idx() + ast.u32_type_idx - ast.int_type_idx
ast.idx_to_type(left_type.idx() + ast.u32_type_idx - ast.int_type_idx)
}

node = ast.AssignStmt{
Expand Down
43 changes: 25 additions & 18 deletions vlib/v/checker/check_types.v
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,16 @@ fn (c &Checker) check_multiple_ptr_match(got ast.Type, expected ast.Type, param
return true
}

fn (mut c Checker) check_expected_call_arg(got ast.Type, expected_ ast.Type, language ast.Language, arg ast.CallArg) ! {
if got == 0 {
fn (mut c Checker) check_expected_call_arg(got_ ast.Type, expected_ ast.Type, language ast.Language, arg ast.CallArg) ! {
if got_ == 0 {
return error('unexpected 0 type')
}
mut expected := expected_
mut expected := c.table.unaliased_type(expected_)
is_aliased := expected != expected_
is_exp_sumtype := c.table.type_kind(expected_) == .sum_type
got := c.table.unaliased_type(got_)
// variadic
if expected.has_flag(.variadic) {
if expected_.has_flag(.variadic) {
exp_type_sym := c.table.sym(expected_)
exp_info := exp_type_sym.info as ast.Array
expected = exp_info.elem_type
Expand Down Expand Up @@ -242,39 +245,39 @@ fn (mut c Checker) check_expected_call_arg(got ast.Type, expected_ ast.Type, lan
// passing &expr where no-pointer is expected
if expected != ast.voidptr_type && !expected.is_ptr() && got.is_ptr()
&& arg.expr.is_reference() {
got_typ_str, expected_typ_str := c.get_string_names_of(got, expected)
got_typ_str, expected_typ_str := c.get_string_names_of(got_, expected_)
return error('cannot use `${got_typ_str}` as `${expected_typ_str}`')
}
if expected.has_flag(.option) {
got_is_ptr := got.is_ptr()
|| (arg.expr is ast.Ident && (arg.expr as ast.Ident).is_mut())
|| arg.expr is ast.None
if (expected.is_ptr() && !got_is_ptr) || (!expected.is_ptr() && got.is_ptr()) {
got_typ_str, expected_typ_str := c.get_string_names_of(got, expected)
got_typ_str, expected_typ_str := c.get_string_names_of(got_, expected_)
return error('cannot use `${got_typ_str}` as `${expected_typ_str}`')
}
}

// `fn foo(mut p &Expr); mut expr := Expr{}; foo(mut expr)`
if arg.is_mut && expected.nr_muls() > 1 && !got.is_ptr() {
got_typ_str, expected_typ_str := c.get_string_names_of(got, expected)
got_typ_str, expected_typ_str := c.get_string_names_of(got_, expected_)
return error('cannot use `${got_typ_str}` as `${expected_typ_str}`')
}

exp_sym_idx := c.table.sym(expected).idx
got_sym_idx := c.table.sym(got).idx
exp_sym_idx := expected.idx()
got_sym_idx := got.idx()

if expected.is_ptr() && got.is_ptr() && exp_sym_idx != got_sym_idx
&& exp_sym_idx in [ast.u8_type_idx, ast.byteptr_type_idx]
&& got_sym_idx !in [ast.u8_type_idx, ast.byteptr_type_idx] {
got_typ_str, expected_typ_str := c.get_string_names_of(got, expected)
got_typ_str, expected_typ_str := c.get_string_names_of(got_, expected_)
return error('cannot use `${got_typ_str}` as `${expected_typ_str}`')
}

if !expected.has_flag(.option) && got.has_flag(.option)
&& (!(arg.expr is ast.Ident || arg.expr is ast.ComptimeSelector)
|| (arg.expr is ast.Ident && c.comptime.get_ct_type_var(arg.expr) != .field_var)) {
got_typ_str, expected_typ_str := c.get_string_names_of(got, expected)
got_typ_str, expected_typ_str := c.get_string_names_of(got_, expected_)
return error('cannot use `${got_typ_str}` as `${expected_typ_str}`, it must be unwrapped first')
}
}
Expand Down Expand Up @@ -308,16 +311,20 @@ fn (mut c Checker) check_expected_call_arg(got ast.Type, expected_ ast.Type, lan
return
}
}

if c.check_types(got, expected) {
exp_type := if !is_aliased || expected_.has_flag(.variadic) {
expected
} else {
expected_
}
if c.check_types(if is_exp_sumtype { got_ } else { got }, exp_type) {
if language == .v && idx_got == ast.voidptr_type_idx {
if expected.is_int_valptr() || expected.is_int() || expected.is_ptr() {
return
}
exp_sym := c.table.final_sym(expected)
if exp_sym.language == .v
&& exp_sym.kind !in [.voidptr, .charptr, .byteptr, .function, .placeholder, .array_fixed, .sum_type, .struct] {
got_typ_str, expected_typ_str := c.get_string_names_of(got, expected)
got_typ_str, expected_typ_str := c.get_string_names_of(got_, exp_type)
return error('cannot use `${got_typ_str}` as `${expected_typ_str}`')
}
}
Expand All @@ -343,20 +350,20 @@ fn (mut c Checker) check_expected_call_arg(got ast.Type, expected_ ast.Type, lan
|| !c.check_same_module(got, expected)
|| (!got.is_ptr() && !expected.is_ptr()
&& got_typ_sym.name != expected_typ_sym.name) {
got_typ_str, expected_typ_str := c.get_string_names_of(got, expected)
got_typ_str, expected_typ_str := c.get_string_names_of(got_, exp_type)
return error('cannot use `${got_typ_str}` as `${expected_typ_str}`')
}
return
}
if got == ast.void_type {
return error('`${arg.expr}` (no value) used as value')
}
got_typ_str, expected_typ_str := c.get_string_names_of(got, expected)
got_typ_str, expected_typ_str := c.get_string_names_of(got_, exp_type)
return error('cannot use `${got_typ_str}` as `${expected_typ_str}`')
}

if got != ast.void_type {
got_typ_str, expected_typ_str := c.get_string_names_of(got, expected)
got_typ_str, expected_typ_str := c.get_string_names_of(got_, exp_type)
return error('cannot use `${got_typ_str}` as `${expected_typ_str}`')
}
}
Expand Down Expand Up @@ -468,7 +475,7 @@ fn (mut c Checker) check_basic(got ast.Type, expected ast.Type) bool {
array_info := parent_elem_sym.array_info()
elem_type := c.table.find_or_register_array_with_dims(array_info.elem_type,
array_info.nr_dims + exp_sym.info.nr_dims)
if c.table.type_to_str(got) == c.table.type_to_str(elem_type) {
if c.table.type_to_str(got) == c.table.type_to_str(ast.idx_to_type(elem_type)) {
return true
}
}
Expand Down
10 changes: 5 additions & 5 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -1490,7 +1490,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
valid_generic := util.is_generic_type_name(name) && c.table.cur_fn != unsafe { nil }
&& name in c.table.cur_fn.generic_names
if valid_generic {
name_type = ast.idx_to_type(c.table.find_type_idx(name)).set_flag(.generic)
name_type = c.table.find_type(name).set_flag(.generic)
}
}
ast.TypeOf {
Expand Down Expand Up @@ -1704,7 +1704,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
} else {
'wrapping the `${rec_sym.name}` object in a `struct` declared as `@[heap]`'
}
c.error('method `${c.table.type_to_str(receiver.idx())}.${method.name}` cannot be used as a variable outside `unsafe` blocks as its receiver might refer to an object stored on stack. Consider ${suggestion}.',
c.error('method `${c.table.type_to_str(receiver.idx_type())}.${method.name}` cannot be used as a variable outside `unsafe` blocks as its receiver might refer to an object stored on stack. Consider ${suggestion}.',
node.expr.pos().extend(node.pos))
}
}
Expand Down Expand Up @@ -3142,7 +3142,7 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type {
node.pos)
} else if node.stmt != ast.empty_stmt && node.typ == ast.void_type {
c.stmt(mut node.stmt)
node.typ = c.table.find_type_idx((node.stmt as ast.StructDecl).name)
node.typ = c.table.find_type((node.stmt as ast.StructDecl).name)
}
return node.typ
}
Expand Down Expand Up @@ -3494,7 +3494,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
}
} else if to_type.is_int() && mut node.expr is ast.IntegerLiteral {
tt := c.table.type_to_str(to_type)
tsize, _ := c.table.type_size(to_type.idx())
tsize, _ := c.table.type_size(to_type.idx_type())
bit_size := tsize * 8
value_string := match node.expr.val[0] {
`-`, `+` {
Expand Down Expand Up @@ -4828,7 +4828,7 @@ fn (mut c Checker) enum_val(mut node ast.EnumVal) ast.Type {
// In the checker the name for such enums was set to `main.ChanState` instead of
// just `ChanState`.
if node.enum_name.starts_with('${c.mod}.') {
typ_idx = c.table.find_type_idx(node.enum_name['${c.mod}.'.len..])
typ_idx = c.table.find_type(node.enum_name['${c.mod}.'.len..])
if typ_idx == 0 {
c.error('unknown enum `${node.enum_name}` (type_idx=0)', node.pos)
return ast.void_type
Expand Down
Loading

0 comments on commit 67f2e93

Please sign in to comment.