Skip to content

Commit

Permalink
Merge branch 'master' into fix_c_struct_embedded
Browse files Browse the repository at this point in the history
  • Loading branch information
spytheman authored Mar 30, 2024
2 parents a427691 + d49fd0f commit b4f8fcc
Show file tree
Hide file tree
Showing 36 changed files with 354 additions and 136 deletions.
14 changes: 13 additions & 1 deletion .github/workflows/v_apps_and_modules_compile_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ jobs:
# v -cc gcc run /tmp/gitly/tests/first_run.v
# # /tmp/gitly/gitly -ci_run
- name: Build V Language Server (v-analyzer) vlang/v-analyzer
- name: Build vlang/v-analyzer
run: |
echo "Clone v-analyzer"
.github/workflows/retry.sh git clone --depth=1 --filter=blob:none --recursive --shallow-submodules https://github.com/vlang/v-analyzer /tmp/v-analyzer
Expand All @@ -119,6 +119,18 @@ jobs:
echo "Build v-analyzer release"
v build.vsh release
- name: Format vlang/v-analyzer
run: |
cd /tmp/v-analyzer
set +e
v fmt -c .
exit_code=$?
if [[ $exit_code -ne 0 && $exit_code -ne 5 ]]; then
# Don't fail on on internal errors
v fmt -diff .
exit 1
fi
- name: Build vlang/go2v
run: |
echo "Clone Go2V"
Expand Down
3 changes: 1 addition & 2 deletions cmd/tools/vvet/vet_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ fn check_path(vexe string, dir string, tests []string) int {
for path in paths {
program := path
print(path + ' ')
// -force is needed so that `v vet` would not skip the regression files
res := os.execute('${os.quoted_path(vexe)} vet -force -nocolor ${os.quoted_path(program)}')
res := os.execute('${os.quoted_path(vexe)} vet -nocolor ${os.quoted_path(program)}')
if res.exit_code < 0 {
panic(res.output)
}
Expand Down
30 changes: 14 additions & 16 deletions cmd/tools/vvet/vvet.v
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ struct Options {

const term_colors = term.can_show_color_on_stderr()
const clean_seq = ['[', '', ']', '', ' ', '']
const exclude_dirs = ['test', 'slow_test', 'testdata']

fn main() {
vet_options := cmdline.options_after(os.args, ['vet'])
mut vt := Vet{
opt: Options{
is_force: '-force' in vet_options
is_werror: '-W' in vet_options
is_verbose: '-verbose' in vet_options || '-v' in vet_options
show_warnings: '-hide-warnings' !in vet_options && '-w' !in vet_options
Expand All @@ -64,14 +64,19 @@ fn main() {
}
if os.is_dir(path) {
vt.vprintln("vetting folder: '${path}' ...")
vfiles := os.walk_ext(path, '.v')
vvfiles := os.walk_ext(path, '.vv')
mut files := []string{}
files << vfiles
files << vvfiles
for file in files {
vt.vet_file(file)
}
overwrite_exclude := exclude_dirs.any(path.contains(it))
os.walk(path, fn [mut vt, overwrite_exclude] (p string) {
if p.ends_with('.v') || p.ends_with('.vv') {
if !overwrite_exclude {
for d in exclude_dirs {
if p.contains(d) {
return
}
}
}
vt.vet_file(p)
}
})
}
}
vfmt_err_count := vt.errors.filter(it.fix == .vfmt).len
Expand All @@ -96,13 +101,6 @@ fn main() {

// vet_file vets the file read from `path`.
fn (mut vt Vet) vet_file(path string) {
if !vt.opt.is_force && (path.contains('/tests/') || path.contains('/slow_tests/')) {
// skip all /tests/ files, since usually their content is not
// important enough to be documented/vetted, and they may even
// contain intentionally invalid code.
vt.vprintln("skipping test file: '${path}' ...")
return
}
vt.file = path
mut prefs := pref.new_preferences()
prefs.is_vet = true
Expand Down
35 changes: 32 additions & 3 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,12 @@ fn (mut c Checker) check_valid_pascal_case(name string, identifier string, pos t
}

fn (mut c Checker) type_decl(node ast.TypeDecl) {
if node.typ == ast.invalid_type_idx && (node is ast.AliasTypeDecl || node is ast.SumTypeDecl) {
typ_desc := if node is ast.AliasTypeDecl { 'alias' } else { 'sum type' }
c.error('cannot register ${typ_desc} `${node.name}`, another type with this name exists',
node.pos)
return
}
match node {
ast.AliasTypeDecl { c.alias_type_decl(node) }
ast.FnTypeDecl { c.fn_type_decl(node) }
Expand Down Expand Up @@ -579,7 +585,9 @@ fn (mut c Checker) alias_type_decl(node ast.AliasTypeDecl) {
}
// The rest of the parent symbol kinds are also allowed, since they are either primitive types,
// that in turn do not allow recursion, or are abstract enough so that they can not be checked at comptime:
else {}
else {
c.check_any_type(node.parent_type, parent_typ_sym, node.type_pos)
}
/*
.voidptr, .byteptr, .charptr {}
.char, .rune, .bool {}
Expand All @@ -602,6 +610,13 @@ fn (mut c Checker) check_alias_vs_element_type_of_parent(node ast.AliasTypeDecl,
node.type_pos)
}

fn (mut c Checker) check_any_type(typ ast.Type, sym &ast.TypeSymbol, pos token.Pos) {
if sym.kind == .any && !typ.has_flag(.generic) && sym.language != .js
&& c.file.mod.name != 'builtin' {
c.error('cannot use type `any` here', pos)
}
}

fn (mut c Checker) fn_type_decl(node ast.FnTypeDecl) {
c.check_valid_pascal_case(node.name, 'fn type', node.pos)
typ_sym := c.table.sym(node.typ)
Expand Down Expand Up @@ -693,6 +708,7 @@ and use a reference to the sum type instead: `var := &${node.name}(${variant_nam
}
}
}
c.check_any_type(variant.typ, sym, variant.pos)

if sym.name.trim_string_left(sym.mod + '.') == node.name {
c.error('sum type cannot hold itself', variant.pos)
Expand Down Expand Up @@ -1732,6 +1748,7 @@ fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
prev_const_var := c.const_var
c.const_var = unsafe { field }
mut typ := c.check_expr_option_or_result_call(field.expr, c.expr(mut field.expr))
typ = c.cast_fixed_array_ret(typ, c.table.sym(typ))
if ct_value := c.eval_comptime_const_expr(field.expr, 0) {
field.comptime_expr_value = ct_value
if ct_value is u64 {
Expand Down Expand Up @@ -1777,6 +1794,11 @@ fn (mut c Checker) const_decl(mut node ast.ConstDecl) {

fn (mut c Checker) enum_decl(mut node ast.EnumDecl) {
c.check_valid_pascal_case(node.name, 'enum name', node.pos)
if node.typ == ast.invalid_type_idx {
c.error('cannot register enum `${node.name}`, another type with this name exists',
node.pos)
return
}
mut useen := []u64{}
mut iseen := []i64{}
mut seen_enum_field_names := map[string]int{}
Expand Down Expand Up @@ -3038,6 +3060,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
if to_type.has_flag(.result) {
c.error('casting to Result type is forbidden', node.pos)
}
c.check_any_type(to_type, to_sym, node.pos)

if (to_sym.is_number() && from_sym.name == 'JS.Number')
|| (to_sym.is_number() && from_sym.name == 'JS.BigInt')
Expand Down Expand Up @@ -3855,7 +3878,12 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
fn (mut c Checker) concat_expr(mut node ast.ConcatExpr) ast.Type {
mut mr_types := []ast.Type{}
for mut expr in node.vals {
mr_types << c.expr(mut expr)
mut typ := c.expr(mut expr)
if typ == ast.nil_type {
// nil and voidptr produces the same struct type name
typ = ast.voidptr_type
}
mr_types << typ
}
if node.vals.len == 1 {
typ := mr_types[0]
Expand Down Expand Up @@ -4259,7 +4287,8 @@ fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type {
}
}
// TODO: testing ref/deref strategy
if node.op == .amp && !right_type.is_ptr() {
right_is_ptr := right_type.is_ptr()
if node.op == .amp && (!right_is_ptr || (right_is_ptr && node.right is ast.CallExpr)) {
mut expr := node.right
// if ParExpr get the innermost expr
for mut expr is ast.ParExpr {
Expand Down
4 changes: 3 additions & 1 deletion vlib/v/checker/struct.v
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,9 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
c.warn('byte is deprecated, use u8 instead', field.type_pos)
}
}
else {}
else {
c.check_any_type(field.typ, sym, field.type_pos)
}
}

if field.has_default_expr {
Expand Down
3 changes: 0 additions & 3 deletions vlib/v/checker/tests/alias_type_exists.out

This file was deleted.

3 changes: 3 additions & 0 deletions vlib/v/checker/tests/alias_type_unkown.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
vlib/v/checker/tests/alias_type_unkown.vv:1:15: error: unknown type `Bird`
1 | type Pigeon = Bird
| ~~~~
File renamed without changes.
34 changes: 34 additions & 0 deletions vlib/v/checker/tests/any_type_err.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
vlib/v/checker/tests/any_type_err.vv:3:16: error: cannot use type `any` here
1 | // Any types should error, while parametrically polymorphic should not.
2 |
3 | type AnyType = any
| ~~~
4 | type AnySumType = any | string
5 | type AnyPolySumType = T | any
vlib/v/checker/tests/any_type_err.vv:4:19: error: cannot use type `any` here
2 |
3 | type AnyType = any
4 | type AnySumType = any | string
| ~~~
5 | type AnyPolySumType = T | any
6 |
vlib/v/checker/tests/any_type_err.vv:5:27: error: cannot use type `any` here
3 | type AnyType = any
4 | type AnySumType = any | string
5 | type AnyPolySumType = T | any
| ~~~
6 |
7 | type PolyType = T
vlib/v/checker/tests/any_type_err.vv:11:6: error: cannot use type `any` here
9 |
10 | struct AnyStructField[T] {
11 | foo any
| ~~~
12 | bar T
13 | }
vlib/v/checker/tests/any_type_err.vv:16:7: error: cannot use type `any` here
14 |
15 | fn any_cast() {
16 | _ := any('foo')
| ~~~~~~~~~~
17 | }
17 changes: 17 additions & 0 deletions vlib/v/checker/tests/any_type_err.vv
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Any types should error, while parametrically polymorphic should not.

type AnyType = any
type AnySumType = any | string
type AnyPolySumType = T | any

type PolyType = T
type PolySumType = T | string

struct AnyStructField[T] {
foo any
bar T
}

fn any_cast() {
_ := any('foo')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
vlib/v/checker/tests/assign_ref_call_expr_with_ref_return_err.vv:8:6: error: cannot take the address of foo()
6 | }
7 |
8 | _ := &foo()
| ^
9 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@[heap]
struct Foo {}

fn foo() &Foo {
return &Foo{}
}

_ := &foo()

2 changes: 1 addition & 1 deletion vlib/v/checker/tests/struct_field_with_any_type_err.out
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
vlib/v/checker/tests/struct_field_with_any_type_err.vv:2:6: error: cannot use `any` type here
vlib/v/checker/tests/struct_field_with_any_type_err.vv:2:6: error: cannot use type `any` here
1 | struct My_type {
2 | fld any
| ~~~
Expand Down
28 changes: 28 additions & 0 deletions vlib/v/checker/tests/type_exists_err.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
vlib/v/checker/tests/type_exists_err.vv:3:1: error: cannot register alias `Foo`, another type with this name exists
1 | struct Foo {}
2 |
3 | type Foo = Foo
| ~~~~~~~~
4 |
5 | type Foo = string
vlib/v/checker/tests/type_exists_err.vv:5:1: error: cannot register alias `Foo`, another type with this name exists
3 | type Foo = Foo
4 |
5 | type Foo = string
| ~~~~~~~~
6 |
7 | type Foo = int | string
vlib/v/checker/tests/type_exists_err.vv:7:1: error: cannot register sum type `Foo`, another type with this name exists
5 | type Foo = string
6 |
7 | type Foo = int | string
| ~~~~~~~~
8 |
9 | enum Foo {
vlib/v/checker/tests/type_exists_err.vv:9:1: error: cannot register enum `Foo`, another type with this name exists
7 | type Foo = int | string
8 |
9 | enum Foo {
| ~~~~~~~~
10 | @none
11 | }
11 changes: 11 additions & 0 deletions vlib/v/checker/tests/type_exists_err.vv
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
struct Foo {}

type Foo = Foo

type Foo = string

type Foo = int | string

enum Foo {
@none
}
Loading

0 comments on commit b4f8fcc

Please sign in to comment.