Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp committed Jan 24, 2025
1 parent eb06ce9 commit 3299512
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 15 deletions.
10 changes: 6 additions & 4 deletions vlib/v/ast/ast.v
Original file line number Diff line number Diff line change
Expand Up @@ -906,10 +906,11 @@ pub mut:
// 10 <- original type (orig_type)
// [11, 12, 13] <- cast order (smartcasts)
// 12 <- the current casted type (typ)
pos token.Pos
is_used bool // whether the local variable was used in other expressions
is_changed bool // to detect mutable vars that are never changed
ct_type_var ComptimeVarKind // comptime variable type
pos token.Pos
is_used bool // whether the local variable was used in other expressions
is_changed bool // to detect mutable vars that are never changed
ct_type_var ComptimeVarKind // comptime variable type
ct_type_unwrapped bool // true when the comptime variable gets unwrapped
// (for setting the position after the or block for autofree)
is_or bool // `x := foo() or { ... }`
is_tmp bool // for tmp for loop vars, so that autofree can skip them
Expand Down Expand Up @@ -1995,6 +1996,7 @@ pub struct ComptimeSelector {
pub:
has_parens bool // if $() is used, for vfmt
pos token.Pos
or_block OrExpr
pub mut:
left Expr
left_type Type
Expand Down
13 changes: 12 additions & 1 deletion vlib/v/checker/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -925,8 +925,12 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
fn (mut c Checker) change_flags_if_comptime_expr(mut left ast.Ident, right ast.Expr) {
if mut left.obj is ast.Var {
if right is ast.ComptimeSelector {
left.obj.ct_type_var = .field_var
left.obj.typ = c.comptime.comptime_for_field_type
if right.or_block.kind == .propagate_option {
left.obj.typ = left.obj.typ.clear_flag(.option)
} else if right.or_block.kind == .absent {
left.obj.ct_type_var = .field_var
}
} else if right is ast.InfixExpr {
right_ct_var := c.comptime.get_ct_type_var(right.left)
if right_ct_var != .no_comptime {
Expand Down Expand Up @@ -960,6 +964,13 @@ fn (mut c Checker) change_flags_if_comptime_expr(mut left ast.Ident, right ast.E
// mark variable as generic var because its type changes according to fn return generic resolution type
left.obj.ct_type_var = .generic_var
}
} else if right is ast.PostfixExpr && right.op == .question {
if right.expr is ast.Ident && right.expr.ct_expr {
right_obj_var := right.expr.obj as ast.Var
left.obj.ct_type_unwrapped = true
left.obj.ct_type_var = right_obj_var.ct_type_var
left.obj.typ = c.comptime.comptime_for_field_type.clear_flag(.option)
}
}
}
}
3 changes: 3 additions & 0 deletions vlib/v/checker/comptime.v
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ fn (mut c Checker) comptime_selector(mut node ast.ComptimeSelector) ast.Type {
}
expr_type = c.type_resolver.get_comptime_selector_type(node, ast.void_type)
if expr_type != ast.void_type {
if node.or_block.kind == .propagate_option {
return expr_type.clear_flag(.option)
}
return expr_type
}
expr_name := node.field_expr.expr.str()
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/checker/postfix.v
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module checker
import v.ast

fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type {
typ := c.unwrap_generic(c.expr(mut node.expr))
typ := c.unwrap_generic(c.type_resolver.get_type_or_default(node, c.expr(mut node.expr)))
typ_sym := c.table.sym(typ)
is_non_void_pointer := typ.is_any_kind_of_pointer() && typ_sym.kind != .voidptr

Expand Down Expand Up @@ -36,7 +36,7 @@ fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type {
typ_str := c.table.type_to_str(typ)
c.error('invalid operation: ${node.op.str()} (non-numeric type `${typ_str}`)',
node.pos)
} else {
} else if node.op != .question {
node.auto_locked, _ = c.fail_if_immutable(mut node.expr)
}
node.typ = typ
Expand Down
14 changes: 14 additions & 0 deletions vlib/v/gen/c/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,20 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
left.obj.typ = var_type
g.assign_ct_type = var_type
}
} else if val is ast.PostfixExpr && val.op == .question
&& (val.expr is ast.Ident && val.expr.ct_expr) {
ctyp := g.unwrap_generic(g.type_resolver.get_type(val))
if ctyp != ast.void_type {
var_type = ctyp
val_type = var_type
left.obj.typ = var_type
g.assign_ct_type = var_type

ct_type_var := g.comptime.get_ct_type_var(val.expr)
if ct_type_var == .field_var {
g.type_resolver.update_ct_type(left.name, ctyp)
}
}
}
}
is_auto_heap = left.obj.is_auto_heap
Expand Down
12 changes: 8 additions & 4 deletions vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -3664,10 +3664,14 @@ fn (mut g Gen) expr(node_ ast.Expr) {
g.writeln('if (${expr_str}.state != 0) {')
g.writeln2('\tpanic_option_not_set(_SLIT("none"));', '}')
g.write(cur_line)
typ := g.resolve_comptime_type(node.expr, node.typ)
g.write('*(${g.base_type(typ)}*)&')
g.expr(node.expr)
g.write('.data')
if node.expr is ast.ComptimeSelector {
typ := g.resolve_comptime_type(node.expr, node.typ)
g.write('*(${g.base_type(typ)}*)&')
g.expr(node.expr)
g.write('.data')
} else {
g.expr(node.expr)
}
} else {
g.expr(node.expr)
}
Expand Down
5 changes: 5 additions & 0 deletions vlib/v/parser/comptime.v
Original file line number Diff line number Diff line change
Expand Up @@ -526,5 +526,10 @@ fn (mut p Parser) comptime_selector(left ast.Expr) ast.Expr {
left: left
field_expr: expr
pos: start_pos.extend(p.prev_tok.pos())
or_block: ast.OrExpr{
stmts: []ast.Stmt{}
kind: if p.tok.kind == .question { .propagate_option } else { .absent }
pos: p.tok.pos()
}
}
}
4 changes: 2 additions & 2 deletions vlib/v/tests/comptime/comptime_var_assignment_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ fn encode_struct[T](val T) []string {
$for field in T.fields {
value := val.$(field.name)
$if field.is_option {
gg := value
gg := value ?
println(gg)
out << gg.str()
out << '${value}'
} $else {
gg := value
println(gg)
Expand Down
22 changes: 20 additions & 2 deletions vlib/v/type_resolver/type_resolver.v
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ pub fn (mut t TypeResolver) get_type_or_default(node ast.Expr, default_typ ast.T
return t.resolver.unwrap_generic(node.typ)
}
}
ast.PostfixExpr {
if node.op == .question && node.expr is ast.Ident && node.expr.ct_expr {
ctyp := t.get_type(node)
return if ctyp != ast.void_type { ctyp } else { default_typ }
}
}
else {
return default_typ
}
Expand Down Expand Up @@ -174,7 +180,11 @@ pub fn (mut t TypeResolver) get_type(node ast.Expr) ast.Type {
}
.field_var {
// field var from $for loop
t.info.comptime_for_field_type
if node.obj.ct_type_unwrapped {
t.info.comptime_for_field_type.clear_flag(.option)
} else {
t.info.comptime_for_field_type
}
}
else {
ast.void_type
Expand All @@ -183,7 +193,11 @@ pub fn (mut t TypeResolver) get_type(node ast.Expr) ast.Type {
}
} else if node is ast.ComptimeSelector {
// val.$(field.name)
return t.get_comptime_selector_type(node, ast.void_type)
ctyp := t.get_comptime_selector_type(node, ast.void_type)
if node.or_block.kind == .propagate_option {
return ctyp.clear_flag(.option)
}
return ctyp
} else if node is ast.SelectorExpr {
if t.info.is_comptime_selector_type(node) {
return t.get_type_from_comptime_var(node.expr as ast.Ident)
Expand Down Expand Up @@ -223,6 +237,10 @@ pub fn (mut t TypeResolver) get_type(node ast.Expr) ast.Type {
} else if node is ast.CastExpr && node.typ.has_flag(.generic) {
// T(expr)
return t.resolver.unwrap_generic(node.typ)
} else if node is ast.PostfixExpr && node.op == .question
&& (node.expr is ast.Ident && node.expr.ct_expr) {
ctyp := t.get_type(node.expr)
return ctyp.clear_flag(.option)
}
return ast.void_type
}

0 comments on commit 3299512

Please sign in to comment.