Skip to content

Commit b9e9192

Browse files
authored
ast,checker,cgen,parser: fix comptime $if assign expr (fix #26061) (#26242)
1 parent 7dd55a9 commit b9e9192

11 files changed

Lines changed: 154 additions & 50 deletions

File tree

‎vlib/v/ast/table.v‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,10 @@ pub fn (mut t Table) convert_generic_type(generic_type Type, generic_names []str
18091809
if generic_names.len != to_types.len {
18101810
return none
18111811
}
1812+
type_idx := generic_type.idx()
1813+
if type_idx == 0 || type_idx >= t.type_symbols.len {
1814+
return none
1815+
}
18121816
mut sym := t.sym(generic_type)
18131817
if sym.name in generic_names {
18141818
index := generic_names.index(sym.name)

‎vlib/v/checker/checker.v‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,9 @@ fn (mut c Checker) expr_or_block_err(kind ast.OrKind, expr_name string, pos toke
14391439

14401440
// return the actual type of the expression, once the result or option type is handled
14411441
fn (mut c Checker) check_expr_option_or_result_call(expr ast.Expr, ret_type ast.Type) ast.Type {
1442+
if ret_type.idx() == 0 {
1443+
return ret_type
1444+
}
14421445
match expr {
14431446
ast.CallExpr {
14441447
mut expr_ret_type := expr.return_type

‎vlib/v/checker/comptime.v‎

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,18 @@ fn (mut c Checker) get_expr_type(cond ast.Expr) ast.Type {
829829
} else if c.is_generic_ident(cond.name) {
830830
// generic type `T`
831831
idx := c.table.cur_fn.generic_names.index(cond.name)
832-
return c.table.cur_concrete_types[idx]
832+
if idx >= 0 && idx < c.table.cur_concrete_types.len {
833+
concrete_type := c.table.cur_concrete_types[idx]
834+
if concrete_type != 0 {
835+
return concrete_type
836+
}
837+
}
838+
type_idx := c.table.find_type_idx(cond.name)
839+
return if type_idx == 0 {
840+
ast.void_type
841+
} else {
842+
ast.new_type(type_idx).set_flag(.generic)
843+
}
833844
} else if var := cond.scope.find_var(cond.name) {
834845
// var
835846
checked_type = c.unwrap_generic(var.typ)
@@ -855,11 +866,29 @@ fn (mut c Checker) get_expr_type(cond ast.Expr) ast.Type {
855866
// for `indirections` we also return the `typ`
856867
return typ
857868
}
858-
if cond.gkind_field in [.typ, .indirections] {
859-
// for `indirections` we also return the `typ`
860-
return c.unwrap_generic(cond.name_type)
861-
} else if cond.gkind_field == .unaliased_typ {
862-
return c.table.unaliased_type(c.unwrap_generic(cond.name_type))
869+
if cond.gkind_field in [.typ, .indirections, .unaliased_typ] {
870+
if cond.expr is ast.Ident {
871+
generic_name := cond.expr.name
872+
if c.table.cur_fn != unsafe { nil }
873+
&& generic_name in c.table.cur_fn.generic_names {
874+
idx := c.table.cur_fn.generic_names.index(generic_name)
875+
if idx >= 0 && idx < c.table.cur_concrete_types.len {
876+
concrete_type := c.table.cur_concrete_types[idx]
877+
if cond.gkind_field == .unaliased_typ {
878+
return c.table.unaliased_type(concrete_type)
879+
}
880+
return concrete_type
881+
}
882+
}
883+
}
884+
unwrapped := c.unwrap_generic(cond.name_type)
885+
if cond.gkind_field == .unaliased_typ {
886+
if unwrapped.idx() == 0 || unwrapped.has_flag(.generic) {
887+
return unwrapped
888+
}
889+
return c.table.unaliased_type(unwrapped)
890+
}
891+
return unwrapped
863892
} else {
864893
if cond.expr is ast.TypeOf {
865894
return c.type_resolver.typeof_field_type(c.type_resolver.typeof_type(cond.expr.expr,

‎vlib/v/checker/fn.v‎

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2952,24 +2952,23 @@ fn (mut c Checker) post_process_generic_fns() ! {
29522952
// Loop thru each generic function concrete type.
29532953
// Check each specific fn instantiation.
29542954
for i in 0 .. c.file.generic_fns.len {
2955-
mut node := c.file.generic_fns[i]
2956-
c.mod = node.mod
2957-
fkey := node.fkey()
2955+
c.mod = c.file.generic_fns[i].mod
2956+
fkey := c.file.generic_fns[i].fkey()
29582957
all_generic_fns[fkey]++
29592958
if all_generic_fns[fkey] > generic_fn_cutoff_limit_per_fn {
29602959
c.error('${fkey} generic function visited more than ${generic_fn_cutoff_limit_per_fn} times',
2961-
node.pos)
2960+
c.file.generic_fns[i].pos)
29622961
return error('fkey: ${fkey}')
29632962
}
29642963
gtypes := c.table.fn_generic_types[fkey]
29652964
$if trace_post_process_generic_fns ? {
2966-
eprintln('> post_process_generic_fns ${node.mod} | ${node.name} | fkey: ${fkey} | gtypes: ${gtypes} | c.file.generic_fns.len: ${c.file.generic_fns.len}')
2965+
eprintln('> post_process_generic_fns ${c.file.generic_fns[i].mod} | ${c.file.generic_fns[i].name} | fkey: ${fkey} | gtypes: ${gtypes} | c.file.generic_fns.len: ${c.file.generic_fns.len}')
29672966
}
29682967
for concrete_types in gtypes {
29692968
c.table.cur_concrete_types = concrete_types
2970-
c.fn_decl(mut node)
2971-
if node.name in ['veb.run', 'veb.run_at', 'x.vweb.run', 'x.vweb.run_at', 'vweb.run',
2972-
'vweb.run_at'] {
2969+
c.fn_decl(mut c.file.generic_fns[i])
2970+
if c.file.generic_fns[i].name in ['veb.run', 'veb.run_at', 'x.vweb.run', 'x.vweb.run_at',
2971+
'vweb.run', 'vweb.run_at'] {
29732972
for ct in concrete_types {
29742973
if ct !in c.vweb_gen_types {
29752974
c.vweb_gen_types << ct
@@ -2979,8 +2978,8 @@ fn (mut c Checker) post_process_generic_fns() ! {
29792978
}
29802979
c.table.cur_concrete_types = []
29812980
$if trace_post_process_generic_fns ? {
2982-
if node.generic_names.len > 0 {
2983-
eprintln(' > fn_decl node.name: ${node.name} | generic_names: ${node.generic_names} | ninstances: ${node.ninstances}')
2981+
if c.file.generic_fns[i].generic_names.len > 0 {
2982+
eprintln(' > fn_decl node.name: ${c.file.generic_fns[i].name} | generic_names: ${c.file.generic_fns[i].generic_names} | ninstances: ${c.file.generic_fns[i].ninstances}')
29842983
}
29852984
}
29862985
}

‎vlib/v/checker/if.v‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
7474
c.expected_type = c.expected_or_type
7575
}
7676
expr_required := c.expected_type != ast.void_type
77+
|| (node.is_comptime && node.is_expr && node.has_else && c.fn_level > 0)
7778
former_expected_type := c.expected_type
7879
if node_is_expr {
7980
c.expected_expr_type = c.expected_type

‎vlib/v/checker/match.v‎

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ import v.token
66
import strings
77

88
fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
9-
node.is_expr = c.expected_type != ast.void_type
9+
if !node.is_comptime {
10+
node.is_expr = c.expected_type != ast.void_type
11+
}
1012
node.expected_type = c.expected_type
1113
if mut node.cond is ast.ParExpr && !c.pref.translated && !c.file.is_translated {
1214
c.warn('unnecessary `()` in `match` condition, use `match expr {` instead of `match (expr) {`.',
1315
node.cond.pos)
1416
}
15-
if node.is_expr {
17+
expr_required := c.expected_type != ast.void_type
18+
|| (node.is_comptime && node.is_expr && c.fn_level > 0)
19+
if node.is_expr || expr_required {
1620
c.expected_expr_type = c.expected_type
1721
defer(fn) {
1822
c.expected_expr_type = ast.void_type
@@ -46,12 +50,15 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
4650
if !c.ensure_type_exists(node.cond_type, node.pos) {
4751
return ast.void_type
4852
}
49-
c.check_expr_option_or_result_call(node.cond, cond_type)
50-
cond_type_sym := c.table.sym(cond_type)
51-
cond_is_option := cond_type.has_flag(.option)
53+
if node.cond_type == 0 {
54+
return ast.void_type
55+
}
56+
c.check_expr_option_or_result_call(node.cond, node.cond_type)
57+
cond_type_sym := c.table.sym(node.cond_type)
58+
cond_is_option := node.cond_type.has_flag(.option)
5259
node.is_sum_type = cond_type_sym.kind in [.interface, .sum_type]
5360
c.match_exprs(mut node, cond_type_sym)
54-
c.expected_type = cond_type
61+
c.expected_type = node.cond_type
5562
mut first_iteration := true
5663
mut infer_cast_type := ast.void_type
5764
mut need_explicit_cast := false
@@ -64,8 +71,9 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
6471
mut comptime_match_found_branch := false
6572
mut comptime_match_cond_value := ''
6673
if node.is_comptime {
67-
if node.cond in [ast.ComptimeType, ast.TypeNode]
68-
|| (node.cond is ast.Ident && (c.is_generic_ident(node.cond.name))) {
74+
if node.cond in [ast.ComptimeType, ast.TypeNode] || (node.cond is ast.Ident
75+
&& (c.is_generic_ident(node.cond.name)))
76+
|| (node.cond is ast.SelectorExpr && node.cond.gkind_field in [.typ, .unaliased_typ]) {
6977
// must be a type `$match`
7078
c.inside_x_matches_type = true
7179
} else {
@@ -284,8 +292,8 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
284292
if cond_type_sym.kind == .none {
285293
c.error('`none` cannot be a match condition', node.pos)
286294
}
287-
// If the last statement is an expression, return its type
288-
if branch.stmts.len > 0 && node.is_expr {
295+
if branch.stmts.len > 0 && node.is_expr
296+
&& (!node.is_comptime || (node.is_comptime && comptime_match_branch_result)) {
289297
mut stmt := branch.stmts.last()
290298
if mut stmt is ast.ExprStmt {
291299
c.expected_type = if c.expected_expr_type != ast.void_type {
@@ -471,7 +479,9 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
471479
ret_type = if stmt.types.len > 0 { stmt.types[0] } else { c.expected_type }
472480
}
473481
}
474-
first_iteration = false
482+
if !node.is_comptime || (node.is_comptime && comptime_match_branch_result) {
483+
first_iteration = false
484+
}
475485
if node.is_comptime {
476486
// branches may not have been processed by c.stmts()
477487
if has_top_return(branch.stmts) {
@@ -573,6 +583,9 @@ fn (mut c Checker) get_comptime_number_value(mut expr ast.Expr) ?i64 {
573583

574584
fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSymbol) {
575585
c.expected_type = node.expected_type
586+
if node.cond_type.idx() == 0 {
587+
return
588+
}
576589
cond_sym := c.table.sym(node.cond_type)
577590
mut enum_ref_checked := false
578591
mut is_comptime_value_match := false

‎vlib/v/gen/c/comptime.v‎

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ fn (mut g Gen) gen_comptime_selector(expr ast.ComptimeSelector) string {
4444
}
4545

4646
fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) {
47+
if node.kind == .compile_error || node.kind == .compile_warn {
48+
// handled by checker, this branch was not taken
49+
return
50+
}
4751
if node.kind == .embed_file {
4852
// $embed_file('/path/to/file')
4953
g.gen_embed_file_init(mut node)
@@ -368,12 +372,27 @@ fn (mut g Gen) gen_branch_context_string() string {
368372

369373
fn (mut g Gen) comptime_if(node ast.IfExpr) {
370374
tmp_var := g.new_tmp_var()
371-
is_opt_or_result := node.typ.has_option_or_result()
372-
is_array_fixed := g.table.final_sym(node.typ).kind == .array_fixed
373-
line := if node.is_expr {
375+
mut inferred_typ := node.typ
376+
if node.is_expr && node.typ == ast.void_type && node.branches.len > 0 {
377+
for branch in node.branches {
378+
if branch.stmts.len > 0 {
379+
last_stmt := branch.stmts.last()
380+
if last_stmt is ast.ExprStmt {
381+
expr_typ := g.type_resolver.get_type_or_default(last_stmt.expr, last_stmt.typ)
382+
if expr_typ != ast.void_type && !expr_typ.has_flag(.generic) {
383+
inferred_typ = expr_typ
384+
break
385+
}
386+
}
387+
}
388+
}
389+
}
390+
is_opt_or_result := inferred_typ.has_option_or_result()
391+
is_array_fixed := g.table.final_sym(inferred_typ).kind == .array_fixed
392+
line := if node.is_expr && inferred_typ != ast.void_type {
374393
stmt_str := g.go_before_last_stmt()
375394
g.write(util.tabs(g.indent))
376-
styp := g.styp(node.typ)
395+
styp := g.styp(inferred_typ)
377396
g.writeln('${styp} ${tmp_var};')
378397
stmt_str
379398
} else {
@@ -446,9 +465,9 @@ fn (mut g Gen) comptime_if(node ast.IfExpr) {
446465
g.skip_stmt_pos = true
447466
if is_opt_or_result {
448467
tmp_var2 := g.new_tmp_var()
449-
g.write('{ ${g.base_type(node.typ)} ${tmp_var2} = ')
468+
g.write('{ ${g.base_type(inferred_typ)} ${tmp_var2} = ')
450469
g.stmt(last)
451-
g.writeln('builtin___result_ok(&(${g.base_type(node.typ)}[]) { ${tmp_var2} }, (_result*)(&${tmp_var}), sizeof(${g.base_type(node.typ)}));')
470+
g.writeln('builtin___result_ok(&(${g.base_type(inferred_typ)}[]) { ${tmp_var2} }, (_result*)(&${tmp_var}), sizeof(${g.base_type(inferred_typ)}));')
452471
g.writeln('}')
453472
} else {
454473
g.write('\t${tmp_var} = ')
@@ -465,14 +484,14 @@ fn (mut g Gen) comptime_if(node ast.IfExpr) {
465484
g.skip_stmt_pos = true
466485
if is_opt_or_result {
467486
tmp_var2 := g.new_tmp_var()
468-
base_styp := g.base_type(node.typ)
487+
base_styp := g.base_type(inferred_typ)
469488
g.write('{ ${base_styp} ${tmp_var2} = ')
470489
g.stmt(last)
471490
g.writeln('builtin___result_ok(&(${base_styp}[]) { ${tmp_var2} }, (_result*)(&${tmp_var}), sizeof(${base_styp}));')
472491
g.writeln('}')
473492
} else if is_array_fixed {
474493
tmp_var2 := g.new_tmp_var()
475-
base_styp := g.base_type(node.typ)
494+
base_styp := g.base_type(inferred_typ)
476495
g.write('{ ${base_styp} ${tmp_var2} = ')
477496
g.stmt(last)
478497
if g.out.last_n(2).contains(';') {
@@ -976,11 +995,28 @@ fn (mut g Gen) comptime_selector_type(node ast.SelectorExpr) ast.Type {
976995

977996
fn (mut g Gen) comptime_match(node ast.MatchExpr) {
978997
tmp_var := g.new_tmp_var()
979-
is_opt_or_result := node.return_type.has_option_or_result()
980-
line := if node.is_expr {
998+
mut inferred_typ := node.return_type
999+
if node.is_expr && (node.return_type == ast.void_type || node.return_type.idx() == 0)
1000+
&& node.branches.len > 0 {
1001+
for branch in node.branches {
1002+
if branch.stmts.len > 0 {
1003+
last_stmt := branch.stmts.last()
1004+
if last_stmt is ast.ExprStmt {
1005+
expr_typ := g.type_resolver.get_type_or_default(last_stmt.expr, last_stmt.typ)
1006+
if expr_typ != ast.void_type && expr_typ.idx() != 0
1007+
&& !expr_typ.has_flag(.generic) {
1008+
inferred_typ = expr_typ
1009+
break
1010+
}
1011+
}
1012+
}
1013+
}
1014+
}
1015+
is_opt_or_result := inferred_typ.has_option_or_result()
1016+
line := if node.is_expr && inferred_typ != ast.void_type && inferred_typ.idx() != 0 {
9811017
stmt_str := g.go_before_last_stmt()
9821018
g.write(util.tabs(g.indent))
983-
styp := g.styp(node.return_type)
1019+
styp := g.styp(inferred_typ)
9841020
g.writeln('${styp} ${tmp_var};')
9851021
stmt_str
9861022
} else {
@@ -1034,9 +1070,9 @@ fn (mut g Gen) comptime_match(node ast.MatchExpr) {
10341070
g.skip_stmt_pos = true
10351071
if is_opt_or_result {
10361072
tmp_var2 := g.new_tmp_var()
1037-
g.write('{ ${g.base_type(node.return_type)} ${tmp_var2} = ')
1073+
g.write('{ ${g.base_type(inferred_typ)} ${tmp_var2} = ')
10381074
g.stmt(last)
1039-
g.writeln('builtin___result_ok(&(${g.base_type(node.return_type)}[]) { ${tmp_var2} }, (_result*)(&${tmp_var}), sizeof(${g.base_type(node.return_type)}));')
1075+
g.writeln('builtin___result_ok(&(${g.base_type(inferred_typ)}[]) { ${tmp_var2} }, (_result*)(&${tmp_var}), sizeof(${g.base_type(inferred_typ)}));')
10401076
g.writeln('}')
10411077
} else {
10421078
g.write('\t${tmp_var} = ')
@@ -1054,9 +1090,9 @@ fn (mut g Gen) comptime_match(node ast.MatchExpr) {
10541090
g.skip_stmt_pos = true
10551091
if is_opt_or_result {
10561092
tmp_var2 := g.new_tmp_var()
1057-
g.write('{ ${g.base_type(node.return_type)} ${tmp_var2} = ')
1093+
g.write('{ ${g.base_type(inferred_typ)} ${tmp_var2} = ')
10581094
g.stmt(last)
1059-
g.writeln('builtin___result_ok(&(${g.base_type(node.return_type)}[]) { ${tmp_var2} }, (_result*)(&${tmp_var}), sizeof(${g.base_type(node.return_type)}));')
1095+
g.writeln('builtin___result_ok(&(${g.base_type(inferred_typ)}[]) { ${tmp_var2} }, (_result*)(&${tmp_var}), sizeof(${g.base_type(inferred_typ)}));')
10601096
g.writeln('}')
10611097
} else {
10621098
g.write('${tmp_var} = ')

‎vlib/v/parser/expr.v‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,14 @@ fn (mut p Parser) check_expr(precedence int) !ast.Expr {
126126
p.is_stmt_ident = is_stmt_ident
127127
}
128128
.key_if {
129-
return p.if_expr(true, false)
129+
mut is_expr := false
130+
if p.prev_tok.kind.is_assign() {
131+
is_expr = true
132+
}
133+
return p.if_expr(true, is_expr)
130134
}
131135
.key_match {
132-
return p.match_expr(true)
136+
return p.match_expr(true, p.prev_tok.kind.is_assign())
133137
}
134138
else {
135139
return p.unexpected_with_pos(p.peek_tok.pos(),
@@ -184,10 +188,10 @@ fn (mut p Parser) check_expr(precedence int) !ast.Expr {
184188
}
185189
}
186190
.key_match {
187-
if p.peek_tok.kind in [.lpar, .lsbr] && p.peek_tok.is_next_to(p.tok) {
188-
node = p.call_expr(p.language, p.mod)
191+
node = if p.peek_tok.kind in [.lpar, .lsbr] && p.peek_tok.is_next_to(p.tok) {
192+
p.call_expr(p.language, p.mod)
189193
} else {
190-
node = p.match_expr(false)
194+
p.match_expr(false, false)
191195
}
192196
}
193197
.key_select {

‎vlib/v/parser/if_match.v‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,10 @@ fn (mut p Parser) resolve_at_expr(expr ast.AtExpr) !string {
305305
return ''
306306
}
307307

308-
fn (mut p Parser) match_expr(is_comptime bool) ast.MatchExpr {
308+
fn (mut p Parser) match_expr(is_comptime bool, is_expr bool) ast.MatchExpr {
309309
mut match_first_pos := p.tok.pos()
310310
old_inside_ct_match := p.inside_ct_match
311+
is_expr_ := p.prev_tok.kind == .key_return || is_expr
311312
if is_comptime {
312313
p.next() // `$`
313314
match_first_pos = p.prev_tok.pos().extend(p.tok.pos())
@@ -506,6 +507,7 @@ fn (mut p Parser) match_expr(is_comptime bool) ast.MatchExpr {
506507
pos.update_last_line(p.prev_tok.line_nr)
507508
return ast.MatchExpr{
508509
is_comptime: is_comptime
510+
is_expr: is_expr_
509511
branches: branches
510512
cond: cond
511513
is_sum_type: is_sum_type

0 commit comments

Comments
 (0)