checker: improve errors with compile-time field access (#8373)
parent
4aee997689
commit
d012f2713b
|
@ -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)
|
||||
|
|
|
@ -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 |
|
||||
11 |
|
||||
|
|
|
@ -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 | }
|
||||
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 |
|
||||
|
|
|
@ -8,8 +8,11 @@ fn test<T>() {
|
|||
$for f in T.fields {
|
||||
$if f.typ is string {
|
||||
t.$f = '3'
|
||||
fv := Foo{}
|
||||
_ = t.$fv.name
|
||||
}
|
||||
}
|
||||
_ = t.$f.name
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
Loading…
Reference in New Issue