all: change optional to option (#16914)

This commit is contained in:
JalonSolov 2023-01-09 01:36:45 -05:00 committed by GitHub
parent 241109516f
commit 90941b3b1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
255 changed files with 1428 additions and 1428 deletions

View file

@ -107,7 +107,7 @@
- `Option` and `Result` are now separate types: `?Foo` and `!Foo` respectively. Old code will continue working for 1 year and will result in a warning/hint. - `Option` and `Result` are now separate types: `?Foo` and `!Foo` respectively. Old code will continue working for 1 year and will result in a warning/hint.
- Hundreds of new checks in the type checker. - Hundreds of new checks in the type checker.
- All V's backends have been split up into separate processes. As the result, building V got 26% faster. - All V's backends have been split up into separate processes. As the result, building V got 26% faster.
- Maps and arrays can now return optionals: `m[bad_key] or { ... }`, `if x := arr[key] { ... }`. - Maps and arrays can now return options: `m[bad_key] or { ... }`, `if x := arr[key] { ... }`.
- `ustring` has been replaced with `[]rune` (works just like in Go). - `ustring` has been replaced with `[]rune` (works just like in Go).
- Maps can now have non-string keys. - Maps can now have non-string keys.
- A new compiler pass for transforming the AST (doesn't slow the compiler too much, adds about 25ms to `v self`). It eliminates unreachable branches and performs other simple optimizations and transformations. - A new compiler pass for transforming the AST (doesn't slow the compiler too much, adds about 25ms to `v self`). It eliminates unreachable branches and performs other simple optimizations and transformations.
@ -447,14 +447,14 @@ used in some industries.
- `fn init()` for module initialization. - `fn init()` for module initialization.
- `a in [1, 2, 3]` optimization: no array gets allocated. - `a in [1, 2, 3]` optimization: no array gets allocated.
- Raw strings: `s := r'hello\nworld'`. - Raw strings: `s := r'hello\nworld'`.
- `if a := func() { }` syntax for handling optionals. - `if a := func() { }` syntax for handling options.
- f32/f64 comparison now uses machine epsilon by default. - f32/f64 comparison now uses machine epsilon by default.
## V 0.1.21 ## V 0.1.21
*30 Sep 2019* *30 Sep 2019*
- `none` keyword for optionals. - `none` keyword for options.
- Solaris support. - Solaris support.
- All table lookup functions now use `none`. - All table lookup functions now use `none`.
- varargs: `fn foo(bar int, params ...string) {`. - varargs: `fn foo(bar int, params ...string) {`.
@ -535,7 +535,7 @@ this backend.
- `libcurl` dependency was removed from the `http` module. - `libcurl` dependency was removed from the `http` module.
- All function arguments are now immutable by default (previously they could be - All function arguments are now immutable by default (previously they could be
modifed inside the function). modifed inside the function).
- `http` functions now return optionals. - `http` functions now return options.
- `sync.WaitGroup`. - `sync.WaitGroup`.
- `vweb` static files serving. - `vweb` static files serving.
- `crypto.rand` module. - `crypto.rand` module.
@ -629,8 +629,8 @@ this backend.
## V 0.1.12 ## V 0.1.12
*4 Jul 2019* *4 Jul 2019*
- V can finally compile itself on Windows (https://github.com/vlang/v#mingw-w64). - V can finally compile itself on Windows (https://github.com/vlang/v#mingw-w64).
- `os` module now uses optionals in all functions that return `File`. - `os` module now uses options in all functions that return `File`.
- Lots of bugs with optionals were fixed. - Lots of bugs with options were fixed.
- `println` was optimized. It no longer results in allocations. - `println` was optimized. It no longer results in allocations.
Now it also works correctly with all integer types. Now it also works correctly with all integer types.
- Lots of `vfmt` fixes, it will be enabled tomorrow. - Lots of `vfmt` fixes, it will be enabled tomorrow.

View file

@ -6,7 +6,7 @@
- [ ] Parallel C compilation - [ ] Parallel C compilation
- [ ] `recover()` from panics - [ ] `recover()` from panics
- [x] vfmt: add missing imports (like goimports) - [x] vfmt: add missing imports (like goimports)
- [ ] Recursive structs via optionals: `struct Node { next ?Node }` - [ ] Recursive structs via options: `struct Node { next ?Node }`
- [ ] Optional function struct fields - [ ] Optional function struct fields
- [ ] Handle function pointers safely, remove `if function == 0 {` - [ ] Handle function pointers safely, remove `if function == 0 {`
- [x] Bundle OpenSSL like GC - [x] Bundle OpenSSL like GC

View file

@ -614,7 +614,7 @@ fn (t Tree) struct_field(node ast.StructField) &Node {
obj.add_terse('anon_struct_decl', t.struct_decl(node.anon_struct_decl)) obj.add_terse('anon_struct_decl', t.struct_decl(node.anon_struct_decl))
obj.add_terse('unaliased_typ', t.type_node(node.unaliased_typ)) obj.add_terse('unaliased_typ', t.type_node(node.unaliased_typ))
obj.add('type_pos', t.pos(node.type_pos)) obj.add('type_pos', t.pos(node.type_pos))
obj.add('optional_pos', t.pos(node.optional_pos)) obj.add('option_pos', t.pos(node.option_pos))
obj.add_terse('has_default_expr', t.bool_node(node.has_default_expr)) obj.add_terse('has_default_expr', t.bool_node(node.has_default_expr))
obj.add_terse('default_expr_typ', t.type_node(node.default_expr_typ)) obj.add_terse('default_expr_typ', t.type_node(node.default_expr_typ))
obj.add_terse('default_expr', t.expr(node.default_expr)) obj.add_terse('default_expr', t.expr(node.default_expr))
@ -1474,7 +1474,7 @@ fn (t Tree) ident_var(node ast.IdentVar) &Node {
obj.add_terse('is_mut', t.bool_node(node.is_mut)) obj.add_terse('is_mut', t.bool_node(node.is_mut))
obj.add_terse('is_static', t.bool_node(node.is_static)) obj.add_terse('is_static', t.bool_node(node.is_static))
obj.add_terse('is_volatile', t.bool_node(node.is_volatile)) obj.add_terse('is_volatile', t.bool_node(node.is_volatile))
obj.add_terse('is_optional', t.bool_node(node.is_optional)) obj.add_terse('is_option', t.bool_node(node.is_option))
obj.add_terse('share', t.enum_node(node.share)) obj.add_terse('share', t.enum_node(node.share))
return obj return obj
} }

View file

@ -125,7 +125,7 @@ In your terminal, you can:
* [Interfaces](#interfaces) * [Interfaces](#interfaces)
* [Sum types](#sum-types) * [Sum types](#sum-types)
* [Option/Result types & error handling](#optionresult-types-and-error-handling) * [Option/Result types & error handling](#optionresult-types-and-error-handling)
* [Handling optionals/results](#handling-optionalsresults) * [Handling options/results](#handling-optionsresults)
* [Custom error types](#custom-error-types) * [Custom error types](#custom-error-types)
* [Generics](#generics) * [Generics](#generics)
* [Concurrency](#concurrency) * [Concurrency](#concurrency)
@ -1344,7 +1344,7 @@ if v := m['abc'] {
} }
``` ```
The same optional check applies to arrays: The same option check applies to arrays:
```v ```v
arr := [1, 2, 3] arr := [1, 2, 3]
@ -3595,7 +3595,7 @@ fn (r Repo) find_user_by_id(id int) !User {
return error('User ${id} not found') return error('User ${id} not found')
} }
// A version of the function using an optional // A version of the function using an option
fn (r Repo) find_user_by_id2(id int) ?User { fn (r Repo) find_user_by_id2(id int) ?User {
for user in r.users { for user in r.users {
if user.id == id { if user.id == id {
@ -3622,7 +3622,7 @@ fn main() {
V used to combine `Option` and `Result` into one type, now they are separate. V used to combine `Option` and `Result` into one type, now they are separate.
The amount of work required to "upgrade" a function to an optional/result function is minimal; The amount of work required to "upgrade" a function to an option/result function is minimal;
you have to add a `?` or `!` to the return type and return an error when something goes wrong. you have to add a `?` or `!` to the return type and return an error when something goes wrong.
This is the primary mechanism for error handling in V. They are still values, like in Go, This is the primary mechanism for error handling in V. They are still values, like in Go,
@ -3639,9 +3639,9 @@ user := repo.find_user_by_id(7) or {
} }
``` ```
#### Handling optionals/results #### Handling options/results
There are four ways of handling an optional/result. The first method is to There are four ways of handling an option/result. The first method is to
propagate the error: propagate the error:
```v ```v
@ -3655,8 +3655,8 @@ fn f(url string) !string {
`http.get` returns `!http.Response`. Because `!` follows the call, the `http.get` returns `!http.Response`. Because `!` follows the call, the
error will be propagated to the caller of `f`. When using `?` after a error will be propagated to the caller of `f`. When using `?` after a
function call producing an optional, the enclosing function must return function call producing an option, the enclosing function must return
an optional as well. If error propagation is used in the `main()` an option as well. If error propagation is used in the `main()`
function it will `panic` instead, since the error cannot be propagated function it will `panic` instead, since the error cannot be propagated
any further. any further.
@ -3679,7 +3679,7 @@ entire program, or use a control flow statement (`return`, `break`, `continue`,
to break from the current block. to break from the current block.
Note that `break` and `continue` can only be used inside a `for` loop. Note that `break` and `continue` can only be used inside a `for` loop.
V does not have a way to forcibly "unwrap" an optional (as other languages do, V does not have a way to forcibly "unwrap" an option (as other languages do,
for instance Rust's `unwrap()` or Swift's `!`). To do this, use `or { panic(err) }` instead. for instance Rust's `unwrap()` or Swift's `!`). To do this, use `or { panic(err) }` instead.
--- ---
@ -3708,7 +3708,7 @@ The fourth method is to use `if` unwrapping:
import net.http import net.http
if resp := http.get('https://google.com') { if resp := http.get('https://google.com') {
println(resp.body) // resp is a http.Response, not an optional println(resp.body) // resp is a http.Response, not an option
} else { } else {
println(err) println(err)
} }
@ -3988,7 +3988,7 @@ A channel can be closed to indicate that no further objects can be pushed. Any a
to do so will then result in a runtime panic (with the exception of `select` and to do so will then result in a runtime panic (with the exception of `select` and
`try_push()` - see below). Attempts to pop will return immediately if the `try_push()` - see below). Attempts to pop will return immediately if the
associated channel has been closed and the buffer is empty. This situation can be associated channel has been closed and the buffer is empty. This situation can be
handled using an `or {}` block (see [Handling optionals/results](#handling-optionalsresults)). handled using an `or {}` block (see [Handling options/results](#handling-optionsresults)).
```v wip ```v wip
ch := chan int{} ch := chan int{}

View file

@ -83,14 +83,14 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
vhalt() vhalt()
} }
// panic_optional_not_set is called by V, when you use option error propagation in your main function. // panic_option_not_set is called by V, when you use option error propagation in your main function.
// It ends the program with a panic. // It ends the program with a panic.
[noreturn] [noreturn]
pub fn panic_optional_not_set(s string) { pub fn panic_option_not_set(s string) {
panic('optional not set (${s})') panic('option not set (${s})')
} }
// panic_optional_not_set is called by V, when you use result error propagation in your main function // panic_result_not_set is called by V, when you use result error propagation in your main function
// It ends the program with a panic. // It ends the program with a panic.
[noreturn] [noreturn]
pub fn panic_result_not_set(s string) { pub fn panic_result_not_set(s string) {

View file

@ -120,7 +120,7 @@ pub:
// //
is_shared bool // `f shared Abc` is_shared bool // `f shared Abc`
is_atomic bool // `f atomic int` , TODO is_atomic bool // `f atomic int` , TODO
is_optional bool // `f ?string` , TODO is_option bool // `f ?string` , TODO
// //
is_array bool // `f []string` , TODO is_array bool // `f []string` , TODO
is_map bool // `f map[string]int` , TODO is_map bool // `f map[string]int` , TODO

View file

@ -107,7 +107,7 @@ pub fn error_with_code(message string, code int) IError {
} }
} }
// Option is the base of V's internal optional return system. // Option is the base of V's internal option return system.
struct Option { struct Option {
state u8 state u8
err IError = none__ err IError = none__
@ -116,7 +116,7 @@ struct Option {
// derived Option_xxx types // derived Option_xxx types
} }
// option is the base of V's internal optional return system. // option is the base of V's internal option return system.
struct _option { struct _option {
state u8 state u8
err IError = none__ err IError = none__

View file

@ -84,7 +84,7 @@ pub fn utf8_str_len(s string) int {
// valid utf8 in the string, and could result in // valid utf8 in the string, and could result in
// values greater than the utf32 spec // values greater than the utf32 spec
// it has been replaced by `utf8_to_utf32` which // it has been replaced by `utf8_to_utf32` which
// has an optional return type. // has an option return type.
// //
// this function is left for backward compatibility // this function is left for backward compatibility
// it is used in vlib/builtin/string.v, // it is used in vlib/builtin/string.v,

View file

@ -3,7 +3,7 @@ import os
struct DbConfig {} struct DbConfig {}
fn test_json_decode_with_optional_arg() { fn test_json_decode_with_option_arg() {
if ret := print_info() { if ret := print_info() {
println(ret) println(ret)
} else { } else {

View file

@ -5,7 +5,7 @@ struct Foo {
num ?int num ?int
} }
fn test_json_encode_struct_with_optional_field() { fn test_json_encode_struct_with_option_field() {
f1 := Foo{ f1 := Foo{
name: 'hello' name: 'hello'
} }

View file

@ -3,7 +3,7 @@ module strconv
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
// TODO: use optionals, or some way to return default with error. // TODO: use options, or some way to return default with error.
const ( const (
// int_size is the size in bits of an int or uint value. // int_size is the size in bits of an int or uint value.
// int_size = 32 << (~u32(0) >> 63) // int_size = 32 << (~u32(0) >> 63)

View file

@ -662,7 +662,7 @@ fn (mut s Scanner) validate_and_skip_headers() ! {
// NICE-TO-HAVE-TODO Check other types of (UTF-?) headers and yield an error. TOML is UTF-8 only. // NICE-TO-HAVE-TODO Check other types of (UTF-?) headers and yield an error. TOML is UTF-8 only.
// Skip optional UTF-8 heaser, if any. // Skip optional UTF-8 header, if any.
if s.at() == 0xEF && s.peek(1) == 0xBB && s.peek(2) == 0xBF { if s.at() == 0xEF && s.peek(1) == 0xBB && s.peek(2) == 0xBF {
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'skipping UTF-8 byte order mark (BOM)') util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'skipping UTF-8 byte order mark (BOM)')
s.header_len = 3 s.header_len = 3

View file

@ -296,7 +296,7 @@ pub struct StructField {
pub: pub:
pos token.Pos pos token.Pos
type_pos token.Pos type_pos token.Pos
optional_pos token.Pos option_pos token.Pos
comments []Comment comments []Comment
i int i int
has_default_expr bool has_default_expr bool
@ -791,7 +791,7 @@ pub mut:
is_mut bool is_mut bool
is_static bool is_static bool
is_volatile bool is_volatile bool
is_optional bool is_option bool
share ShareType share ShareType
} }

View file

@ -224,7 +224,7 @@ pub fn (t &Table) fn_type_signature(f &Fn) string {
} }
if f.return_type != 0 && f.return_type != void_type { if f.return_type != 0 && f.return_type != void_type {
sym := t.sym(f.return_type) sym := t.sym(f.return_type)
opt := if f.return_type.has_flag(.optional) { 'option_' } else { '' } opt := if f.return_type.has_flag(.option) { 'option_' } else { '' }
res := if f.return_type.has_flag(.result) { 'result_' } else { '' } res := if f.return_type.has_flag(.result) { 'result_' } else { '' }
sig += '__${opt}${res}${sym.cname}' sig += '__${opt}${res}${sym.cname}'
@ -256,7 +256,7 @@ pub fn (t &Table) fn_type_source_signature(f &Fn) string {
sig += ' !' sig += ' !'
} else if f.return_type != void_type { } else if f.return_type != void_type {
return_type_sym := t.sym(f.return_type) return_type_sym := t.sym(f.return_type)
if f.return_type.has_flag(.optional) { if f.return_type.has_flag(.option) {
sig += ' ?${return_type_sym.name}' sig += ' ?${return_type_sym.name}'
} else if f.return_type.has_flag(.result) { } else if f.return_type.has_flag(.result) {
sig += ' !${return_type_sym.name}' sig += ' !${return_type_sym.name}'
@ -882,7 +882,7 @@ pub fn (t &Table) known_type_idx(typ Type) bool {
pub fn (t &Table) array_name(elem_type Type) string { pub fn (t &Table) array_name(elem_type Type) string {
elem_type_sym := t.sym(elem_type) elem_type_sym := t.sym(elem_type)
ptr := if elem_type.is_ptr() { '&'.repeat(elem_type.nr_muls()) } else { '' } ptr := if elem_type.is_ptr() { '&'.repeat(elem_type.nr_muls()) } else { '' }
opt := if elem_type.has_flag(.optional) { '?' } else { '' } opt := if elem_type.has_flag(.option) { '?' } else { '' }
res := if elem_type.has_flag(.result) { '!' } else { '' } res := if elem_type.has_flag(.result) { '!' } else { '' }
return '[]${opt}${res}${ptr}${elem_type_sym.name}' return '[]${opt}${res}${ptr}${elem_type_sym.name}'
} }
@ -891,7 +891,7 @@ pub fn (t &Table) array_name(elem_type Type) string {
pub fn (t &Table) array_cname(elem_type Type) string { pub fn (t &Table) array_cname(elem_type Type) string {
elem_type_sym := t.sym(elem_type) elem_type_sym := t.sym(elem_type)
suffix := if elem_type.is_ptr() { '_ptr'.repeat(elem_type.nr_muls()) } else { '' } suffix := if elem_type.is_ptr() { '_ptr'.repeat(elem_type.nr_muls()) } else { '' }
opt := if elem_type.has_flag(.optional) { '_option_' } else { '' } opt := if elem_type.has_flag(.option) { '_option_' } else { '' }
res := if elem_type.has_flag(.result) { '_result_' } else { '' } res := if elem_type.has_flag(.result) { '_result_' } else { '' }
if elem_type_sym.cname.contains('[') { if elem_type_sym.cname.contains('[') {
type_name := elem_type_sym.cname.replace_each(['[', '_T_', ', ', '_', ']', '']) type_name := elem_type_sym.cname.replace_each(['[', '_T_', ', ', '_', ']', ''])
@ -907,7 +907,7 @@ pub fn (t &Table) array_cname(elem_type Type) string {
pub fn (t &Table) array_fixed_name(elem_type Type, size int, size_expr Expr) string { pub fn (t &Table) array_fixed_name(elem_type Type, size int, size_expr Expr) string {
elem_type_sym := t.sym(elem_type) elem_type_sym := t.sym(elem_type)
ptr := if elem_type.is_ptr() { '&'.repeat(elem_type.nr_muls()) } else { '' } ptr := if elem_type.is_ptr() { '&'.repeat(elem_type.nr_muls()) } else { '' }
opt := if elem_type.has_flag(.optional) { '?' } else { '' } opt := if elem_type.has_flag(.option) { '?' } else { '' }
res := if elem_type.has_flag(.result) { '!' } else { '' } res := if elem_type.has_flag(.result) { '!' } else { '' }
size_str := if size_expr is EmptyExpr || size != 987654321 { size_str := if size_expr is EmptyExpr || size != 987654321 {
size.str() size.str()
@ -921,7 +921,7 @@ pub fn (t &Table) array_fixed_name(elem_type Type, size int, size_expr Expr) str
pub fn (t &Table) array_fixed_cname(elem_type Type, size int) string { pub fn (t &Table) array_fixed_cname(elem_type Type, size int) string {
elem_type_sym := t.sym(elem_type) elem_type_sym := t.sym(elem_type)
suffix := if elem_type.is_ptr() { '_ptr${elem_type.nr_muls()}' } else { '' } suffix := if elem_type.is_ptr() { '_ptr${elem_type.nr_muls()}' } else { '' }
opt := if elem_type.has_flag(.optional) { '_option_' } else { '' } opt := if elem_type.has_flag(.option) { '_option_' } else { '' }
res := if elem_type.has_flag(.result) { '_result_' } else { '' } res := if elem_type.has_flag(.result) { '_result_' } else { '' }
if elem_type_sym.cname.contains('[') { if elem_type_sym.cname.contains('[') {
type_name := elem_type_sym.cname.replace_each(['[', '_T_', ', ', '_', ']', '']) type_name := elem_type_sym.cname.replace_each(['[', '_T_', ', ', '_', ']', ''])
@ -978,7 +978,7 @@ pub fn (t &Table) promise_cname(return_type Type) string {
[inline] [inline]
pub fn (t &Table) thread_name(return_type Type) string { pub fn (t &Table) thread_name(return_type Type) string {
if return_type.idx() == void_type_idx { if return_type.idx() == void_type_idx {
if return_type.has_flag(.optional) { if return_type.has_flag(.option) {
return 'thread ?' return 'thread ?'
} else if return_type.has_flag(.result) { } else if return_type.has_flag(.result) {
return 'thread !' return 'thread !'
@ -988,7 +988,7 @@ pub fn (t &Table) thread_name(return_type Type) string {
} }
return_type_sym := t.sym(return_type) return_type_sym := t.sym(return_type)
ptr := if return_type.is_ptr() { '&' } else { '' } ptr := if return_type.is_ptr() { '&' } else { '' }
opt := if return_type.has_flag(.optional) { '?' } else { '' } opt := if return_type.has_flag(.option) { '?' } else { '' }
res := if return_type.has_flag(.result) { '!' } else { '' } res := if return_type.has_flag(.result) { '!' } else { '' }
return 'thread ${opt}${res}${ptr}${return_type_sym.name}' return 'thread ${opt}${res}${ptr}${return_type_sym.name}'
} }
@ -996,7 +996,7 @@ pub fn (t &Table) thread_name(return_type Type) string {
[inline] [inline]
pub fn (t &Table) thread_cname(return_type Type) string { pub fn (t &Table) thread_cname(return_type Type) string {
if return_type == void_type { if return_type == void_type {
if return_type.has_flag(.optional) { if return_type.has_flag(.option) {
return '__v_thread_Option_void' return '__v_thread_Option_void'
} else if return_type.has_flag(.result) { } else if return_type.has_flag(.result) {
return '__v_thread_Result_void' return '__v_thread_Result_void'
@ -1006,7 +1006,7 @@ pub fn (t &Table) thread_cname(return_type Type) string {
} }
return_type_sym := t.sym(return_type) return_type_sym := t.sym(return_type)
suffix := if return_type.is_ptr() { '_ptr' } else { '' } suffix := if return_type.is_ptr() { '_ptr' } else { '' }
opt := if return_type.has_flag(.optional) { '_option_' } else { '' } opt := if return_type.has_flag(.option) { '_option_' } else { '' }
res := if return_type.has_flag(.result) { '_result_' } else { '' } res := if return_type.has_flag(.result) { '_result_' } else { '' }
return '__v_thread_${opt}${res}${return_type_sym.cname}${suffix}' return '__v_thread_${opt}${res}${return_type_sym.cname}${suffix}'
} }
@ -1018,7 +1018,7 @@ pub fn (t &Table) map_name(key_type Type, value_type Type) string {
key_type_sym := t.sym(key_type) key_type_sym := t.sym(key_type)
value_type_sym := t.sym(value_type) value_type_sym := t.sym(value_type)
ptr := if value_type.is_ptr() { '&'.repeat(value_type.nr_muls()) } else { '' } ptr := if value_type.is_ptr() { '&'.repeat(value_type.nr_muls()) } else { '' }
opt := if value_type.has_flag(.optional) { '?' } else { '' } opt := if value_type.has_flag(.option) { '?' } else { '' }
res := if value_type.has_flag(.result) { '!' } else { '' } res := if value_type.has_flag(.result) { '!' } else { '' }
return 'map[${key_type_sym.name}]${opt}${res}${ptr}${value_type_sym.name}' return 'map[${key_type_sym.name}]${opt}${res}${ptr}${value_type_sym.name}'
} }
@ -1028,7 +1028,7 @@ pub fn (t &Table) map_cname(key_type Type, value_type Type) string {
key_type_sym := t.sym(key_type) key_type_sym := t.sym(key_type)
value_type_sym := t.sym(value_type) value_type_sym := t.sym(value_type)
suffix := if value_type.is_ptr() { '_ptr'.repeat(value_type.nr_muls()) } else { '' } suffix := if value_type.is_ptr() { '_ptr'.repeat(value_type.nr_muls()) } else { '' }
opt := if value_type.has_flag(.optional) { '_option_' } else { '' } opt := if value_type.has_flag(.option) { '_option_' } else { '' }
res := if value_type.has_flag(.result) { '_result_' } else { '' } res := if value_type.has_flag(.result) { '_result_' } else { '' }
if value_type_sym.cname.contains('[') { if value_type_sym.cname.contains('[') {
type_name := value_type_sym.cname.replace_each(['[', '_T_', ', ', '_', ']', '']) type_name := value_type_sym.cname.replace_each(['[', '_T_', ', ', '_', ']', ''])

View file

@ -105,7 +105,7 @@ pub mut:
// max of 8 // max of 8
pub enum TypeFlag { pub enum TypeFlag {
optional option
result result
variadic variadic
generic generic
@ -280,8 +280,8 @@ pub fn (t Type) debug() []string {
res << 'idx: 0x${t.idx().hex():-8}' res << 'idx: 0x${t.idx().hex():-8}'
res << 'type: 0x${t.hex():-8}' res << 'type: 0x${t.hex():-8}'
res << 'nr_muls: ${t.nr_muls()}' res << 'nr_muls: ${t.nr_muls()}'
if t.has_flag(.optional) { if t.has_flag(.option) {
res << 'optional' res << 'option'
} }
if t.has_flag(.result) { if t.has_flag(.result) {
res << 'result' res << 'result'
@ -486,7 +486,7 @@ pub const (
pub const ( pub const (
void_type = new_type(void_type_idx) void_type = new_type(void_type_idx)
ovoid_type = new_type(void_type_idx).set_flag(.optional) // the return type of `fn ()?` ovoid_type = new_type(void_type_idx).set_flag(.option) // the return type of `fn ()?`
rvoid_type = new_type(void_type_idx).set_flag(.result) // the return type of `fn () !` rvoid_type = new_type(void_type_idx).set_flag(.result) // the return type of `fn () !`
voidptr_type = new_type(voidptr_type_idx) voidptr_type = new_type(voidptr_type_idx)
byteptr_type = new_type(byteptr_type_idx) byteptr_type = new_type(byteptr_type_idx)
@ -569,7 +569,7 @@ pub mut:
// returns TypeSymbol kind only if there are no type modifiers // returns TypeSymbol kind only if there are no type modifiers
pub fn (t &Table) type_kind(typ Type) Kind { pub fn (t &Table) type_kind(typ Type) Kind {
if typ.nr_muls() > 0 || typ.has_flag(.optional) || typ.has_flag(.result) { if typ.nr_muls() > 0 || typ.has_flag(.option) || typ.has_flag(.result) {
return Kind.placeholder return Kind.placeholder
} }
return t.sym(typ).kind return t.sym(typ).kind
@ -866,7 +866,7 @@ pub fn (t &TypeSymbol) is_builtin() bool {
// type_size returns the size and alignment (in bytes) of `typ`, similarly to C's `sizeof()` and `alignof()`. // type_size returns the size and alignment (in bytes) of `typ`, similarly to C's `sizeof()` and `alignof()`.
pub fn (t &Table) type_size(typ Type) (int, int) { pub fn (t &Table) type_size(typ Type) (int, int) {
if typ.has_flag(.optional) || typ.has_flag(.result) { if typ.has_flag(.option) || typ.has_flag(.result) {
return t.type_size(ast.error_type_idx) return t.type_size(ast.error_type_idx)
} }
if typ.nr_muls() > 0 { if typ.nr_muls() > 0 {
@ -1328,7 +1328,7 @@ pub fn (t &Table) type_to_str_using_aliases(typ Type, import_aliases map[string]
res += ']' res += ']'
} }
.void { .void {
if typ.has_flag(.optional) { if typ.has_flag(.option) {
res = '?' res = '?'
return res return res
} }
@ -1369,7 +1369,7 @@ pub fn (t &Table) type_to_str_using_aliases(typ Type, import_aliases map[string]
if nr_muls > 0 && !typ.has_flag(.variadic) { if nr_muls > 0 && !typ.has_flag(.variadic) {
res = strings.repeat(`&`, nr_muls) + res res = strings.repeat(`&`, nr_muls) + res
} }
if typ.has_flag(.optional) { if typ.has_flag(.option) {
res = '?${res}' res = '?${res}'
} }
if typ.has_flag(.result) { if typ.has_flag(.result) {

View file

@ -37,30 +37,30 @@ fn test_flags() {
mut t := ast.new_type(ast.void_type_idx) mut t := ast.new_type(ast.void_type_idx)
idx := t.idx() idx := t.idx()
nr_muls := t.nr_muls() nr_muls := t.nr_muls()
t = t.set_flag(ast.TypeFlag.optional) t = t.set_flag(ast.TypeFlag.option)
assert t.has_flag(ast.TypeFlag.optional) == true assert t.has_flag(ast.TypeFlag.option) == true
assert t.has_flag(ast.TypeFlag.variadic) == false assert t.has_flag(ast.TypeFlag.variadic) == false
assert t.has_flag(ast.TypeFlag.generic) == false assert t.has_flag(ast.TypeFlag.generic) == false
t = t.set_flag(ast.TypeFlag.variadic) t = t.set_flag(ast.TypeFlag.variadic)
assert t.has_flag(ast.TypeFlag.optional) == true assert t.has_flag(ast.TypeFlag.option) == true
assert t.has_flag(ast.TypeFlag.variadic) == true assert t.has_flag(ast.TypeFlag.variadic) == true
assert t.has_flag(ast.TypeFlag.generic) == false assert t.has_flag(ast.TypeFlag.generic) == false
t = t.set_flag(ast.TypeFlag.generic) t = t.set_flag(ast.TypeFlag.generic)
assert t.has_flag(ast.TypeFlag.optional) == true assert t.has_flag(ast.TypeFlag.option) == true
assert t.has_flag(ast.TypeFlag.variadic) == true assert t.has_flag(ast.TypeFlag.variadic) == true
assert t.has_flag(ast.TypeFlag.generic) == true assert t.has_flag(ast.TypeFlag.generic) == true
assert t.idx() == idx assert t.idx() == idx
assert t.nr_muls() == nr_muls assert t.nr_muls() == nr_muls
t = t.clear_flag(ast.TypeFlag.optional) t = t.clear_flag(ast.TypeFlag.option)
assert t.has_flag(ast.TypeFlag.optional) == false assert t.has_flag(ast.TypeFlag.option) == false
assert t.has_flag(ast.TypeFlag.variadic) == true assert t.has_flag(ast.TypeFlag.variadic) == true
assert t.has_flag(ast.TypeFlag.generic) == true assert t.has_flag(ast.TypeFlag.generic) == true
t = t.clear_flag(ast.TypeFlag.variadic) t = t.clear_flag(ast.TypeFlag.variadic)
assert t.has_flag(ast.TypeFlag.optional) == false assert t.has_flag(ast.TypeFlag.option) == false
assert t.has_flag(ast.TypeFlag.variadic) == false assert t.has_flag(ast.TypeFlag.variadic) == false
assert t.has_flag(ast.TypeFlag.generic) == true assert t.has_flag(ast.TypeFlag.generic) == true
t = t.clear_flag(ast.TypeFlag.generic) t = t.clear_flag(ast.TypeFlag.generic)
assert t.has_flag(ast.TypeFlag.optional) == false assert t.has_flag(ast.TypeFlag.option) == false
assert t.has_flag(ast.TypeFlag.variadic) == false assert t.has_flag(ast.TypeFlag.variadic) == false
assert t.has_flag(ast.TypeFlag.generic) == false assert t.has_flag(ast.TypeFlag.generic) == false
assert t.idx() == idx assert t.idx() == idx
@ -74,7 +74,7 @@ fn test_derive() {
t = t.set_nr_muls(10) t = t.set_nr_muls(10)
mut t2 := ast.new_type(ast.i16_type_idx) mut t2 := ast.new_type(ast.i16_type_idx)
t2 = t2.derive(t) t2 = t2.derive(t)
assert t2.has_flag(ast.TypeFlag.optional) == false assert t2.has_flag(ast.TypeFlag.option) == false
assert t2.has_flag(ast.TypeFlag.variadic) == true assert t2.has_flag(ast.TypeFlag.variadic) == true
assert t2.has_flag(ast.TypeFlag.generic) == true assert t2.has_flag(ast.TypeFlag.generic) == true
assert t2.nr_muls() == 10 assert t2.nr_muls() == 10

View file

@ -130,7 +130,7 @@ fn (mut c Checker) check_types(got ast.Type, expected ast.Type) bool {
} }
} }
// allow direct int-literal assignment for pointers for now // allow direct int-literal assignment for pointers for now
// maybe in the future optionals should be used for that // maybe in the future options should be used for that
if expected.is_real_pointer() { if expected.is_real_pointer() {
if got == ast.int_literal_type { if got == ast.int_literal_type {
return true return true
@ -146,15 +146,15 @@ fn (mut c Checker) check_types(got ast.Type, expected ast.Type) bool {
if expected == ast.charptr_type && got == ast.char_type.ref() { if expected == ast.charptr_type && got == ast.char_type.ref() {
return true return true
} }
if expected.has_flag(.optional) || expected.has_flag(.result) { if expected.has_flag(.option) || expected.has_flag(.result) {
sym := c.table.sym(got) sym := c.table.sym(got)
if ((sym.idx == ast.error_type_idx || got in [ast.none_type, ast.error_type]) if ((sym.idx == ast.error_type_idx || got in [ast.none_type, ast.error_type])
&& expected.has_flag(.optional)) && expected.has_flag(.option))
|| ((sym.idx == ast.error_type_idx || got == ast.error_type) || ((sym.idx == ast.error_type_idx || got == ast.error_type)
&& expected.has_flag(.result)) { && expected.has_flag(.result)) {
// IError // IError
return true return true
} else if !c.check_basic(got, expected.clear_flag(.optional).clear_flag(.result)) { } else if !c.check_basic(got, expected.clear_flag(.option).clear_flag(.result)) {
return false return false
} }
} }
@ -402,7 +402,7 @@ fn (mut c Checker) check_matching_function_symbols(got_type_sym &ast.TypeSymbol,
if got_fn.params.len != exp_fn.params.len { if got_fn.params.len != exp_fn.params.len {
return false return false
} }
if got_fn.return_type.has_flag(.optional) != exp_fn.return_type.has_flag(.optional) { if got_fn.return_type.has_flag(.option) != exp_fn.return_type.has_flag(.option) {
return false return false
} }
if got_fn.return_type.has_flag(.result) != exp_fn.return_type.has_flag(.result) { if got_fn.return_type.has_flag(.result) != exp_fn.return_type.has_flag(.result) {
@ -581,7 +581,7 @@ fn (mut c Checker) promote(left_type ast.Type, right_type ast.Type) ast.Type {
} }
if right_type.is_number() && left_type.is_number() { if right_type.is_number() && left_type.is_number() {
return c.promote_num(left_type, right_type) return c.promote_num(left_type, right_type)
} else if left_type.has_flag(.optional) != right_type.has_flag(.optional) { } else if left_type.has_flag(.option) != right_type.has_flag(.option) {
// incompatible // incompatible
return ast.void_type return ast.void_type
} else { } else {
@ -645,7 +645,7 @@ fn (c &Checker) expected_msg(got ast.Type, expected ast.Type) string {
fn (mut c Checker) symmetric_check(left ast.Type, right ast.Type) bool { fn (mut c Checker) symmetric_check(left ast.Type, right ast.Type) bool {
// allow direct int-literal assignment for pointers for now // allow direct int-literal assignment for pointers for now
// maybe in the future optionals should be used for that // maybe in the future options should be used for that
if right.is_ptr() || right.is_pointer() { if right.is_ptr() || right.is_pointer() {
if left == ast.int_literal_type { if left == ast.int_literal_type {
return true return true

View file

@ -920,23 +920,23 @@ fn (mut c Checker) type_implements(typ ast.Type, interface_type ast.Type, pos to
return true return true
} }
// return the actual type of the expression, once the optional is handled // return the actual type of the expression, once the option is handled
fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type ast.Type) ast.Type { fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type ast.Type) ast.Type {
if expr is ast.CallExpr { if expr is ast.CallExpr {
mut expr_ret_type := expr.return_type mut expr_ret_type := expr.return_type
if expr_ret_type != 0 && c.table.sym(expr_ret_type).kind == .alias { if expr_ret_type != 0 && c.table.sym(expr_ret_type).kind == .alias {
unaliased_ret_type := c.table.unaliased_type(expr_ret_type) unaliased_ret_type := c.table.unaliased_type(expr_ret_type)
if unaliased_ret_type.has_flag(.optional) || unaliased_ret_type.has_flag(.result) { if unaliased_ret_type.has_flag(.option) || unaliased_ret_type.has_flag(.result) {
expr_ret_type = unaliased_ret_type expr_ret_type = unaliased_ret_type
} }
} }
if expr_ret_type.has_flag(.optional) || expr_ret_type.has_flag(.result) { if expr_ret_type.has_flag(.option) || expr_ret_type.has_flag(.result) {
return_modifier_kind := if expr_ret_type.has_flag(.optional) { return_modifier_kind := if expr_ret_type.has_flag(.option) {
'an option' 'an option'
} else { } else {
'a result' 'a result'
} }
return_modifier := if expr_ret_type.has_flag(.optional) { '?' } else { '!' } return_modifier := if expr_ret_type.has_flag(.option) { '?' } else { '!' }
if expr.or_block.kind == .absent { if expr.or_block.kind == .absent {
if c.inside_defer { if c.inside_defer {
c.error('${expr.name}() returns ${return_modifier_kind}, so it should have an `or {}` block at the end', c.error('${expr.name}() returns ${return_modifier_kind}, so it should have an `or {}` block at the end',
@ -948,25 +948,25 @@ fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type ast.Type) ast.Typ
} else { } else {
c.check_or_expr(expr.or_block, ret_type, expr_ret_type) c.check_or_expr(expr.or_block, ret_type, expr_ret_type)
} }
return ret_type.clear_flag(.optional).clear_flag(.result) return ret_type.clear_flag(.option).clear_flag(.result)
} else if expr.or_block.kind == .block { } else if expr.or_block.kind == .block {
c.error('unexpected `or` block, the function `${expr.name}` does neither return an optional nor a result', c.error('unexpected `or` block, the function `${expr.name}` does not return an option or a result',
expr.or_block.pos) expr.or_block.pos)
} else if expr.or_block.kind == .propagate_option { } else if expr.or_block.kind == .propagate_option {
c.error('unexpected `?`, the function `${expr.name}` does not return an optional', c.error('unexpected `?`, the function `${expr.name}` does not return an option',
expr.or_block.pos) expr.or_block.pos)
} else if expr.or_block.kind == .propagate_result { } else if expr.or_block.kind == .propagate_result {
c.error('unexpected `!`, the function `${expr.name}` does not return a result', c.error('unexpected `!`, the function `${expr.name}` does not return a result',
expr.or_block.pos) expr.or_block.pos)
} }
} else if expr is ast.SelectorExpr && c.table.sym(ret_type).kind != .chan { } else if expr is ast.SelectorExpr && c.table.sym(ret_type).kind != .chan {
if expr.typ.has_flag(.optional) || expr.typ.has_flag(.result) { if expr.typ.has_flag(.option) || expr.typ.has_flag(.result) {
with_modifier_kind := if expr.typ.has_flag(.optional) { with_modifier_kind := if expr.typ.has_flag(.option) {
'an option' 'an option'
} else { } else {
'a result' 'a result'
} }
with_modifier := if expr.typ.has_flag(.optional) { '?' } else { '!' } with_modifier := if expr.typ.has_flag(.option) { '?' } else { '!' }
if expr.or_block.kind == .absent { if expr.or_block.kind == .absent {
if c.inside_defer { if c.inside_defer {
c.error('field `${expr.field_name}` is ${with_modifier_kind}, so it should have an `or {}` block at the end', c.error('field `${expr.field_name}` is ${with_modifier_kind}, so it should have an `or {}` block at the end',
@ -978,12 +978,12 @@ fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type ast.Type) ast.Typ
} else { } else {
c.check_or_expr(expr.or_block, ret_type, expr.typ) c.check_or_expr(expr.or_block, ret_type, expr.typ)
} }
return ret_type.clear_flag(.optional).clear_flag(.result) return ret_type.clear_flag(.option).clear_flag(.result)
} else if expr.or_block.kind == .block { } else if expr.or_block.kind == .block {
c.error('unexpected `or` block, the field `${expr.field_name}` is neither an optional, nor a result', c.error('unexpected `or` block, the field `${expr.field_name}` is neither an option, nor a result',
expr.or_block.pos) expr.or_block.pos)
} else if expr.or_block.kind == .propagate_option { } else if expr.or_block.kind == .propagate_option {
c.error('unexpected `?`, the field `${expr.field_name}` is not an optional', c.error('unexpected `?`, the field `${expr.field_name}` is not an option',
expr.or_block.pos) expr.or_block.pos)
} else if expr.or_block.kind == .propagate_result { } else if expr.or_block.kind == .propagate_result {
c.error('unexpected `!`, result fields are not supported', expr.or_block.pos) c.error('unexpected `!`, result fields are not supported', expr.or_block.pos)
@ -998,18 +998,18 @@ fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type ast.Type) ast.Typ
fn (mut c Checker) check_or_expr(node ast.OrExpr, ret_type ast.Type, expr_return_type ast.Type) { fn (mut c Checker) check_or_expr(node ast.OrExpr, ret_type ast.Type, expr_return_type ast.Type) {
if node.kind == .propagate_option { if node.kind == .propagate_option {
if c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.return_type.has_flag(.optional) if c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.return_type.has_flag(.option)
&& !c.table.cur_fn.is_main && !c.table.cur_fn.is_test && !c.inside_const { && !c.table.cur_fn.is_main && !c.table.cur_fn.is_test && !c.inside_const {
c.add_instruction_for_optional_type() c.add_instruction_for_option_type()
c.error('to propagate the call, `${c.table.cur_fn.name}` must return an optional type', c.error('to propagate the call, `${c.table.cur_fn.name}` must return an option type',
node.pos) node.pos)
} }
if !expr_return_type.has_flag(.optional) { if !expr_return_type.has_flag(.option) {
if expr_return_type.has_flag(.result) { if expr_return_type.has_flag(.result) {
c.warn('propagating a result like an option is deprecated, use `foo()!` instead of `foo()?`', c.warn('propagating a result like an option is deprecated, use `foo()!` instead of `foo()?`',
node.pos) node.pos)
} else { } else {
c.error('to propagate an option, the call must also return an optional type', c.error('to propagate an option, the call must also return an option type',
node.pos) node.pos)
} }
} }
@ -1038,7 +1038,7 @@ fn (mut c Checker) check_or_expr(node ast.OrExpr, ret_type ast.Type, expr_return
return return
} }
last_stmt := node.stmts.last() last_stmt := node.stmts.last()
c.check_or_last_stmt(last_stmt, ret_type, expr_return_type.clear_flag(.optional).clear_flag(.result)) c.check_or_last_stmt(last_stmt, ret_type, expr_return_type.clear_flag(.option).clear_flag(.result))
} }
fn (mut c Checker) check_or_last_stmt(stmt ast.Stmt, ret_type ast.Type, expr_return_type ast.Type) { fn (mut c Checker) check_or_last_stmt(stmt ast.Stmt, ret_type ast.Type, expr_return_type ast.Type) {
@ -1046,7 +1046,7 @@ fn (mut c Checker) check_or_last_stmt(stmt ast.Stmt, ret_type ast.Type, expr_ret
match stmt { match stmt {
ast.ExprStmt { ast.ExprStmt {
c.expected_type = ret_type c.expected_type = ret_type
c.expected_or_type = ret_type.clear_flag(.optional).clear_flag(.result) c.expected_or_type = ret_type.clear_flag(.option).clear_flag(.result)
last_stmt_typ := c.expr(stmt.expr) last_stmt_typ := c.expr(stmt.expr)
c.expected_or_type = ast.void_type c.expected_or_type = ast.void_type
type_fits := c.check_types(last_stmt_typ, ret_type) type_fits := c.check_types(last_stmt_typ, ret_type)
@ -1071,7 +1071,7 @@ fn (mut c Checker) check_or_last_stmt(stmt ast.Stmt, ret_type ast.Type, expr_ret
} }
return return
} }
expected_type_name := c.table.type_to_str(ret_type.clear_flag(.optional).clear_flag(.result)) expected_type_name := c.table.type_to_str(ret_type.clear_flag(.option).clear_flag(.result))
c.error('`or` block must provide a default value of type `${expected_type_name}`, or return/continue/break or call a [noreturn] function like panic(err) or exit(1)', c.error('`or` block must provide a default value of type `${expected_type_name}`, or return/continue/break or call a [noreturn] function like panic(err) or exit(1)',
stmt.expr.pos()) stmt.expr.pos())
} else { } else {
@ -1080,7 +1080,7 @@ fn (mut c Checker) check_or_last_stmt(stmt ast.Stmt, ret_type ast.Type, expr_ret
return return
} }
type_name := c.table.type_to_str(last_stmt_typ) type_name := c.table.type_to_str(last_stmt_typ)
expected_type_name := c.table.type_to_str(ret_type.clear_flag(.optional).clear_flag(.result)) expected_type_name := c.table.type_to_str(ret_type.clear_flag(.option).clear_flag(.result))
c.error('wrong return type `${type_name}` in the `or {}` block, expected `${expected_type_name}`', c.error('wrong return type `${type_name}` in the `or {}` block, expected `${expected_type_name}`',
stmt.expr.pos()) stmt.expr.pos())
} }
@ -1094,7 +1094,7 @@ fn (mut c Checker) check_or_last_stmt(stmt ast.Stmt, ret_type ast.Type, expr_ret
} }
ast.Return {} ast.Return {}
else { else {
expected_type_name := c.table.type_to_str(ret_type.clear_flag(.optional).clear_flag(.result)) expected_type_name := c.table.type_to_str(ret_type.clear_flag(.option).clear_flag(.result))
c.error('last statement in the `or {}` block should be an expression of type `${expected_type_name}` or exit parent scope', c.error('last statement in the `or {}` block should be an expression of type `${expected_type_name}` or exit parent scope',
stmt.pos) stmt.pos)
} }
@ -1219,8 +1219,8 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
} }
node.expr_type = typ node.expr_type = typ
if !(node.expr is ast.Ident && (node.expr as ast.Ident).kind == .constant) { if !(node.expr is ast.Ident && (node.expr as ast.Ident).kind == .constant) {
if node.expr_type.has_flag(.optional) { if node.expr_type.has_flag(.option) {
c.error('cannot access fields of an optional, handle the error with `or {...}` or propagate it with `?`', c.error('cannot access fields of an option, handle the error with `or {...}` or propagate it with `?`',
node.pos) node.pos)
} else if node.expr_type.has_flag(.result) { } else if node.expr_type.has_flag(.result) {
c.error('cannot access fields of a result, handle the error with `or {...}` or propagate it with `!`', c.error('cannot access fields of a result, handle the error with `or {...}` or propagate it with `!`',
@ -1337,7 +1337,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
} }
node.typ = field.typ node.typ = field.typ
if node.or_block.kind == .block { if node.or_block.kind == .block {
c.expected_or_type = node.typ.clear_flag(.optional).clear_flag(.result) c.expected_or_type = node.typ.clear_flag(.option).clear_flag(.result)
c.stmts_ending_with_expression(node.or_block.stmts) c.stmts_ending_with_expression(node.or_block.stmts)
c.expected_or_type = ast.void_type c.expected_or_type = ast.void_type
} }
@ -2338,25 +2338,25 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
mut ret_type := c.call_expr(mut node) mut ret_type := c.call_expr(mut node)
if ret_type != 0 && c.table.sym(ret_type).kind == .alias { if ret_type != 0 && c.table.sym(ret_type).kind == .alias {
unaliased_type := c.table.unaliased_type(ret_type) unaliased_type := c.table.unaliased_type(ret_type)
if unaliased_type.has_flag(.optional) || unaliased_type.has_flag(.result) { if unaliased_type.has_flag(.option) || unaliased_type.has_flag(.result) {
ret_type = unaliased_type ret_type = unaliased_type
} }
} }
if !ret_type.has_flag(.optional) && !ret_type.has_flag(.result) { if !ret_type.has_flag(.option) && !ret_type.has_flag(.result) {
if node.or_block.kind == .block { if node.or_block.kind == .block {
c.error('unexpected `or` block, the function `${node.name}` does neither return an optional nor a result', c.error('unexpected `or` block, the function `${node.name}` does not return an option or a result',
node.or_block.pos) node.or_block.pos)
} else if node.or_block.kind == .propagate_option { } else if node.or_block.kind == .propagate_option {
c.error('unexpected `?`, the function `${node.name}` does neither return an optional nor a result', c.error('unexpected `?`, the function `${node.name}` does not return an option or a result',
node.or_block.pos) node.or_block.pos)
} else if node.or_block.kind == .propagate_result { } else if node.or_block.kind == .propagate_result {
c.error('unexpected `!`, the function `${node.name}` does neither return an optional nor a result', c.error('unexpected `!`, the function `${node.name}` does not return an option or a result',
node.or_block.pos) node.or_block.pos)
} }
} }
if node.or_block.kind != .absent { if node.or_block.kind != .absent {
if ret_type.has_flag(.optional) { if ret_type.has_flag(.option) {
ret_type = ret_type.clear_flag(.optional) ret_type = ret_type.clear_flag(.option)
} }
if ret_type.has_flag(.result) { if ret_type.has_flag(.result) {
ret_type = ret_type.clear_flag(.result) ret_type = ret_type.clear_flag(.result)
@ -2401,7 +2401,7 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
unwrapped_expr_type := c.unwrap_generic(node.expr_type) unwrapped_expr_type := c.unwrap_generic(node.expr_type)
tsym := c.table.sym(unwrapped_expr_type) tsym := c.table.sym(unwrapped_expr_type)
c.table.dumps[int(unwrapped_expr_type.clear_flag(.optional).clear_flag(.result))] = tsym.cname c.table.dumps[int(unwrapped_expr_type.clear_flag(.option).clear_flag(.result))] = tsym.cname
node.cname = tsym.cname node.cname = tsym.cname
return node.expr_type return node.expr_type
} }
@ -2425,18 +2425,18 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
c.inside_if_guard = true c.inside_if_guard = true
node.expr_type = c.expr(node.expr) node.expr_type = c.expr(node.expr)
c.inside_if_guard = old_inside_if_guard c.inside_if_guard = old_inside_if_guard
if !node.expr_type.has_flag(.optional) && !node.expr_type.has_flag(.result) { if !node.expr_type.has_flag(.option) && !node.expr_type.has_flag(.result) {
mut no_opt_or_res := true mut no_opt_or_res := true
match mut node.expr { match mut node.expr {
ast.IndexExpr { ast.IndexExpr {
no_opt_or_res = false no_opt_or_res = false
node.expr_type = node.expr_type.set_flag(.optional) node.expr_type = node.expr_type.set_flag(.option)
node.expr.is_option = true node.expr.is_option = true
} }
ast.PrefixExpr { ast.PrefixExpr {
if node.expr.op == .arrow { if node.expr.op == .arrow {
no_opt_or_res = false no_opt_or_res = false
node.expr_type = node.expr_type.set_flag(.optional) node.expr_type = node.expr_type.set_flag(.option)
node.expr.is_option = true node.expr.is_option = true
} }
} }
@ -2519,21 +2519,21 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
return ret_type return ret_type
} }
if !ret_type.has_flag(.optional) && !ret_type.has_flag(.result) { if !ret_type.has_flag(.option) && !ret_type.has_flag(.result) {
if node.or_block.kind == .block { if node.or_block.kind == .block {
c.error('unexpected `or` block, the field `${node.field_name}` is neither an optional, nor a result', c.error('unexpected `or` block, the field `${node.field_name}` is neither an option, nor a result',
node.or_block.pos) node.or_block.pos)
} else if node.or_block.kind == .propagate_option { } else if node.or_block.kind == .propagate_option {
c.error('unexpected `?`, the field `${node.field_name}` is neither an optional, nor a result', c.error('unexpected `?`, the field `${node.field_name}` is neither an option, nor a result',
node.or_block.pos) node.or_block.pos)
} else if node.or_block.kind == .propagate_result { } else if node.or_block.kind == .propagate_result {
c.error('unexpected `!`, the field `${node.field_name}` is neither an optional, nor a result', c.error('unexpected `!`, the field `${node.field_name}` is neither an option, nor a result',
node.or_block.pos) node.or_block.pos)
} }
} }
if node.or_block.kind != .absent { if node.or_block.kind != .absent {
if ret_type.has_flag(.optional) { if ret_type.has_flag(.option) {
ret_type = ret_type.clear_flag(.optional) ret_type = ret_type.clear_flag(.option)
} }
if ret_type.has_flag(.result) { if ret_type.has_flag(.result) {
ret_type = ret_type.clear_flag(.result) ret_type = ret_type.clear_flag(.result)
@ -2641,8 +2641,8 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
mut to_sym := c.table.sym(to_type) // type to be used as cast mut to_sym := c.table.sym(to_type) // type to be used as cast
mut final_to_sym := c.table.final_sym(to_type) mut final_to_sym := c.table.final_sym(to_type)
if to_type.has_flag(.optional) { if to_type.has_flag(.option) {
c.error('casting to optional type is forbidden', node.pos) c.error('casting to option type is forbidden', node.pos)
} else if to_type.has_flag(.result) { } else if to_type.has_flag(.result) {
c.error('casting to result type is forbidden', node.pos) c.error('casting to result type is forbidden', node.pos)
} }
@ -2674,7 +2674,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
node.expr_type = c.promote_num(node.expr_type, xx) node.expr_type = c.promote_num(node.expr_type, xx)
from_type = node.expr_type from_type = node.expr_type
} }
if !c.table.sumtype_has_variant(to_type, from_type, false) && !to_type.has_flag(.optional) if !c.table.sumtype_has_variant(to_type, from_type, false) && !to_type.has_flag(.option)
&& !to_type.has_flag(.result) { && !to_type.has_flag(.result) {
ft := c.table.type_to_str(from_type) ft := c.table.type_to_str(from_type)
tt := c.table.type_to_str(to_type) tt := c.table.type_to_str(to_type)
@ -2736,8 +2736,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
} else if to_type == ast.bool_type && from_type != ast.bool_type && !c.inside_unsafe } else if to_type == ast.bool_type && from_type != ast.bool_type && !c.inside_unsafe
&& !c.pref.translated && !c.file.is_translated { && !c.pref.translated && !c.file.is_translated {
c.error('cannot cast to bool - use e.g. `some_int != 0` instead', node.pos) c.error('cannot cast to bool - use e.g. `some_int != 0` instead', node.pos)
} else if from_type == ast.none_type && !to_type.has_flag(.optional) } else if from_type == ast.none_type && !to_type.has_flag(.option) && !to_type.has_flag(.result) {
&& !to_type.has_flag(.result) {
type_name := c.table.type_to_str(to_type) type_name := c.table.type_to_str(to_type)
c.error('cannot cast `none` to `${type_name}`', node.pos) c.error('cannot cast `none` to `${type_name}`', node.pos)
} else if from_sym.kind == .struct_ && !from_type.is_ptr() { } else if from_sym.kind == .struct_ && !from_type.is_ptr() {
@ -2751,11 +2750,11 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
ft := c.table.type_to_str(from_type) ft := c.table.type_to_str(from_type)
tt := c.table.type_to_str(to_type) tt := c.table.type_to_str(to_type)
c.error('cannot cast type `${ft}` to `${tt}`', node.pos) c.error('cannot cast type `${ft}` to `${tt}`', node.pos)
} else if from_type.has_flag(.optional) || from_type.has_flag(.result) } else if from_type.has_flag(.option) || from_type.has_flag(.result)
|| from_type.has_flag(.variadic) { || from_type.has_flag(.variadic) {
// variadic case can happen when arrays are converted into variadic // variadic case can happen when arrays are converted into variadic
msg := if from_type.has_flag(.optional) { msg := if from_type.has_flag(.option) {
'an optional' 'an option'
} else if from_type.has_flag(.result) { } else if from_type.has_flag(.result) {
'a result' 'a result'
} else { } else {
@ -3083,7 +3082,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
} }
} }
if mut obj.expr is ast.IfGuardExpr { if mut obj.expr is ast.IfGuardExpr {
// new variable from if guard shouldn't have the optional flag for further use // new variable from if guard shouldn't have the option flag for further use
// a temp variable will be generated which unwraps it // a temp variable will be generated which unwraps it
sym := c.table.sym(obj.expr.expr_type) sym := c.table.sym(obj.expr.expr_type)
if sym.kind == .multi_return { if sym.kind == .multi_return {
@ -3096,7 +3095,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
} }
} }
} else { } else {
typ = obj.expr.expr_type.clear_flag(.optional).clear_flag(.result) typ = obj.expr.expr_type.clear_flag(.option).clear_flag(.result)
} }
} else if obj.expr is ast.EmptyExpr { } else if obj.expr is ast.EmptyExpr {
c.error('invalid variable `${node.name}`', node.pos) c.error('invalid variable `${node.name}`', node.pos)
@ -3105,19 +3104,19 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
typ = c.expr(obj.expr) typ = c.expr(obj.expr)
} }
} }
is_optional := typ.has_flag(.optional) || typ.has_flag(.result) is_option := typ.has_flag(.option) || typ.has_flag(.result)
node.kind = .variable node.kind = .variable
node.info = ast.IdentVar{ node.info = ast.IdentVar{
typ: typ typ: typ
is_optional: is_optional is_option: is_option
} }
if !is_sum_type_cast { if !is_sum_type_cast {
obj.typ = typ obj.typ = typ
} }
node.obj = obj node.obj = obj
// unwrap optional (`println(x)`) // unwrap option (`println(x)`)
if is_optional { if is_option {
return typ.clear_flag(.optional).clear_flag(.result) return typ.clear_flag(.option).clear_flag(.result)
} }
return typ return typ
} }
@ -3158,7 +3157,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
if mut obj.expr is ast.CallExpr { if mut obj.expr is ast.CallExpr {
if obj.expr.or_block.kind != .absent { if obj.expr.or_block.kind != .absent {
typ = typ.clear_flag(.optional).clear_flag(.result) typ = typ.clear_flag(.option).clear_flag(.result)
} }
} }
} }
@ -3613,8 +3612,8 @@ fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type {
node.pos.extend(node.right.pos)) node.pos.extend(node.right.pos))
} }
if node.right.typ.has_flag(.optional) { if node.right.typ.has_flag(.option) {
c.error('cannot take the address of an optional field', node.pos.extend(node.right.pos)) c.error('cannot take the address of an option field', node.pos.extend(node.right.pos))
} }
} }
} }
@ -3742,13 +3741,13 @@ fn (mut c Checker) check_index(typ_sym &ast.TypeSymbol, index ast.Expr, index_ty
} }
} }
} }
if index_type.has_flag(.optional) || index_type.has_flag(.result) { if index_type.has_flag(.option) || index_type.has_flag(.result) {
type_str := if typ_sym.kind == .string { type_str := if typ_sym.kind == .string {
'(type `${typ_sym.name}`)' '(type `${typ_sym.name}`)'
} else { } else {
'(array type `${typ_sym.name}`)' '(array type `${typ_sym.name}`)'
} }
c.error('cannot use optional or result as index ${type_str}', pos) c.error('cannot use option or result as index ${type_str}', pos)
} }
} }
} }
@ -3789,10 +3788,11 @@ fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type {
&& typ !in [ast.byteptr_type, ast.charptr_type] && !typ.has_flag(.variadic) { && typ !in [ast.byteptr_type, ast.charptr_type] && !typ.has_flag(.variadic) {
c.error('type `${typ_sym.name}` does not support indexing', node.pos) c.error('type `${typ_sym.name}` does not support indexing', node.pos)
} }
if typ.has_flag(.optional) { if typ.has_flag(.option) {
c.error('type `?${typ_sym.name}` is optional, it does not support indexing', node.left.pos()) c.error('type `?${typ_sym.name}` is an option, it does not support indexing',
node.left.pos())
} else if typ.has_flag(.result) { } else if typ.has_flag(.result) {
c.error('type `!${typ_sym.name}` is result, it does not support indexing', node.left.pos()) c.error('type `!${typ_sym.name}` is a result, it does not support indexing', node.left.pos())
} }
if typ_sym.kind == .string && !typ.is_ptr() && node.is_setter { if typ_sym.kind == .string && !typ.is_ptr() && node.is_setter {
c.error('cannot assign to s[i] since V strings are immutable\n' + c.error('cannot assign to s[i] since V strings are immutable\n' +
@ -4004,7 +4004,7 @@ fn (mut c Checker) add_error_detail_with_pos(msg string, pos token.Pos) {
c.add_error_detail(util.formatted_error('details:', msg, c.file.path, pos)) c.add_error_detail(util.formatted_error('details:', msg, c.file.path, pos))
} }
fn (mut c Checker) add_instruction_for_optional_type() { fn (mut c Checker) add_instruction_for_option_type() {
c.add_error_detail_with_pos('prepend ? before the declaration of the return type of `${c.table.cur_fn.name}`', c.add_error_detail_with_pos('prepend ? before the declaration of the return type of `${c.table.cur_fn.name}`',
c.table.cur_fn.return_type_pos) c.table.cur_fn.return_type_pos)
} }

View file

@ -188,7 +188,7 @@ fn (mut c Checker) comptime_for(node ast.ComptimeFor) {
unwrapped_expr_type := c.unwrap_generic(field.typ) unwrapped_expr_type := c.unwrap_generic(field.typ)
tsym := c.table.sym(unwrapped_expr_type) tsym := c.table.sym(unwrapped_expr_type)
c.table.dumps[int(unwrapped_expr_type.clear_flag(.optional).clear_flag(.result).clear_flag(.atomic_f))] = tsym.cname c.table.dumps[int(unwrapped_expr_type.clear_flag(.option).clear_flag(.result).clear_flag(.atomic_f))] = tsym.cname
} }
c.comptime_for_field_var = '' c.comptime_for_field_var = ''
c.inside_comptime_for_field = false c.inside_comptime_for_field = false
@ -445,7 +445,7 @@ fn (mut c Checker) evaluate_once_comptime_if_attribute(mut node ast.Attr) bool {
if node.ct_expr is ast.Ident { if node.ct_expr is ast.Ident {
if node.ct_opt { if node.ct_opt {
if node.ct_expr.name in constants.valid_comptime_not_user_defined { if node.ct_expr.name in constants.valid_comptime_not_user_defined {
c.error('optional `[if expression ?]` tags, can be used only for user defined identifiers', c.error('option `[if expression ?]` tags, can be used only for user defined identifiers',
node.pos) node.pos)
node.ct_skip = true node.ct_skip = true
} else { } else {
@ -765,7 +765,7 @@ fn (mut c Checker) check_comptime_is_field_selector(node ast.SelectorExpr) bool
[inline] [inline]
fn (mut c Checker) check_comptime_is_field_selector_bool(node ast.SelectorExpr) bool { fn (mut c Checker) check_comptime_is_field_selector_bool(node ast.SelectorExpr) bool {
if c.check_comptime_is_field_selector(node) { if c.check_comptime_is_field_selector(node) {
return node.field_name in ['is_mut', 'is_pub', 'is_shared', 'is_atomic', 'is_optional', return node.field_name in ['is_mut', 'is_pub', 'is_shared', 'is_atomic', 'is_option',
'is_array', 'is_map', 'is_chan', 'is_struct', 'is_alias'] 'is_array', 'is_map', 'is_chan', 'is_struct', 'is_alias']
} }
return false return false
@ -781,7 +781,7 @@ fn (mut c Checker) get_comptime_selector_bool_field(field_name string) bool {
'is_mut' { return field.is_mut } 'is_mut' { return field.is_mut }
'is_shared' { return field_typ.has_flag(.shared_f) } 'is_shared' { return field_typ.has_flag(.shared_f) }
'is_atomic' { return field_typ.has_flag(.atomic_f) } 'is_atomic' { return field_typ.has_flag(.atomic_f) }
'is_optional' { return field.typ.has_flag(.optional) } 'is_option' { return field.typ.has_flag(.option) }
'is_array' { return field_sym.kind in [.array, .array_fixed] } 'is_array' { return field_sym.kind in [.array, .array_fixed] }
'is_map' { return field_sym.kind == .map } 'is_map' { return field_sym.kind == .map }
'is_chan' { return field_sym.kind == .chan } 'is_chan' { return field_sym.kind == .chan }

View file

@ -116,12 +116,12 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
// } // }
array_info := type_sym.array_info() array_info := type_sym.array_info()
node.elem_type = array_info.elem_type node.elem_type = array_info.elem_type
// clear optional flag incase of: `fn opt_arr() ?[]int { return [] }` // clear option flag incase of: `fn opt_arr() ?[]int { return [] }`
return if c.expected_type.has_flag(.shared_f) { return if c.expected_type.has_flag(.shared_f) {
c.expected_type.clear_flag(.shared_f).deref() c.expected_type.clear_flag(.shared_f).deref()
} else { } else {
c.expected_type c.expected_type
}.clear_flag(.optional).clear_flag(.result) }.clear_flag(.option).clear_flag(.result)
} }
// [1,2,3] // [1,2,3]
if node.exprs.len > 0 && node.elem_type == ast.void_type { if node.exprs.len > 0 && node.elem_type == ast.void_type {
@ -282,7 +282,7 @@ fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
sym := c.table.sym(c.expected_type) sym := c.table.sym(c.expected_type)
if sym.kind == .map { if sym.kind == .map {
info := sym.map_info() info := sym.map_info()
node.typ = c.expected_type.clear_flag(.optional).clear_flag(.result) node.typ = c.expected_type.clear_flag(.option).clear_flag(.result)
node.key_type = info.key_type node.key_type = info.key_type
node.value_type = info.value_type node.value_type = info.value_type
return node.typ return node.typ

View file

@ -117,7 +117,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
if multi_type == ast.error_type { if multi_type == ast.error_type {
c.error('type `IError` cannot be used in multi-return, return an option instead', c.error('type `IError` cannot be used in multi-return, return an option instead',
node.return_type_pos) node.return_type_pos)
} else if multi_type.has_flag(.optional) { } else if multi_type.has_flag(.option) {
c.error('option cannot be used in multi-return, return an option instead', c.error('option cannot be used in multi-return, return an option instead',
node.return_type_pos) node.return_type_pos)
} else if multi_type.has_flag(.result) { } else if multi_type.has_flag(.result) {
@ -211,9 +211,8 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
c.error('invalid use of reserved type `${param.name}` as a parameter name', c.error('invalid use of reserved type `${param.name}` as a parameter name',
param.pos) param.pos)
} }
if param.typ.has_flag(.optional) || param.typ.has_flag(.result) { if param.typ.has_flag(.option) || param.typ.has_flag(.result) {
c.error('optional or result type argument is not supported currently', c.error('option or result type argument is not supported currently', param.type_pos)
param.type_pos)
} }
arg_typ_sym := c.table.sym(param.typ) arg_typ_sym := c.table.sym(param.typ)
if arg_typ_sym.info is ast.Struct { if arg_typ_sym.info is ast.Struct {
@ -333,7 +332,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
} }
if node.return_type != ast.void_type_idx if node.return_type != ast.void_type_idx
&& node.return_type.clear_flag(.optional) != ast.void_type_idx && node.return_type.clear_flag(.option) != ast.void_type_idx
&& node.return_type.clear_flag(.result) != ast.void_type_idx { && node.return_type.clear_flag(.result) != ast.void_type_idx {
c.error('test functions should either return nothing at all, or be marked to return `?` or `!`', c.error('test functions should either return nothing at all, or be marked to return `?` or `!`',
node.pos) node.pos)
@ -343,7 +342,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
c.table.cur_fn = unsafe { node } c.table.cur_fn = unsafe { node }
// c.table.cur_fn = node // c.table.cur_fn = node
// Add return if `fn(...) ? {...}` have no return at end // Add return if `fn(...) ? {...}` have no return at end
if node.return_type != ast.void_type && node.return_type.has_flag(.optional) if node.return_type != ast.void_type && node.return_type.has_flag(.option)
&& (node.stmts.len == 0 || node.stmts.last() !is ast.Return) { && (node.stmts.len == 0 || node.stmts.last() !is ast.Return) {
sym := c.table.sym(node.return_type) sym := c.table.sym(node.return_type)
if sym.kind == .void { if sym.kind == .void {
@ -476,7 +475,7 @@ fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type {
c.inside_fn_arg = old_inside_fn_arg c.inside_fn_arg = old_inside_fn_arg
// autofree: mark args that have to be freed (after saving them in tmp exprs) // autofree: mark args that have to be freed (after saving them in tmp exprs)
free_tmp_arg_vars := c.pref.autofree && !c.is_builtin_mod && node.args.len > 0 free_tmp_arg_vars := c.pref.autofree && !c.is_builtin_mod && node.args.len > 0
&& !node.args[0].typ.has_flag(.optional) && !node.args[0].typ.has_flag(.result) && !node.args[0].typ.has_flag(.option) && !node.args[0].typ.has_flag(.result)
if free_tmp_arg_vars && !c.inside_const { if free_tmp_arg_vars && !c.inside_const {
for i, arg in node.args { for i, arg in node.args {
if arg.typ != ast.string_type { if arg.typ != ast.string_type {
@ -497,7 +496,7 @@ fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type {
node.free_receiver = true node.free_receiver = true
} }
} }
c.expected_or_type = node.return_type.clear_flag(.optional).clear_flag(.result) c.expected_or_type = node.return_type.clear_flag(.option).clear_flag(.result)
c.stmts_ending_with_expression(node.or_block.stmts) c.stmts_ending_with_expression(node.or_block.stmts)
c.expected_or_type = ast.void_type c.expected_or_type = ast.void_type
@ -505,15 +504,14 @@ fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type {
&& !c.table.cur_fn.is_test { && !c.table.cur_fn.is_test {
// TODO: use just `if node.or_block.kind == .propagate_result && !c.table.cur_fn.return_type.has_flag(.result) {` after the deprecation for ?!Type // TODO: use just `if node.or_block.kind == .propagate_result && !c.table.cur_fn.return_type.has_flag(.result) {` after the deprecation for ?!Type
if node.or_block.kind == .propagate_result && !c.table.cur_fn.return_type.has_flag(.result) if node.or_block.kind == .propagate_result && !c.table.cur_fn.return_type.has_flag(.result)
&& !c.table.cur_fn.return_type.has_flag(.optional) { && !c.table.cur_fn.return_type.has_flag(.option) {
c.add_instruction_for_result_type() c.add_instruction_for_result_type()
c.error('to propagate the result call, `${c.table.cur_fn.name}` must return a result', c.error('to propagate the result call, `${c.table.cur_fn.name}` must return a result',
node.or_block.pos) node.or_block.pos)
} }
if node.or_block.kind == .propagate_option if node.or_block.kind == .propagate_option && !c.table.cur_fn.return_type.has_flag(.option) {
&& !c.table.cur_fn.return_type.has_flag(.optional) { c.add_instruction_for_option_type()
c.add_instruction_for_optional_type() c.error('to propagate the option call, `${c.table.cur_fn.name}` must return an option',
c.error('to propagate the optional call, `${c.table.cur_fn.name}` must return an optional',
node.or_block.pos) node.or_block.pos)
} }
} }
@ -611,7 +609,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
match tsym.info { match tsym.info {
ast.Struct { ast.Struct {
mut ret_type := tsym.info.concrete_types[0] mut ret_type := tsym.info.concrete_types[0]
ret_type = ret_type.set_flag(.optional) ret_type = ret_type.set_flag(.option)
node.return_type = ret_type node.return_type = ret_type
return ret_type return ret_type
} }
@ -1328,8 +1326,8 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
} else { } else {
'unknown method or field: `${left_sym.name}.${method_name}`' 'unknown method or field: `${left_sym.name}.${method_name}`'
} }
if left_type.has_flag(.optional) { if left_type.has_flag(.option) {
c.error('optional type cannot be called directly', node.left.pos()) c.error('option type cannot be called directly', node.left.pos())
return ast.void_type return ast.void_type
} else if left_type.has_flag(.result) { } else if left_type.has_flag(.result) {
c.error('result type cannot be called directly', node.left.pos()) c.error('result type cannot be called directly', node.left.pos())
@ -1401,7 +1399,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
c.table.cur_fn.has_await = true c.table.cur_fn.has_await = true
} }
node.return_type = info.concrete_types[0] node.return_type = info.concrete_types[0]
node.return_type.set_flag(.optional) node.return_type.set_flag(.option)
return node.return_type return node.return_type
} else if left_sym.kind == .thread && method_name == 'wait' { } else if left_sym.kind == .thread && method_name == 'wait' {
info := left_sym.info as ast.Thread info := left_sym.info as ast.Thread
@ -1960,7 +1958,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
fn (mut c Checker) go_expr(mut node ast.GoExpr) ast.Type { fn (mut c Checker) go_expr(mut node ast.GoExpr) ast.Type {
ret_type := c.call_expr(mut node.call_expr) ret_type := c.call_expr(mut node.call_expr)
if node.call_expr.or_block.kind != .absent { if node.call_expr.or_block.kind != .absent {
c.error('optional handling cannot be done in `go` call. Do it when calling `.wait()`', c.error('option handling cannot be done in `go` call. Do it when calling `.wait()`',
node.call_expr.or_block.pos) node.call_expr.or_block.pos)
} }
// Make sure there are no mutable arguments // Make sure there are no mutable arguments
@ -2072,8 +2070,8 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, node ast
arg_expr := node.args[0].expr arg_expr := node.args[0].expr
match arg_expr { match arg_expr {
ast.AnonFn { ast.AnonFn {
if arg_expr.decl.return_type.has_flag(.optional) { if arg_expr.decl.return_type.has_flag(.option) {
c.error('optional needs to be unwrapped before using it in map/filter', c.error('option needs to be unwrapped before using it in map/filter',
node.args[0].pos) node.args[0].pos)
} }
if arg_expr.decl.params.len > 1 { if arg_expr.decl.params.len > 1 {
@ -2094,8 +2092,8 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, node ast
c.error('${arg_expr.name} does not exist', arg_expr.pos) c.error('${arg_expr.name} does not exist', arg_expr.pos)
return return
} }
if func.return_type.has_flag(.optional) { if func.return_type.has_flag(.option) {
c.error('optional needs to be unwrapped before using it in map/filter', c.error('option needs to be unwrapped before using it in map/filter',
node.pos) node.pos)
} }
if func.params.len > 1 { if func.params.len > 1 {
@ -2114,8 +2112,8 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, node ast
expr := arg_expr.obj.expr expr := arg_expr.obj.expr
if expr is ast.AnonFn { if expr is ast.AnonFn {
// copied from above // copied from above
if expr.decl.return_type.has_flag(.optional) { if expr.decl.return_type.has_flag(.option) {
c.error('optional needs to be unwrapped before using it in map/filter', c.error('option needs to be unwrapped before using it in map/filter',
arg_expr.pos) arg_expr.pos)
} }
if expr.decl.params.len > 1 { if expr.decl.params.len > 1 {
@ -2145,9 +2143,9 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, node ast
c.error('type mismatch, `${arg_expr.name}` does not return anything', c.error('type mismatch, `${arg_expr.name}` does not return anything',
arg_expr.pos) arg_expr.pos)
} else if !is_map && arg_expr.return_type != ast.bool_type { } else if !is_map && arg_expr.return_type != ast.bool_type {
if arg_expr.or_block.kind != .absent && (arg_expr.return_type.has_flag(.optional) if arg_expr.or_block.kind != .absent && (arg_expr.return_type.has_flag(.option)
|| arg_expr.return_type.has_flag(.result)) || arg_expr.return_type.has_flag(.result))
&& arg_expr.return_type.clear_flag(.optional).clear_flag(.result) == ast.bool_type { && arg_expr.return_type.clear_flag(.option).clear_flag(.result) == ast.bool_type {
return return
} }
c.error('type mismatch, `${arg_expr.name}` must return a bool', arg_expr.pos) c.error('type mismatch, `${arg_expr.name}` must return a bool', arg_expr.pos)
@ -2283,8 +2281,8 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as
c.error('`.wait()` does not have any arguments', node.args[0].pos) c.error('`.wait()` does not have any arguments', node.args[0].pos)
} }
thread_ret_type := elem_sym.thread_info().return_type thread_ret_type := elem_sym.thread_info().return_type
if thread_ret_type.has_flag(.optional) { if thread_ret_type.has_flag(.option) {
c.error('`.wait()` cannot be called for an array when thread functions return optionals. Iterate over the arrays elements instead and handle each returned optional with `or`.', c.error('`.wait()` cannot be called for an array when thread functions return options. Iterate over the arrays elements instead and handle each returned option with `or`.',
node.pos) node.pos)
} else if thread_ret_type.has_flag(.result) { } else if thread_ret_type.has_flag(.result) {
c.error('`.wait()` cannot be called for an array when thread functions return results. Iterate over the arrays elements instead and handle each returned result with `or`.', c.error('`.wait()` cannot be called for an array when thread functions return results. Iterate over the arrays elements instead and handle each returned result with `or`.',

View file

@ -17,7 +17,7 @@ fn (mut c Checker) for_c_stmt(node ast.ForCStmt) {
for right in node.inc.right { for right in node.inc.right {
if right is ast.CallExpr { if right is ast.CallExpr {
if right.or_block.stmts.len > 0 { if right.or_block.stmts.len > 0 {
c.error('optionals are not allowed in `for statement increment` (yet)', c.error('options are not allowed in `for statement increment` (yet)',
right.pos) right.pos)
} }
} }
@ -98,8 +98,8 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
c.error('a struct must have a `next()` method to be an iterator', node.cond.pos()) c.error('a struct must have a `next()` method to be an iterator', node.cond.pos())
return return
} }
if !next_fn.return_type.has_flag(.optional) { if !next_fn.return_type.has_flag(.option) {
c.error('iterator method `next()` must return an optional', node.cond.pos()) c.error('iterator method `next()` must return an option', node.cond.pos())
} }
return_sym := c.table.sym(next_fn.return_type) return_sym := c.table.sym(next_fn.return_type)
if return_sym.kind == .multi_return { if return_sym.kind == .multi_return {
@ -109,7 +109,7 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
if next_fn.params.len != 1 { if next_fn.params.len != 1 {
c.error('iterator method `next()` must have 0 parameters', node.cond.pos()) c.error('iterator method `next()` must have 0 parameters', node.cond.pos())
} }
mut val_type := next_fn.return_type.clear_flag(.optional).clear_flag(.result) mut val_type := next_fn.return_type.clear_flag(.option).clear_flag(.result)
if node.val_is_mut { if node.val_is_mut {
val_type = val_type.ref() val_type = val_type.ref()
} }

View file

@ -47,7 +47,7 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
// check condition type is boolean // check condition type is boolean
c.expected_type = ast.bool_type c.expected_type = ast.bool_type
cond_typ := c.unwrap_generic(c.expr(branch.cond)) cond_typ := c.unwrap_generic(c.expr(branch.cond))
if (cond_typ.idx() != ast.bool_type_idx || cond_typ.has_flag(.optional) if (cond_typ.idx() != ast.bool_type_idx || cond_typ.has_flag(.option)
|| cond_typ.has_flag(.result)) && !c.pref.translated && !c.file.is_translated { || cond_typ.has_flag(.result)) && !c.pref.translated && !c.file.is_translated {
c.error('non-bool type `${c.table.type_to_str(cond_typ)}` used as if condition', c.error('non-bool type `${c.table.type_to_str(cond_typ)}` used as if condition',
branch.cond.pos()) branch.cond.pos())
@ -202,7 +202,7 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
node.is_expr = true node.is_expr = true
node.typ = c.expected_type node.typ = c.expected_type
} }
if c.expected_type.has_flag(.optional) || c.expected_type.has_flag(.result) { if c.expected_type.has_flag(.option) || c.expected_type.has_flag(.result) {
if node.typ == ast.void_type { if node.typ == ast.void_type {
node.is_expr = true node.is_expr = true
node.typ = c.expected_type node.typ = c.expected_type

View file

@ -330,7 +330,7 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
left_name := c.table.type_to_str(unwrapped_left_type) left_name := c.table.type_to_str(unwrapped_left_type)
right_name := c.table.type_to_str(unwrapped_right_type) right_name := c.table.type_to_str(unwrapped_right_type)
c.error('mismatched types `${left_name}` and `${right_name}`', left_right_pos) c.error('mismatched types `${left_name}` and `${right_name}`', left_right_pos)
} else if promoted_type.has_flag(.optional) || promoted_type.has_flag(.result) { } else if promoted_type.has_flag(.option) || promoted_type.has_flag(.result) {
s := c.table.type_to_str(promoted_type) s := c.table.type_to_str(promoted_type)
c.error('`${node.op}` cannot be used with `${s}`', node.pos) c.error('`${node.op}` cannot be used with `${s}`', node.pos)
} else if promoted_type.is_float() { } else if promoted_type.is_float() {
@ -429,9 +429,9 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
} }
} }
} }
} else if left_type.has_flag(.optional) || right_type.has_flag(.optional) { } else if left_type.has_flag(.option) || right_type.has_flag(.option) {
opt_comp_pos := if left_type.has_flag(.optional) { left_pos } else { right_pos } opt_comp_pos := if left_type.has_flag(.option) { left_pos } else { right_pos }
c.error('unwrapped optional cannot be compared in an infix expression', c.error('unwrapped option cannot be compared in an infix expression',
opt_comp_pos) opt_comp_pos)
} }
} }
@ -652,11 +652,11 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
c.error('cannot use operator `${node.op}` with `${right_sym.name}`', node.pos) c.error('cannot use operator `${node.op}` with `${right_sym.name}`', node.pos)
} }
// TODO move this to symmetric_check? Right now it would break `return 0` for `fn()?int ` // TODO move this to symmetric_check? Right now it would break `return 0` for `fn()?int `
left_is_optional := left_type.has_flag(.optional) left_is_option := left_type.has_flag(.option)
right_is_optional := right_type.has_flag(.optional) right_is_option := right_type.has_flag(.option)
if left_is_optional || right_is_optional { if left_is_option || right_is_option {
opt_infix_pos := if left_is_optional { left_pos } else { right_pos } opt_infix_pos := if left_is_option { left_pos } else { right_pos }
c.error('unwrapped optional cannot be used in an infix expression', opt_infix_pos) c.error('unwrapped option cannot be used in an infix expression', opt_infix_pos)
} }
left_is_result := left_type.has_flag(.result) left_is_result := left_type.has_flag(.result)

View file

@ -268,8 +268,8 @@ fn (mut c Checker) resolve_generic_interface(typ ast.Type, interface_type ast.Ty
} }
} else if c.table.get_type_name(imethod.return_type) == gt_name { } else if c.table.get_type_name(imethod.return_type) == gt_name {
mut ret_typ := method.return_type mut ret_typ := method.return_type
if imethod.return_type.has_flag(.optional) { if imethod.return_type.has_flag(.option) {
ret_typ = ret_typ.clear_flag(.optional) ret_typ = ret_typ.clear_flag(.option)
} else if imethod.return_type.has_flag(.result) { } else if imethod.return_type.has_flag(.result) {
ret_typ = ret_typ.clear_flag(.result) ret_typ = ret_typ.clear_flag(.result)
} }

View file

@ -61,7 +61,7 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
expr_type := c.expr(stmt.expr) expr_type := c.expr(stmt.expr)
stmt.typ = expr_type stmt.typ = expr_type
if first_iteration { if first_iteration {
if node.is_expr && (node.expected_type.has_flag(.optional) if node.is_expr && (node.expected_type.has_flag(.option)
|| node.expected_type.has_flag(.result) || node.expected_type.has_flag(.result)
|| c.table.type_kind(node.expected_type) in [.sum_type, .multi_return]) { || c.table.type_kind(node.expected_type) in [.sum_type, .multi_return]) {
c.check_match_branch_last_stmt(stmt, node.expected_type, expr_type) c.check_match_branch_last_stmt(stmt, node.expected_type, expr_type)

View file

@ -14,7 +14,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
mut expected_type := c.unwrap_generic(c.expected_type) mut expected_type := c.unwrap_generic(c.expected_type)
if expected_type != 0 && c.table.sym(expected_type).kind == .alias { if expected_type != 0 && c.table.sym(expected_type).kind == .alias {
unaliased_type := c.table.unaliased_type(expected_type) unaliased_type := c.table.unaliased_type(expected_type)
if unaliased_type.has_flag(.optional) || unaliased_type.has_flag(.result) { if unaliased_type.has_flag(.option) || unaliased_type.has_flag(.result) {
expected_type = unaliased_type expected_type = unaliased_type
} }
} }
@ -32,7 +32,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
if node.exprs.len == 0 { if node.exprs.len == 0 {
return return
} }
exp_is_optional := expected_type.has_flag(.optional) exp_is_option := expected_type.has_flag(.option)
exp_is_result := expected_type.has_flag(.result) exp_is_result := expected_type.has_flag(.result)
mut expected_types := [expected_type] mut expected_types := [expected_type]
if expected_type_sym.info is ast.MultiReturn { if expected_type_sym.info is ast.MultiReturn {
@ -92,18 +92,18 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
} }
} }
} }
// allow `none` & `error` return types for function that returns optional // allow `none` & `error` return types for function that returns option
option_type_idx := c.table.type_idxs['_option'] option_type_idx := c.table.type_idxs['_option']
result_type_idx := c.table.type_idxs['_result'] result_type_idx := c.table.type_idxs['_result']
got_types_0_idx := got_types[0].idx() got_types_0_idx := got_types[0].idx()
if (exp_is_optional if (exp_is_option
&& got_types_0_idx in [ast.none_type_idx, ast.error_type_idx, option_type_idx]) && got_types_0_idx in [ast.none_type_idx, ast.error_type_idx, option_type_idx])
|| (exp_is_result && got_types_0_idx in [ast.error_type_idx, result_type_idx]) { || (exp_is_result && got_types_0_idx in [ast.error_type_idx, result_type_idx]) {
return return
} }
if expected_types.len > 0 && expected_types.len != got_types.len { if expected_types.len > 0 && expected_types.len != got_types.len {
// `fn foo() !(int, string) { return Err{} }` // `fn foo() !(int, string) { return Err{} }`
if (exp_is_optional || exp_is_result) && node.exprs.len == 1 { if (exp_is_option || exp_is_result) && node.exprs.len == 1 {
got_typ := c.expr(node.exprs[0]) got_typ := c.expr(node.exprs[0])
got_typ_sym := c.table.sym(got_typ) got_typ_sym := c.table.sym(got_typ)
if got_typ_sym.kind == .struct_ && c.type_implements(got_typ, ast.error_type, node.pos) { if got_typ_sym.kind == .struct_ && c.type_implements(got_typ, ast.error_type, node.pos) {
@ -126,7 +126,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
} }
for i, exp_type in expected_types { for i, exp_type in expected_types {
got_typ := c.unwrap_generic(got_types[i]) got_typ := c.unwrap_generic(got_types[i])
if got_typ.has_flag(.optional) && (!exp_type.has_flag(.optional) if got_typ.has_flag(.option) && (!exp_type.has_flag(.option)
|| c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) { || c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) {
pos := node.exprs[expr_idxs[i]].pos() pos := node.exprs[expr_idxs[i]].pos()
c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument', c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument',
@ -228,7 +228,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
} }
} }
} }
if exp_is_optional && node.exprs.len > 0 { if exp_is_option && node.exprs.len > 0 {
expr0 := node.exprs[0] expr0 := node.exprs[0]
if expr0 is ast.CallExpr { if expr0 is ast.CallExpr {
if expr0.or_block.kind == .propagate_option && node.exprs.len == 1 { if expr0.or_block.kind == .propagate_option && node.exprs.len == 1 {

View file

@ -7,7 +7,7 @@ import v.ast
import v.token import v.token
fn (mut c Checker) get_default_fmt(ftyp ast.Type, typ ast.Type) u8 { fn (mut c Checker) get_default_fmt(ftyp ast.Type, typ ast.Type) u8 {
if ftyp.has_flag(.optional) || ftyp.has_flag(.result) { if ftyp.has_flag(.option) || ftyp.has_flag(.result) {
return `s` return `s`
} else if typ.is_float() { } else if typ.is_float() {
return `g` return `g`
@ -32,7 +32,7 @@ fn (mut c Checker) get_default_fmt(ftyp ast.Type, typ ast.Type) u8 {
} }
if ftyp in [ast.string_type, ast.bool_type] if ftyp in [ast.string_type, ast.bool_type]
|| sym.kind in [.enum_, .array, .array_fixed, .struct_, .map, .multi_return, .sum_type, .interface_, .none_] || sym.kind in [.enum_, .array, .array_fixed, .struct_, .map, .multi_return, .sum_type, .interface_, .none_]
|| ftyp.has_flag(.optional) || ftyp.has_flag(.result) || sym.has_method('str') { || ftyp.has_flag(.option) || ftyp.has_flag(.result) || sym.has_method('str') {
return `s` return `s`
} else { } else {
return `_` return `_`

View file

@ -72,7 +72,7 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
for i, field in node.fields { for i, field in node.fields {
if field.typ.has_flag(.result) { if field.typ.has_flag(.result) {
c.error('struct field does not support storing result', field.optional_pos) c.error('struct field does not support storing result', field.option_pos)
} }
c.ensure_type_exists(field.typ, field.type_pos) or { return } c.ensure_type_exists(field.typ, field.type_pos) or { return }
c.ensure_generic_type_specify_type_names(field.typ, field.type_pos) or { return } c.ensure_generic_type_specify_type_names(field.typ, field.type_pos) or { return }
@ -119,7 +119,7 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
if field.has_default_expr { if field.has_default_expr {
c.expected_type = field.typ c.expected_type = field.typ
default_expr_type := c.expr(field.default_expr) default_expr_type := c.expr(field.default_expr)
if !field.typ.has_flag(.optional) && !field.typ.has_flag(.result) { if !field.typ.has_flag(.option) && !field.typ.has_flag(.result) {
c.check_expr_opt_call(field.default_expr, default_expr_type) c.check_expr_opt_call(field.default_expr, default_expr_type)
} }
struct_sym.info.fields[i].default_expr_typ = default_expr_type struct_sym.info.fields[i].default_expr_typ = default_expr_type
@ -463,7 +463,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
if expr_type == ast.void_type { if expr_type == ast.void_type {
c.error('`${field.expr}` (no value) used as value', field.pos) c.error('`${field.expr}` (no value) used as value', field.pos)
} }
if !field_info.typ.has_flag(.optional) && !field.typ.has_flag(.result) { if !field_info.typ.has_flag(.option) && !field.typ.has_flag(.result) {
expr_type = c.check_expr_opt_call(field.expr, expr_type) expr_type = c.check_expr_opt_call(field.expr, expr_type)
} }
expr_type_sym := c.table.sym(expr_type) expr_type_sym := c.table.sym(expr_type)

View file

@ -0,0 +1,6 @@
vlib/v/checker/tests/aliased_option_fn_call_err.vv:8:10: error: foo() returns an option, so it should have either an `or {}` block, or `?` at the end
6 |
7 | fn main() {
8 | println(foo())
| ~~~~~
9 | }

View file

@ -1,6 +0,0 @@
vlib/v/checker/tests/aliased_optional_fn_call_err.vv:8:10: error: foo() returns an option, so it should have either an `or {}` block, or `?` at the end
6 |
7 | fn main(){
8 | println(foo())
| ~~~~~
9 | }

View file

@ -0,0 +1,21 @@
vlib/v/checker/tests/array_filter_map_option_function_err.vv:14:25: error: option needs to be unwrapped before using it in map/filter
12 | }
13 |
14 | arr_struct2 := arr.map(option_mapping_struct)
| ~~~~~~~~~~~~~~~~~~~~~
15 | println(arr_struct2)
16 |
vlib/v/checker/tests/array_filter_map_option_function_err.vv:17:18: error: option needs to be unwrapped before using it in map/filter
15 | println(arr_struct2)
16 |
17 | arr_int2 := arr.map(option_mapping_int)
| ~~~~~~~~~~~~~~~~~~~~~~~
18 | println(arr_int2)
19 |
vlib/v/checker/tests/array_filter_map_option_function_err.vv:20:20: error: option needs to be unwrapped before using it in map/filter
18 | println(arr_int2)
19 |
20 | arr_filter := arr.filter(option_mapping_int)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
21 | println(arr_filter)
22 | }

View file

@ -1,7 +1,7 @@
fn main() { fn main() {
arr := [1, 2, 3, 4, 5] arr := [1, 2, 3, 4, 5]
optional_mapping_struct := fn (n int) ?MyStruct { option_mapping_struct := fn (n int) ?MyStruct {
if n < 0 { if n < 0 {
return none return none
} else { } else {
@ -11,13 +11,13 @@ fn main() {
} }
} }
arr_struct2 := arr.map(optional_mapping_struct) arr_struct2 := arr.map(option_mapping_struct)
println(arr_struct2) println(arr_struct2)
arr_int2 := arr.map(optional_mapping_int) arr_int2 := arr.map(option_mapping_int)
println(arr_int2) println(arr_int2)
arr_filter := arr.filter(optional_mapping_int) arr_filter := arr.filter(option_mapping_int)
println(arr_filter) println(arr_filter)
} }
@ -25,7 +25,7 @@ struct MyStruct {
my_field int my_field int
} }
fn optional_mapping_int(n int) ?int { fn option_mapping_int(n int) ?int {
if n < 0 { if n < 0 {
return none return none
} else { } else {

View file

@ -1,21 +0,0 @@
vlib/v/checker/tests/array_filter_map_optional_function_err.vv:14:25: error: optional needs to be unwrapped before using it in map/filter
12 | }
13 |
14 | arr_struct2 := arr.map(optional_mapping_struct)
| ~~~~~~~~~~~~~~~~~~~~~~~
15 | println(arr_struct2)
16 |
vlib/v/checker/tests/array_filter_map_optional_function_err.vv:17:18: error: optional needs to be unwrapped before using it in map/filter
15 | println(arr_struct2)
16 |
17 | arr_int2 := arr.map(optional_mapping_int)
| ~~~~~~~~~~~~~~~~~~~~~~~~~
18 | println(arr_int2)
19 |
vlib/v/checker/tests/array_filter_map_optional_function_err.vv:20:20: error: optional needs to be unwrapped before using it in map/filter
18 | println(arr_int2)
19 |
20 | arr_filter := arr.filter(optional_mapping_int)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21 | println(arr_filter)
22 | }

View file

@ -0,0 +1,6 @@
vlib/v/checker/tests/assert_option_err.vv:4:9: error: assert can be used only with `bool` expressions, but found `void` instead
2 |
3 | fn main() {
4 | assert os.truncate('testfile.txt', 6666) or { panic(err) }
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 | }

View file

@ -0,0 +1,5 @@
import os
fn main() {
assert os.truncate('testfile.txt', 6666) or { panic(err) }
}

View file

@ -1,6 +0,0 @@
vlib/v/checker/tests/assert_optional_err.vv:4:9: error: assert can be used only with `bool` expressions, but found `void` instead
2 |
3 | fn main(){
4 | assert os.truncate("testfile.txt", 6666) or { panic(err) }
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 | }

View file

@ -1,5 +0,0 @@
import os
fn main(){
assert os.truncate("testfile.txt", 6666) or { panic(err) }
}

View file

@ -1,2 +1,2 @@
optional compitme define works comptime option define works
non optional comptime define works comptime non-option define works

View file

@ -1,7 +1,7 @@
vlib/v/checker/tests/custom_comptime_define_error.vv:6:13: error: undefined ident: `mysymbol` vlib/v/checker/tests/custom_comptime_define_error.vv:6:6: error: undefined ident: `mysymbol`
4 | println('optional compitme define works') 4 | println('comptime option define works')
5 | } 5 | }
6 | $if mysymbol { 6 | $if mysymbol {
| ~~~~~~~~ | ~~~~~~~~
7 | // this will produce a checker error when `-d mysymbol` is not given on the CLI 7 | // this will produce a checker error when `-d mysymbol` is not given on the CLI
8 | println('non optional comptime define works') 8 | println('comptime non-option define works')

View file

@ -1,10 +1,10 @@
fn main() { fn main() {
$if mysymbol ? { $if mysymbol ? {
// this should not produce checker errors, but will print only with `-d mysymbol` // this should not produce checker errors, but will print only with `-d mysymbol`
println('optional compitme define works') println('comptime option define works')
} }
$if mysymbol { $if mysymbol {
// this will produce a checker error when `-d mysymbol` is not given on the CLI // this will produce a checker error when `-d mysymbol` is not given on the CLI
println('non optional comptime define works') println('comptime non-option define works')
} }
} }

View file

@ -1,4 +1,4 @@
vlib/v/checker/tests/defer_optional.vv:5:3: error: opt() returns an option, so it should have an `or {}` block at the end vlib/v/checker/tests/defer_option.vv:5:3: error: opt() returns an option, so it should have an `or {}` block at the end
3 | fn thing() ?string { 3 | fn thing() ?string {
4 | defer { 4 | defer {
5 | opt() 5 | opt()

View file

@ -1,7 +1,7 @@
vlib/v/checker/tests/expression_should_return_an_option.vv:28:10: error: expression should either return an option or a result vlib/v/checker/tests/expression_should_return_an_option.vv:26:10: error: expression should either return an option or a result
26 | } 24 | return_option(true) or { println(err) }
27 | // should be an checker error: 25 | // should be an checker error:
28 | if x := return_string() { 26 | if x := return_string() {
| ~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~
29 | println('x: $x') 27 | println('x: ${x}')
30 | } 28 | }

View file

@ -1,4 +1,4 @@
fn return_optional(fail bool) ?string { fn return_option(fail bool) ?string {
if fail { if fail {
return error('nope') return error('nope')
} }
@ -11,21 +11,19 @@ fn return_string() string {
fn main() { fn main() {
// works // works
if r := return_optional(false) { if r := return_option(false) {
println(r) println(r)
} }
// works // works
if r := return_optional(false) { if r := return_option(false) {
println(r) println(r)
} else { } else {
println(err) println(err)
} }
// works // works
return_optional(true) or { return_option(true) or { println(err) }
println(err)
}
// should be an checker error: // should be an checker error:
if x := return_string() { if x := return_string() {
println('x: $x') println('x: ${x}')
} }
} }

View file

@ -0,0 +1,5 @@
vlib/v/checker/tests/fn_arg_of_option_err.vv:1:17: error: option or result type argument is not supported currently
1 | fn option_arg(x ?int) {
| ~~~~
2 | println('int type: ${x}')
3 | }

View file

@ -0,0 +1,7 @@
fn option_arg(x ?int) {
println('int type: ${x}')
}
fn main() {
option_arg(1)
}

View file

@ -1,5 +0,0 @@
vlib/v/checker/tests/fn_arg_of_optional_err.vv:1:19: error: optional or result type argument is not supported currently
1 | fn optional_arg(x ?int) {
| ~~~~
2 | println('int type: $x')
3 | }

View file

@ -1,7 +0,0 @@
fn optional_arg(x ?int) {
println('int type: $x')
}
fn main() {
optional_arg(1)
}

View file

@ -0,0 +1,7 @@
vlib/v/checker/tests/fn_check_for_matching_option_result_in_fields.vv:7:3: error: cannot assign to field `f`: expected `fn (voidptr)`, not `fn (voidptr) ?`
5 | fn main() {
6 | a := Abc{
7 | f: fn (data voidptr) ? {}
| ~~~~~~~~~~~~~~~~~~~~~~~~~
8 | }
9 | println(a)

View file

@ -1,7 +0,0 @@
vlib/v/checker/tests/fn_check_for_matching_optional_result_in_fields.vv:7:3: error: cannot assign to field `f`: expected `fn (voidptr)`, not `fn (voidptr) ?`
5 | fn main() {
6 | a := Abc{
7 | f: fn (data voidptr) ? {}
| ~~~~~~~~~~~~~~~~~~~~~~~~~
8 | }
9 | println(a)

View file

@ -1,4 +1,4 @@
vlib/v/checker/tests/fn_return_or_err.vv:6:17: error: unexpected `or` block, the function `pop` does neither return an optional nor a result vlib/v/checker/tests/fn_return_or_err.vv:6:17: error: unexpected `or` block, the function `pop` does not return an option or a result
4 | 4 |
5 | pub fn next(mut v []Typ) Typ { 5 | pub fn next(mut v []Typ) Typ {
6 | return v.pop() or { Typ{} } 6 | return v.pop() or { Typ{} }

View file

@ -1,4 +1,4 @@
vlib/v/checker/tests/for_c_stmt_with_optional_call.vv:15:31: error: optionals are not allowed in `for statement increment` (yet) vlib/v/checker/tests/for_c_stmt_with_option_call.vv:15:31: error: options are not allowed in `for statement increment` (yet)
13 | for t := 0; t < tests; t++ { 13 | for t := 0; t < tests; t++ {
14 | mut v := []bool{len: nmax, init: false} 14 | mut v := []bool{len: nmax, init: false}
15 | for x := 0; !v[x]; x = rand.intn(n) or { 0 } { 15 | for x := 0; !v[x]; x = rand.intn(n) or { 0 } {

View file

@ -0,0 +1,7 @@
vlib/v/checker/tests/for_in_index_option.vv:4:17: error: for in: cannot index `![]string`
2 |
3 | fn main() {
4 | for file in os.ls('.') {
| ~~~~~~~
5 | println(file)
6 | }

View file

@ -0,0 +1,7 @@
import os
fn main() {
for file in os.ls('.') {
println(file)
}
}

View file

@ -1,7 +0,0 @@
vlib/v/checker/tests/for_in_index_optional.vv:3:18: error: for in: cannot index `![]string`
1 | import os
2 | fn main() {
3 | for file in os.ls('.') {
| ~~~~~~~
4 | println(file)
5 | }

View file

@ -1,6 +0,0 @@
import os
fn main() {
for file in os.ls('.') {
println(file)
}
}

View file

@ -0,0 +1,7 @@
vlib/v/checker/tests/go_append_option_to_threads_err.vv:5:15: error: cannot append `thread !` to `[]thread`
3 | fn main() {
4 | mut ths := []thread{}
5 | ths << spawn foo()
| ~~~~~
6 | ths.wait()
7 | }

View file

@ -2,6 +2,6 @@ fn foo() ! {}
fn main() { fn main() {
mut ths := []thread{} mut ths := []thread{}
ths << go foo() ths << spawn foo()
ths.wait() ths.wait()
} }

View file

@ -1,7 +0,0 @@
vlib/v/checker/tests/go_append_optional_to_threads_err.vv:5:12: error: cannot append `thread !` to `[]thread`
3 | fn main() {
4 | mut ths := []thread{}
5 | ths << go foo()
| ~~~~~
6 | ths.wait()
7 | }

View file

@ -1,32 +1,32 @@
vlib/v/checker/tests/go_wait_or.vv:11:16: error: unexpected `?`, the function `wait` does neither return an optional nor a result vlib/v/checker/tests/go_wait_or.vv:11:16: error: unexpected `?`, the function `wait` does not return an option or a result
9 | go d(1) 9 | go d(1)
10 | ] 10 | ]
11 | r := tg.wait()? 11 | r := tg.wait()?
| ^ | ^
12 | println(r) 12 | println(r)
13 | s := tg[0].wait() or { panic('problem') } 13 | s := tg[0].wait() or { panic('problem') }
vlib/v/checker/tests/go_wait_or.vv:13:20: error: unexpected `or` block, the function `wait` does neither return an optional nor a result vlib/v/checker/tests/go_wait_or.vv:13:20: error: unexpected `or` block, the function `wait` does not return an option or a result
11 | r := tg.wait()? 11 | r := tg.wait()?
12 | println(r) 12 | println(r)
13 | s := tg[0].wait() or { panic('problem') } 13 | s := tg[0].wait() or { panic('problem') }
| ~~~~~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~
14 | println(s) 14 | println(s)
15 | tg2 := [ 15 | tg2 := [
vlib/v/checker/tests/go_wait_or.vv:19:13: error: unexpected `or` block, the function `wait` does neither return an optional nor a result vlib/v/checker/tests/go_wait_or.vv:19:13: error: unexpected `or` block, the function `wait` does not return an option or a result
17 | go e(1) 17 | go e(1)
18 | ] 18 | ]
19 | tg2.wait() or { panic('problem') } 19 | tg2.wait() or { panic('problem') }
| ~~~~~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~
20 | tg2[0].wait()? 20 | tg2[0].wait()?
21 | tg3 := [ 21 | tg3 := [
vlib/v/checker/tests/go_wait_or.vv:20:15: error: unexpected `?`, the function `wait` does neither return an optional nor a result vlib/v/checker/tests/go_wait_or.vv:20:15: error: unexpected `?`, the function `wait` does not return an option or a result
18 | ] 18 | ]
19 | tg2.wait() or { panic('problem') } 19 | tg2.wait() or { panic('problem') }
20 | tg2[0].wait()? 20 | tg2[0].wait()?
| ^ | ^
21 | tg3 := [ 21 | tg3 := [
22 | go f(0) 22 | go f(0)
vlib/v/checker/tests/go_wait_or.vv:25:6: error: `.wait()` cannot be called for an array when thread functions return optionals. Iterate over the arrays elements instead and handle each returned optional with `or`. vlib/v/checker/tests/go_wait_or.vv:25:6: error: `.wait()` cannot be called for an array when thread functions return options. Iterate over the arrays elements instead and handle each returned option with `or`.
23 | go f(1) 23 | go f(1)
24 | ] 24 | ]
25 | tg3.wait() or { panic('problem') } 25 | tg3.wait() or { panic('problem') }
@ -47,7 +47,7 @@ vlib/v/checker/tests/go_wait_or.vv:31:15: error: wait() returns an option, so it
| ~~~~~~ | ~~~~~~
32 | println(a) 32 | println(a)
33 | } 33 | }
vlib/v/checker/tests/go_wait_or.vv:38:6: error: `.wait()` cannot be called for an array when thread functions return optionals. Iterate over the arrays elements instead and handle each returned optional with `or`. vlib/v/checker/tests/go_wait_or.vv:38:6: error: `.wait()` cannot be called for an array when thread functions return options. Iterate over the arrays elements instead and handle each returned option with `or`.
36 | go g(1) 36 | go g(1)
37 | ] 37 | ]
38 | tg4.wait() 38 | tg4.wait()
@ -61,7 +61,7 @@ vlib/v/checker/tests/go_wait_or.vv:39:9: error: wait() returns an option, so it
| ~~~~~~ | ~~~~~~
40 | go g(3) or { panic('problem') } 40 | go g(3) or { panic('problem') }
41 | } 41 | }
vlib/v/checker/tests/go_wait_or.vv:40:10: error: optional handling cannot be done in `go` call. Do it when calling `.wait()` vlib/v/checker/tests/go_wait_or.vv:40:10: error: option handling cannot be done in `go` call. Do it when calling `.wait()`
38 | tg4.wait() 38 | tg4.wait()
39 | tg4[0].wait() 39 | tg4[0].wait()
40 | go g(3) or { panic('problem') } 40 | go g(3) or { panic('problem') }

View file

@ -0,0 +1,7 @@
vlib/v/checker/tests/if_expr_option_err.vv:6:5: error: non-bool type `?bool` used as if condition
4 |
5 | fn main() {
6 | if get_bool() {
| ~~~~~~~~~~
7 | println('Using plain lists')
8 | }

View file

@ -4,6 +4,6 @@ fn get_bool() ?bool {
fn main() { fn main() {
if get_bool() { if get_bool() {
println("Using plain lists") println('Using plain lists')
} }
} }

View file

@ -1,7 +0,0 @@
vlib/v/checker/tests/if_expr_optional_err.vv:6:5: error: non-bool type `?bool` used as if condition
4 |
5 | fn main() {
6 | if get_bool() {
| ~~~~~~~~~~
7 | println("Using plain lists")
8 | }

View file

@ -0,0 +1,7 @@
vlib/v/checker/tests/index_of_option_err.vv:6:7: error: type `?[]int` is an option, it does not support indexing
4 |
5 | fn main() {
6 | a := abc()[0] or { 5 }
| ~~~~~
7 | dump(a)
8 | }

View file

@ -1,7 +0,0 @@
vlib/v/checker/tests/index_of_optional_err.vv:6:7: error: type `?[]int` is optional, it does not support indexing
4 |
5 | fn main() {
6 | a := abc()[0] or { 5 }
| ~~~~~
7 | dump(a)
8 | }

View file

@ -0,0 +1,7 @@
vlib/v/checker/tests/infix_compare_option_err.vv:6:5: error: unwrapped option cannot be compared in an infix expression
4 |
5 | fn main() {
6 | if foo() > foo() {
| ~~~~~
7 | }
8 | }

View file

@ -0,0 +1,8 @@
fn foo() ?int {
return 0
}
fn main() {
if foo() > foo() {
}
}

View file

@ -1,6 +0,0 @@
vlib/v/checker/tests/infix_compare_optional_err.vv:6:5: error: unwrapped optional cannot be compared in an infix expression
4 |
5 | fn main(){
6 | if foo() > foo() {}
| ~~~~~
7 | }

View file

@ -1,7 +0,0 @@
fn foo() ?int{
return 0
}
fn main(){
if foo() > foo() {}
}

View file

@ -26,7 +26,7 @@ vlib/v/checker/tests/infix_err.vv:11:7: error: `+` cannot be used with `?int`
| ^ | ^
12 | _ = int(0) + g() // FIXME not detected 12 | _ = int(0) + g() // FIXME not detected
13 | _ = g() + int(3) 13 | _ = g() + int(3)
vlib/v/checker/tests/infix_err.vv:12:14: error: unwrapped optional cannot be used in an infix expression vlib/v/checker/tests/infix_err.vv:12:14: error: unwrapped option cannot be used in an infix expression
10 | 10 |
11 | _ = 4 + g() 11 | _ = 4 + g()
12 | _ = int(0) + g() // FIXME not detected 12 | _ = int(0) + g() // FIXME not detected

View file

@ -0,0 +1,13 @@
vlib/v/checker/tests/option_fields_addr_err.vv:9:10: error: cannot take the address of an option field
7 | fn main() {
8 | x := Wrapper{}
9 | if _ := &x.value {
| ~~~~~~~~
10 | }
11 |
vlib/v/checker/tests/option_fields_addr_err.vv:12:7: error: cannot take the address of an option field
10 | }
11 |
12 | _ := &x.value
| ~~~~~~~~
13 | }

View file

@ -0,0 +1,168 @@
vlib/v/checker/tests/option_fn_err.vv:12:16: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
10 |
11 | const (
12 | const_value = bar(0)
| ~~~~~~
13 | )
14 |
vlib/v/checker/tests/option_fn_err.vv:18:15: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
16 | f fn (int)
17 | mut:
18 | value int = bar(0)
| ~~~~~~
19 | opt ?int = bar(0)
20 | }
vlib/v/checker/tests/option_fn_err.vv:32:2: error: foo() returns an option, so it should have either an `or {}` block, or `?` at the end
30 | fn main() {
31 | // call fn
32 | foo()
| ~~~~~
33 | _ := bar(0)
34 | println(twice(bar(0)))
vlib/v/checker/tests/option_fn_err.vv:33:7: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
31 | // call fn
32 | foo()
33 | _ := bar(0)
| ~~~~~~
34 | println(twice(bar(0)))
35 |
vlib/v/checker/tests/option_fn_err.vv:34:16: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
32 | foo()
33 | _ := bar(0)
34 | println(twice(bar(0)))
| ~~~~~~
35 |
36 | // anon fn
vlib/v/checker/tests/option_fn_err.vv:37:16: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
35 |
36 | // anon fn
37 | fn (_ int) {}(bar(0))
| ~~~~~~
38 |
39 | // assert
vlib/v/checker/tests/option_fn_err.vv:40:9: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
38 |
39 | // assert
40 | assert bar(true)
| ~~~~~~~~~
41 |
42 | // struct
vlib/v/checker/tests/option_fn_err.vv:45:10: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
43 | mut v := Data{
44 | f: fn (_ int) {}
45 | value: bar(0)
| ~~~~~~
46 | opt: bar(0)
47 | }
vlib/v/checker/tests/option_fn_err.vv:48:8: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
46 | opt: bar(0)
47 | }
48 | v.add(bar(0)) // call method
| ~~~~~~
49 | v.f(bar(0)) // call fn field
50 |
vlib/v/checker/tests/option_fn_err.vv:49:6: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
47 | }
48 | v.add(bar(0)) // call method
49 | v.f(bar(0)) // call fn field
| ~~~~~~
50 |
51 | // array
vlib/v/checker/tests/option_fn_err.vv:53:9: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
51 | // array
52 | mut arr := [1, 2]
53 | arr << bar(0)
| ~~~~~~
54 | // init
55 | _ := [bar(0)]
vlib/v/checker/tests/option_fn_err.vv:55:8: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
53 | arr << bar(0)
54 | // init
55 | _ := [bar(0)]
| ~~~~~~
56 | _ := []int{len: 1, init: bar(0)}
57 | _ := [bar(0)]!
vlib/v/checker/tests/option_fn_err.vv:56:27: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
54 | // init
55 | _ := [bar(0)]
56 | _ := []int{len: 1, init: bar(0)}
| ~~~~~~
57 | _ := [bar(0)]!
58 | _ := [1]int{init: bar(0)}
vlib/v/checker/tests/option_fn_err.vv:57:8: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
55 | _ := [bar(0)]
56 | _ := []int{len: 1, init: bar(0)}
57 | _ := [bar(0)]!
| ~~~~~~
58 | _ := [1]int{init: bar(0)}
59 | // index
vlib/v/checker/tests/option_fn_err.vv:60:13: error: cannot use option or result as index (array type `[]int`)
58 | _ := [1]int{init: bar(0)}
59 | // index
60 | println(arr[bar(0)])
| ~~~~~~~~
61 | // array builtin methods
62 | arr.insert(0, bar(0))
vlib/v/checker/tests/option_fn_err.vv:62:16: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
60 | println(arr[bar(0)])
61 | // array builtin methods
62 | arr.insert(0, bar(0))
| ~~~~~~
63 | arr.prepend(bar(0))
64 | arr.contains(bar(0))
vlib/v/checker/tests/option_fn_err.vv:63:14: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
61 | // array builtin methods
62 | arr.insert(0, bar(0))
63 | arr.prepend(bar(0))
| ~~~~~~
64 | arr.contains(bar(0))
65 | arr.index(bar(0))
vlib/v/checker/tests/option_fn_err.vv:64:15: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
62 | arr.insert(0, bar(0))
63 | arr.prepend(bar(0))
64 | arr.contains(bar(0))
| ~~~~~~
65 | arr.index(bar(0))
66 | println(arr.map(bar(0)))
vlib/v/checker/tests/option_fn_err.vv:65:12: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
63 | arr.prepend(bar(0))
64 | arr.contains(bar(0))
65 | arr.index(bar(0))
| ~~~~~~
66 | println(arr.map(bar(0)))
67 | println(arr.filter(bar(true)))
vlib/v/checker/tests/option_fn_err.vv:66:18: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
64 | arr.contains(bar(0))
65 | arr.index(bar(0))
66 | println(arr.map(bar(0)))
| ~~~~~~
67 | println(arr.filter(bar(true)))
68 | println(arr.any(bar(true)))
vlib/v/checker/tests/option_fn_err.vv:67:21: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
65 | arr.index(bar(0))
66 | println(arr.map(bar(0)))
67 | println(arr.filter(bar(true)))
| ~~~~~~~~~
68 | println(arr.any(bar(true)))
69 | println(arr.all(bar(true)))
vlib/v/checker/tests/option_fn_err.vv:68:18: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
66 | println(arr.map(bar(0)))
67 | println(arr.filter(bar(true)))
68 | println(arr.any(bar(true)))
| ~~~~~~~~~
69 | println(arr.all(bar(true)))
70 |
vlib/v/checker/tests/option_fn_err.vv:69:18: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
67 | println(arr.filter(bar(true)))
68 | println(arr.any(bar(true)))
69 | println(arr.all(bar(true)))
| ~~~~~~~~~
70 |
71 | match bar(0) {
vlib/v/checker/tests/option_fn_err.vv:71:8: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
69 | println(arr.all(bar(true)))
70 |
71 | match bar(0) {
| ~~~~~~
72 | 0 {}
73 | else {}

View file

@ -1,5 +1,4 @@
// use option without ? or an or block in places where it is not allowed
// use optional without ? or an or block in places where it is not allowed
fn foo() ? { fn foo() ? {
println('foo is called') println('foo is called')
@ -42,9 +41,9 @@ fn main() {
// struct // struct
mut v := Data{ mut v := Data{
f: fn (_ int) {}, f: fn (_ int) {}
value: bar(0), value: bar(0)
opt: bar(0), opt: bar(0)
} }
v.add(bar(0)) // call method v.add(bar(0)) // call method
v.f(bar(0)) // call fn field v.f(bar(0)) // call fn field

View file

@ -0,0 +1,6 @@
vlib/v/checker/tests/option_in_dump_err.vv:10:7: error: create() returns an option, so it should have either an `or {}` block, or `?` at the end
8 |
9 | fn main() {
10 | dump(create())
| ~~~~~~~~
11 | }

View file

@ -0,0 +1,6 @@
vlib/v/checker/tests/option_in_println_mismatch.vv:6:23: error: wrong return type `string` in the `or {}` block, expected `int`
4 |
5 | fn main() {
6 | println(funcy() or { '' })
| ~~
7 | }

View file

@ -1,4 +1,4 @@
vlib/v/checker/tests/optional_interface_mismatch.vv:11:9: error: mismatched types `?MObject` and `string` vlib/v/checker/tests/option_interface_mismatch.vv:11:9: error: mismatched types `?MObject` and `string`
9 | 9 |
10 | fn give_string(line string) ?MObject { 10 | fn give_string(line string) ?MObject {
11 | return if true { 'string' } else { 'string' } 11 | return if true { 'string' } else { 'string' }

View file

@ -0,0 +1,13 @@
vlib/v/checker/tests/option_or_block_mismatch.vv:10:18: error: wrong return type `Bar` in the `or {}` block, expected `&Bar`
8 |
9 | fn main() {
10 | x := foo() or { Bar{} }
| ~~~~~
11 | println(x)
12 |
vlib/v/checker/tests/option_or_block_mismatch.vv:13:13: error: the default expression type in the `or` block should be `&Bar`, instead you gave a value of type `Bar`
11 | println(x)
12 |
13 | foo() or { Bar{} }
| ~~~~~
14 | }

View file

@ -0,0 +1,7 @@
vlib/v/checker/tests/option_or_block_none_err.vv:19:32: error: wrong return type `none` in the `or {}` block, expected `Animal`
17 |
18 | fn main() {
19 | mut dog := new_animal(9) or { none }
| ~~~~
20 |
21 | println(dog)

View file

@ -0,0 +1,7 @@
vlib/v/checker/tests/option_or_block_returns_value_of_incompatible_type.vv:13:3: error: the default expression type in the `or` block should be `string`, instead you gave a value of type `int literal`
11 | // must be of the same type of the return
12 | // type of the `test_option` function
13 | 123
| ~~~
14 | // 'I break things'
15 | }

View file

@ -0,0 +1,16 @@
fn test_option(fail bool) ?string {
if fail {
return error('false')
}
return 'fff'
}
fn main() {
// a := test_option(false) or { println(err) }
test_option(true) or {
// must be of the same type of the return
// type of the `test_option` function
123
// 'I break things'
}
}

View file

@ -0,0 +1,28 @@
vlib/v/checker/tests/option_propagate_nested.vv:10:18: error: to propagate the option call, `xx_prop` must return an option
8 |
9 | fn xx_prop() string {
10 | s := ret(raise()?)
| ^
11 | return s
12 | }
Details: vlib/v/checker/tests/option_propagate_nested.vv:9:14: details: prepend ? before the declaration of the return type of `xx_prop`
7 | }
8 |
9 | fn xx_prop() string {
| ~~~~~~
10 | s := ret(raise()?)
11 | return s
vlib/v/checker/tests/option_propagate_nested.vv:28:21: error: to propagate the option call, `aa_propagate` must return an option
26 |
27 | fn (mut s St) aa_propagate() {
28 | f := retf(s.raise()?)
| ^
29 | s.z = 7.5
30 | println(f)
Details: vlib/v/checker/tests/option_propagate_nested.vv:27:30: details: prepend ? before the declaration of the return type of `aa_propagate`
25 | }
26 |
27 | fn (mut s St) aa_propagate() {
| ^
28 | f := retf(s.raise()?)
29 | s.z = 7.5

View file

@ -1,4 +1,4 @@
vlib/v/checker/tests/optional_type_call_err.vv:4:5: error: result type cannot be called directly vlib/v/checker/tests/option_type_call_err.vv:4:5: error: result type cannot be called directly
2 | 2 |
3 | fn main() { 3 | fn main() {
4 | os.ls('.').filter(it.ends_with('.v')) or { return } 4 | os.ls('.').filter(it.ends_with('.v')) or { return }

View file

@ -0,0 +1,5 @@
vlib/v/checker/tests/option_variable_err.vv:2:7: error: casting to option type is forbidden
1 | fn main() {
2 | _ := ?bool(false)
| ~~~~~~~~~~~~
3 | }

View file

@ -1,13 +0,0 @@
vlib/v/checker/tests/optional_fields_addr_err.vv:9:10: error: cannot take the address of an optional field
7 | fn main() {
8 | x := Wrapper{}
9 | if _ := &x.value {
| ~~~~~~~~
10 | }
11 |
vlib/v/checker/tests/optional_fields_addr_err.vv:12:7: error: cannot take the address of an optional field
10 | }
11 |
12 | _ := &x.value
| ~~~~~~~~
13 | }

Some files were not shown because too many files have changed in this diff Show more