mirror of
https://github.com/vlang/v.git
synced 2025-09-13 22:42:26 +03:00
Merge branch 'vlang:master' into master
This commit is contained in:
commit
147d5b5709
28 changed files with 321 additions and 66 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
// vtest retry: 3
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
|
@ -6138,6 +6138,10 @@ that are substituted at compile time:
|
||||||
- `@BUILD_DATE` => replaced with the build date, for example '2024-09-13' .
|
- `@BUILD_DATE` => replaced with the build date, for example '2024-09-13' .
|
||||||
- `@BUILD_TIME` => replaced with the build time, for example '12:32:07' .
|
- `@BUILD_TIME` => replaced with the build time, for example '12:32:07' .
|
||||||
- `@BUILD_TIMESTAMP` => replaced with the build timestamp, for example '1726219885' .
|
- `@BUILD_TIMESTAMP` => replaced with the build timestamp, for example '1726219885' .
|
||||||
|
- `@OS` => replaced with the OS type, for example 'linux' .
|
||||||
|
- `@CCOMPILER` => replaced with the C compiler type, for example 'gcc' .
|
||||||
|
- `@BACKEND` => replaced with current language backend, for example 'c' or 'golang' .
|
||||||
|
- `@PLATFORM` => replaced with the platform type, for example 'amd64' .
|
||||||
Note: `@BUILD_DATE`, `@BUILD_TIME`, `@BUILD_TIMESTAMP` represent times in the UTC timezone.
|
Note: `@BUILD_DATE`, `@BUILD_TIME`, `@BUILD_TIMESTAMP` represent times in the UTC timezone.
|
||||||
By default, they are based on the current time of the compilation/build. They can be overridden
|
By default, they are based on the current time of the compilation/build. They can be overridden
|
||||||
by setting the environment variable `SOURCE_DATE_EPOCH`. That is also useful while making
|
by setting the environment variable `SOURCE_DATE_EPOCH`. That is also useful while making
|
||||||
|
|
|
@ -934,9 +934,7 @@ pub fn (fm FlagMapper) to_struct[T](defaults ?T) !T {
|
||||||
.f64()
|
.f64()
|
||||||
} $else $if field.typ is bool {
|
} $else $if field.typ is bool {
|
||||||
if arg := f.arg {
|
if arg := f.arg {
|
||||||
if arg != '' {
|
return error('can not assign `${arg}` to bool field `${field.name}`')
|
||||||
return error('can not assign `${arg}` to bool field `${field.name}`')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result.$(field.name) = !the_default.$(field.name)
|
result.$(field.name) = !the_default.$(field.name)
|
||||||
} $else $if field.typ is string {
|
} $else $if field.typ is string {
|
||||||
|
@ -1037,7 +1035,7 @@ fn (mut fm FlagMapper) map_v(flag_ctx FlagContext, field StructField) !bool {
|
||||||
next := flag_ctx.next
|
next := flag_ctx.next
|
||||||
|
|
||||||
if field.hints.has(.is_bool) {
|
if field.hints.has(.is_bool) {
|
||||||
if flag_name == field.match_name {
|
if flag_name == field.match_name || flag_name == field.short {
|
||||||
arg := if flag_raw.contains('=') { flag_raw.all_after('=') } else { '' }
|
arg := if flag_raw.contains('=') { flag_raw.all_after('=') } else { '' }
|
||||||
if arg != '' {
|
if arg != '' {
|
||||||
return error('flag `${flag_raw}` can not be assigned to bool field "${field.name}"')
|
return error('flag `${flag_raw}` can not be assigned to bool field "${field.name}"')
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import flag
|
import flag
|
||||||
|
|
||||||
const args_bool_short = ['some.exe', '-h']
|
|
||||||
const args_bool_long = ['some.exe', '-help']
|
|
||||||
|
|
||||||
struct CliOptions {
|
struct CliOptions {
|
||||||
show_help bool @[long: 'help'; short: h]
|
show_help bool @[long: 'help'; short: h]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_short_tail_bool() {
|
struct CliOptions2 {
|
||||||
cli_options, unmatched := flag.to_struct[CliOptions](args_bool_short,
|
show_help bool @[long: 'help'; short: h]
|
||||||
|
long string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_v_style_short_tail_bool() {
|
||||||
|
cli_options, unmatched := flag.to_struct[CliOptions](['some.exe', '-h'],
|
||||||
skip: 1
|
skip: 1
|
||||||
style: .v
|
style: .v
|
||||||
mode: .relaxed
|
mode: .relaxed
|
||||||
|
@ -24,8 +26,8 @@ fn test_short_tail_bool() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_long_tail_bool() {
|
fn test_v_style_long_tail_bool() {
|
||||||
cli_options, unmatched := flag.to_struct[CliOptions](args_bool_long,
|
cli_options, unmatched := flag.to_struct[CliOptions](['some.exe', '-help'],
|
||||||
skip: 1
|
skip: 1
|
||||||
style: .v
|
style: .v
|
||||||
mode: .relaxed
|
mode: .relaxed
|
||||||
|
@ -40,3 +42,39 @@ fn test_long_tail_bool() {
|
||||||
assert false
|
assert false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_v_style_short_bool() {
|
||||||
|
cli_options, unmatched := flag.to_struct[CliOptions2](['some.exe', '-h', '-long', 'val'],
|
||||||
|
skip: 1
|
||||||
|
style: .v
|
||||||
|
mode: .relaxed
|
||||||
|
)!
|
||||||
|
|
||||||
|
if unmatched.len > 0 {
|
||||||
|
assert false
|
||||||
|
}
|
||||||
|
if cli_options.show_help {
|
||||||
|
assert true
|
||||||
|
} else {
|
||||||
|
assert false
|
||||||
|
}
|
||||||
|
assert cli_options.long == 'val'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_v_style_long_bool() {
|
||||||
|
cli_options, unmatched := flag.to_struct[CliOptions2](['some.exe', '-help', '-long', 'val'],
|
||||||
|
skip: 1
|
||||||
|
style: .v
|
||||||
|
mode: .relaxed
|
||||||
|
)!
|
||||||
|
|
||||||
|
if unmatched.len > 0 {
|
||||||
|
assert false
|
||||||
|
}
|
||||||
|
if cli_options.show_help {
|
||||||
|
assert true
|
||||||
|
} else {
|
||||||
|
assert false
|
||||||
|
}
|
||||||
|
assert cli_options.long == 'val'
|
||||||
|
}
|
||||||
|
|
|
@ -158,10 +158,13 @@ pub fn (c TcpConn) read_ptr(buf_ptr &u8, len int) !int {
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$if trace_tcp ? {
|
ecode := error_code()
|
||||||
eprintln('<<< TcpConn.read_ptr | c.sock.handle: ${c.sock.handle} | buf_ptr: ${ptr_str(buf_ptr)} len: ${len} | res: ${res}')
|
|
||||||
}
|
|
||||||
if res > 0 {
|
if res > 0 {
|
||||||
|
$if trace_tcp ? {
|
||||||
|
eprintln(
|
||||||
|
'<<< TcpConn.read_ptr | c.sock.handle: ${c.sock.handle} | buf_ptr: ${ptr_str(buf_ptr)} | len: ${len} | res: ${res} |\n' +
|
||||||
|
unsafe { buf_ptr.vstring_with_len(len) })
|
||||||
|
}
|
||||||
$if trace_tcp_data_read ? {
|
$if trace_tcp_data_read ? {
|
||||||
eprintln(
|
eprintln(
|
||||||
'<<< TcpConn.read_ptr | 1 data.len: ${res:6} | hex: ${unsafe { buf_ptr.vbytes(res) }.hex()} | data: ' +
|
'<<< TcpConn.read_ptr | 1 data.len: ${res:6} | hex: ${unsafe { buf_ptr.vbytes(res) }.hex()} | data: ' +
|
||||||
|
@ -169,7 +172,7 @@ pub fn (c TcpConn) read_ptr(buf_ptr &u8, len int) !int {
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
code := if should_ewouldblock { int(error_ewouldblock) } else { error_code() }
|
code := if should_ewouldblock { int(error_ewouldblock) } else { ecode }
|
||||||
if code in [int(error_ewouldblock), int(error_eagain), C.EINTR] {
|
if code in [int(error_ewouldblock), int(error_eagain), C.EINTR] {
|
||||||
c.wait_for_read()!
|
c.wait_for_read()!
|
||||||
res = $if is_coroutine ? {
|
res = $if is_coroutine ? {
|
||||||
|
@ -178,7 +181,9 @@ pub fn (c TcpConn) read_ptr(buf_ptr &u8, len int) !int {
|
||||||
C.recv(c.sock.handle, voidptr(buf_ptr), len, msg_dontwait)
|
C.recv(c.sock.handle, voidptr(buf_ptr), len, msg_dontwait)
|
||||||
}
|
}
|
||||||
$if trace_tcp ? {
|
$if trace_tcp ? {
|
||||||
eprintln('<<< TcpConn.read_ptr | c.sock.handle: ${c.sock.handle} | buf_ptr: ${ptr_str(buf_ptr)} len: ${len} | res: ${res}')
|
eprintln(
|
||||||
|
'<<< TcpConn.read_ptr | c.sock.handle: ${c.sock.handle} | buf_ptr: ${ptr_str(buf_ptr)} | len: ${len} | res: ${res} | code: ${code} |\n' +
|
||||||
|
unsafe { buf_ptr.vstring_with_len(len) })
|
||||||
}
|
}
|
||||||
$if trace_tcp_data_read ? {
|
$if trace_tcp_data_read ? {
|
||||||
if res > 0 {
|
if res > 0 {
|
||||||
|
@ -234,11 +239,11 @@ pub fn (mut c TcpConn) write_ptr(b &u8, len int) !int {
|
||||||
} $else {
|
} $else {
|
||||||
C.send(c.sock.handle, ptr, remaining, msg_nosignal)
|
C.send(c.sock.handle, ptr, remaining, msg_nosignal)
|
||||||
}
|
}
|
||||||
|
code := error_code()
|
||||||
$if trace_tcp_data_write ? {
|
$if trace_tcp_data_write ? {
|
||||||
eprintln('>>> TcpConn.write_ptr | data chunk, total_sent: ${total_sent:6}, remaining: ${remaining:6}, ptr: ${voidptr(ptr):x} => sent: ${sent:6}')
|
eprintln('>>> TcpConn.write_ptr | data chunk, total_sent: ${total_sent:6}, remaining: ${remaining:6}, ptr: ${voidptr(ptr):x} => sent: ${sent:6}')
|
||||||
}
|
}
|
||||||
if sent < 0 {
|
if sent < 0 {
|
||||||
code := error_code()
|
|
||||||
$if trace_tcp_send_failures ? {
|
$if trace_tcp_send_failures ? {
|
||||||
eprintln('>>> TcpConn.write_ptr | send_failure, data.len: ${len:6}, total_sent: ${total_sent:6}, remaining: ${remaining:6}, ptr: ${voidptr(ptr):x}, c.write_timeout: ${c.write_timeout:3} => sent: ${sent:6}, error code: ${code:3}')
|
eprintln('>>> TcpConn.write_ptr | send_failure, data.len: ${len:6}, total_sent: ${total_sent:6}, remaining: ${remaining:6}, ptr: ${voidptr(ptr):x}, c.write_timeout: ${c.write_timeout:3} => sent: ${sent:6}, error code: ${code:3}')
|
||||||
}
|
}
|
||||||
|
@ -456,9 +461,8 @@ pub fn (mut l TcpListener) accept_only() !&TcpConn {
|
||||||
} $else {
|
} $else {
|
||||||
C.accept(l.sock.handle, 0, 0)
|
C.accept(l.sock.handle, 0, 0)
|
||||||
}
|
}
|
||||||
|
code := error_code()
|
||||||
if !l.is_blocking && new_handle <= 0 {
|
if !l.is_blocking && new_handle <= 0 {
|
||||||
code := error_code()
|
|
||||||
if code in [int(error_einprogress), int(error_ewouldblock), int(error_eagain), C.EINTR] {
|
if code in [int(error_einprogress), int(error_ewouldblock), int(error_eagain), C.EINTR] {
|
||||||
l.wait_for_accept()!
|
l.wait_for_accept()!
|
||||||
new_handle = $if is_coroutine ? {
|
new_handle = $if is_coroutine ? {
|
||||||
|
@ -642,10 +646,10 @@ fn (mut s TcpSocket) connect(a Addr) ! {
|
||||||
} $else {
|
} $else {
|
||||||
C.connect(s.handle, voidptr(&a), a.len())
|
C.connect(s.handle, voidptr(&a), a.len())
|
||||||
}
|
}
|
||||||
|
ecode := error_code()
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ecode := error_code()
|
|
||||||
// On nix non-blocking sockets we expect einprogress
|
// On nix non-blocking sockets we expect einprogress
|
||||||
// On windows we expect res == -1 && error_code() == ewouldblock
|
// On windows we expect res == -1 && error_code() == ewouldblock
|
||||||
if (is_windows && ecode == int(error_ewouldblock)) || (!is_windows && res == -1
|
if (is_windows && ecode == int(error_ewouldblock)) || (!is_windows && res == -1
|
||||||
|
|
|
@ -2190,16 +2190,15 @@ pub fn (mut t Table) unwrap_generic_type_ex(typ Type, generic_names []string, co
|
||||||
Interface {
|
Interface {
|
||||||
// resolve generic types inside methods
|
// resolve generic types inside methods
|
||||||
mut imethods := ts.info.methods.clone()
|
mut imethods := ts.info.methods.clone()
|
||||||
|
gn_names := t.get_real_generic_names(typ, generic_names)
|
||||||
for mut method in imethods {
|
for mut method in imethods {
|
||||||
if unwrap_typ := t.convert_generic_type(method.return_type, generic_names,
|
if unwrap_typ := t.convert_generic_type(method.return_type, gn_names,
|
||||||
concrete_types)
|
concrete_types[..gn_names.len])
|
||||||
{
|
{
|
||||||
method.return_type = unwrap_typ
|
method.return_type = unwrap_typ
|
||||||
}
|
}
|
||||||
for mut param in method.params {
|
for mut param in method.params {
|
||||||
if unwrap_typ := t.convert_generic_type(param.typ, generic_names,
|
if unwrap_typ := t.convert_generic_type(param.typ, gn_names, concrete_types) {
|
||||||
concrete_types)
|
|
||||||
{
|
|
||||||
param.typ = unwrap_typ
|
param.typ = unwrap_typ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2289,6 +2288,7 @@ pub fn (mut t Table) generic_insts_to_concrete() {
|
||||||
fields[i].typ = t.unwrap_generic_type(fields[i].typ,
|
fields[i].typ = t.unwrap_generic_type(fields[i].typ,
|
||||||
generic_names, info.concrete_types)
|
generic_names, info.concrete_types)
|
||||||
}
|
}
|
||||||
|
|
||||||
if t_typ := t.convert_generic_type(fields[i].typ, generic_names,
|
if t_typ := t.convert_generic_type(fields[i].typ, generic_names,
|
||||||
info.concrete_types)
|
info.concrete_types)
|
||||||
{
|
{
|
||||||
|
@ -2464,6 +2464,18 @@ pub fn (mut t Table) generic_insts_to_concrete() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extracts all generic names from Type<A>[B] => B when <A>[B] is present
|
||||||
|
// otherwise generic_names is returned
|
||||||
|
pub fn (t &Table) get_real_generic_names(typ Type, generic_names []string) []string {
|
||||||
|
if typ.has_flag(.generic) {
|
||||||
|
typ_name := t.type_to_str(typ)
|
||||||
|
if typ_name.contains('>[') {
|
||||||
|
return typ_name.split('>[')[1].all_before_last(']').split(',')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return generic_names
|
||||||
|
}
|
||||||
|
|
||||||
// Extracts all type names from given types, notice that MultiReturn will be decompose
|
// Extracts all type names from given types, notice that MultiReturn will be decompose
|
||||||
// and will not included in returned string
|
// and will not included in returned string
|
||||||
pub fn (t &Table) get_generic_names(generic_types []Type) []string {
|
pub fn (t &Table) get_generic_names(generic_types []Type) []string {
|
||||||
|
|
|
@ -4030,6 +4030,18 @@ fn (mut c Checker) at_expr(mut node ast.AtExpr) ast.Type {
|
||||||
.build_timestamp {
|
.build_timestamp {
|
||||||
node.val = util.stable_build_time.unix().str()
|
node.val = util.stable_build_time.unix().str()
|
||||||
}
|
}
|
||||||
|
.os {
|
||||||
|
node.val = pref.get_host_os().lower()
|
||||||
|
}
|
||||||
|
.ccompiler {
|
||||||
|
node.val = c.pref.ccompiler_type.str()
|
||||||
|
}
|
||||||
|
.backend {
|
||||||
|
node.val = c.pref.backend.str()
|
||||||
|
}
|
||||||
|
.platform {
|
||||||
|
node.val = c.pref.arch.str()
|
||||||
|
}
|
||||||
.unknown {
|
.unknown {
|
||||||
c.error('unknown @ identifier: ${node.name}. Available identifiers: ${token.valid_at_tokens}',
|
c.error('unknown @ identifier: ${node.name}. Available identifiers: ${token.valid_at_tokens}',
|
||||||
node.pos)
|
node.pos)
|
||||||
|
|
|
@ -1472,6 +1472,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
mut has_decompose := false
|
mut has_decompose := false
|
||||||
|
mut nr_multi_values := 0
|
||||||
for i, mut call_arg in node.args {
|
for i, mut call_arg in node.args {
|
||||||
if func.params.len == 0 {
|
if func.params.len == 0 {
|
||||||
continue
|
continue
|
||||||
|
@ -1482,21 +1483,22 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
||||||
if !func.is_variadic && has_decompose {
|
if !func.is_variadic && has_decompose {
|
||||||
c.error('cannot have parameter after array decompose', node.pos)
|
c.error('cannot have parameter after array decompose', node.pos)
|
||||||
}
|
}
|
||||||
|
param_i := i + nr_multi_values
|
||||||
param := if func.is_variadic && i >= func.params.len - 1 {
|
param := if func.is_variadic && i >= func.params.len - 1 {
|
||||||
func.params.last()
|
func.params.last()
|
||||||
} else {
|
} else {
|
||||||
func.params[i]
|
func.params[param_i]
|
||||||
}
|
}
|
||||||
// registers if the arg must be passed by ref to disable auto deref args
|
// registers if the arg must be passed by ref to disable auto deref args
|
||||||
call_arg.should_be_ptr = param.typ.is_ptr() && !param.is_mut
|
call_arg.should_be_ptr = param.typ.is_ptr() && !param.is_mut
|
||||||
if func.is_variadic && call_arg.expr is ast.ArrayDecompose {
|
if func.is_variadic && call_arg.expr is ast.ArrayDecompose {
|
||||||
if i > func.params.len - 1 {
|
if param_i > func.params.len - 1 {
|
||||||
c.error('too many arguments in call to `${func.name}`', node.pos)
|
c.error('too many arguments in call to `${func.name}`', node.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
has_decompose = call_arg.expr is ast.ArrayDecompose
|
has_decompose = call_arg.expr is ast.ArrayDecompose
|
||||||
already_checked := node.language != .js && call_arg.expr is ast.CallExpr
|
already_checked := node.language != .js && call_arg.expr is ast.CallExpr
|
||||||
if func.is_variadic && i >= func.params.len - 1 {
|
if func.is_variadic && param_i >= func.params.len - 1 {
|
||||||
param_sym := c.table.sym(param.typ)
|
param_sym := c.table.sym(param.typ)
|
||||||
mut expected_type := param.typ
|
mut expected_type := param.typ
|
||||||
if param_sym.info is ast.Array {
|
if param_sym.info is ast.Array {
|
||||||
|
@ -1688,15 +1690,16 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
||||||
multi_param := if func.is_variadic && i >= func.params.len - 1 {
|
multi_param := if func.is_variadic && i >= func.params.len - 1 {
|
||||||
func.params.last()
|
func.params.last()
|
||||||
} else {
|
} else {
|
||||||
func.params[n + i]
|
func.params[n + param_i]
|
||||||
}
|
}
|
||||||
c.check_expected_call_arg(curr_arg, c.unwrap_generic(multi_param.typ),
|
c.check_expected_call_arg(curr_arg, c.unwrap_generic(multi_param.typ),
|
||||||
node.language, call_arg) or {
|
node.language, call_arg) or {
|
||||||
c.error('${err.msg()} in argument ${i + n + 1} to `${fn_name}` from ${c.table.type_to_str(arg_typ)}',
|
c.error('${err.msg()} in argument ${param_i + n + 1} to `${fn_name}` from ${c.table.type_to_str(arg_typ)}',
|
||||||
call_arg.pos)
|
call_arg.pos)
|
||||||
continue out
|
continue out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
nr_multi_values += arg_typ_sym.info.types.len - 1
|
||||||
continue
|
continue
|
||||||
} else if param_typ_sym.info is ast.Struct && arg_typ_sym.info is ast.Struct
|
} else if param_typ_sym.info is ast.Struct && arg_typ_sym.info is ast.Struct
|
||||||
&& param_typ_sym.info.is_anon {
|
&& param_typ_sym.info.is_anon {
|
||||||
|
@ -1788,13 +1791,14 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
c.error('${err.msg()} in argument ${i + 1} to `${fn_name}`', call_arg.pos)
|
c.error('${err.msg()} in argument ${i + nr_multi_values + 1} to `${fn_name}`',
|
||||||
|
call_arg.pos)
|
||||||
}
|
}
|
||||||
if final_param_sym.kind == .struct && arg_typ !in [ast.voidptr_type, ast.nil_type]
|
if final_param_sym.kind == .struct && arg_typ !in [ast.voidptr_type, ast.nil_type]
|
||||||
&& !c.check_multiple_ptr_match(arg_typ, param.typ, param, call_arg) {
|
&& !c.check_multiple_ptr_match(arg_typ, param.typ, param, call_arg) {
|
||||||
got_typ_str, expected_typ_str := c.get_string_names_of(arg_typ, param.typ)
|
got_typ_str, expected_typ_str := c.get_string_names_of(arg_typ, param.typ)
|
||||||
c.error('cannot use `${got_typ_str}` as `${expected_typ_str}` in argument ${i + 1} to `${fn_name}`',
|
c.error('cannot use `${got_typ_str}` as `${expected_typ_str}` in argument ${i +
|
||||||
call_arg.pos)
|
nr_multi_values + 1} to `${fn_name}`', call_arg.pos)
|
||||||
}
|
}
|
||||||
// Warn about automatic (de)referencing, which will be removed soon.
|
// Warn about automatic (de)referencing, which will be removed soon.
|
||||||
if func.language != .c && !c.inside_unsafe && !(call_arg.is_mut && param.is_mut) {
|
if func.language != .c && !c.inside_unsafe && !(call_arg.is_mut && param.is_mut) {
|
||||||
|
@ -2924,6 +2928,17 @@ fn (mut c Checker) check_expected_arg_count(mut node ast.CallExpr, f &ast.Fn) !
|
||||||
return error('')
|
return error('')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if node.args.len > 1 && node.args.any(it.expr is ast.CallExpr
|
||||||
|
&& it.expr.nr_ret_values > 1) {
|
||||||
|
mut check_args := 0
|
||||||
|
for arg in node.args {
|
||||||
|
if arg.expr is ast.CallExpr && arg.expr.nr_ret_values > 0 {
|
||||||
|
check_args += arg.expr.nr_ret_values
|
||||||
|
} else {
|
||||||
|
check_args += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nr_args = check_args
|
||||||
}
|
}
|
||||||
if min_required_params < 0 {
|
if min_required_params < 0 {
|
||||||
min_required_params = 0
|
min_required_params = 0
|
||||||
|
@ -2966,7 +2981,7 @@ fn (mut c Checker) check_expected_arg_count(mut node ast.CallExpr, f &ast.Fn) !
|
||||||
)
|
)
|
||||||
return error('')
|
return error('')
|
||||||
} else if !f.is_variadic && nr_args > nr_params {
|
} else if !f.is_variadic && nr_args > nr_params {
|
||||||
unexpected_args_pos := node.args[min_required_params].pos.extend(node.args.last().pos)
|
unexpected_args_pos := node.args[int_min(min_required_params, node.args.len - 1)].pos.extend(node.args.last().pos)
|
||||||
// c.error('3expected ${min_required_params} arguments, but got ${nr_args}', unexpected_args_pos)
|
// c.error('3expected ${min_required_params} arguments, but got ${nr_args}', unexpected_args_pos)
|
||||||
c.fn_call_error_have_want(
|
c.fn_call_error_have_want(
|
||||||
nr_params: min_required_params
|
nr_params: min_required_params
|
||||||
|
|
18
vlib/v/checker/tests/multi_return_arg_missing_err.out
Normal file
18
vlib/v/checker/tests/multi_return_arg_missing_err.out
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
vlib/v/checker/tests/multi_return_arg_missing_err.vv:12:14: error: expected 2 arguments, but got 3
|
||||||
|
10 |
|
||||||
|
11 | fn main() {
|
||||||
|
12 | expect_2(1, returning_2())
|
||||||
|
| ~~~~~~~~~~~~~
|
||||||
|
13 | expect_2(returning_2(), 1)
|
||||||
|
14 | expect_4(returning_2(), returning_2())
|
||||||
|
Details: have (int literal, (int, int))
|
||||||
|
want (int, int)
|
||||||
|
vlib/v/checker/tests/multi_return_arg_missing_err.vv:13:26: error: expected 2 arguments, but got 3
|
||||||
|
11 | fn main() {
|
||||||
|
12 | expect_2(1, returning_2())
|
||||||
|
13 | expect_2(returning_2(), 1)
|
||||||
|
| ^
|
||||||
|
14 | expect_4(returning_2(), returning_2())
|
||||||
|
15 | }
|
||||||
|
Details: have ((int, int), int literal)
|
||||||
|
want (int, int)
|
15
vlib/v/checker/tests/multi_return_arg_missing_err.vv
Normal file
15
vlib/v/checker/tests/multi_return_arg_missing_err.vv
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
fn expect_2(a int, b int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_4(a int, b int, c int, d int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn returning_2() (int, int) {
|
||||||
|
return 1, 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
expect_2(1, returning_2())
|
||||||
|
expect_2(returning_2(), 1)
|
||||||
|
expect_4(returning_2(), returning_2())
|
||||||
|
}
|
|
@ -5,24 +5,20 @@ vlib/v/checker/tests/multi_return_err.vv:18:10: error: cannot use `f64` as `int`
|
||||||
| ~~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
19 | my_func3(my_func2(), 'foo')
|
19 | my_func3(my_func2(), 'foo')
|
||||||
20 | my_func4('foo', my_func2())
|
20 | my_func4('foo', my_func2())
|
||||||
vlib/v/checker/tests/multi_return_err.vv:19:2: error: expected 3 arguments, but got 2
|
vlib/v/checker/tests/multi_return_err.vv:19:11: error: cannot use `f64` as `int` in argument 2 to `my_func3` from (int, f64)
|
||||||
17 | fn main() {
|
17 | fn main() {
|
||||||
18 | my_func(my_func2())
|
18 | my_func(my_func2())
|
||||||
19 | my_func3(my_func2(), 'foo')
|
19 | my_func3(my_func2(), 'foo')
|
||||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
20 | my_func4('foo', my_func2())
|
20 | my_func4('foo', my_func2())
|
||||||
21 | my_func(my_func5())
|
21 | my_func(my_func5())
|
||||||
Details: have ((int, f64), string)
|
vlib/v/checker/tests/multi_return_err.vv:20:18: error: cannot use `f64` as `int` in argument 3 to `my_func4` from (int, f64)
|
||||||
want (int, int, string)
|
|
||||||
vlib/v/checker/tests/multi_return_err.vv:20:2: error: expected 3 arguments, but got 2
|
|
||||||
18 | my_func(my_func2())
|
18 | my_func(my_func2())
|
||||||
19 | my_func3(my_func2(), 'foo')
|
19 | my_func3(my_func2(), 'foo')
|
||||||
20 | my_func4('foo', my_func2())
|
20 | my_func4('foo', my_func2())
|
||||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
21 | my_func(my_func5())
|
21 | my_func(my_func5())
|
||||||
22 | my_func(my_func6())
|
22 | my_func(my_func6())
|
||||||
Details: have (string, (int, f64))
|
|
||||||
want (string, int, int)
|
|
||||||
vlib/v/checker/tests/multi_return_err.vv:21:2: error: expected 2 arguments, but got 1
|
vlib/v/checker/tests/multi_return_err.vv:21:2: error: expected 2 arguments, but got 1
|
||||||
19 | my_func3(my_func2(), 'foo')
|
19 | my_func3(my_func2(), 'foo')
|
||||||
20 | my_func4('foo', my_func2())
|
20 | my_func4('foo', my_func2())
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
import math
|
|
||||||
import os
|
|
||||||
import math
|
|
||||||
// keep comment
|
|
||||||
import gg
|
|
||||||
import gg { MouseButton }
|
|
||||||
import time { Duration }
|
|
||||||
import time { Duration }
|
|
||||||
import math.complex { Complex }
|
|
||||||
import math.complex { Complex }
|
|
||||||
|
|
||||||
const mypi = math.pi
|
|
||||||
const mb = MouseButton{}
|
|
||||||
const complex = Complex{}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
println(os.path_separator)
|
|
||||||
}
|
|
|
@ -1107,6 +1107,7 @@ pub fn (mut g Gen) get_sumtype_variant_name(typ ast.Type, sym ast.TypeSymbol) st
|
||||||
pub fn (mut g Gen) write_typeof_functions() {
|
pub fn (mut g Gen) write_typeof_functions() {
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
g.writeln('// >> typeof() support for sum types / interfaces')
|
g.writeln('// >> typeof() support for sum types / interfaces')
|
||||||
|
mut already_generated_ifaces := map[string]bool{}
|
||||||
for ityp, sym in g.table.type_symbols {
|
for ityp, sym in g.table.type_symbols {
|
||||||
if sym.kind == .sum_type {
|
if sym.kind == .sum_type {
|
||||||
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
|
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
|
||||||
|
@ -1177,6 +1178,10 @@ pub fn (mut g Gen) write_typeof_functions() {
|
||||||
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
|
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if sym.cname in already_generated_ifaces {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
already_generated_ifaces[sym.cname] = true
|
||||||
g.definitions.writeln('${g.static_non_parallel}char * v_typeof_interface_${sym.cname}(int sidx);')
|
g.definitions.writeln('${g.static_non_parallel}char * v_typeof_interface_${sym.cname}(int sidx);')
|
||||||
if g.pref.parallel_cc {
|
if g.pref.parallel_cc {
|
||||||
g.extern_out.writeln('extern char * v_typeof_interface_${sym.cname}(int sidx);')
|
g.extern_out.writeln('extern char * v_typeof_interface_${sym.cname}(int sidx);')
|
||||||
|
@ -1805,11 +1810,15 @@ static inline void __${sym.cname}_pushval(${sym.cname} ch, ${push_arg} val) {
|
||||||
interface_non_generic_syms << sym
|
interface_non_generic_syms << sym
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mut already_generated_ifaces := map[string]bool{}
|
||||||
for sym in interface_non_generic_syms {
|
for sym in interface_non_generic_syms {
|
||||||
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
|
if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
g.write_interface_typesymbol_declaration(sym)
|
if sym.cname !in already_generated_ifaces {
|
||||||
|
g.write_interface_typesymbol_declaration(sym)
|
||||||
|
already_generated_ifaces[sym.cname] = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7859,6 +7868,7 @@ fn (mut g Gen) interface_table() string {
|
||||||
}
|
}
|
||||||
mut sb := strings.new_builder(100)
|
mut sb := strings.new_builder(100)
|
||||||
mut conversion_functions := strings.new_builder(100)
|
mut conversion_functions := strings.new_builder(100)
|
||||||
|
mut already_generated_ifaces := map[string]bool{}
|
||||||
interfaces := g.table.type_symbols.filter(it.kind == .interface && it.info is ast.Interface)
|
interfaces := g.table.type_symbols.filter(it.kind == .interface && it.info is ast.Interface)
|
||||||
for isym in interfaces {
|
for isym in interfaces {
|
||||||
inter_info := isym.info as ast.Interface
|
inter_info := isym.info as ast.Interface
|
||||||
|
@ -7868,6 +7878,10 @@ fn (mut g Gen) interface_table() string {
|
||||||
if g.pref.skip_unused && isym.idx !in g.table.used_features.used_syms {
|
if g.pref.skip_unused && isym.idx !in g.table.used_features.used_syms {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if isym.cname in already_generated_ifaces {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
already_generated_ifaces[isym.cname] = true
|
||||||
// interface_name is for example Speaker
|
// interface_name is for example Speaker
|
||||||
interface_name := isym.cname
|
interface_name := isym.cname
|
||||||
// generate a struct that references interface methods
|
// generate a struct that references interface methods
|
||||||
|
|
|
@ -432,6 +432,9 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||||
if !w.uses_array && !w.is_direct_array_access {
|
if !w.uses_array && !w.is_direct_array_access {
|
||||||
w.uses_array = true
|
w.uses_array = true
|
||||||
}
|
}
|
||||||
|
if node.elem_type.has_flag(.option) {
|
||||||
|
w.used_option++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ast.Assoc {
|
ast.Assoc {
|
||||||
w.exprs(node.exprs)
|
w.exprs(node.exprs)
|
||||||
|
@ -1180,6 +1183,9 @@ pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) {
|
||||||
w.mark_by_type(isym.info.key_type)
|
w.mark_by_type(isym.info.key_type)
|
||||||
w.mark_by_type(isym.info.value_type)
|
w.mark_by_type(isym.info.value_type)
|
||||||
w.features.used_maps++
|
w.features.used_maps++
|
||||||
|
if isym.info.value_type.has_flag(.option) {
|
||||||
|
w.used_option++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ast.Alias {
|
ast.Alias {
|
||||||
w.mark_by_type(isym.info.parent_type)
|
w.mark_by_type(isym.info.parent_type)
|
||||||
|
@ -1295,9 +1301,6 @@ fn (mut w Walker) mark_resource_dependencies() {
|
||||||
w.fn_by_name('strings.new_builder')
|
w.fn_by_name('strings.new_builder')
|
||||||
w.uses_free[ast.string_type] = true
|
w.uses_free[ast.string_type] = true
|
||||||
}
|
}
|
||||||
if w.uses_eq {
|
|
||||||
w.fn_by_name('fast_string_eq')
|
|
||||||
}
|
|
||||||
if w.features.auto_str_ptr {
|
if w.features.auto_str_ptr {
|
||||||
w.fn_by_name('isnil')
|
w.fn_by_name('isnil')
|
||||||
w.fn_by_name('tos4')
|
w.fn_by_name('tos4')
|
||||||
|
@ -1594,6 +1597,9 @@ pub fn (mut w Walker) finalize(include_panic_deps bool) {
|
||||||
w.mark_by_sym_name('StrIntpData')
|
w.mark_by_sym_name('StrIntpData')
|
||||||
w.mark_by_sym_name('StrIntpMem')
|
w.mark_by_sym_name('StrIntpMem')
|
||||||
}
|
}
|
||||||
|
if w.uses_eq {
|
||||||
|
w.fn_by_name('fast_string_eq')
|
||||||
|
}
|
||||||
|
|
||||||
// remove unused symbols
|
// remove unused symbols
|
||||||
w.remove_unused_fn_generic_types()
|
w.remove_unused_fn_generic_types()
|
||||||
|
|
|
@ -511,6 +511,10 @@ fn (mut p Parser) at() ast.AtExpr {
|
||||||
'@BUILD_DATE' { token.AtKind.build_date }
|
'@BUILD_DATE' { token.AtKind.build_date }
|
||||||
'@BUILD_TIME' { token.AtKind.build_time }
|
'@BUILD_TIME' { token.AtKind.build_time }
|
||||||
'@BUILD_TIMESTAMP' { token.AtKind.build_timestamp }
|
'@BUILD_TIMESTAMP' { token.AtKind.build_timestamp }
|
||||||
|
'@OS' { token.AtKind.os }
|
||||||
|
'@CCOMPILER' { token.AtKind.ccompiler }
|
||||||
|
'@BACKEND' { token.AtKind.backend }
|
||||||
|
'@PLATFORM' { token.AtKind.platform }
|
||||||
else { token.AtKind.unknown }
|
else { token.AtKind.unknown }
|
||||||
}
|
}
|
||||||
expr := ast.AtExpr{
|
expr := ast.AtExpr{
|
||||||
|
|
|
@ -310,6 +310,11 @@ fn (mut p Parser) import_syms(mut parent ast.Import) {
|
||||||
for p.tok.kind == .name {
|
for p.tok.kind == .name {
|
||||||
pos := p.tok.pos()
|
pos := p.tok.pos()
|
||||||
alias := p.check_name()
|
alias := p.check_name()
|
||||||
|
if alias in p.imported_symbols {
|
||||||
|
p.error_with_pos('cannot register symbol `${alias}`, it was already imported',
|
||||||
|
pos)
|
||||||
|
return
|
||||||
|
}
|
||||||
p.imported_symbols[alias] = parent.mod + '.' + alias
|
p.imported_symbols[alias] = parent.mod + '.' + alias
|
||||||
// so we can work with this in fmt+checker
|
// so we can work with this in fmt+checker
|
||||||
parent.syms << ast.ImportSymbol{
|
parent.syms << ast.ImportSymbol{
|
||||||
|
|
3
vlib/v/parser/tests/module_import_same_symbol2_err.out
Normal file
3
vlib/v/parser/tests/module_import_same_symbol2_err.out
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
vlib/v/parser/tests/module_import_same_symbol2_err.vv:1:20: error: cannot register symbol `max`, it was already imported
|
||||||
|
1 | import math { max, max }
|
||||||
|
| ~~~
|
1
vlib/v/parser/tests/module_import_same_symbol2_err.vv
Normal file
1
vlib/v/parser/tests/module_import_same_symbol2_err.vv
Normal file
|
@ -0,0 +1 @@
|
||||||
|
import math { max, max }
|
4
vlib/v/parser/tests/module_import_same_symbol_err.out
Normal file
4
vlib/v/parser/tests/module_import_same_symbol_err.out
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
vlib/v/parser/tests/module_import_same_symbol_err.vv:2:17: error: cannot register symbol `max`, it was already imported
|
||||||
|
1 | import math { max }
|
||||||
|
2 | import arrays { max }
|
||||||
|
| ~~~
|
2
vlib/v/parser/tests/module_import_same_symbol_err.vv
Normal file
2
vlib/v/parser/tests/module_import_same_symbol_err.vv
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
import math { max }
|
||||||
|
import arrays { max }
|
|
@ -5,4 +5,5 @@ vlib/v/scanner/tests/unknown_comptime_var_err.vv:2:9: error: @ must be used befo
|
||||||
3 | }
|
3 | }
|
||||||
Details: available compile time variables: @VROOT, @VMODROOT, @VEXEROOT, @FN, @METHOD, @MOD,
|
Details: available compile time variables: @VROOT, @VMODROOT, @VEXEROOT, @FN, @METHOD, @MOD,
|
||||||
@STRUCT, @VEXE, @FILE, @DIR, @LINE, @COLUMN, @VHASH, @VCURRENTHASH, @VMOD_FILE, @VMODHASH,
|
@STRUCT, @VEXE, @FILE, @DIR, @LINE, @COLUMN, @VHASH, @VCURRENTHASH, @VMOD_FILE, @VMODHASH,
|
||||||
@FILE_LINE, @LOCATION, @BUILD_DATE, @BUILD_TIME, @BUILD_TIMESTAMP
|
@FILE_LINE, @LOCATION, @BUILD_DATE, @BUILD_TIME, @BUILD_TIMESTAMP, @OS, @CCOMPILER,
|
||||||
|
@BACKEND, @PLATFORM
|
||||||
|
|
|
@ -198,3 +198,27 @@ fn test_at_build_date_time_timestamp() {
|
||||||
now_utc := dump(time.utc().unix())
|
now_utc := dump(time.utc().unix())
|
||||||
assert now_utc >= bts.i64()
|
assert now_utc >= bts.i64()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_at_os() {
|
||||||
|
println('Current OS is ${@OS}')
|
||||||
|
assert @OS in ['termux', 'android', 'wasm32_emscripten', 'linux', 'ios', 'macos', 'windows',
|
||||||
|
'freebsd', 'openbsd', 'netbsd', 'dragonfly', 'serenity', 'plan9', 'vinix', 'solaris', 'haiku',
|
||||||
|
'js_node', 'js_freestanding', 'js_browser']
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_at_ccompiler() {
|
||||||
|
println('Current C Compiler is ${@CCOMPILER}')
|
||||||
|
assert @CCOMPILER in ['gcc', 'tinyc', 'clang', 'emcc', 'mingw', 'msvc', 'cplusplus']
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_at_backend() {
|
||||||
|
println('Current language backend is ${@BACKEND}')
|
||||||
|
assert @BACKEND in ['c', 'golang', 'interpret', 'js_node', 'js_browser', 'js_freestanding',
|
||||||
|
'native', 'wasm']
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_at_platform() {
|
||||||
|
println('Current Platform is ${@PLATFORM}')
|
||||||
|
assert @PLATFORM in ['amd64', 'arm64', 'arm32', 'rv64', 'rv32', 'i386', 's390x', 'ppc64le',
|
||||||
|
'loongarch64', 'js_node', 'js_browser', 'js_freestanding', 'wasm32']
|
||||||
|
}
|
||||||
|
|
79
vlib/v/tests/generics/generic_interface_field_test.v
Normal file
79
vlib/v/tests/generics/generic_interface_field_test.v
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
pub struct Range[T] {
|
||||||
|
pub:
|
||||||
|
from T
|
||||||
|
to T
|
||||||
|
inclusive bool
|
||||||
|
pub mut:
|
||||||
|
step T = T(1)
|
||||||
|
i T
|
||||||
|
mut:
|
||||||
|
started bool
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut r Range[T]) next[T]() ?T {
|
||||||
|
if !r.started {
|
||||||
|
r.started = true
|
||||||
|
assert r.step > 0
|
||||||
|
if r.from > r.to {
|
||||||
|
r.step = -r.step
|
||||||
|
}
|
||||||
|
r.i = r.from
|
||||||
|
}
|
||||||
|
i := r.i
|
||||||
|
next_i := i + r.step
|
||||||
|
if r.inclusive {
|
||||||
|
if r.step < 0 && i < r.to {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
if r.step > 0 && i > r.to {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if r.step < 0 && i <= r.to {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
if r.step > 0 && i >= r.to {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.i = next_i
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface Iterator[T] {
|
||||||
|
mut:
|
||||||
|
next() ?T
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Zip[A, B] {
|
||||||
|
mut:
|
||||||
|
a Iterator[A]
|
||||||
|
b Iterator[B]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Pair[A, B] {
|
||||||
|
a A
|
||||||
|
b B
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut z Zip[A, B]) next[A, B]() ?Pair[A, B] {
|
||||||
|
a := z.a.next()?
|
||||||
|
b := z.b.next()?
|
||||||
|
return Pair[A, B]{a, b}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_main() {
|
||||||
|
mut r1 := Range{
|
||||||
|
from: 5
|
||||||
|
to: 10
|
||||||
|
}
|
||||||
|
_ := Iterator[int](r1)
|
||||||
|
|
||||||
|
mut r2 := Range{
|
||||||
|
from: 10
|
||||||
|
to: 5
|
||||||
|
}
|
||||||
|
_ := Iterator[int](r2)
|
||||||
|
|
||||||
|
_ := Zip[int, int]{}
|
||||||
|
}
|
6
vlib/v/tests/options/option_map_val_test.v
Normal file
6
vlib/v/tests/options/option_map_val_test.v
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
fn test_main() {
|
||||||
|
mut m := map[int]?u32{}
|
||||||
|
if c := m[0] {
|
||||||
|
println('c: ${c} not none!')
|
||||||
|
}
|
||||||
|
}
|
0
vlib/v/tests/skip_unused/option_array_init.run.out
Normal file
0
vlib/v/tests/skip_unused/option_array_init.run.out
Normal file
6
vlib/v/tests/skip_unused/option_array_init.vv
Normal file
6
vlib/v/tests/skip_unused/option_array_init.vv
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
fn main() {
|
||||||
|
mut a := []?u32{len: 0xFF}
|
||||||
|
if c := a[0] {
|
||||||
|
println('c: ${c} not none!')
|
||||||
|
}
|
||||||
|
}
|
|
@ -189,6 +189,10 @@ pub enum AtKind {
|
||||||
build_date
|
build_date
|
||||||
build_time
|
build_time
|
||||||
build_timestamp
|
build_timestamp
|
||||||
|
os
|
||||||
|
ccompiler
|
||||||
|
backend
|
||||||
|
platform
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const assign_tokens = [Kind.assign, .decl_assign, .plus_assign, .minus_assign, .mult_assign,
|
pub const assign_tokens = [Kind.assign, .decl_assign, .plus_assign, .minus_assign, .mult_assign,
|
||||||
|
@ -197,7 +201,8 @@ pub const assign_tokens = [Kind.assign, .decl_assign, .plus_assign, .minus_assig
|
||||||
|
|
||||||
pub const valid_at_tokens = ['@VROOT', '@VMODROOT', '@VEXEROOT', '@FN', '@METHOD', '@MOD', '@STRUCT',
|
pub const valid_at_tokens = ['@VROOT', '@VMODROOT', '@VEXEROOT', '@FN', '@METHOD', '@MOD', '@STRUCT',
|
||||||
'@VEXE', '@FILE', '@DIR', '@LINE', '@COLUMN', '@VHASH', '@VCURRENTHASH', '@VMOD_FILE',
|
'@VEXE', '@FILE', '@DIR', '@LINE', '@COLUMN', '@VHASH', '@VCURRENTHASH', '@VMOD_FILE',
|
||||||
'@VMODHASH', '@FILE_LINE', '@LOCATION', '@BUILD_DATE', '@BUILD_TIME', '@BUILD_TIMESTAMP']
|
'@VMODHASH', '@FILE_LINE', '@LOCATION', '@BUILD_DATE', '@BUILD_TIME', '@BUILD_TIMESTAMP', '@OS',
|
||||||
|
'@CCOMPILER', '@BACKEND', '@PLATFORM']
|
||||||
|
|
||||||
pub const token_str = build_token_str()
|
pub const token_str = build_token_str()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue