checker: check types with $for/$if introspection (#8984)

pull/8989/head
Nick Treleaven 2021-02-26 14:26:50 +00:00 committed by GitHub
parent 1a8ff9d7dd
commit 4ad95cfeaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 9 deletions

View File

@ -3109,12 +3109,11 @@ fn (mut c Checker) stmt(node ast.Stmt) {
c.branch_stmt(node)
}
ast.CompFor {
if node.typ > table.void_type {
sym := c.table.get_type_symbol(node.typ)
if sym.kind == .placeholder {
typ := c.unwrap_generic(node.typ)
sym := c.table.get_type_symbol(typ)
if sym.kind == .placeholder || typ.has_flag(.generic) {
c.error('unknown type `$sym.name`', node.typ_pos)
}
}
c.stmts(node.stmts)
}
ast.ConstDecl {
@ -4806,7 +4805,11 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
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
got_type := c.unwrap_generic((branch.cond.right as ast.Type).typ)
sym := c.table.get_type_symbol(got_type)
if sym.kind == .placeholder || got_type.has_flag(.generic) {
c.error('unknown type `$sym.name`', branch.cond.right.position())
}
if left is ast.SelectorExpr {
comptime_field_name = left.expr.str()
c.comptime_fields_type[comptime_field_name] = got_type

View File

@ -12,7 +12,7 @@ vlib/v/checker/tests/comptime_field_selector_not_name_err.vv:12:12: error: unkno
| ~~
13 | }
14 | }
vlib/v/checker/tests/comptime_field_selector_not_name_err.vv:15:10: error: compile time field access can only be used when iterating over `T.fields`
vlib/v/checker/tests/comptime_field_selector_not_name_err.vv:15:10: error: undefined ident: `f`
13 | }
14 | }
15 | _ = t.$(f.name)

View File

@ -3,10 +3,53 @@ vlib/v/checker/tests/comptime_for.vv:2:12: error: unknown type `Huh`
2 | $for m in Huh.methods {}
| ~~~
3 | $for f in Huh.fields {}
4 | }
4 | $for f in T.fields {
vlib/v/checker/tests/comptime_for.vv:3:12: error: unknown type `Huh`
1 | fn unknown() {
2 | $for m in Huh.methods {}
3 | $for f in Huh.fields {}
| ~~~
4 | }
4 | $for f in T.fields {
5 | $if f.typ is Huh {}
vlib/v/checker/tests/comptime_for.vv:4:12: error: unknown type `T`
2 | $for m in Huh.methods {}
3 | $for f in Huh.fields {}
4 | $for f in T.fields {
| ^
5 | $if f.typ is Huh {}
6 | $if f.typ is T {}
vlib/v/checker/tests/comptime_for.vv:5:16: error: unknown type `Huh`
3 | $for f in Huh.fields {}
4 | $for f in T.fields {
5 | $if f.typ is Huh {}
| ~~~
6 | $if f.typ is T {}
7 | }
vlib/v/checker/tests/comptime_for.vv:6:16: error: unknown type `T`
4 | $for f in T.fields {
5 | $if f.typ is Huh {}
6 | $if f.typ is T {}
| ^
7 | }
8 | _ = m
vlib/v/checker/tests/comptime_for.vv:8:6: error: undefined ident: `m`
6 | $if f.typ is T {}
7 | }
8 | _ = m
| ^
9 | }
10 |
vlib/v/checker/tests/comptime_for.vv:14:16: error: unknown type `U`
12 | $for f in T.fields {
13 | $if f.typ is T {}
14 | $if f.typ is U {}
| ^
15 | }
16 | _ = f
vlib/v/checker/tests/comptime_for.vv:16:6: error: undefined ident: `f`
14 | $if f.typ is U {}
15 | }
16 | _ = f
| ^
17 | }
18 |

View File

@ -1,4 +1,23 @@
fn unknown() {
$for m in Huh.methods {}
$for f in Huh.fields {}
$for f in T.fields {
$if f.typ is Huh {}
$if f.typ is T {}
}
_ = m
}
fn gf<T>() {
$for f in T.fields {
$if f.typ is T {}
$if f.typ is U {}
}
_ = f
}
struct S1 {
i int
}
gf<S1>()

View File

@ -227,6 +227,7 @@ fn (mut p Parser) comp_for() ast.CompFor {
p.check(.dot)
for_val := p.check_name()
mut kind := ast.CompForKind.methods
p.open_scope()
if for_val == 'methods' {
p.scope.register(ast.Var{
name: val_var
@ -247,6 +248,7 @@ fn (mut p Parser) comp_for() ast.CompFor {
}
spos := p.tok.position()
stmts := p.parse_block()
p.close_scope()
return ast.CompFor{
val_var: val_var
stmts: stmts