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()
|
rtype = rtype.deref()
|
||||||
}
|
}
|
||||||
right_name := c.table.type_to_str(rtype)
|
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
|
// 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))
|
right_sym := c.table.final_sym(c.unwrap_generic(right_type))
|
||||||
if node.op == .mul {
|
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() {
|
if right_type.is_ptr() {
|
||||||
return right_type.deref()
|
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) {
|
fn (mut g Gen) gen_option_error(target_type ast.Type, expr ast.Expr) {
|
||||||
styp := g.typ(g.unwrap_generic(target_type))
|
styp := g.typ(g.unwrap_generic(target_type))
|
||||||
g.write('(${styp}){ .state=2, .err=')
|
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} }')
|
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 {
|
if is_ptr && !is_var_mut {
|
||||||
ref_str := '&'.repeat(typ.nr_muls())
|
ref_str := '&'.repeat(typ.nr_muls())
|
||||||
g.write('str_intp(1, _MOV((StrIntpData[]){{_SLIT("${ref_str}"), ${si_s_code} ,{.d_s = isnil(')
|
g.write('str_intp(1, _MOV((StrIntpData[]){{_SLIT("${ref_str}"), ${si_s_code} ,{.d_s = isnil(')
|
||||||
g.expr(expr)
|
if is_ptr && typ.has_flag(.option) {
|
||||||
g.write(') ? _SLIT("nil") : ')
|
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}(')
|
g.write('${str_fn_name}(')
|
||||||
if str_method_expects_ptr && !is_ptr {
|
if str_method_expects_ptr && !is_ptr {
|
||||||
g.write('&')
|
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) {
|
} else if !str_method_expects_ptr && !is_shared && (is_ptr || is_var_mut) {
|
||||||
g.write('*'.repeat(typ.nr_muls()))
|
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.file_base in ['map.v', 'map_d_gcboehm_opt.v']) {
|
||||||
p.error_with_pos("deprecated map syntax, use syntax like `{'age': 20}`",
|
p.error_with_pos("deprecated map syntax, use syntax like `{'age': 20}`",
|
||||||
p.tok.pos())
|
p.tok.pos())
|
||||||
|
} else if p.tok.kind == .question && p.peek_tok.kind == .amp {
|
||||||
|
node = p.prefix_expr()
|
||||||
} else {
|
} else {
|
||||||
if p.inside_comptime_if && p.is_generic_name() && p.peek_tok.kind != .dot {
|
if p.inside_comptime_if && p.is_generic_name() && p.peek_tok.kind != .dot {
|
||||||
// $if T is string {}
|
// $if T is string {}
|
||||||
@ -660,6 +662,10 @@ fn (p &Parser) fileis(s string) bool {
|
|||||||
|
|
||||||
fn (mut p Parser) prefix_expr() ast.Expr {
|
fn (mut p Parser) prefix_expr() ast.Expr {
|
||||||
mut pos := p.tok.pos()
|
mut pos := p.tok.pos()
|
||||||
|
is_option := p.tok.kind == .question
|
||||||
|
if is_option {
|
||||||
|
p.next()
|
||||||
|
}
|
||||||
op := p.tok.kind
|
op := p.tok.kind
|
||||||
if op == .amp {
|
if op == .amp {
|
||||||
p.is_amp = true
|
p.is_amp = true
|
||||||
@ -678,6 +684,9 @@ fn (mut p Parser) prefix_expr() ast.Expr {
|
|||||||
if mut right is ast.CastExpr {
|
if mut right is ast.CastExpr {
|
||||||
// Handle &Type(x), as well as &&Type(x) etc:
|
// Handle &Type(x), as well as &&Type(x) etc:
|
||||||
p.recast_as_pointer(mut right, pos)
|
p.recast_as_pointer(mut right, pos)
|
||||||
|
if is_option {
|
||||||
|
right.typ = right.typ.set_flag(.option)
|
||||||
|
}
|
||||||
return right
|
return right
|
||||||
}
|
}
|
||||||
if mut right is ast.SelectorExpr {
|
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