checker: improve errors with compile-time field access (#8373)

pull/8401/head
Nick Treleaven 2021-01-28 23:45:00 +00:00 committed by GitHub
parent 4aee997689
commit d012f2713b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 7 deletions

View File

@ -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)

View File

@ -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 |

View File

@ -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 |

View File

@ -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() {