Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

checker: fix comptime evaluation on infix expr #23344

Merged
merged 17 commits into from
Jan 3, 2025
6 changes: 3 additions & 3 deletions vlib/math/stats/stats_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -428,13 +428,13 @@ fn test_covariance() {
fn test_lag1_autocorrelation() {
mut data := [10.0, 4.45, 5.9, 2.7]
mut o := stats.lag1_autocorrelation(data)
assert math.alike(o, -0.554228566606572)
assert math.alike(o, -0.5542285495255542)
felipensp marked this conversation as resolved.
Show resolved Hide resolved
data = [-3.0, 67.31, 4.4, 1.89]
o = stats.lag1_autocorrelation(data)
assert math.alike(o, -0.5102510823460722)
assert math.alike(o, -0.5102510688760657)
data = [12.0, 7.88, 76.122, 54.83]
o = stats.lag1_autocorrelation(data)
assert math.alike(o, 0.10484451825170164)
assert math.alike(o, 0.10484451223403927)

// test for int, i64, f32 array
assert stats.lag1_autocorrelation[int]([1, 2, 3, 1]) == 0
Expand Down
31 changes: 24 additions & 7 deletions vlib/v/checker/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
node.left_types = []
mut right_len := node.right.len
mut right_first_type := ast.void_type
old_recheck := c.inside_recheck
// check if we are rechecking an already checked expression on generic rechecking
c.inside_recheck = old_recheck || node.right_types.len > 0
defer {
c.inside_recheck = old_recheck
}
for i, mut right in node.right {
if right in [ast.CallExpr, ast.IfExpr, ast.LockExpr, ast.MatchExpr, ast.DumpExpr,
ast.SelectorExpr, ast.ParExpr, ast.ComptimeCall] {
Expand All @@ -37,7 +43,9 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
}
right_type_sym := c.table.sym(right_type)
// fixed array returns an struct, but when assigning it must be the array type
right_type = c.cast_fixed_array_ret(right_type, right_type_sym)
if right_type_sym.info is ast.ArrayFixed {
right_type = c.cast_fixed_array_ret(right_type, right_type_sym)
}
if i == 0 {
right_first_type = right_type
node.right_types = [
Expand All @@ -62,11 +70,23 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
}
}
}
}
if mut right is ast.InfixExpr {
} else if mut right is ast.InfixExpr {
if right.op == .arrow {
c.error('cannot use `<-` on the right-hand side of an assignment, as it does not return any values',
right.pos)
} else if c.inside_recheck {
mut right_type := c.expr(mut right)
right_type_sym := c.table.sym(right_type)
// fixed array returns an struct, but when assigning it must be the array type
if right_type_sym.info is ast.ArrayFixed {
right_type = c.cast_fixed_array_ret(right_type, right_type_sym)
}
if i == 0 {
right_first_type = right_type
node.right_types = [
c.check_expr_option_or_result_call(right, right_first_type),
]
}
}
}
if mut right is ast.Ident {
Expand Down Expand Up @@ -182,16 +202,13 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
node.right_types << c.check_expr_option_or_result_call(node.right[i],
right_type)
}
} else {
} else if c.inside_recheck {
// on generic recheck phase it might be needed to resolve the rhs again
if i < node.right.len && c.comptime.has_comptime_expr(node.right[i]) {
mut expr := mut node.right[i]
old_inside_recheck := c.inside_recheck
c.inside_recheck = true
right_type := c.expr(mut expr)
node.right_types[i] = c.check_expr_option_or_result_call(node.right[i],
right_type)
c.inside_recheck = old_inside_recheck
}
}
mut right := if i < node.right.len { node.right[i] } else { node.right[0] }
Expand Down
62 changes: 62 additions & 0 deletions vlib/v/tests/comptime/comptime_infix_assign_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
enum Flag {
usa_old_glory
all_other_bad_excuses_for_a_flag
}

struct Test {
is_foo bool
name [5]u8
}

fn enc[T](item T) string {
$if T is $int {
len := match typeof(item).name {
'i8', 'u8' { u8(2) }
'i16', 'u16' { 4 }
'int', 'u32', 'i32' { 8 }
'i64', 'u64' { 16 }
else { return '' }
}
return u64_to_hex(item, len)
} $else $if T is $array {
mut hex := ''
for val in item {
hex += enc(val)
}
return hex
} $else $if T is $struct {
mut hex := ''
$for field in T.fields {
hex += enc(item.$(field.name)) + '_'
}
return hex
} $else {
if typeof(item).name == 'bool' {
return enc(int(item))
}
$if debug {
println('cannot encode ${T}(s)')
}
return ''
}
}

@[direct_array_access; inline]
fn u64_to_hex(nn u64, len u8) string {
mut n := nn
mut buf := [17]u8{}
buf[len] = 0
mut i := 0
for i = len - 1; i >= 0; i-- {
d := u8(n & 0xF)
buf[i] = if d < 10 { d + `0` } else { d + 87 }
n = n >> 4
}
return unsafe { tos(memdup(&buf[0], len + 1), len) }
}

fn test_main() {
assert enc(Test{}) == '00000000_0000000000_'
assert enc(Test{ is_foo: true }) == '00000001_0000000000_'
assert enc(Test{ name: [u8(1), 2, 3, 4, 5]! }) == '00000000_0102030405_'
}
Loading