Skip to content

Commit

Permalink
Merge branch 'vlang:master' into fix-vinit_caller
Browse files Browse the repository at this point in the history
  • Loading branch information
kbkpbot authored Jan 20, 2025
2 parents 3e66827 + f9d3bd3 commit a1803b8
Show file tree
Hide file tree
Showing 20 changed files with 205 additions and 41 deletions.
3 changes: 2 additions & 1 deletion cmd/tools/modules/testing/common.v
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,8 @@ pub fn new_test_session(_vargs string, will_compile bool) TestSession {
if !os.exists('/usr/local/include/wkhtmltox/pdf.h') {
skip_files << 'examples/c_interop_wkhtmltopdf.v' // needs installation of wkhtmltopdf from https://github.com/wkhtmltopdf/packaging/releases
}
skip_files << 'vlib/veb/tests/veb_app_test.v' // imports the `sqlite` module, which in turn includes sqlite3.h
skip_files << 'vlib/vweb/vweb_app_test.v' // imports the `sqlite` module, which in turn includes `sqlite3.h`
skip_files << 'vlib/veb/tests/veb_app_test.v' // imports the `sqlite` module, which in turn includes `sqlite3.h`
}
$if !macos {
skip_files << 'examples/macos_tray/tray.v'
Expand Down
2 changes: 1 addition & 1 deletion cmd/tools/test_if_v_test_system_works.v
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ fn check_assert_continues_works() ! {
result.has('assert_continues_option_works_test.v:5: fn test_fail2')
result.has('> assert 2 == 4').has('> assert 2 == 1').has('> assert 2 == 0')
// Check if a test function, tagged with [assert_continues], has the same behaviour, without needing additional options
create_test('assert_continues_tag_works_test.v', '[assert_continues]fn test_fail1() { assert 2==4\nassert 2==1\nassert 2==0 }\nfn test_ok(){ assert true }\nfn test_fail2() { assert false\n assert false }')!
create_test('assert_continues_tag_works_test.v', '@[assert_continues]fn test_fail1() { assert 2==4\nassert 2==1\nassert 2==0 }\nfn test_ok(){ assert true }\nfn test_fail2() { assert false\n assert false }')!
tag_res := check_fail('${vexe} assert_continues_tag_works_test.v')
tag_res.has('assert_continues_tag_works_test.v:1: fn test_fail1')
tag_res.has('assert_continues_tag_works_test.v:2: fn test_fail1')
Expand Down
4 changes: 2 additions & 2 deletions doc/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -5768,8 +5768,8 @@ Deprecated functions cause warnings, which cause errors if built with `-prod`. T
CI breakage, it is advisable to set a future date, ahead of the date when the code is merged. This
gives people who actively developed V projects, the chance to see the deprecation notice at least
once and fix the uses. Setting a date in the next 30 days, assumes they would have compiled their
projects manually at least once, within that time. For small changes, this should be plenty time.
For complex changes, this time may need to be longer.
projects manually at least once, within that time. For small changes, this should be plenty
of time. For complex changes, this time may need to be longer.
Different V projects and maintainers may reasonably choose different deprecation policies.
Depending on the type and impact of the change, you may want to consult with them first, before
Expand Down
2 changes: 1 addition & 1 deletion vlib/regex/regex_util.v
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ pub fn (mut re RE) replace(in_txt string, repl_str string) string {
return res.str()
}

// replace_n return a string where the firts count matches are replaced with the repl_str string,
// replace_n return a string where the first count matches are replaced with the repl_str string,
// if count is > 0 the replace began from the start of the string toward the end
// if count is < 0 the replace began from the end of the string toward the start
// if count is 0 do nothing
Expand Down
5 changes: 3 additions & 2 deletions vlib/v/ast/ast.v
Original file line number Diff line number Diff line change
Expand Up @@ -925,8 +925,9 @@ pub:
name string
pos token.Pos
typ Type
smartcasts []Type // nested sum types require nested smart casting, for that a list of types is needed
orig_type Type // original sumtype type; 0 if it's not a sumtype
orig_type Type // original sumtype type; 0 if it's not a sumtype
pub mut:
smartcasts []Type // nested sum types require nested smart casting, for that a list of types is needed
// TODO: move this to a real docs site later
// 10 <- original type (orig_type)
// [11, 12, 13] <- cast order (smartcasts)
Expand Down
10 changes: 10 additions & 0 deletions vlib/v/ast/scope.v
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,16 @@ pub fn (mut s Scope) register_struct_field(name string, field ScopeStructField)
s.struct_fields[name] = field
}

pub fn (mut s Scope) register_or_update_struct_field(name string, field ScopeStructField) {
if mut f := s.struct_fields[name] {
if f.struct_type == field.struct_type && f.name == field.name {
s.struct_fields[name].smartcasts = field.smartcasts
return
}
}
s.struct_fields[name] = field
}

pub fn (mut s Scope) register(obj ScopeObject) {
if !(obj.name == '_' || obj.name in s.objects) {
s.objects[obj.name] = obj
Expand Down
35 changes: 24 additions & 11 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -4273,7 +4273,7 @@ fn (mut c Checker) smartcast(mut expr ast.Expr, cur_type ast.Type, to_type_ ast.
mut is_mut := false
mut smartcasts := []ast.Type{}
expr_sym := c.table.sym(expr.expr_type)
mut orig_type := 0
mut orig_type := ast.no_type
if field := c.table.find_field(expr_sym, expr.field_name) {
if field.is_mut {
if root_ident := expr.root_ident() {
Expand All @@ -4286,20 +4286,33 @@ fn (mut c Checker) smartcast(mut expr ast.Expr, cur_type ast.Type, to_type_ ast.
orig_type = field.typ
}
}
if field := scope.find_struct_field(expr.expr.str(), expr.expr_type, expr.field_name) {
mut nested_unwrap := false
if mut field := scope.find_struct_field(expr.expr.str(), expr.expr_type, expr.field_name) {
smartcasts << field.smartcasts
nested_unwrap = smartcasts.len > 1
}
// smartcast either if the value is immutable or if the mut argument is explicitly given
if !is_mut || expr.is_mut || is_option_unwrap {
if !is_mut || expr.is_mut || is_option_unwrap || orig_type.has_flag(.option) {
smartcasts << to_type
scope.register_struct_field(expr.expr.str(), ast.ScopeStructField{
struct_type: expr.expr_type
name: expr.field_name
typ: cur_type
smartcasts: smartcasts
pos: expr.pos
orig_type: orig_type
})
if nested_unwrap {
scope.register_or_update_struct_field(expr.expr.str(), ast.ScopeStructField{
struct_type: expr.expr_type
name: expr.field_name
typ: cur_type
smartcasts: smartcasts
pos: expr.pos
orig_type: orig_type
})
} else {
scope.register_struct_field(expr.expr.str(), ast.ScopeStructField{
struct_type: expr.expr_type
name: expr.field_name
typ: cur_type
smartcasts: smartcasts
pos: expr.pos
orig_type: orig_type
})
}
} else {
c.smartcast_mut_pos = expr.pos
}
Expand Down
27 changes: 15 additions & 12 deletions vlib/v/checker/match.v
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,18 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
} else {
node.expected_type
}
expr_type := if stmt.expr is ast.CallExpr {
expr_type := c.unwrap_generic(if stmt.expr is ast.CallExpr {
stmt.typ
} else {
c.expr(mut stmt.expr)
}
})
unwrapped_expected_type := c.unwrap_generic(node.expected_type)
stmt.typ = expr_type
if first_iteration {
if node.expected_type.has_option_or_result()
|| c.table.type_kind(node.expected_type) in [.sum_type, .multi_return] {
c.check_match_branch_last_stmt(stmt, node.expected_type, expr_type)
if unwrapped_expected_type.has_option_or_result()
|| c.table.type_kind(unwrapped_expected_type) in [.sum_type, .multi_return] {
c.check_match_branch_last_stmt(stmt, unwrapped_expected_type,
expr_type)
ret_type = node.expected_type
} else {
ret_type = expr_type
Expand All @@ -105,10 +107,9 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
}
} else {
if ret_type.idx() != expr_type.idx() {
if node.expected_type.has_option_or_result()
if unwrapped_expected_type.has_option_or_result()
&& c.table.sym(stmt.typ).kind == .struct
&& (c.table.sym(ret_type).kind != .sum_type
|| !c.check_types(expr_type, ret_type))
&& !c.check_types(expr_type, c.unwrap_generic(ret_type))
&& c.type_implements(stmt.typ, ast.error_type, node.pos) {
stmt.expr = ast.CastExpr{
expr: stmt.expr
Expand All @@ -119,7 +120,8 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
}
stmt.typ = ast.error_type
} else {
c.check_match_branch_last_stmt(stmt, ret_type, expr_type)
c.check_match_branch_last_stmt(stmt, c.unwrap_generic(ret_type),
expr_type)
if ret_type.is_number() && expr_type.is_number() && !c.inside_return {
ret_type = c.promote_num(ret_type, expr_type)
}
Expand All @@ -130,13 +132,13 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
stmt_sym := c.table.sym(stmt.typ)
if ret_sym.kind !in [.sum_type, .interface]
&& stmt_sym.kind in [.sum_type, .interface] {
c.error('return type mismatch, it should be `${ret_sym.name}`',
c.error('return type mismatch, it should be `${ret_sym.name}`, but it is instead `${c.table.type_to_str(expr_type)}`',
stmt.pos)
}
if ret_type.nr_muls() != stmt.typ.nr_muls()
&& stmt.typ.idx() !in [ast.voidptr_type_idx, ast.nil_type_idx] {
type_name := '&'.repeat(ret_type.nr_muls()) + ret_sym.name
c.error('return type mismatch, it should be `${type_name}`',
c.error('return type mismatch, it should be `${type_name}`, but it is instead `${c.table.type_to_str(expr_type)}`',
stmt.pos)
}
}
Expand Down Expand Up @@ -279,7 +281,8 @@ fn (mut c Checker) check_match_branch_last_stmt(last_stmt ast.ExprStmt, ret_type
return
}
}
c.error('return type mismatch, it should be `${ret_sym.name}`', last_stmt.pos)
c.error('return type mismatch, it should be `${ret_sym.name}`, but it is instead `${c.table.type_to_str(expr_type)}`',
last_stmt.pos)
}
} else if expr_type == ast.void_type && ret_type.idx() == ast.void_type_idx
&& ret_type.has_option_or_result() {
Expand Down
5 changes: 4 additions & 1 deletion vlib/v/checker/str.v
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,15 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type {
mut ftyp := c.expr(mut expr)
ftyp = c.type_resolver.get_type_or_default(expr, c.check_expr_option_or_result_call(expr,
ftyp))
if ftyp == ast.void_type {
if ftyp == ast.void_type || ftyp == 0 {
c.error('expression does not return a value', expr.pos())
} else if ftyp == ast.char_type && ftyp.nr_muls() == 0 {
c.error('expression returning type `char` cannot be used in string interpolation directly, print its address or cast it to an integer instead',
expr.pos())
}
if ftyp == 0 {
return ast.void_type
}
c.markused_string_inter_lit(mut node, ftyp)
c.fail_if_unreadable(expr, ftyp, 'interpolation object')
node.expr_types << ftyp
Expand Down
49 changes: 49 additions & 0 deletions vlib/v/checker/tests/invalid_generic_field_err.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
vlib/v/checker/tests/invalid_generic_field_err.vv:4:15: error: type `User` has no field named `typo`
2 |
3 | fn (u &User) debug_1() {
4 | println('${u.typo}')
| ~~~~
5 | }
6 |
vlib/v/checker/tests/invalid_generic_field_err.vv:4:15: error: expression does not return a value
2 |
3 | fn (u &User) debug_1() {
4 | println('${u.typo}')
| ~~~~
5 | }
6 |
vlib/v/checker/tests/invalid_generic_field_err.vv:8:9: error: `User` has no property `typo`
6 |
7 | fn debug_2[T](t T) {
8 | _ := t.typo
| ~~~~
9 | }
10 |
vlib/v/checker/tests/invalid_generic_field_err.vv:8:4: error: assignment mismatch: 1 variable 0 values
6 |
7 | fn debug_2[T](t T) {
8 | _ := t.typo
| ~~
9 | }
10 |
vlib/v/checker/tests/invalid_generic_field_err.vv:12:15: error: `User` has no property `typo`
10 |
11 | fn debug_3[T](t T) {
12 | println('${t.typo}')
| ~~~~
13 | }
14 |
vlib/v/checker/tests/invalid_generic_field_err.vv:12:15: error: expression does not return a value
10 |
11 | fn debug_3[T](t T) {
12 | println('${t.typo}')
| ~~~~
13 | }
14 |
vlib/v/checker/tests/invalid_generic_field_err.vv:12:2: error: `println` can not print void expressions
10 |
11 | fn debug_3[T](t T) {
12 | println('${t.typo}')
| ~~~~~~~~~~~~~~~~~~~~
13 | }
14 |
20 changes: 20 additions & 0 deletions vlib/v/checker/tests/invalid_generic_field_err.vv
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
struct User {}

fn (u &User) debug_1() {
println('${u.typo}')
}

fn debug_2[T](t T) {
_ := t.typo
}

fn debug_3[T](t T) {
println('${t.typo}')
}

fn main() {
u := &User{}
u.debug_1()
debug_2(u)
debug_3(u)
}
7 changes: 7 additions & 0 deletions vlib/v/checker/tests/match_generic_case_err.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
vlib/v/checker/tests/match_generic_case_err.vv:16:4: error: return type mismatch, it should be `int`, but it is instead `string`
14 | }
15 | 'int' {
16 | v
| ^
17 | }
18 | else {
22 changes: 22 additions & 0 deletions vlib/v/checker/tests/match_generic_case_err.vv
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module main

import strconv

fn main() {
println(to_int('1'))
println(to_int(1))
}

fn to_int[T](v T) i64 {
return match typeof(v).name {
'string' {
strconv.atoi(v) or { 0 }
}
'int' {
v
}
else {
0
}
}
}
10 changes: 5 additions & 5 deletions vlib/v/checker/tests/match_return_mismatch_type_err.out
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,35 @@ vlib/v/checker/tests/match_return_mismatch_type_err.vv:27:6: warning: cannot ass
| ^
28 | string { &any }
29 | else { &variable }
vlib/v/checker/tests/match_return_mismatch_type_err.vv:4:10: error: return type mismatch, it should be `string`
vlib/v/checker/tests/match_return_mismatch_type_err.vv:4:10: error: return type mismatch, it should be `string`, but it is instead `int literal`
2 | a := match 1 {
3 | 1 { 'aa' }
4 | else { 22 }
| ~~
5 | }
6 | println(a)
vlib/v/checker/tests/match_return_mismatch_type_err.vv:18:10: error: return type mismatch, it should be `&string`
vlib/v/checker/tests/match_return_mismatch_type_err.vv:18:10: error: return type mismatch, it should be `&string`, but it is instead `string`
16 | _ = match any {
17 | string { &any }
18 | else { variable }
| ~~~~~~~~
19 | }
20 |
vlib/v/checker/tests/match_return_mismatch_type_err.vv:23:10: error: return type mismatch, it should be `string`
vlib/v/checker/tests/match_return_mismatch_type_err.vv:23:10: error: return type mismatch, it should be `string`, but it is instead `&string`
21 | _ = match any {
22 | string { any }
23 | else { &variable }
| ^
24 | }
25 |
vlib/v/checker/tests/match_return_mismatch_type_err.vv:43:10: error: return type mismatch, it should be `&string`
vlib/v/checker/tests/match_return_mismatch_type_err.vv:43:10: error: return type mismatch, it should be `&string`, but it is instead `string`
41 | _ = match any {
42 | string { &any }
43 | else { variable }
| ~~~~~~~~
44 | }
45 |
vlib/v/checker/tests/match_return_mismatch_type_err.vv:48:10: error: return type mismatch, it should be `string`
vlib/v/checker/tests/match_return_mismatch_type_err.vv:48:10: error: return type mismatch, it should be `string`, but it is instead `&string`
46 | _ = match any {
47 | string { any }
48 | else { &variable }
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/tests/match_return_sumtype_mismatch_err.out
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
vlib/v/checker/tests/match_return_sumtype_mismatch_err.vv:15:11: error: return type mismatch, it should be `Myt`
vlib/v/checker/tests/match_return_sumtype_mismatch_err.vv:15:11: error: return type mismatch, it should be `Myt`, but it is instead `rune`
13 | return match b {
14 | true { St('TRUE') }
15 | false { `F` }
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/tests/return_match_expr_type_mismatch.out
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
vlib/v/checker/tests/return_match_expr_type_mismatch.vv:18:16: error: return type mismatch, it should be `SomeTuple`
vlib/v/checker/tests/return_match_expr_type_mismatch.vv:18:16: error: return type mismatch, it should be `SomeTuple`, but it is instead `Poss1`
16 | fn get_file(item PossOwner) ?SomeTuple {
17 | return match item.pos {
18 | Poss1 { item.pos }
Expand Down
7 changes: 5 additions & 2 deletions vlib/v/parser/parser.v
Original file line number Diff line number Diff line change
Expand Up @@ -1937,12 +1937,15 @@ fn (mut p Parser) is_attributes() bool {
return true
}

// when is_top_stmt is true attrs are added to p.attrs
// when is_top_stmt is true, attrs are added to p.attrs
fn (mut p Parser) attributes() {
start_pos := p.tok.pos()
mut is_at := false
if p.tok.kind == .lsbr {
p.warn('`[attr]` has been deprecated, use `@[attr]` instead')
if p.pref.is_fmt {
} else {
p.error('`[attr]` has been deprecated, use `@[attr]` instead')
}
// [attr]
p.check(.lsbr)
} else if p.tok.kind == .at {
Expand Down
8 changes: 8 additions & 0 deletions vlib/v/pref/pref.v
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,14 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
}
res.compile_defines << 'is_coroutine'
res.compile_defines_all << 'is_coroutine'
$if macos {
dyld_fallback_paths := os.getenv('DYLD_FALLBACK_LIBRARY_PATH')
so_dir := os.dir(so_path)
if !dyld_fallback_paths.contains(so_dir) {
env := [dyld_fallback_paths, so_dir].filter(it.len).join(':')
os.setenv('DYLD_FALLBACK_LIBRARY_PATH', env, true)
}
}
} $else {
println('coroutines only work on macos & linux for now')
}
Expand Down
Loading

0 comments on commit a1803b8

Please sign in to comment.