From 4ad95cfeafc10cc102ddbf0b06e4c50ea842a1f1 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 26 Feb 2021 14:26:50 +0000 Subject: [PATCH] checker: check types with $for/$if introspection (#8984) --- vlib/v/checker/checker.v | 15 +++--- .../comptime_field_selector_not_name_err.out | 2 +- vlib/v/checker/tests/comptime_for.out | 47 ++++++++++++++++++- vlib/v/checker/tests/comptime_for.vv | 19 ++++++++ vlib/v/parser/comptime.v | 2 + 5 files changed, 76 insertions(+), 9 deletions(-) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index b26e9a5fef..4d033c589b 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3109,11 +3109,10 @@ 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 { - c.error('unknown type `$sym.name`', node.typ_pos) - } + 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) } @@ -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 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 4be48f244d..c53955c555 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 @@ -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) diff --git a/vlib/v/checker/tests/comptime_for.out b/vlib/v/checker/tests/comptime_for.out index 29e3def2ac..0eea091a31 100644 --- a/vlib/v/checker/tests/comptime_for.out +++ b/vlib/v/checker/tests/comptime_for.out @@ -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 | diff --git a/vlib/v/checker/tests/comptime_for.vv b/vlib/v/checker/tests/comptime_for.vv index 36ed340426..a6d67a063c 100644 --- a/vlib/v/checker/tests/comptime_for.vv +++ b/vlib/v/checker/tests/comptime_for.vv @@ -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() { + $for f in T.fields { + $if f.typ is T {} + $if f.typ is U {} + } + _ = f +} + +struct S1 { + i int +} + +gf() diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index b28df5fee7..3bc6e1fb97 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -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