Skip to content

Commit cb525f0

Browse files
authored
v: complete support for smartcasting to a comptime variable type (#20270)
1 parent 7b04476 commit cb525f0

File tree

11 files changed

+112
-14
lines changed

11 files changed

+112
-14
lines changed

vlib/v/ast/ast.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,7 @@ pub enum ComptimeVarKind {
804804
value_var // map value from `for k,v in t.$(field.name)`
805805
field_var // comptime field var `a := t.$(field.name)`
806806
generic_param // generic fn parameter
807+
smartcast // smart cast when used in `is v` (when `v` is from $for .variants)
807808
}
808809

809810
@[minify]

vlib/v/checker/checker.v

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3843,6 +3843,7 @@ fn (mut c Checker) smartcast(mut expr ast.Expr, cur_type ast.Type, to_type_ ast.
38433843
mut is_already_casted := false
38443844
mut orig_type := 0
38453845
mut is_inherited := false
3846+
mut ct_type_var := ast.ComptimeVarKind.no_comptime
38463847
if mut expr.obj is ast.Var {
38473848
is_mut = expr.obj.is_mut
38483849
smartcasts << expr.obj.smartcasts
@@ -3851,19 +3852,25 @@ fn (mut c Checker) smartcast(mut expr ast.Expr, cur_type ast.Type, to_type_ ast.
38513852
orig_type = expr.obj.typ
38523853
}
38533854
is_inherited = expr.obj.is_inherited
3855+
ct_type_var = if expr.obj.ct_type_var == .field_var {
3856+
.smartcast
3857+
} else {
3858+
.no_comptime
3859+
}
38543860
}
38553861
// smartcast either if the value is immutable or if the mut argument is explicitly given
38563862
if (!is_mut || expr.is_mut) && !is_already_casted {
38573863
smartcasts << to_type
38583864
scope.register(ast.Var{
38593865
name: expr.name
3860-
typ: cur_type
3866+
typ: if ct_type_var == .smartcast { to_type } else { cur_type }
38613867
pos: expr.pos
38623868
is_used: true
38633869
is_mut: expr.is_mut
38643870
is_inherited: is_inherited
38653871
smartcasts: smartcasts
38663872
orig_type: orig_type
3873+
ct_type_var: ct_type_var
38673874
})
38683875
} else if is_mut && !expr.is_mut {
38693876
c.smartcast_mut_pos = expr.pos

vlib/v/checker/if.v

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
140140
if sym.kind == .placeholder || got_type.has_flag(.generic) {
141141
c.error('unknown type `${sym.name}`', branch.cond.right.pos())
142142
}
143-
144143
if left is ast.SelectorExpr {
145144
comptime_field_name = left.expr.str()
146145
c.comptime.type_map[comptime_field_name] = got_type
@@ -519,6 +518,9 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope) {
519518
c.smartcast(mut node.left, node.left_type, node.left_type.clear_flag(.option), mut
520519
scope)
521520
} else if node.op == .key_is {
521+
if node.left_type == ast.Type(0) {
522+
node.left_type = c.expr(mut node.left)
523+
}
522524
right_expr := node.right
523525
right_type := match right_expr {
524526
ast.TypeNode {
@@ -527,15 +529,24 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope) {
527529
ast.None {
528530
ast.none_type_idx
529531
}
532+
ast.Ident {
533+
if right_expr.name == c.comptime.comptime_for_variant_var {
534+
println(c.comptime.type_map['${c.comptime.comptime_for_variant_var}.typ'])
535+
c.comptime.type_map['${c.comptime.comptime_for_variant_var}.typ']
536+
} else {
537+
c.error('invalid type `${right_expr}`', right_expr.pos)
538+
ast.Type(0)
539+
}
540+
}
530541
else {
531542
c.error('invalid type `${right_expr}`', right_expr.pos())
532543
ast.Type(0)
533544
}
534545
}
535546
if right_type != ast.Type(0) {
536-
left_sym := c.table.sym(node.left_type)
537547
right_sym := c.table.sym(right_type)
538548
mut expr_type := c.expr(mut node.left)
549+
left_sym := c.table.sym(expr_type)
539550
if left_sym.kind == .aggregate {
540551
expr_type = (left_sym.info as ast.Aggregate).sum_type
541552
}
@@ -548,7 +559,8 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope) {
548559
expr_str := c.table.type_to_str(expr_type)
549560
c.error('cannot use type `${expect_str}` as type `${expr_str}`', node.pos)
550561
}
551-
if node.left in [ast.Ident, ast.SelectorExpr] && node.right is ast.TypeNode {
562+
if node.left in [ast.Ident, ast.SelectorExpr]
563+
&& node.right in [ast.ComptimeType, ast.TypeNode, ast.Ident] {
552564
is_variable := if mut node.left is ast.Ident {
553565
node.left.kind == .variable
554566
} else {

vlib/v/checker/infix.v

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,14 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
648648
ast.None {
649649
ast.none_type_idx
650650
}
651+
ast.Ident {
652+
if right_expr.name == c.comptime.comptime_for_variant_var {
653+
c.comptime.type_map['${c.comptime.comptime_for_variant_var}.typ']
654+
} else {
655+
c.error('invalid type `${right_expr}`', right_expr.pos)
656+
ast.Type(0)
657+
}
658+
}
651659
else {
652660
c.error('invalid type `${right_expr}`', right_expr.pos())
653661
ast.Type(0)

vlib/v/comptime/comptimeinfo.v

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ pub fn (mut ct ComptimeInfo) get_comptime_var_type(node ast.Expr) ast.Type {
5353
// generic parameter from current function
5454
node.obj.typ
5555
}
56+
.smartcast {
57+
ct.type_map['${ct.comptime_for_variant_var}.typ'] or { ast.void_type }
58+
}
5659
.key_var, .value_var {
5760
// key and value variables from normal for stmt
5861
ct.type_map[node.name] or { ast.void_type }

vlib/v/gen/c/cgen.v

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4402,7 +4402,8 @@ fn (mut g Gen) ident(node ast.Ident) {
44024402
mut is_option := false
44034403
if node.info is ast.IdentVar {
44044404
if node.obj is ast.Var {
4405-
if !g.is_assign_lhs && node.obj.ct_type_var !in [.generic_param, .no_comptime] {
4405+
if !g.is_assign_lhs
4406+
&& node.obj.ct_type_var !in [.smartcast, .generic_param, .no_comptime] {
44064407
comptime_type := g.comptime.get_comptime_var_type(node)
44074408
if comptime_type.has_flag(.option) {
44084409
if (g.inside_opt_or_res || g.left_is_opt) && node.or_expr.kind == .absent {
@@ -4508,7 +4509,8 @@ fn (mut g Gen) ident(node ast.Ident) {
45084509
} else {
45094510
g.write('*')
45104511
}
4511-
} else if g.inside_interface_deref && g.table.is_interface_var(node.obj) {
4512+
} else if (g.inside_interface_deref && g.table.is_interface_var(node.obj))
4513+
|| node.obj.ct_type_var == .smartcast {
45124514
g.write('*')
45134515
} else if is_option {
45144516
g.write('*(${g.base_type(node.obj.typ)}*)')
@@ -4542,7 +4544,11 @@ fn (mut g Gen) ident(node ast.Ident) {
45424544
g.write(')')
45434545
}
45444546
}
4545-
if !is_option_unwrap && obj_sym.kind in [.sum_type, .interface_] {
4547+
if node.obj.ct_type_var == .smartcast {
4548+
cur_variant_sym := g.table.sym(g.comptime.type_map['${g.comptime.comptime_for_variant_var}.typ'])
4549+
g.write('${dot}_${cur_variant_sym.cname}')
4550+
} else if !is_option_unwrap
4551+
&& obj_sym.kind in [.sum_type, .interface_] {
45464552
g.write('${dot}_${cast_sym.cname}')
45474553
}
45484554
}

vlib/v/gen/c/comptime.v

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,11 @@ fn (mut g Gen) comptime_if(node ast.IfExpr) {
399399
fn (mut g Gen) get_expr_type(cond ast.Expr) ast.Type {
400400
match cond {
401401
ast.Ident {
402-
return g.unwrap_generic(cond.obj.typ)
402+
return if g.comptime.is_comptime_var(cond) {
403+
g.unwrap_generic(g.comptime.get_comptime_var_type(cond))
404+
} else {
405+
g.unwrap_generic(cond.obj.typ)
406+
}
403407
}
404408
ast.TypeNode {
405409
return g.unwrap_generic(cond.typ)
@@ -922,7 +926,7 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
922926
g.comptime.inside_comptime_for = true
923927
g.push_new_comptime_info()
924928
for variant in sym.info.variants {
925-
g.comptime.comptime_for_field_var = node.val_var
929+
g.comptime.comptime_for_variant_var = node.val_var
926930
g.comptime.type_map['${node.val_var}.typ'] = variant
927931

928932
g.writeln('/* variant ${i} */ {')

vlib/v/gen/c/infix.v

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,11 @@ fn (mut g Gen) infix_expr_is_op(node ast.InfixExpr) {
720720
}
721721
if node.right is ast.None {
722722
g.write('${ast.none_type.idx()} /* none */')
723+
} else if node.right is ast.Ident && node.right.name == g.comptime.comptime_for_variant_var {
724+
variant_idx := g.comptime.type_map['${g.comptime.comptime_for_variant_var}.typ'] or {
725+
ast.void_type
726+
}
727+
g.write('${variant_idx.idx()}')
723728
} else {
724729
g.expr(node.right)
725730
}

vlib/v/parser/parse_type.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ fn (mut p Parser) parse_sum_type_variants() []ast.TypeNode {
434434
pos: type_pos
435435
end_comments: end_comments
436436
}
437+
437438
if p.tok.kind != .pipe {
438439
break
439440
}

vlib/v/parser/parser.v

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2536,11 +2536,17 @@ fn (mut p Parser) name_expr() ast.Expr {
25362536
}
25372537
p.expecting_type = false
25382538
// get type position before moving to next
2539-
type_pos := p.tok.pos()
2540-
typ := p.parse_type()
2541-
return ast.TypeNode{
2542-
typ: typ
2543-
pos: type_pos
2539+
is_known_var := p.scope.known_var(p.tok.lit)
2540+
if is_known_var {
2541+
p.mark_var_as_used(p.tok.lit)
2542+
return p.ident(ast.Language.v)
2543+
} else {
2544+
type_pos := p.tok.pos()
2545+
typ := p.parse_type()
2546+
return ast.TypeNode{
2547+
typ: typ
2548+
pos: type_pos
2549+
}
25442550
}
25452551
}
25462552
language := match p.tok.lit {

0 commit comments

Comments
 (0)