From b944927f09c628dc93648ea12dcb259828bfb38c Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Wed, 27 Dec 2023 16:22:44 -0300 Subject: [PATCH] v: unwrap an option value automatically, inside `if o != none {` (#20275) --- vlib/v/checker/if.v | 3 ++ vlib/v/gen/c/cgen.v | 23 ++++++++--- vlib/v/tests/option_cast_test.v | 69 +++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 vlib/v/tests/option_cast_test.v diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index 9a0dbbbccebdd5..7a969628993646 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -515,6 +515,9 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope) { if node.op == .and { c.smartcast_if_conds(mut node.left, mut scope) c.smartcast_if_conds(mut node.right, mut scope) + } else if node.left is ast.Ident && node.op == .ne && node.right is ast.None { + c.smartcast(mut node.left, node.left_type, node.left_type.clear_flag(.option), mut + scope) } else if node.op == .key_is { right_expr := node.right right_type := match right_expr { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 178a9adee7032b..52272583e3be3b 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -4495,19 +4495,27 @@ fn (mut g Gen) ident(node ast.Ident) { if node.obj.smartcasts.len > 0 { obj_sym := g.table.sym(node.obj.typ) if !prevent_sum_type_unwrapping_once { - for _ in node.obj.smartcasts { + for _, typ in node.obj.smartcasts { + is_option_unwrap := is_option && typ == node.obj.typ.clear_flag(.option) g.write('(') if obj_sym.kind == .sum_type && !is_auto_heap { - g.write('*') if is_option { + if !is_option_unwrap { + g.write('*(') + } styp := g.base_type(node.obj.typ) - g.write('(*(${styp}*)') + g.write('*(${styp}*)') + } else { + g.write('*') } } else if g.inside_interface_deref && g.table.is_interface_var(node.obj) { g.write('*') + } else if is_option { + g.write('*(${g.base_type(node.obj.typ)}*)') } } for i, typ in node.obj.smartcasts { + is_option_unwrap := is_option && typ == node.obj.typ.clear_flag(.option) cast_sym := g.table.sym(g.unwrap_generic(typ)) if obj_sym.kind == .interface_ && cast_sym.kind == .interface_ { ptr := '*'.repeat(node.obj.typ.nr_muls()) @@ -4529,9 +4537,14 @@ fn (mut g Gen) ident(node ast.Ident) { g.write('${dot}_${sym.cname}') } else { if is_option { - g.write('.data)') + g.write('.data') + if !is_option_unwrap { + g.write(')') + } + } + if !is_option_unwrap && obj_sym.kind in [.sum_type, .interface_] { + g.write('${dot}_${cast_sym.cname}') } - g.write('${dot}_${cast_sym.cname}') } } g.write(')') diff --git a/vlib/v/tests/option_cast_test.v b/vlib/v/tests/option_cast_test.v new file mode 100644 index 00000000000000..5acdb22ca0d9cb --- /dev/null +++ b/vlib/v/tests/option_cast_test.v @@ -0,0 +1,69 @@ +struct Test { + a int +} + +type MySum = f64 | int + +type MyAlias = Test + +fn test_int() { + a := ?int(1) + if a != none { + assert dump(a) == 1 + assert true + } else { + assert false + } +} + +fn test_struct() { + b := ?Test{ + a: 1 + } + if b != none { + assert dump(b) == Test{ + a: 1 + } + assert true + } else { + assert false + } +} + +fn test_string() { + c := ?string('foo') + if c != none { + assert dump(c) == 'foo' + assert true + } else { + assert false + } +} + +fn test_sum_type() { + d := ?MySum(1.2) + assert d != none + + if d != none { + assert dump(d) == MySum(1.2) + assert true + } else { + assert false + } +} + +fn test_alias() { + d := ?MyAlias(Test{ + a: 1 + }) + assert d != none + + if d != none { + assert dump(d) == Test{ + a: 1 + } + assert true + } else { + assert false + } +}