Skip to content

Commit 27829d5

Browse files
authored
jsgen: cannot assign unsafe nil values (fix #24407, #24436) (#24458)
1 parent 3f76b69 commit 27829d5

File tree

3 files changed

+91
-2
lines changed

3 files changed

+91
-2
lines changed

vlib/v/gen/js/builtin_types.v

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,20 @@ fn (mut g JsGen) gen_builtin_prototype(c BuiltinPrototypeConfig) {
329329
g.writeln('function ${c.typ_name}__eq(self,other) { return ${c.eq}; } ')
330330
}
331331

332+
fn (mut g JsGen) gen_nil_const() {
333+
g.writeln('const nil__ = new \$ref(new nil());')
334+
g.gen_builtin_prototype(
335+
typ_name: 'nil'
336+
val_name: 'str'
337+
default_value: 'new String("&nil")'
338+
constructor: 'this.str = str.toString(); this.len = this.str.length'
339+
value_of: 'null'
340+
to_string: '"&nil"'
341+
eq: 'new bool(self.valueOf() === other.valueOf())'
342+
to_jsval: 'null'
343+
)
344+
}
345+
332346
// generate builtin type definitions, used for casting and methods.
333347
fn (mut g JsGen) gen_builtin_type_defs() {
334348
g.inc_indent()

vlib/v/gen/js/js.v

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) stri
143143
graph.add(g.file.mod.name, imports)
144144
// builtin types
145145
if g.file.mod.name == 'builtin' && !g.generated_builtin {
146+
g.gen_nil_const()
146147
g.gen_builtin_type_defs()
147148
g.writeln('Object.defineProperty(array.prototype,"len", { get: function() {return new int(this.arr.arr.length);}, set: function(l) { this.arr.arr.length = l.valueOf(); } }); ')
148149
g.writeln('Object.defineProperty(map.prototype,"len", { get: function() {return new int(this.length);}, set: function(l) { } }); ')
@@ -965,7 +966,7 @@ fn (mut g JsGen) expr(node_ ast.Expr) {
965966
g.gen_lock_expr(node)
966967
}
967968
ast.Nil {
968-
g.write('null')
969+
g.write('nil__')
969970
}
970971
ast.NodeError {}
971972
ast.None {
@@ -1345,7 +1346,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
13451346
g.expr(left)
13461347
}
13471348

1348-
is_ptr := stmt.op == .assign && stmt.left_types[i].is_ptr() && !array_set
1349+
is_ptr := stmt.op == .assign && stmt.right_types[i].is_ptr() && !array_set
13491350
if is_ptr {
13501351
g.write('.val')
13511352
}

vlib/v/gen/js/tests/unsafe.v

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
struct Bar {
2+
value int
3+
}
4+
5+
struct Foo1 {
6+
mut:
7+
name &string
8+
}
9+
10+
struct Foo2 {
11+
mut:
12+
name ?&string
13+
}
14+
15+
struct Foo3 {
16+
mut:
17+
bar &Bar
18+
}
19+
20+
fn main() {
21+
// Basic test of assigning nil to a string pointer
22+
mut str := 'hi!'
23+
mut str_ptr := &str
24+
unsafe {
25+
str_ptr = nil
26+
}
27+
println(str_ptr) // should print '&nil'
28+
assert str_ptr == unsafe { nil }
29+
30+
// Test initializing a pointer field with nil
31+
f1 := Foo1{
32+
name: unsafe { nil }
33+
}
34+
assert f1.name == unsafe { nil }
35+
36+
// Test assigning nil to an optional pointer field
37+
mut f2 := Foo2{}
38+
unsafe {
39+
f2.name = nil
40+
}
41+
if f2.name != none {
42+
assert f2.name == unsafe { nil }
43+
} else {
44+
assert false
45+
}
46+
47+
// Test assigning nil to a struct pointer
48+
mut f3 := &Foo2{}
49+
unsafe {
50+
f3 = nil
51+
}
52+
assert f3 == unsafe { nil }
53+
54+
// Test with custom struct fields
55+
mut f4 := Foo3{
56+
bar: &Bar{42}
57+
}
58+
unsafe {
59+
f4.bar = nil
60+
}
61+
assert f4.bar == unsafe { nil }
62+
63+
// Test with nil pointers in arrays
64+
mut ptrs := []&string{len: 3, init: unsafe { nil }}
65+
p0, p1 := 'hello', 'world'
66+
ptrs[0] = &p0
67+
ptrs[1] = &p1
68+
unsafe {
69+
ptrs[2] = nil
70+
}
71+
assert ptrs[0] != unsafe { nil }
72+
assert ptrs[1] != unsafe { nil }
73+
assert ptrs[2] == unsafe { nil }
74+
}

0 commit comments

Comments
 (0)