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:
parent
51bb8cda15
commit
12ec0e9fe1
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
6
vlib/v/checker/tests/option_ptr_err.out
Normal file
6
vlib/v/checker/tests/option_ptr_err.out
Normal 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 | }
|
4
vlib/v/checker/tests/option_ptr_err.vv
Normal file
4
vlib/v/checker/tests/option_ptr_err.vv
Normal file
@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
mut var := unsafe { ?&int(none) }
|
||||
assert *var == 0
|
||||
}
|
@ -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} }')
|
||||
}
|
||||
|
||||
|
@ -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()))
|
||||
}
|
||||
|
@ -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 {
|
||||
|
56
vlib/v/tests/option_ptr_test.v
Normal file
56
vlib/v/tests/option_ptr_test.v
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user