diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index eb6f151cf7..0a662262e1 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3377,13 +3377,19 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { node.field_expr.position()) } if node.field_expr is ast.SelectorExpr { + left_pos := node.field_expr.expr.position() + if c.comptime_fields_type.len == 0 { + c.error('compile time field access can only be used when iterating over `T.fields`', + left_pos) + } expr_name := node.field_expr.expr.str() if expr_name in c.comptime_fields_type { return c.comptime_fields_type[expr_name] } + c.error('unknown `\$for` variable `$expr_name`', left_pos) + } else { + c.error('expected selector expression e.g. `$(field.name)`', node.field_expr.position()) } - c.error('compile time field access can only be used when iterating over `T.fields`', - node.field_expr.position()) return table.void_type } ast.ConcatExpr { @@ -4458,12 +4464,14 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type { } if node.is_comptime { // Skip checking if needed // smartcast field type on comptime if + mut comptime_field_name := '' if branch.cond is ast.InfixExpr { if branch.cond.op == .key_is { left := branch.cond.left got_type := (branch.cond.right as ast.Type).typ if left is ast.SelectorExpr { - c.comptime_fields_type[left.expr.str()] = got_type + comptime_field_name = left.expr.str() + c.comptime_fields_type[comptime_field_name] = got_type is_comptime_type_is_expr = true } else if left is ast.Type { is_comptime_type_is_expr = true @@ -4488,6 +4496,9 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type { } else if !is_comptime_type_is_expr { node.branches[i].stmts = [] } + if comptime_field_name.len > 0 { + c.comptime_fields_type.delete(comptime_field_name) + } c.skip_flags = cur_skip_flags } else { c.stmts(branch.stmts) diff --git a/vlib/v/checker/tests/comptime_field_selector_not_in_for_err.out b/vlib/v/checker/tests/comptime_field_selector_not_in_for_err.out index e8e07aed9d..b5634fde55 100644 --- a/vlib/v/checker/tests/comptime_field_selector_not_in_for_err.out +++ b/vlib/v/checker/tests/comptime_field_selector_not_in_for_err.out @@ -1,7 +1,7 @@ -vlib/v/checker/tests/comptime_field_selector_not_in_for_err.vv:9:5: error: compile time field access can only be used when iterating over `T.fields` +vlib/v/checker/tests/comptime_field_selector_not_in_for_err.vv:9:5: error: expected selector expression e.g. `$(field.name)` 7 | mut t := T{} 8 | name := 'test' 9 | t.$name = '3' | ~~~~ 10 | } - 11 | \ No newline at end of file + 11 | diff --git a/vlib/v/checker/tests/comptime_field_selector_not_name_err.out b/vlib/v/checker/tests/comptime_field_selector_not_name_err.out index 2bedf135e0..e178f1c3f5 100644 --- a/vlib/v/checker/tests/comptime_field_selector_not_name_err.out +++ b/vlib/v/checker/tests/comptime_field_selector_not_name_err.out @@ -3,5 +3,19 @@ vlib/v/checker/tests/comptime_field_selector_not_name_err.vv:10:7: error: expect 9 | $if f.typ is string { 10 | t.$f = '3' | ^ - 11 | } - 12 | } \ No newline at end of file + 11 | fv := Foo{} + 12 | _ = t.$fv.name +vlib/v/checker/tests/comptime_field_selector_not_name_err.vv:12:11: error: unknown `$for` variable `fv` + 10 | t.$f = '3' + 11 | fv := Foo{} + 12 | _ = t.$fv.name + | ~~ + 13 | } + 14 | } +vlib/v/checker/tests/comptime_field_selector_not_name_err.vv:15:9: error: compile time field access can only be used when iterating over `T.fields` + 13 | } + 14 | } + 15 | _ = t.$f.name + | ^ + 16 | } + 17 | diff --git a/vlib/v/checker/tests/comptime_field_selector_not_name_err.vv b/vlib/v/checker/tests/comptime_field_selector_not_name_err.vv index 3683352fb5..58ff07f946 100644 --- a/vlib/v/checker/tests/comptime_field_selector_not_name_err.vv +++ b/vlib/v/checker/tests/comptime_field_selector_not_name_err.vv @@ -8,8 +8,11 @@ fn test() { $for f in T.fields { $if f.typ is string { t.$f = '3' + fv := Foo{} + _ = t.$fv.name } } + _ = t.$f.name } fn main() {