Skip to content

Commit 2604fc1

Browse files
authored
jsgen: fix maps being always constructed using string keys (fix #24607) (fix #24671) (#24673)
1 parent e8fe334 commit 2604fc1

4 files changed

Lines changed: 129 additions & 18 deletions

File tree

‎vlib/builtin/js/map.js.v‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ fn (mut m map) internal_set(key JS.Any, val JS.Any) {
1010
//$if es5 {
1111
#if (key.hasOwnProperty('$toJS')) key = key.$toJS();
1212
#if (!(key in m.val.map)) m.val.length++;
13-
#m.val.map[key] = val
13+
#m.val.map[key].val = val
1414
/*} $else {
1515
# if (key.hasOwnProperty('$toJS')) key = key.$toJS();
1616
# m.val.m.set(key,val);
@@ -23,7 +23,7 @@ fn (mut m map) internal_get(key JS.Any) JS.Any {
2323
mut val := JS.Any(unsafe { nil })
2424
//$if es5 {
2525
#if (typeof key != "string" && key.hasOwnProperty('$toJS')) key = key.$toJS();
26-
#val = m.val.map[key]
26+
#val = m.val.map[key].val
2727
/*} $else {
2828
# if (key.hasOwnProperty('$toJS')) key = key.$toJS();
2929
# val = m.val.m.get(key)
@@ -49,14 +49,14 @@ pub fn (m &map) free() {}
4949

5050
pub fn (m map) keys() array {
5151
ret := JS.makeEmptyArray()
52-
#for (var key in m.map) array_push(ret,new string(`${key}`),false);
52+
#for (var key in m.map) array_push(ret,m.map[key].key,false)
5353

5454
return ret
5555
}
5656

5757
pub fn (m map) values() array {
5858
ret := JS.makeEmptyArray()
59-
#for (var key in m.map) array_push(ret,m.map[key],false);
59+
#for (var key in m.map) array_push(ret,m.map[key].val,false);
6060

6161
return ret
6262
}

‎vlib/v/gen/js/auto_str_methods.v‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ fn (mut g JsGen) gen_str_for_map(info ast.Map, styp string, str_fn_name string)
610610
g.definitions.writeln('\tlet keys = Object.keys(m.map);')
611611
g.definitions.writeln('\tfor (let j = 0; j < keys.length;j++) {')
612612
g.definitions.writeln('\t\tlet key = keys[j];')
613-
g.definitions.writeln('\t\tlet value = m.map[key];')
613+
g.definitions.writeln('\t\tlet value = m.map[key].val;')
614614
g.definitions.writeln('\t\tkey = new ${key_styp}(key);')
615615
if key_sym.kind == .string {
616616
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string("\'" + key.str + "\'"));')

‎vlib/v/gen/js/js.v‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,7 +1328,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
13281328
g.expr(left.left)
13291329
g.write('.map[')
13301330
g.expr(left.index)
1331-
g.write('.\$toJS()] = ')
1331+
g.write('.\$toJS()] = { val: ')
13321332
} else {
13331333
g.write('.arr.set(')
13341334
g.write('new int(')
@@ -1426,6 +1426,11 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
14261426
if array_set && !map_set {
14271427
g.write(')')
14281428
}
1429+
if left is ast.IndexExpr && left.is_map {
1430+
g.write(', key: ')
1431+
g.expr(left.index)
1432+
g.write(' }')
1433+
}
14291434
if semicolon {
14301435
if g.inside_loop {
14311436
g.write('; ')
@@ -1511,7 +1516,7 @@ fn (mut g JsGen) gen_enum_decl(it ast.EnumDecl) {
15111516
if field.has_expr && field.expr is ast.IntegerLiteral {
15121517
i = field.expr.val.int()
15131518
}
1514-
g.writeln('${i},')
1519+
g.writeln('new int(${i}),')
15151520
i++
15161521
}
15171522
g.dec_indent()
@@ -1707,7 +1712,7 @@ fn (mut g JsGen) gen_for_in_stmt(it ast.ForInStmt) {
17071712
g.writeln('for (var ${tmp2} in ${tmp}.map) {')
17081713

17091714
g.inc_indent()
1710-
g.writeln('let ${val} = ${tmp}.map[${tmp2}];')
1715+
g.writeln('let ${val} = ${tmp}.map[${tmp2}].val;')
17111716
sym := g.table.sym(it.key_type)
17121717
if sym.is_number() {
17131718
g.writeln('let ${key} = new ${g.styp(it.key_type)}(+${tmp2})')
@@ -3216,8 +3221,11 @@ fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) {
32163221
g.write('[')
32173222
g.expr(key)
32183223
g.write('.\$toJS()]')
3219-
g.write(': ')
3224+
g.write(': { val: ')
32203225
g.expr(val)
3226+
g.write(', key: ')
3227+
g.expr(key)
3228+
g.write(' }')
32213229
if i < it.keys.len - 1 {
32223230
g.write(',')
32233231
}

‎vlib/v/gen/js/tests/map.v‎

Lines changed: 112 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1+
type T0 = int | string
2+
type T1 = T0 | rune
3+
14
struct Point {
25
x f64
36
y f64
47
}
58

9+
enum Colors {
10+
red = 1
11+
green
12+
blue
13+
}
14+
615
fn generic_map[T](items map[string]T) []T {
716
return items.values()
817
}
@@ -226,17 +235,111 @@ fn test_map_len() {
226235
assert items_2.len == 2
227236
}
228237

229-
fn test_rune_keys() {
230-
mut m := {
238+
fn test_map_with_different_key_types() {
239+
// map[int]string
240+
mut items_1 := {
241+
1: 'one'
242+
2: 'two'
243+
3: 'three'
244+
}
245+
assert typeof(items_1).name == 'map[int]string'
246+
assert items_1[2] == 'two'
247+
items_1[4] = 'four'
248+
assert items_1[4].len == 4
249+
keys_1 := items_1.keys()
250+
assert keys_1.contains(1)
251+
assert keys_1.contains(2)
252+
assert keys_1.contains(3)
253+
assert keys_1.contains(4)
254+
assert '${items_1}' == "{1: 'one', 2: 'two', 3: 'three', 4: 'four'}"
255+
256+
// map[string]int
257+
mut items_2 := {
258+
'one': 1
259+
'two': 2
260+
'three': 3
261+
}
262+
assert typeof(items_2).name == 'map[string]int'
263+
assert items_2['two'] == 2
264+
items_2['four'] = 4
265+
assert items_2['four'] == 4
266+
keys_2 := items_2.keys()
267+
assert keys_2.contains('one')
268+
assert keys_2.contains('two')
269+
assert keys_2.contains('three')
270+
assert keys_2.contains('four')
271+
assert '${items_2}' == "{'one': 1, 'two': 2, 'three': 3, 'four': 4}"
272+
273+
// map[f64]string
274+
mut items_3 := {
275+
1.1: 'one dot one'
276+
2.2: 'two dot two'
277+
3.3: 'three dot three'
278+
}
279+
assert typeof(items_3).name == 'map[f64]string'
280+
assert items_3[2.2] == 'two dot two'
281+
items_3[4.4] = 'four dot four'
282+
assert items_3[4.4].len == 13
283+
keys_3 := items_3.keys()
284+
assert keys_3.contains(1.1)
285+
assert keys_3.contains(2.2)
286+
assert keys_3.contains(3.3)
287+
assert keys_3.contains(4.4)
288+
assert '${items_3}' == "{1.1: 'one dot one', 2.2: 'two dot two', 3.3: 'three dot three', 4.4: 'four dot four'}"
289+
290+
// map[u8]string
291+
mut items_4 := {
292+
u8(1): 'one'
293+
2: 'two'
294+
}
295+
assert typeof(items_4).name == 'map[u8]string'
296+
assert items_4[2] == 'two'
297+
items_4[3] = 'three'
298+
assert items_4[3].len == 5
299+
keys_4 := items_4.keys()
300+
assert keys_4.contains(1)
301+
assert keys_4.contains(2)
302+
assert keys_4.contains(3)
303+
assert '${items_4}' == "{49: 'one', 50: 'two', 51: 'three'}"
304+
305+
// map[rune]int
306+
mut items_5 := {
231307
`!`: 2
232308
`%`: 3
233309
}
234-
assert typeof(m).name == 'map[rune]int'
235-
assert m[`!`] == 2
236-
m[`@`] = 7
237-
assert m.len == 3
238-
println(m)
239-
assert '${m}' == '{`!`: 2, `%`: 3, `@`: 7}'
310+
assert typeof(items_5).name == 'map[rune]int'
311+
assert items_5[`!`] == 2
312+
items_5[`@`] = 7
313+
assert items_5.len == 3
314+
keys_5 := items_5.keys()
315+
assert keys_5.contains(`!`)
316+
assert keys_5.contains(`%`)
317+
assert keys_5.contains(`@`)
318+
assert '${items_5}' == '{`!`: 2, `%`: 3, `@`: 7}'
319+
320+
// map[sum-type]string
321+
mut items_6 := {
322+
T1(T0(1)): 'one'
323+
T0('2'): 'two'
324+
}
325+
items_6[`!`] = 'exclamation'
326+
assert items_6[`!`].len == 11
327+
keys_6 := items_6.keys()
328+
assert keys_6.contains(T0(1))
329+
assert keys_6.contains(T0('2'))
330+
assert keys_6.contains(`!`)
331+
332+
// map[enum-type]string
333+
mut items_7 := {
334+
Colors.red: 'red'
335+
.green: 'green'
336+
}
337+
items_7[.blue] = 'blue'
338+
assert items_7[.blue].len == 4
339+
keys_7 := items_7.keys()
340+
keys_7.contains(.red)
341+
keys_7.contains(.green)
342+
keys_7.contains(.blue)
240343
}
241344

242345
fn main() {
@@ -246,5 +349,5 @@ fn main() {
246349
test_keys_method_with_generic_constraints()
247350
test_direct_map_access()
248351
test_map_len()
249-
test_rune_keys()
352+
test_map_with_different_key_types()
250353
}

0 commit comments

Comments
 (0)