Compare commits

...

24 Commits

Author SHA1 Message Date
Delyan Angelov 9d764cd25e
ci: enable again the `v install ui` task
ci/woodpecker/push/vc Pipeline was successful Details
ci/woodpecker/push/docker Pipeline was successful Details
ci/woodpecker/push/arch Pipeline was successful Details
2022-04-21 10:35:00 +02:00
StunxFS 4dd35da9b0
tools: minor cleanup in fast.v (#14117) 2022-04-21 10:35:00 +02:00
ChAoS_UnItY 73260c6fc0
checker, cgen: allow static (fixed) arrays in `in` operator (#14121) 2022-04-21 10:35:00 +02:00
Delyan Angelov 80c278222c
ci: temporarily use `git clone https://github.com/vlang/xyz ~/.vmodules/xyz` instead of `v install xyz` 2022-04-21 10:35:00 +02:00
sunnylcw 864a4ffa6c
doc: add link to V's standard library documentation at the start (#14114) 2022-04-21 10:35:00 +02:00
Delyan Angelov 13e2d73339
bootstrap: remove -I ./thirdparty/stdatomic/nix from make files (#14111) 2022-04-21 10:34:58 +02:00
lemon 262ec40851
builtin: fix `-cc gcc -gc boehm` on linux and macos (#14115) 2022-04-21 10:34:34 +02:00
Nick Treleaven 47ae5a93d4
builtin: remove unnecessary casts for defunct small unsigned warning (#14108) 2022-04-21 10:34:34 +02:00
yuyi 1a76b50004
checker: minor cleanup in assign_stmt() (#14107) 2022-04-21 10:34:34 +02:00
Hunam 1e42538e22
os: small cleanup of function description (#14112) 2022-04-21 10:34:34 +02:00
mjh 43e810024c
datatypes: fix bst child access, when .root is 0 (#14080) 2022-04-21 10:34:34 +02:00
Larpon 1cb4fe5a0a
os: add info about overwritten content to `write_file` (#14109) 2022-04-21 10:34:34 +02:00
yuyi 5ec0820332
ast: minor cleanup of types.v (#14103) 2022-04-21 10:34:34 +02:00
yuyi 81a178ee8d
checker, cgen: use 'stmts.last()' instead of 'stmts[stmts.len - 1]' (#14105) 2022-04-21 10:34:34 +02:00
yuyi 9abf3a62c0
checker: fix error for fn with multi return (#14095) 2022-04-21 10:34:34 +02:00
yuyi f7dbbba7ae
checker: fix error for assign array of aliases (#14096) 2022-04-21 10:34:33 +02:00
Alexander Medvednikov fac15fb862
builtin: define C.abs() 2022-04-21 10:34:33 +02:00
Isaiah ae3906141d
vpm: fix get_all_modules() (#14097) 2022-04-21 10:34:33 +02:00
yuyi 9c7da323f1
checker: check error for arguments of array.contains() (#14102) 2022-04-21 10:34:33 +02:00
playX 9c9b50933c
v.util: add math to builtin_module_names (temporary fix for C2V) (#14100) 2022-04-21 10:34:33 +02:00
playX 0065dba88a
checker: c2v fixes (#14091) 2022-04-21 10:34:33 +02:00
Delyan Angelov f3ce968124
sync: use #insert for atomic.h, so that bootstrapping can be simplified 2022-04-21 10:34:33 +02:00
Delyan Angelov b03aa06152
checker, cgen: add support for #insert, to simplify bootstrapping V 2022-04-21 10:34:33 +02:00
JalonSolov 43efdd464e
checker: fix error message when number of generic parameters is incorrect (#14090) 2022-04-21 10:34:33 +02:00
44 changed files with 451 additions and 151 deletions

View File

@ -429,7 +429,7 @@ jobs:
- name: Test new v.c
run: |
.\v.exe -o v.c cmd/v
gcc -Werror -I ./thirdparty/stdatomic/win -municode -w v.c
gcc -Werror -municode -w v.c
- name: Install dependencies
run: |
.\v.exe setup-freetype
@ -534,7 +534,7 @@ jobs:
- name: Test new v.c
run: |
.\v.exe -o v.c cmd/v
.\thirdparty\tcc\tcc.exe -I ./thirdparty/stdatomic/win -Werror -w -ladvapi32 -bt10 v.c
.\thirdparty\tcc\tcc.exe -Werror -w -ladvapi32 -bt10 v.c
- name: Install dependencies
run: |
.\v.exe setup-freetype
@ -575,7 +575,7 @@ jobs:
## .\v.exe wipe-cache
## .\make.bat -tcc32
## - name: Test new v.c
## run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -I ./thirdparty/stdatomic/win -Werror -g -w -ladvapi32 -bt10 v.c
## run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -Werror -g -w -ladvapi32 -bt10 v.c
## - name: v doctor
## run: ./v doctor
##

View File

@ -14,7 +14,7 @@ jobs:
timeout-minutes: 30
env:
VFLAGS: -cc tcc -no-retry-compilation
B_CFLAGS: -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w
B_CFLAGS: -g -std=gnu11 -w
B_LFLAGS: -lm -lpthread
steps:
- uses: actions/checkout@v2
@ -52,7 +52,7 @@ jobs:
timeout-minutes: 30
env:
VFLAGS: -cc clang
B_CFLAGS: -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w
B_CFLAGS: -g -std=gnu11 -w
B_LFLAGS: -lm -lpthread
steps:
- uses: actions/checkout@v2

View File

@ -71,14 +71,14 @@ jobs:
- name: v.c can be compiled and run with -os cross
run: |
./v -os cross -o /tmp/v.c cmd/v
gcc -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w -o v_from_vc /tmp/v.c -lm -lpthread
gcc -g -std=gnu11 -w -o v_from_vc /tmp/v.c -lm -lpthread
ls -lart v_from_vc
./v_from_vc version
- name: v_win.c can be compiled and run with -os windows
run: |
./v -cc msvc -os windows -o /tmp/v_win.c cmd/v
x86_64-w64-mingw32-gcc -I ./thirdparty/stdatomic/win /tmp/v_win.c -std=c99 -w -municode -o v_from_vc.exe
x86_64-w64-mingw32-gcc /tmp/v_win.c -std=c99 -w -municode -o v_from_vc.exe
ls -lart v_from_vc.exe
wine64 ./v_from_vc.exe version

View File

@ -210,7 +210,7 @@ jobs:
## gitly
- name: Install markdown
run: ./v install markdown
run: git clone https://github.com/vlang/markdown ~/.vmodules/markdown
- name: Build Gitly
run: |
git clone --depth 1 https://github.com/vlang/gitly
@ -222,6 +222,15 @@ jobs:
./x
cd ..
## libsodium
- name: Install libsodium-dev package
run: sudo apt-get install --quiet -y libsodium-dev
- name: Install the libsodium wrapper
run: git clone https://github.com/vlang/libsodium ~/.vmodules/libsodium
- name: Test libsodium
run: VJOBS=1 ./v -stats test ~/.vmodules/libsodium
## vex
- name: Install Vex dependencies
run: sudo apt-get install --quiet -y libsodium-dev libssl-dev sqlite3 libsqlite3-dev
@ -234,18 +243,6 @@ jobs:
- name: Run Vex Tests
run: ./v test ~/.vmodules/nedpals/vex
## vpm modules
- name: Install UI through VPM
run: ./v install ui
## libsodium
- name: Install libsodium-dev package
run: sudo apt-get install --quiet -y libsodium-dev
- name: Installl the libsodium wrapper through VPM
run: ./v install libsodium
- name: Test libsodium
run: VJOBS=1 ./v -stats test ~/.vmodules/libsodium
## Go2V
- name: Clone & Build go2v
run: git clone --depth=1 https://github.com/vlang/go2v go2v/
@ -259,3 +256,7 @@ jobs:
run: git clone --depth=1 https://github.com/vlang/pdf ~/.vmodules/pdf/
- name: PDF examples should compile
run: ./v should-compile-all ~/.vmodules/pdf/examples
## vpm modules
- name: Install UI through VPM
run: ./v install ui

View File

@ -1,10 +1,10 @@
FROM mstorsjo/llvm-mingw
LABEL maintainer="Vitaly Takmazov <vitalyster@gmail.com>"
LABEL maintainer="Delyan Angelov <delian66@gmail.com>"
COPY . .
RUN make
RUN ./v -os windows -o v.c cmd/v
RUN x86_64-w64-mingw32-gcc v.c -std=c99 -I ./thirdparty/stdatomic/win -w -municode -o v.exe
RUN x86_64-w64-mingw32-gcc v.c -std=c99 -w -municode -o v.exe
RUN file v.exe
CMD [ "bash" ]

View File

@ -84,13 +84,13 @@ endif
all: latest_vc latest_tcc
ifdef WIN32
$(CC) $(CFLAGS) -std=c99 -municode -w -I ./thirdparty/stdatomic/nix -o v1.exe $(VC)/$(VCFILE) $(LDFLAGS)
$(CC) $(CFLAGS) -std=c99 -municode -w -o v1.exe $(VC)/$(VCFILE) $(LDFLAGS)
v1.exe -no-parallel -o v2.exe $(VFLAGS) cmd/v
v2.exe -o $(V) $(VFLAGS) cmd/v
del v1.exe
del v2.exe
else
$(CC) $(CFLAGS) -std=gnu99 -w -I ./thirdparty/stdatomic/nix -o v1.exe $(VC)/$(VCFILE) -lm -lpthread $(LDFLAGS)
$(CC) $(CFLAGS) -std=gnu99 -w -o v1.exe $(VC)/$(VCFILE) -lm -lpthread $(LDFLAGS)
./v1.exe -no-parallel -o v2.exe $(VFLAGS) cmd/v
./v2.exe -o $(V) $(VFLAGS) cmd/v
rm -rf v1.exe v2.exe

View File

@ -6,7 +6,7 @@ LDFLAGS ?=
all:
rm -rf vc/
git clone --depth 1 --quiet https://git.rustybever.be/Chewing_Bever/vc
$(CC) $(CFLAGS) -std=gnu11 -w -I ./thirdparty/stdatomic/nix -o v1 vc/v.c -lm -lexecinfo -lpthread $(LDFLAGS)
$(CC) $(CFLAGS) -std=gnu11 -w -o v1 vc/v.c -lm -lexecinfo -lpthread $(LDFLAGS)
./v1 -no-parallel -o v2 $(VFLAGS) cmd/v
./v2 -o v $(VFLAGS) cmd/v
rm -rf v1 v2 vc/

View File

@ -28,7 +28,8 @@ fn main() {
return
}
}
// Fetch the last commit's hash
// fetch the last commit's hash
commit := exec('git rev-parse HEAD')[..8]
if !os.exists('table.html') {
os.create('table.html') ?
@ -42,13 +43,10 @@ fn main() {
return
}
}
// for i, commit in commits {
message := exec('git log --pretty=format:"%s" -n1 $commit')
// println('\n${i + 1}/$commits.len Benchmarking commit $commit "$message"')
println('\nBenchmarking commit $commit "$message"')
// Build an optimized V
// println('Checking out ${commit}...')
// exec('git checkout $commit')
// build an optimized V
println(' Building vprod...')
os.chdir(vdir) ?
if os.args.contains('-noprod') {
@ -56,9 +54,11 @@ fn main() {
} else {
exec('./v -o vprod -prod -prealloc cmd/v')
}
// cache vlib modules
exec('$vdir/v wipe-cache')
exec('$vdir/v -o v2 -prod cmd/v')
// measure
diff1 := measure('$vdir/vprod $voptions -o v.c cmd/v', 'v.c')
mut tcc_path := 'tcc'
@ -71,23 +71,24 @@ fn main() {
if os.args.contains('-clang') {
tcc_path = 'clang'
}
diff2 := measure('$vdir/vprod $voptions -cc $tcc_path -o v2 cmd/v', 'v2')
diff3 := 0 // measure('$vdir/vprod -native $vdir/cmd/tools/1mil.v', 'native 1mil')
diff4 := measure('$vdir/vprod -usecache $voptions -cc clang examples/hello_world.v',
'hello.v')
vc_size := os.file_size('v.c') / 1000
// scan/parse/check/cgen
scan, parse, check, cgen, vlines := measure_steps(vdir)
// println('Building V took ${diff}ms')
commit_date := exec('git log -n1 --pretty="format:%at" $commit')
date := time.unix(commit_date.int())
//
os.chdir(fast_dir) ?
mut out := os.create('table.html') ?
// Place the new row on top
// place the new row on top
html_message := message.replace_each(['<', '&lt;', '>', '&gt;'])
table =
'<tr>
' <tr>
<td>$date.format()</td>
<td><a target=_blank href="https://github.com/vlang/v/commit/$commit">$commit</a></td>
<td>$html_message</td>
@ -106,7 +107,8 @@ fn main() {
table.trim_space()
out.writeln(table) ?
out.close()
// Regenerate index.html
// regenerate index.html
header := os.read_file('header.html') ?
footer := os.read_file('footer.html') ?
mut res := os.create('index.html') ?
@ -114,10 +116,8 @@ fn main() {
res.writeln(table) ?
res.writeln(footer) ?
res.close()
//}
// exec('git checkout master')
// os.write_file('last_commit.txt', commits[commits.len - 1]) ?
// Upload the result to github pages
// upload the result to github pages
if os.args.contains('-upload') {
println('uploading...')
os.chdir('website') ?
@ -134,7 +134,7 @@ fn exec(s string) string {
return e.output.trim_right('\r\n')
}
// returns milliseconds
// measure returns milliseconds
fn measure(cmd string, description string) int {
println(' Measuring $description')
println(' Warming up...')
@ -186,7 +186,7 @@ fn measure_steps(vdir string) (int, int, int, int, int) {
cgen = line[0].int()
}
} else {
// Fetch number of V lines
// fetch number of V lines
if line[0].contains('V') && line[0].contains('source') && line[0].contains('size') {
start := line[0].index(':') or { 0 }
end := line[0].index('lines,') or { 0 }

View File

@ -584,17 +584,22 @@ fn get_all_modules() []string {
mut read_len := 0
mut modules := []string{}
for read_len < s.len {
mut start_token := '<a href="/mod'
mut start_token := "<a href='/mod"
end_token := '</a>'
// get the start index of the module entry
mut start_index := s.index_after(start_token, read_len)
if start_index == -1 {
break
start_token = '<a href="/mod'
start_index = s.index_after(start_token, read_len)
if start_index == -1 {
break
}
}
// get the index of the end of anchor (a) opening tag
// we use the previous start_index to make sure we are getting a module and not just a random 'a' tag
start_token = '">'
start_token = '>'
start_index = s.index_after(start_token, start_index) + start_token.len
// get the index of the end of module entry
end_index := s.index_after(end_token, start_index)
if end_index == -1 {

View File

@ -81,6 +81,18 @@ fn get_all_commands() []Command {
runcmd: .execute
expect: 'Hello, World!\n'
}
if os.getenv('V_CI_MUSL').len == 0 {
for compiler_name in ['clang', 'gcc'] {
if _ := os.find_abs_path_of_executable(compiler_name) {
res << Command{
line: '$vexe -cc $compiler_name -gc boehm run examples/hello_world.v'
okmsg: '`v -cc $compiler_name -gc boehm run examples/hello_world.v` works'
runcmd: .execute
expect: 'Hello, World!\n'
}
}
}
}
res << Command{
line: '$vexe interpret examples/hello_world.v'
okmsg: 'V can interpret hello world.'
@ -210,9 +222,8 @@ fn get_all_commands() []Command {
rmfile: 'examples/tetris/tetris'
}
$if macos || linux {
ipath := '$vroot/thirdparty/stdatomic/nix'
res << Command{
line: '$vexe -o v.c cmd/v && cc -Werror -I ${os.quoted_path(ipath)} v.c -lpthread -lm && rm -rf a.out'
line: '$vexe -o v.c cmd/v && cc -Werror v.c -lpthread -lm && rm -rf a.out'
label: 'v.c should be buildable with no warnings...'
okmsg: 'v.c can be compiled without warnings. This is good :)'
rmfile: 'v.c'

View File

@ -1,5 +1,7 @@
# V Documentation
(See https://modules.vlang.io/ for documentation of V's standard library)
## Introduction
V is a statically typed compiled programming language designed for building maintainable software.

View File

@ -119,7 +119,7 @@ REM By default, use tcc, since we have it prebuilt:
:tcc_strap
:tcc32_strap
echo ^> Attempting to build v_win.c with "!tcc_exe!"
"!tcc_exe!" -Bthirdparty/tcc -Ithirdparty/stdatomic/win -bt10 -g -w -o v.exe vc\v_win.c -ladvapi32
"!tcc_exe!" -Bthirdparty/tcc -bt10 -g -w -o v.exe vc\v_win.c -ladvapi32
if %ERRORLEVEL% NEQ 0 goto :compile_error
echo ^> Compiling .\v.exe with itself
v.exe -keepc -g -showcc -cc "!tcc_exe!" -cflags -Bthirdparty/tcc -o v2.exe cmd/v
@ -137,7 +137,7 @@ if %ERRORLEVEL% NEQ 0 (
)
echo ^> Attempting to build v_win.c with Clang
clang -std=c99 -Ithirdparty/stdatomic/win -municode -g -w -o v.exe .\vc\v_win.c -ladvapi32
clang -std=c99 -municode -g -w -o v.exe .\vc\v_win.c -ladvapi32
if %ERRORLEVEL% NEQ 0 (
echo In most cases, compile errors happen because the version of Clang installed is too old
clang --version
@ -160,7 +160,7 @@ if %ERRORLEVEL% NEQ 0 (
)
echo ^> Attempting to build v_win.c with GCC
gcc -std=c99 -municode -Ithirdparty/stdatomic/win -g -w -o v.exe .\vc\v_win.c -ladvapi32
gcc -std=c99 -municode -g -w -o v.exe .\vc\v_win.c -ladvapi32
if %ERRORLEVEL% NEQ 0 (
echo In most cases, compile errors happen because the version of GCC installed is too old
gcc --version
@ -202,7 +202,7 @@ if exist "%InstallDir%\Common7\Tools\vsdevcmd.bat" (
set ObjFile=.v.c.obj
echo ^> Attempting to build v_win.c with MSVC
cl.exe /volatile:ms /I thirdparty\stdatomic\win /Fo%ObjFile% /O2 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no
cl.exe /volatile:ms /Fo%ObjFile% /O2 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no
if %ERRORLEVEL% NEQ 0 (
echo In some cases, compile errors happen because of the MSVC compiler version
cl.exe

View File

@ -32,13 +32,14 @@ $if dynamic_boehm ? {
$if macos || linux {
#flag -DGC_PTHREADS=1
#flag -I@VEXEROOT/thirdparty/libgc/include
#flag -lpthread -ldl
#flag -lpthread
$if (prod && !tinyc && !debug) || !(amd64 || arm64 || i386 || arm32) {
// TODO: replace the architecture check with a `!$exists("@VEXEROOT/thirdparty/tcc/lib/libgc.a")` comptime call
#flag @VEXEROOT/thirdparty/libgc/gc.o
} $else {
#flag @VEXEROOT/thirdparty/tcc/lib/libgc.a
}
#flag -ldl
} $else $if freebsd {
// Tested on FreeBSD 13.0-RELEASE-p3, with clang, gcc and tcc:
#flag -DBUS_PAGE_FAULT=T_PAGEFLT

View File

@ -53,6 +53,7 @@ fn C.chmod(&char, u32) int
fn C.printf(&char, ...voidptr) int
fn C.puts(&char) int
fn C.abs(f64) f64
fn C.fputs(str &char, stream &C.FILE) int

View File

@ -775,7 +775,7 @@ fn test_byte_keys() {
m[i]++
assert m[i] == i + 1
}
assert m.len == int(byte_max)
assert m.len == byte_max
keys := m.keys()
for i in u8(0) .. byte_max {
assert keys[i] == i
@ -827,7 +827,7 @@ fn test_u16_keys() {
m[i]++
assert m[i] == i + 1
}
assert m.len == int(end)
assert m.len == end
keys := m.keys()
for i in u16(0) .. end {
assert keys[i] == i

View File

@ -763,7 +763,7 @@ fn test_byte_keys() {
m[i]++
assert m[i] == i + 1
}
assert m.len == int(byte_max)
assert m.len == byte_max
keys := m.keys()
for i in u8(0) .. byte_max {
assert keys[i] == i
@ -815,7 +815,7 @@ fn test_u16_keys() {
m[i]++
assert m[i] == i + 1
}
assert m.len == int(end)
assert m.len == end
keys := m.keys()
for i in u16(0) .. end {
assert keys[i] == i

View File

@ -1937,7 +1937,7 @@ pub fn (name string) match_glob(pattern string) bool {
mut is_inverted := false
mut inner_match := false
mut inner_idx := bstart + 1
mut inner_c := u8(0)
mut inner_c := 0
if inner_idx < plen {
inner_c = pattern[inner_idx]
if inner_c == `^` {

View File

@ -113,7 +113,7 @@ fn (bst &BSTree<T>) contains_helper(node &BSTreeNode<T>, value T) bool {
// remove removes an element with `value` from the BST.
pub fn (mut bst BSTree<T>) remove(value T) bool {
if bst.root == 0 {
if bst.is_empty() {
return false
}
return bst.remove_helper(mut bst.root, value, false)
@ -153,6 +153,9 @@ fn (mut bst BSTree<T>) remove_helper(mut node BSTreeNode<T>, value T, left bool)
// get_max_from_right returns the max element of the BST following the right branch.
fn (bst &BSTree<T>) get_max_from_right(node &BSTreeNode<T>) &BSTreeNode<T> {
if node == 0 {
return new_none_node<T>(false)
}
right_node := node.right
if right_node == 0 || !right_node.is_init {
return node
@ -162,6 +165,9 @@ fn (bst &BSTree<T>) get_max_from_right(node &BSTreeNode<T>) &BSTreeNode<T> {
// get_min_from_left returns the min element of the BST by following the left branch.
fn (bst &BSTree<T>) get_min_from_left(node &BSTreeNode<T>) &BSTreeNode<T> {
if node == 0 {
return new_none_node<T>(false)
}
left_node := node.left
if left_node == 0 || !left_node.is_init {
return node
@ -251,6 +257,9 @@ fn (bst &BSTree<T>) get_node(node &BSTreeNode<T>, value T) &BSTreeNode<T> {
// left_value, exist := bst.to_left(10)
//```
pub fn (bst &BSTree<T>) to_left(value T) ?T {
if bst.is_empty() {
return none
}
node := bst.get_node(bst.root, value)
if !node.is_init {
return none
@ -267,6 +276,9 @@ pub fn (bst &BSTree<T>) to_left(value T) ?T {
// left_value, exist := bst.to_right(10)
//```
pub fn (bst &BSTree<T>) to_right(value T) ?T {
if bst.is_empty() {
return none
}
node := bst.get_node(bst.root, value)
if !node.is_init {
return none
@ -278,6 +290,9 @@ pub fn (bst &BSTree<T>) to_right(value T) ?T {
// max return the max element inside the BST.
// Time complexity O(N) if the BST is not balanced
pub fn (bst &BSTree<T>) max() ?T {
if bst.is_empty() {
return none
}
max := bst.get_max_from_right(bst.root)
if !max.is_init {
return none
@ -288,6 +303,9 @@ pub fn (bst &BSTree<T>) max() ?T {
// min return the minimum element in the BST.
// Time complexity O(N) if the BST is not balanced.
pub fn (bst &BSTree<T>) min() ?T {
if bst.is_empty() {
return none
}
min := bst.get_min_from_left(bst.root)
if !min.is_init {
return none

View File

@ -116,6 +116,7 @@ fn test_remove_from_bst_two() {
// check if we are able to get the max from the BST.
fn test_get_max_in_bst() {
mut bst := BSTree<int>{}
assert (bst.max() or { -1 }) == -1
assert bst.insert(10)
assert bst.insert(20)
assert bst.insert(21)
@ -127,6 +128,7 @@ fn test_get_max_in_bst() {
// check if we are able to get the min from the BST.
fn test_get_min_in_bst() {
mut bst := BSTree<int>{}
assert (bst.min() or { -1 }) == -1
assert bst.insert(10)
assert bst.insert(20)
assert bst.insert(21)

View File

@ -367,7 +367,8 @@ pub fn expand_tilde_to_home(path string) string {
return path
}
// write_file writes `text` data to a file in `path`.
// write_file writes `text` data to the file in `path`.
// If `path` exists, the contents of `path` will be overwritten with the contents of `text`.
pub fn write_file(path string, text string) ? {
mut f := create(path) ?
unsafe { f.write_full_buffer(text.str, usize(text.len)) ? }

View File

@ -5,8 +5,10 @@ module stdatomic
$if windows {
#flag -I @VEXEROOT/thirdparty/stdatomic/win
#insert "@VEXEROOT/thirdparty/stdatomic/win/atomic.h"
} $else {
#flag -I @VEXEROOT/thirdparty/stdatomic/nix
#insert "@VEXEROOT/thirdparty/stdatomic/nix/atomic.h"
}
$if linux {
@ -48,7 +50,6 @@ $if linux {
}
}
#include <atomic.h>
// The following functions are actually generic in C
fn C.atomic_load_ptr(voidptr) voidptr
fn C.atomic_store_ptr(voidptr, voidptr)

View File

@ -262,8 +262,7 @@ pub fn (t Type) str() string {
}
pub fn (t &Table) type_str(typ Type) string {
sym := t.sym(typ)
return sym.name
return t.sym(typ).name
}
// debug returns a verbose representation of the information in the type `t`, useful for tracing/debugging
@ -375,7 +374,7 @@ pub fn (typ Type) is_unsigned() bool {
}
pub fn (typ Type) flip_signedness() Type {
r := match typ {
return match typ {
ast.i8_type { ast.byte_type }
ast.i16_type { ast.u16_type }
ast.int_type { ast.u32_type }
@ -388,7 +387,6 @@ pub fn (typ Type) flip_signedness() Type {
ast.u64_type { ast.i64_type }
else { typ }
}
return r
}
[inline]
@ -510,7 +508,7 @@ pub const (
)
pub fn merge_types(params ...[]Type) []Type {
mut res := []Type{}
mut res := []Type{cap: params.len}
for types in params {
res << types
}
@ -518,10 +516,10 @@ pub fn merge_types(params ...[]Type) []Type {
}
pub fn mktyp(typ Type) Type {
match typ {
ast.float_literal_type { return ast.f64_type }
ast.int_literal_type { return ast.int_type }
else { return typ }
return match typ {
ast.float_literal_type { ast.f64_type }
ast.int_literal_type { ast.int_type }
else { typ }
}
}
@ -827,7 +825,7 @@ pub fn (t &TypeSymbol) is_builtin() bool {
// for debugging/errors only, perf is not an issue
pub fn (k Kind) str() string {
k_str := match k {
return match k {
.placeholder { 'placeholder' }
.void { 'void' }
.voidptr { 'voidptr' }
@ -868,7 +866,6 @@ pub fn (k Kind) str() string {
.aggregate { 'aggregate' }
.thread { 'thread' }
}
return k_str
}
pub fn (kinds []Kind) str() string {

View File

@ -275,18 +275,10 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
if !c.inside_unsafe && !c.pref.translated && !c.file.is_translated {
c.error('modifying variables via dereferencing can only be done in `unsafe` blocks',
node.pos)
} else {
} else if mut left.right is ast.Ident {
// mark `p` in `*p = val` as used:
match mut left.right {
ast.Ident {
match mut left.right.obj {
ast.Var {
left.right.obj.is_used = true
}
else {}
}
}
else {}
if mut left.right.obj is ast.Var {
left.right.obj.is_used = true
}
}
}
@ -330,14 +322,25 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
left_sym := c.table.sym(left_type_unwrapped)
right_sym := c.table.sym(right_type_unwrapped)
if left_sym.kind == .array && !c.inside_unsafe && node.op in [.assign, .decl_assign]
&& right_sym.kind == .array && (left is ast.Ident && !left.is_blank_ident())
&& right_sym.kind == .array && left is ast.Ident && !left.is_blank_ident()
&& right is ast.Ident {
// Do not allow `a = b`, only `a = b.clone()`
c.error('use `array2 $node.op.str() array1.clone()` instead of `array2 $node.op.str() array1` (or use `unsafe`)',
node.pos)
}
if left_sym.kind == .array && right_sym.kind == .array {
// `mut arr := [u8(1),2,3]`
// `arr = [byte(4),5,6]`
left_info := left_sym.info as ast.Array
left_elem_type := c.table.unaliased_type(left_info.elem_type)
right_info := right_sym.info as ast.Array
right_elem_type := c.table.unaliased_type(right_info.elem_type)
if left_info.nr_dims == right_info.nr_dims && left_elem_type == right_elem_type {
continue
}
}
if left_sym.kind == .array_fixed && !c.inside_unsafe && node.op in [.assign, .decl_assign]
&& right_sym.kind == .array_fixed && (left is ast.Ident && !left.is_blank_ident())
&& right_sym.kind == .array_fixed && left is ast.Ident && !left.is_blank_ident()
&& right is ast.Ident {
if right_sym.info is ast.ArrayFixed {
if right_sym.info.elem_type.is_ptr() {
@ -347,8 +350,8 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
}
}
if left_sym.kind == .map && node.op in [.assign, .decl_assign] && right_sym.kind == .map
&& ((right is ast.Ident && right.is_auto_deref_var())
|| !right_type.is_ptr()) && !left.is_blank_ident() && right.is_lvalue() {
&& !left.is_blank_ident() && right.is_lvalue()
&& (!right_type.is_ptr() || (right is ast.Ident && right.is_auto_deref_var())) {
// Do not allow `a = b`
c.error('cannot copy map: call `move` or `clone` method (or use a reference)',
right.pos())
@ -364,8 +367,8 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
c.error('cannot assign to `$left`: ' +
c.expected_msg(right_type_unwrapped, left_type_unwrapped), right.pos())
}
if (right is ast.StructInit || !right_is_ptr) && !(right_sym.is_number()
|| left_type.has_flag(.shared_f)) {
if !right_sym.is_number() && !left_type.has_flag(.shared_f)
&& (right is ast.StructInit || !right_is_ptr) {
left_name := c.table.type_to_str(left_type_unwrapped)
mut rtype := right_type_unwrapped
if rtype.is_ptr() {
@ -476,8 +479,8 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
else {}
}
if node.op in [.plus_assign, .minus_assign, .mod_assign, .mult_assign, .div_assign]
&& ((left_sym.kind == .struct_ && right_sym.kind == .struct_)
|| left_sym.kind == .alias) {
&& (left_sym.kind == .alias || (left_sym.kind == .struct_
&& right_sym.kind == .struct_)) {
left_name := c.table.type_to_str(left_type_unwrapped)
right_name := c.table.type_to_str(right_type_unwrapped)
parent_sym := c.table.final_sym(left_type_unwrapped)
@ -552,7 +555,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
is_shared = left_first.info.share == .shared_t
}
old_inside_ref_lit := c.inside_ref_lit
c.inside_ref_lit = (c.inside_ref_lit || right_node.op == .amp || is_shared)
c.inside_ref_lit = c.inside_ref_lit || right_node.op == .amp || is_shared
c.expr(right_node.right)
c.inside_ref_lit = old_inside_ref_lit
if right_node.op == .amp {

View File

@ -429,13 +429,13 @@ fn (mut c Checker) check_shift(mut node ast.InfixExpr, left_type ast.Type, right
pub fn (mut c Checker) promote(left_type ast.Type, right_type ast.Type) ast.Type {
if left_type.is_any_kind_of_pointer() {
if right_type.is_int() {
if right_type.is_int() || c.pref.translated {
return left_type
} else {
return ast.void_type
}
} else if right_type.is_any_kind_of_pointer() {
if left_type.is_int() {
if left_type.is_int() || c.pref.translated {
return right_type
} else {
return ast.void_type
@ -489,6 +489,8 @@ fn (c &Checker) promote_num(left_type ast.Type, right_type ast.Type) ast.Type {
return if idx_lo == ast.i64_type_idx { type_lo } else { type_hi }
} else if idx_hi - idx_lo < (ast.byte_type_idx - ast.i8_type_idx) {
return type_lo // conversion unsigned -> signed if signed type is larger
} else if c.pref.translated {
return type_hi
} else {
return ast.void_type // conversion signed -> unsigned not allowed
}

View File

@ -442,7 +442,7 @@ pub fn (mut c Checker) alias_type_decl(node ast.AliasTypeDecl) {
c.check_valid_pascal_case(node.name, 'type alias', node.pos)
}
c.ensure_type_exists(node.parent_type, node.type_pos) or { return }
typ_sym := c.table.sym(node.parent_type)
mut typ_sym := c.table.sym(node.parent_type)
if typ_sym.kind in [.placeholder, .int_literal, .float_literal] {
c.error('unknown type `$typ_sym.name`', node.type_pos)
} else if typ_sym.kind == .alias {
@ -594,6 +594,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
}
}
mut return_type := left_type
if node.op != .key_is {
match mut node.left {
ast.Ident, ast.SelectorExpr {
@ -661,6 +662,15 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
}
node.left_type = map_info.key_type
}
.array_fixed {
if left_sym.kind !in [.sum_type, .interface_] {
elem_type := right_final.array_fixed_info().elem_type
c.check_expected(left_type, elem_type) or {
c.error('left operand to `$node.op` does not match the fixed array element type: $err.msg()',
left_right_pos)
}
}
}
else {
c.error('`$node.op.str()` can only be used with arrays and maps',
node.pos)
@ -681,7 +691,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
left_sym = c.table.sym((left_sym.info as ast.Alias).parent_type)
}
// Check if the alias type is not a primitive then allow using operator overloading for aliased `arrays` and `maps`
if left_sym.kind == .alias && left_sym.info is ast.Alias
if !c.pref.translated && left_sym.kind == .alias && left_sym.info is ast.Alias
&& !(c.table.sym((left_sym.info as ast.Alias).parent_type).is_primitive()) {
if left_sym.has_method(node.op.str()) {
if method := left_sym.find_method(node.op.str()) {
@ -699,7 +709,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
c.error('mismatched types `$left_name` and `$right_name`', left_right_pos)
}
}
} else if right_sym.kind == .alias && right_sym.info is ast.Alias
} else if !c.pref.translated && right_sym.kind == .alias && right_sym.info is ast.Alias
&& !(c.table.sym((right_sym.info as ast.Alias).parent_type).is_primitive()) {
if right_sym.has_method(node.op.str()) {
if method := right_sym.find_method(node.op.str()) {
@ -806,6 +816,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
if node.op in [.div, .mod] {
c.check_div_mod_by_zero(node.right, node.op)
}
return_type = promoted_type
}
}
@ -2260,7 +2271,8 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
return
}
match node.kind {
'include' {
'include', 'insert' {
original_flag := node.main
mut flag := node.main
if flag.contains('@VROOT') {
// c.note(checker.vroot_is_deprecated_message, node.pos)
@ -2268,13 +2280,13 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
c.error(err.msg(), node.pos)
return
}
node.val = 'include $vroot'
node.val = '$node.kind $vroot'
node.main = vroot
flag = vroot
}
if flag.contains('@VEXEROOT') {
vroot := flag.replace('@VEXEROOT', os.dir(pref.vexe_path()))
node.val = 'include $vroot'
node.val = '$node.kind $vroot'
node.main = vroot
flag = vroot
}
@ -2283,7 +2295,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
c.error(err.msg(), node.pos)
return
}
node.val = 'include $vroot'
node.val = '$node.kind $vroot'
node.main = vroot
flag = vroot
}
@ -2295,10 +2307,33 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
node.main = env
}
flag_no_comment := flag.all_before('//').trim_space()
if !((flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"'))
|| (flag_no_comment.starts_with('<') && flag_no_comment.ends_with('>'))) {
c.error('including C files should use either `"header_file.h"` or `<header_file.h>` quoting',
node.pos)
if node.kind == 'include' {
if !((flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"'))
|| (flag_no_comment.starts_with('<') && flag_no_comment.ends_with('>'))) {
c.error('including C files should use either `"header_file.h"` or `<header_file.h>` quoting',
node.pos)
}
}
if node.kind == 'insert' {
if !(flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"')) {
c.error('inserting .c or .h files, should use `"header_file.h"` quoting',
node.pos)
}
node.main = node.main.trim('"')
if fcontent := os.read_file(node.main) {
node.val = fcontent
} else {
mut missing_message := 'The file $original_flag, needed for insertion by module `$node.mod`,'
if os.is_file(node.main) {
missing_message += ' is not readable.'
} else {
missing_message += ' does not exist.'
}
if node.msg != '' {
missing_message += ' ${node.msg}.'
}
c.error(missing_message, node.pos)
}
}
}
'pkgconfig' {
@ -2361,7 +2396,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
}
else {
if node.kind != 'define' {
c.error('expected `#define`, `#flag`, `#include` or `#pkgconfig` not $node.val',
c.error('expected `#define`, `#flag`, `#include`, `#insert` or `#pkgconfig` not $node.val',
node.pos)
}
}
@ -3471,7 +3506,7 @@ pub fn (mut c Checker) lock_expr(mut node ast.LockExpr) ast.Type {
// handle `x := rlock a { a.getval() }`
mut ret_type := ast.void_type
if node.stmts.len > 0 {
last_stmt := node.stmts[node.stmts.len - 1]
last_stmt := node.stmts.last()
if last_stmt is ast.ExprStmt {
ret_type = last_stmt.typ
}

View File

@ -302,7 +302,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
// c.table.cur_fn = node
// Add return if `fn(...) ? {...}` have no return at end
if node.return_type != ast.void_type && node.return_type.has_flag(.optional)
&& (node.stmts.len == 0 || node.stmts[node.stmts.len - 1] !is ast.Return) {
&& (node.stmts.len == 0 || node.stmts.last() !is ast.Return) {
sym := c.table.sym(node.return_type)
if sym.kind == .void {
node.stmts << ast.Return{
@ -708,8 +708,8 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
}
if node.concrete_types.len > 0 && func.generic_names.len > 0
&& node.concrete_types.len != func.generic_names.len {
desc := if node.concrete_types.len > func.generic_names.len { 'many' } else { 'little' }
c.error('too $desc generic parameters got $node.concrete_types.len, expected $func.generic_names.len',
plural := if func.generic_names.len == 1 { '' } else { 's' }
c.error('expected $func.generic_names.len generic parameter$plural, got $node.concrete_types.len',
node.concrete_list_pos)
}
for concrete_type in node.concrete_types {
@ -781,6 +781,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
if func.params.len == 0 {
continue
}
param := if func.is_variadic && i >= func.params.len - 1 {
func.params[func.params.len - 1]
} else {
@ -1231,12 +1232,8 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
}
if node.concrete_types.len > 0 && method.generic_names.len > 0
&& node.concrete_types.len != method.generic_names.len {
desc := if node.concrete_types.len > method.generic_names.len {
'many'
} else {
'little'
}
c.error('too $desc generic parameters got $node.concrete_types.len, expected $method.generic_names.len',
plural := if method.generic_names.len == 1 { '' } else { 's' }
c.error('expected $method.generic_names.len generic parameter$plural, got $node.concrete_types.len',
node.concrete_list_pos)
}
for concrete_type in node.concrete_types {
@ -1277,6 +1274,7 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
}
exp_arg_sym := c.table.sym(exp_arg_typ)
c.expected_type = exp_arg_typ
mut got_arg_typ := c.check_expr_opt_call(arg.expr, c.expr(arg.expr))
node.args[i].typ = got_arg_typ
if no_type_promotion {
@ -1895,6 +1893,17 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as
node.return_type = ast.void_type
} else if method_name == 'contains' {
// c.warn('use `value in arr` instead of `arr.contains(value)`', node.pos)
if node.args.len != 1 {
c.error('`.contains()` expected 1 argument, but got $node.args.len', node.pos)
} else {
arg_typ := ast.mktyp(c.expr(node.args[0].expr))
elem_typ_str := c.table.type_to_str(elem_typ)
arg_typ_str := c.table.type_to_str(arg_typ)
if !left_sym.has_method('contains') && elem_typ_str != arg_typ_str {
c.error('`.contains()` expected `$elem_typ_str` argument, but got `$arg_typ_str`',
node.pos)
}
}
node.return_type = ast.bool_type
} else if method_name == 'index' {
node.return_type = ast.int_type

View File

@ -11,8 +11,8 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
mut node_is_expr := false
if node.branches.len > 0 && node.has_else {
stmts := node.branches[0].stmts
if stmts.len > 0 && stmts[stmts.len - 1] is ast.ExprStmt
&& (stmts[stmts.len - 1] as ast.ExprStmt).typ != ast.void_type {
if stmts.len > 0 && stmts.last() is ast.ExprStmt
&& (stmts.last() as ast.ExprStmt).typ != ast.void_type {
node_is_expr = true
}
}
@ -173,6 +173,13 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
continue
}
last_expr.typ = c.expr(last_expr.expr)
if c.table.type_kind(c.expected_type) == .multi_return
&& c.table.type_kind(last_expr.typ) == .multi_return {
if node.typ == ast.void_type {
node.is_expr = true
node.typ = c.expected_type
}
}
if !c.check_types(last_expr.typ, node.typ) {
if node.typ == ast.void_type {
// first branch of if expression
@ -210,6 +217,15 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
if is_noreturn_callexpr(last_expr.expr) {
continue
}
node_sym := c.table.sym(node.typ)
last_sym := c.table.sym(last_expr.typ)
if node_sym.kind == .multi_return && last_sym.kind == .multi_return {
node_types := node_sym.mr_info().types
last_types := last_sym.mr_info().types.map(ast.mktyp(it))
if node_types == last_types {
continue
}
}
c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(last_expr.typ)}`',
node.pos)

View File

@ -72,7 +72,7 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
expr_type := c.expr(stmt.expr)
if first_iteration {
if node.is_expr && (node.expected_type.has_flag(.optional)
|| c.table.type_kind(node.expected_type) == .sum_type) {
|| c.table.type_kind(node.expected_type) in [.sum_type, .multi_return]) {
ret_type = node.expected_type
} else {
ret_type = expr_type
@ -86,6 +86,14 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
&& (ret_type.has_flag(.generic)
|| c.table.is_sumtype_or_in_variant(ret_type, expr_type)))
&& !is_noreturn {
expr_sym := c.table.sym(expr_type)
if expr_sym.kind == .multi_return && ret_sym.kind == .multi_return {
ret_types := ret_sym.mr_info().types
expr_types := expr_sym.mr_info().types.map(ast.mktyp(it))
if expr_types == ret_types {
continue
}
}
c.error('return type mismatch, it should be `$ret_sym.name`',
stmt.expr.pos())
}

View File

@ -0,0 +1,35 @@
vlib/v/checker/tests/array_contains_args_err.vv:3:17: error: `.contains()` expected `int` argument, but got `[]int`
1 | fn main() {
2 | arr := [0]
3 | mut ret := [0].contains([0])
| ~~~~~~~~~~~~~
4 | ret = [0].contains()
5 | ret = [0, 1, 2].contains(0, 1, 2)
vlib/v/checker/tests/array_contains_args_err.vv:4:12: error: `.contains()` expected 1 argument, but got 0
2 | arr := [0]
3 | mut ret := [0].contains([0])
4 | ret = [0].contains()
| ~~~~~~~~~~
5 | ret = [0, 1, 2].contains(0, 1, 2)
6 | ret = [0].contains('a')
vlib/v/checker/tests/array_contains_args_err.vv:5:18: error: `.contains()` expected 1 argument, but got 3
3 | mut ret := [0].contains([0])
4 | ret = [0].contains()
5 | ret = [0, 1, 2].contains(0, 1, 2)
| ~~~~~~~~~~~~~~~~~
6 | ret = [0].contains('a')
7 | ret = [0].contains(arr)
vlib/v/checker/tests/array_contains_args_err.vv:6:12: error: `.contains()` expected `int` argument, but got `string`
4 | ret = [0].contains()
5 | ret = [0, 1, 2].contains(0, 1, 2)
6 | ret = [0].contains('a')
| ~~~~~~~~~~~~~
7 | ret = [0].contains(arr)
8 | println(ret)
vlib/v/checker/tests/array_contains_args_err.vv:7:12: error: `.contains()` expected `int` argument, but got `[]int`
5 | ret = [0, 1, 2].contains(0, 1, 2)
6 | ret = [0].contains('a')
7 | ret = [0].contains(arr)
| ~~~~~~~~~~~~~
8 | println(ret)
9 | }

View File

@ -0,0 +1,9 @@
fn main() {
arr := [0]
mut ret := [0].contains([0])
ret = [0].contains()
ret = [0, 1, 2].contains(0, 1, 2)
ret = [0].contains('a')
ret = [0].contains(arr)
println(ret)
}

View File

@ -4,24 +4,24 @@ vlib/v/checker/tests/check_err_msg_with_generics.vv:15:10: error: cannot cast st
15 | println(int(typ))
| ~~~~~~~~
16 | }
vlib/datatypes/bstree.v:190:17: error: cannot append `T` to `[]T`
188 | }
189 | bst.in_order_traversal_helper(node.left, mut result)
190 | result << node.value
vlib/datatypes/bstree.v:196:17: error: cannot append `T` to `[]T`
194 | }
195 | bst.in_order_traversal_helper(node.left, mut result)
196 | result << node.value
| ~~~~~
191 | bst.in_order_traversal_helper(node.right, mut result)
192 | }
vlib/datatypes/bstree.v:210:17: error: cannot append `T` to `[]T`
208 | bst.post_order_traversal_helper(node.left, mut result)
209 | bst.post_order_traversal_helper(node.right, mut result)
210 | result << node.value
197 | bst.in_order_traversal_helper(node.right, mut result)
198 | }
vlib/datatypes/bstree.v:216:17: error: cannot append `T` to `[]T`
214 | bst.post_order_traversal_helper(node.left, mut result)
215 | bst.post_order_traversal_helper(node.right, mut result)
216 | result << node.value
| ~~~~~
211 | }
212 |
vlib/datatypes/bstree.v:226:17: error: cannot append `T` to `[]T`
224 | return
225 | }
226 | result << node.value
217 | }
218 |
vlib/datatypes/bstree.v:232:17: error: cannot append `T` to `[]T`
230 | return
231 | }
232 | result << node.value
| ~~~~~
227 | bst.pre_order_traversal_helper(node.left, mut result)
228 | bst.pre_order_traversal_helper(node.right, mut result)
233 | bst.pre_order_traversal_helper(node.left, mut result)
234 | bst.pre_order_traversal_helper(node.right, mut result)

View File

@ -0,0 +1 @@
// just some text

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/comptime_insert_err.vv:6:1: error: The file "@VEXEROOT/vlib/v/checker/tests/Non_Existant_File.cc", needed for insertion by module `main`, does not exist.
4 | // some more comments
5 |
6 | #insert "@VEXEROOT/vlib/v/checker/tests/Non_Existant_File.cc"
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 |
8 | fn main() {

View File

@ -0,0 +1,10 @@
// The following file exists, so there should not be a checker error for it:
#insert "@VEXEROOT/vlib/v/checker/tests/comptime_insert_err.cc"
// some more comments
#insert "@VEXEROOT/vlib/v/checker/tests/Non_Existant_File.cc"
fn main() {
println('hello')
}

View File

@ -1,25 +1,25 @@
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:12:18: error: too little generic parameters got 1, expected 2
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:12:18: error: expected 2 generic parameters, got 1
10 |
11 | fn main() {
12 | ret1 := get_name<int>(11, 22)
| ~~~~~
13 | println(ret1)
14 |
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:15:18: error: too many generic parameters got 3, expected 2
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:15:18: error: expected 2 generic parameters, got 3
13 | println(ret1)
14 |
15 | ret2 := get_name<int, int, string>(11, 22, 'hello')
| ~~~~~~~~~~~~~~~~~~
16 | println(ret2)
17 |
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:19:22: error: too little generic parameters got 1, expected 2
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:19:22: error: expected 2 generic parameters, got 1
17 |
18 | foo := Foo{}
19 | ret3 := foo.get_name<int>(11, 22)
| ~~~~~
20 | println(ret3)
21 |
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:22:22: error: too many generic parameters got 3, expected 2
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:22:22: error: expected 2 generic parameters, got 3
20 | println(ret3)
21 |
22 | ret4 := foo.get_name<int, int, string>(11, 22, 'hello')

View File

@ -1,5 +1,5 @@
vlib/v/checker/tests/generics_too_many_parameters.vv:6:8: error: too many generic parameters got 5, expected 1
4 |
vlib/v/checker/tests/generics_too_many_parameters.vv:6:8: error: expected 1 generic parameter, got 5
4 |
5 | fn main() {
6 | foo<bool, int, bool, bool, int>(1)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -1797,6 +1797,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
g.writeln('goto ${c_name(node.name)};')
}
ast.HashStmt {
line_nr := node.pos.line_nr + 1
mut ct_condition := ''
if node.ct_conds.len > 0 {
ct_condition_start := g.out.len
@ -1830,7 +1831,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
}
// Objective C code import, include it after V types, so that e.g. `string` is
// available there
g.definitions.writeln('// added by module `$node.mod`')
g.definitions.writeln('// added by module `$node.mod`, file: ${os.file_name(node.source_file)}:$line_nr:')
g.definitions.writeln(guarded_include)
if ct_condition.len > 0 {
g.definitions.writeln('#endif // \$if $ct_condition')
@ -1841,13 +1842,22 @@ fn (mut g Gen) stmt(node ast.Stmt) {
if ct_condition.len > 0 {
g.includes.writeln('#if $ct_condition')
}
g.includes.writeln('// added by module `$node.mod`')
g.includes.writeln('// added by module `$node.mod`, file: ${os.file_name(node.source_file)}:$line_nr:')
g.includes.writeln(guarded_include)
if ct_condition.len > 0 {
g.includes.writeln('#endif // \$if $ct_condition')
}
g.includes.writeln('\n')
}
} else if node.kind == 'insert' {
if ct_condition.len > 0 {
g.includes.writeln('#if $ct_condition')
}
g.includes.writeln('// inserted by module `$node.mod`, file: ${os.file_name(node.source_file)}:$line_nr:')
g.includes.writeln(node.val)
if ct_condition.len > 0 {
g.includes.writeln('#endif // \$if $ct_condition')
}
} else if node.kind == 'define' {
if ct_condition.len > 0 {
g.includes.writeln('#if $ct_condition')
@ -4933,8 +4943,8 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
g.inside_or_block = false
}
stmts := or_block.stmts
if stmts.len > 0 && stmts[or_block.stmts.len - 1] is ast.ExprStmt
&& (stmts[stmts.len - 1] as ast.ExprStmt).typ != ast.void_type {
if stmts.len > 0 && stmts.last() is ast.ExprStmt
&& (stmts.last() as ast.ExprStmt).typ != ast.void_type {
g.indent++
for i, stmt in stmts {
if i == stmts.len - 1 {
@ -4956,7 +4966,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
g.indent--
} else {
g.stmts(stmts)
if stmts.len > 0 && stmts[or_block.stmts.len - 1] is ast.ExprStmt {
if stmts.len > 0 && stmts.last() is ast.ExprStmt {
g.writeln(';')
}
}

View File

@ -441,6 +441,54 @@ fn (mut g Gen) infix_expr_in_op(node ast.InfixExpr) {
g.expr(node.right)
}
g.write(')')
} else if right.unaliased_sym.kind == .array_fixed {
if left.sym.kind in [.sum_type, .interface_] {
if node.right is ast.ArrayInit {
if node.right.exprs.len > 0 {
mut infix_exprs := []ast.InfixExpr{}
for i in 0 .. node.right.exprs.len {
infix_exprs << ast.InfixExpr{
op: .key_is
left: node.left
left_type: node.left_type
right: node.right.exprs[i]
right_type: node.right.expr_types[i]
}
}
g.write('(')
g.infix_expr_in_sumtype_interface_array(infix_exprs)
g.write(')')
return
}
}
}
if node.right is ast.ArrayInit {
if node.right.exprs.len > 0 {
// `a in [1,2,3]!` optimization => `a == 1 || a == 2 || a == 3`
// avoids an allocation
g.write('(')
g.infix_expr_in_optimization(node.left, node.right)
g.write(')')
return
}
}
if right.sym.info is ast.Array {
elem_type := right.sym.info.elem_type
elem_type_ := g.unwrap(elem_type)
if elem_type_.sym.kind == .sum_type {
if node.left_type in elem_type_.sym.sumtype_info().variants {
new_node_left := ast.CastExpr{
arg: ast.EmptyExpr{}
typ: elem_type
expr: node.left
expr_type: node.left_type
}
g.gen_array_contains(node.right_type, node.right, new_node_left)
return
}
}
}
g.gen_array_contains(node.right_type, node.right, node.left)
} else if right.unaliased_sym.kind == .string {
g.write('string_contains(')
g.expr(node.right)

View File

@ -282,7 +282,7 @@ fn (mut g JsGen) infix_in_not_in_op(node ast.InfixExpr) {
if node.op == .not_in {
g.write('!')
}
if r_sym.unaliased_sym.kind == .array {
if r_sym.unaliased_sym.kind in [.array, .array_fixed] {
fn_name := g.gen_array_contains_method(node.right_type)
g.write('(${fn_name}(')
g.expr(node.right)

View File

@ -69,7 +69,7 @@ fn (mut p Parser) array_init() ast.ArrayInit {
// [100]u8
elem_type = p.parse_type()
if p.table.sym(elem_type).name == 'byte' {
p.error('`byte` has been deprecated in favor of `u8`: use `[10]u8` instead of `[10]byte`')
p.error('`byte` has been deprecated in favor of `u8`: use `[10]u8{}` instead of `[10]byte{}`')
}
last_pos = p.tok.pos()
is_fixed = true

View File

@ -0,0 +1,10 @@
fn test_assign_array_of_aliases() {
mut arr := [u8(1), 2, 3]
arr = [byte(4), 5, 6]
println(arr)
assert arr.len == 3
assert arr[0] == 4
assert arr[1] == 5
assert arr[2] == 6
}

View File

@ -0,0 +1,8 @@
fn test_fixed_array_in_op() {
assert 1 in [1, 2]!
assert `a` in [`a`, `b`]!
assert 'a' in ['a', 'b']!
ch := `"`
assert ch in [`"`, `'`]!
}

View File

@ -0,0 +1,49 @@
fn multret1(i int, j int) (int, int) {
return if i > j { i, 10 } else { 10, j }
}
fn multret2(i int, j int) (int, int) {
return match i > j {
true { i, 10 }
false { 10, j }
}
}
fn multret3(i int, j int) (int, int) {
if i > j {
return i, 10
} else {
return 10, j
}
}
fn multret4(i int, j int) (int, int) {
match i > j {
true { return i, 10 }
false { return 10, j }
}
}
fn test_fn_multi_return() {
mut a, mut b := 0, 0
println(multret1(3, 14))
a, b = multret1(3, 14)
assert a == 10
assert b == 14
println(multret2(3, 14))
a, b = multret2(3, 14)
assert a == 10
assert b == 14
println(multret3(3, 14))
a, b = multret3(3, 14)
assert a == 10
assert b == 14
println(multret4(3, 14))
a, b = multret4(3, 14)
assert a == 10
assert b == 14
}

View File

@ -36,7 +36,7 @@ const (
]
)
const builtin_module_names = ['builtin', 'strconv', 'strings', 'dlmalloc']
const builtin_module_names = ['builtin', 'strconv', 'strings', 'dlmalloc', 'math']
pub fn module_is_builtin(mod string) bool {
// NOTE: using util.builtin_module_parts here breaks -usecache on macos