1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

cgen: support option pointer values - ?&Type (#17397)

This commit is contained in:
Felipe Pena 2023-02-25 09:44:41 -03:00 committed by GitHub
parent 51bb8cda15
commit 12ec0e9fe1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 99 additions and 4 deletions

View File

@ -469,7 +469,9 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
rtype = rtype.deref()
}
right_name := c.table.type_to_str(rtype)
c.error('mismatched types `${left_name}` and `${right_name}`', node.pos)
if !(left_type.has_flag(.option) && right_type == ast.none_type) {
c.error('mismatched types `${left_name}` and `${right_name}`', node.pos)
}
}
}
// Single side check

View File

@ -3783,6 +3783,10 @@ fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type {
}
right_sym := c.table.final_sym(c.unwrap_generic(right_type))
if node.op == .mul {
if right_type.has_flag(.option) {
c.error('type `?${right_sym.name}` is an Option, it must be unwrapped first; use `*var?` to do it',
node.right.pos())
}
if right_type.is_ptr() {
return right_type.deref()
}

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/option_ptr_err.vv:3:10: error: type `?int` is an Option, it must be unwrapped first; use `*var?` to do it
1 | fn main() {
2 | mut var := unsafe { ?&int(none) }
3 | assert *var == 0
| ~~~
4 | }

View File

@ -0,0 +1,4 @@
fn main() {
mut var := unsafe { ?&int(none) }
assert *var == 0
}

View File

@ -4329,7 +4329,12 @@ fn (mut g Gen) gen_result_error(target_type ast.Type, expr ast.Expr) {
fn (mut g Gen) gen_option_error(target_type ast.Type, expr ast.Expr) {
styp := g.typ(g.unwrap_generic(target_type))
g.write('(${styp}){ .state=2, .err=')
g.expr(expr)
if target_type.has_flag(.option) && expr is ast.Ident
&& (expr as ast.Ident).or_expr.kind == .propagate_option {
g.expr(ast.None{}) // option type unwrapping error
} else {
g.expr(expr)
}
g.write(', .data={EMPTY_STRUCT_INITIALIZATION} }')
}

View File

@ -111,12 +111,21 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
if is_ptr && !is_var_mut {
ref_str := '&'.repeat(typ.nr_muls())
g.write('str_intp(1, _MOV((StrIntpData[]){{_SLIT("${ref_str}"), ${si_s_code} ,{.d_s = isnil(')
g.expr(expr)
g.write(') ? _SLIT("nil") : ')
if is_ptr && typ.has_flag(.option) {
g.write('*(${g.base_type(exp_typ)}*)&')
g.expr(expr)
g.write('.data')
g.write(') ? _SLIT("Option(&nil)") : ')
} else {
g.expr(expr)
g.write(') ? _SLIT("nil") : ')
}
}
g.write('${str_fn_name}(')
if str_method_expects_ptr && !is_ptr {
g.write('&')
} else if is_ptr && typ.has_flag(.option) {
g.write('*(${g.typ(typ.set_nr_muls(0))}*)&')
} else if !str_method_expects_ptr && !is_shared && (is_ptr || is_var_mut) {
g.write('*'.repeat(typ.nr_muls()))
}

View File

@ -52,6 +52,8 @@ pub fn (mut p Parser) check_expr(precedence int) !ast.Expr {
&& p.file_base in ['map.v', 'map_d_gcboehm_opt.v']) {
p.error_with_pos("deprecated map syntax, use syntax like `{'age': 20}`",
p.tok.pos())
} else if p.tok.kind == .question && p.peek_tok.kind == .amp {
node = p.prefix_expr()
} else {
if p.inside_comptime_if && p.is_generic_name() && p.peek_tok.kind != .dot {
// $if T is string {}
@ -660,6 +662,10 @@ fn (p &Parser) fileis(s string) bool {
fn (mut p Parser) prefix_expr() ast.Expr {
mut pos := p.tok.pos()
is_option := p.tok.kind == .question
if is_option {
p.next()
}
op := p.tok.kind
if op == .amp {
p.is_amp = true
@ -678,6 +684,9 @@ fn (mut p Parser) prefix_expr() ast.Expr {
if mut right is ast.CastExpr {
// Handle &Type(x), as well as &&Type(x) etc:
p.recast_as_pointer(mut right, pos)
if is_option {
right.typ = right.typ.set_flag(.option)
}
return right
}
if mut right is ast.SelectorExpr {

View File

@ -0,0 +1,56 @@
fn test_simple_opt_ptr() {
val := 123
mut var := unsafe { ?&int(&val) }
assert var? == unsafe { &int(&val) }
}
fn test_simple_writing() {
val := 123
mut var := unsafe { ?&int(&val) }
unsafe {
*var? = 321
}
assert val == 321
}
fn test_simple_deref() ? {
val := 123
mut var := unsafe { ?&int(&val) }
assert *var? == val
mut r := var?
unsafe {
*r = 321
}
assert val == 321
}
fn f_ref(val ?&int) ? {
t := 123
assert *val? == t
}
fn test_simple_writing2() {
val := 123
mut var := unsafe { ?&int(&val) }
unsafe {
*var? = 321
}
x := *var?
assert val == x
}
fn test_simple_fn() {
var := 123
f_ref(&var)
}
fn test_unset_opt_ptr() {
val := 123
mut var := unsafe { ?&int(&val) }
unsafe {
*var? = 1
}
assert var != none
var = none
assert var == none
}