Skip to content

Commit 7178367

Browse files
authored
all: fix error for comptime for in field with generic fn (fix #13409) (#13439)
1 parent 9d0a594 commit 7178367

File tree

14 files changed

+251
-155
lines changed

14 files changed

+251
-155
lines changed

vlib/v/ast/ast.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ pub mut:
534534
should_be_skipped bool // true for calls to `[if someflag?]` functions, when there is no `-d someflag`
535535
concrete_types []Type // concrete types, e.g. <int, string>
536536
concrete_list_pos token.Pos
537+
raw_concrete_types []Type
537538
free_receiver bool // true if the receiver expression needs to be freed
538539
scope &Scope
539540
from_embed_types []Type // holds the type of the embed that the method is called from

vlib/v/checker/assign.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
135135
}
136136
}
137137
}
138+
} else if right is ast.ComptimeSelector {
139+
right_type = c.comptime_fields_default_type
138140
}
139141
if is_decl {
140142
// check generic struct init and return unwrap generic struct type

vlib/v/checker/checker.v

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -70,21 +70,22 @@ pub mut:
7070
rlocked_names []string // vars that are currently read-locked
7171
in_for_count int // if checker is currently in a for loop
7272
// checked_ident string // to avoid infinite checker loops
73-
should_abort bool // when too many errors/warnings/notices are accumulated, .should_abort becomes true. It is checked in statement/expression loops, so the checker can return early, instead of wasting time.
74-
returns bool
75-
scope_returns bool
76-
is_builtin_mod bool // true inside the 'builtin', 'os' or 'strconv' modules; TODO: remove the need for special casing this
77-
is_generated bool // true for `[generated] module xyz` .v files
78-
inside_unsafe bool // true inside `unsafe {}` blocks
79-
inside_const bool // true inside `const ( ... )` blocks
80-
inside_anon_fn bool // true inside `fn() { ... }()`
81-
inside_ref_lit bool // true inside `a := &something`
82-
inside_defer bool // true inside `defer {}` blocks
83-
inside_fn_arg bool // `a`, `b` in `a.f(b)`
84-
inside_ct_attr bool // true inside `[if expr]`
85-
skip_flags bool // should `#flag` and `#include` be skipped
86-
fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc
87-
ct_cond_stack []ast.Expr
73+
should_abort bool // when too many errors/warnings/notices are accumulated, .should_abort becomes true. It is checked in statement/expression loops, so the checker can return early, instead of wasting time.
74+
returns bool
75+
scope_returns bool
76+
is_builtin_mod bool // true inside the 'builtin', 'os' or 'strconv' modules; TODO: remove the need for special casing this
77+
is_generated bool // true for `[generated] module xyz` .v files
78+
inside_unsafe bool // true inside `unsafe {}` blocks
79+
inside_const bool // true inside `const ( ... )` blocks
80+
inside_anon_fn bool // true inside `fn() { ... }()`
81+
inside_ref_lit bool // true inside `a := &something`
82+
inside_defer bool // true inside `defer {}` blocks
83+
inside_fn_arg bool // `a`, `b` in `a.f(b)`
84+
inside_ct_attr bool // true inside `[if expr]`
85+
inside_comptime_for_field bool
86+
skip_flags bool // should `#flag` and `#include` be skipped
87+
fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc
88+
ct_cond_stack []ast.Expr
8889
mut:
8990
stmt_level int // the nesting level inside each stmts list;
9091
// .stmt_level is used to check for `evaluated but not used` ExprStmts like `1 << 1`

vlib/v/checker/comptime.v

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,19 @@ fn (mut c Checker) comptime_for(node ast.ComptimeFor) {
109109
c.error('unknown type `$sym.name`', node.typ_pos)
110110
}
111111
if node.kind == .fields {
112-
c.comptime_fields_type[node.val_var] = node.typ
113-
c.comptime_fields_default_type = node.typ
112+
if sym.kind == .struct_ {
113+
sym_info := sym.info as ast.Struct
114+
c.inside_comptime_for_field = true
115+
for field in sym_info.fields {
116+
c.comptime_fields_type[node.val_var] = node.typ
117+
c.comptime_fields_default_type = field.typ
118+
c.stmts(node.stmts)
119+
}
120+
c.inside_comptime_for_field = false
121+
}
122+
} else {
123+
c.stmts(node.stmts)
114124
}
115-
c.stmts(node.stmts)
116125
}
117126

118127
// comptime const eval

vlib/v/checker/fn.v

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
428428
}
429429
mut has_generic := false // foo<T>() instead of foo<int>()
430430
mut concrete_types := []ast.Type{}
431+
node.concrete_types = node.raw_concrete_types
431432
for concrete_type in node.concrete_types {
432433
if concrete_type.has_flag(.generic) {
433434
has_generic = true
@@ -777,6 +778,13 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
777778

778779
typ := c.check_expr_opt_call(call_arg.expr, c.expr(call_arg.expr))
779780
node.args[i].typ = typ
781+
if c.inside_comptime_for_field {
782+
if mut call_arg.expr is ast.Ident {
783+
if mut call_arg.expr.obj is ast.Var {
784+
node.args[i].typ = call_arg.expr.obj.typ
785+
}
786+
}
787+
}
780788
typ_sym := c.table.sym(typ)
781789
param_typ_sym := c.table.sym(param.typ)
782790
if func.is_variadic && typ.has_flag(.variadic) && node.args.len - 1 > i {
@@ -936,6 +944,9 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
936944
continue
937945
}
938946
c.check_expected_call_arg(utyp, unwrap_typ, node.language, call_arg) or {
947+
if c.comptime_fields_type.len > 0 {
948+
continue
949+
}
939950
c.error('$err.msg() in argument ${i + 1} to `$fn_name`', call_arg.pos)
940951
}
941952
}

vlib/v/checker/tests/comptime_for.out

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,6 @@ vlib/v/checker/tests/comptime_for.vv:4:12: error: unknown type `T`
1818
| ^
1919
5 | $if f.typ is Huh {}
2020
6 | $if f.typ is T {}
21-
vlib/v/checker/tests/comptime_for.vv:5:16: error: unknown type `Huh`
22-
3 | $for f in Huh.fields {}
23-
4 | $for f in T.fields {
24-
5 | $if f.typ is Huh {}
25-
| ~~~
26-
6 | $if f.typ is T {}
27-
7 | }
28-
vlib/v/checker/tests/comptime_for.vv:6:16: error: unknown type `T`
29-
4 | $for f in T.fields {
30-
5 | $if f.typ is Huh {}
31-
6 | $if f.typ is T {}
32-
| ^
33-
7 | }
34-
8 | _ = m
3521
vlib/v/checker/tests/comptime_for.vv:8:6: error: undefined ident: `m`
3622
6 | $if f.typ is T {}
3723
7 | }

vlib/v/checker/tests/comptime_for.vv

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ struct S1 {
2020
i int
2121
}
2222

23-
gf<S1>()
23+
fn main() {
24+
gf<S1>()
25+
}

0 commit comments

Comments
 (0)