jsgen: fix maps being always constructed using string keys (fix #24607) (fix #24671) (#24673)

This commit is contained in:
Gonzalo Chumillas 2025-06-09 09:22:24 +01:00 committed by GitHub
parent e8fe334396
commit 2604fc186f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 129 additions and 18 deletions

View File

@ -10,7 +10,7 @@ fn (mut m map) internal_set(key JS.Any, val JS.Any) {
//$if es5 {
#if (key.hasOwnProperty('$toJS')) key = key.$toJS();
#if (!(key in m.val.map)) m.val.length++;
#m.val.map[key] = val
#m.val.map[key].val = val
/*} $else {
# if (key.hasOwnProperty('$toJS')) key = key.$toJS();
# m.val.m.set(key,val);
@ -23,7 +23,7 @@ fn (mut m map) internal_get(key JS.Any) JS.Any {
mut val := JS.Any(unsafe { nil })
//$if es5 {
#if (typeof key != "string" && key.hasOwnProperty('$toJS')) key = key.$toJS();
#val = m.val.map[key]
#val = m.val.map[key].val
/*} $else {
# if (key.hasOwnProperty('$toJS')) key = key.$toJS();
# val = m.val.m.get(key)
@ -49,14 +49,14 @@ pub fn (m &map) free() {}
pub fn (m map) keys() array {
ret := JS.makeEmptyArray()
#for (var key in m.map) array_push(ret,new string(`${key}`),false);
#for (var key in m.map) array_push(ret,m.map[key].key,false)
return ret
}
pub fn (m map) values() array {
ret := JS.makeEmptyArray()
#for (var key in m.map) array_push(ret,m.map[key],false);
#for (var key in m.map) array_push(ret,m.map[key].val,false);
return ret
}

View File

@ -610,7 +610,7 @@ fn (mut g JsGen) gen_str_for_map(info ast.Map, styp string, str_fn_name string)
g.definitions.writeln('\tlet keys = Object.keys(m.map);')
g.definitions.writeln('\tfor (let j = 0; j < keys.length;j++) {')
g.definitions.writeln('\t\tlet key = keys[j];')
g.definitions.writeln('\t\tlet value = m.map[key];')
g.definitions.writeln('\t\tlet value = m.map[key].val;')
g.definitions.writeln('\t\tkey = new ${key_styp}(key);')
if key_sym.kind == .string {
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string("\'" + key.str + "\'"));')

View File

@ -1328,7 +1328,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
g.expr(left.left)
g.write('.map[')
g.expr(left.index)
g.write('.\$toJS()] = ')
g.write('.\$toJS()] = { val: ')
} else {
g.write('.arr.set(')
g.write('new int(')
@ -1426,6 +1426,11 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
if array_set && !map_set {
g.write(')')
}
if left is ast.IndexExpr && left.is_map {
g.write(', key: ')
g.expr(left.index)
g.write(' }')
}
if semicolon {
if g.inside_loop {
g.write('; ')
@ -1511,7 +1516,7 @@ fn (mut g JsGen) gen_enum_decl(it ast.EnumDecl) {
if field.has_expr && field.expr is ast.IntegerLiteral {
i = field.expr.val.int()
}
g.writeln('${i},')
g.writeln('new int(${i}),')
i++
}
g.dec_indent()
@ -1707,7 +1712,7 @@ fn (mut g JsGen) gen_for_in_stmt(it ast.ForInStmt) {
g.writeln('for (var ${tmp2} in ${tmp}.map) {')
g.inc_indent()
g.writeln('let ${val} = ${tmp}.map[${tmp2}];')
g.writeln('let ${val} = ${tmp}.map[${tmp2}].val;')
sym := g.table.sym(it.key_type)
if sym.is_number() {
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) {
g.write('[')
g.expr(key)
g.write('.\$toJS()]')
g.write(': ')
g.write(': { val: ')
g.expr(val)
g.write(', key: ')
g.expr(key)
g.write(' }')
if i < it.keys.len - 1 {
g.write(',')
}

View File

@ -1,8 +1,17 @@
type T0 = int | string
type T1 = T0 | rune
struct Point {
x f64
y f64
}
enum Colors {
red = 1
green
blue
}
fn generic_map[T](items map[string]T) []T {
return items.values()
}
@ -226,17 +235,111 @@ fn test_map_len() {
assert items_2.len == 2
}
fn test_rune_keys() {
mut m := {
fn test_map_with_different_key_types() {
// map[int]string
mut items_1 := {
1: 'one'
2: 'two'
3: 'three'
}
assert typeof(items_1).name == 'map[int]string'
assert items_1[2] == 'two'
items_1[4] = 'four'
assert items_1[4].len == 4
keys_1 := items_1.keys()
assert keys_1.contains(1)
assert keys_1.contains(2)
assert keys_1.contains(3)
assert keys_1.contains(4)
assert '${items_1}' == "{1: 'one', 2: 'two', 3: 'three', 4: 'four'}"
// map[string]int
mut items_2 := {
'one': 1
'two': 2
'three': 3
}
assert typeof(items_2).name == 'map[string]int'
assert items_2['two'] == 2
items_2['four'] = 4
assert items_2['four'] == 4
keys_2 := items_2.keys()
assert keys_2.contains('one')
assert keys_2.contains('two')
assert keys_2.contains('three')
assert keys_2.contains('four')
assert '${items_2}' == "{'one': 1, 'two': 2, 'three': 3, 'four': 4}"
// map[f64]string
mut items_3 := {
1.1: 'one dot one'
2.2: 'two dot two'
3.3: 'three dot three'
}
assert typeof(items_3).name == 'map[f64]string'
assert items_3[2.2] == 'two dot two'
items_3[4.4] = 'four dot four'
assert items_3[4.4].len == 13
keys_3 := items_3.keys()
assert keys_3.contains(1.1)
assert keys_3.contains(2.2)
assert keys_3.contains(3.3)
assert keys_3.contains(4.4)
assert '${items_3}' == "{1.1: 'one dot one', 2.2: 'two dot two', 3.3: 'three dot three', 4.4: 'four dot four'}"
// map[u8]string
mut items_4 := {
u8(1): 'one'
2: 'two'
}
assert typeof(items_4).name == 'map[u8]string'
assert items_4[2] == 'two'
items_4[3] = 'three'
assert items_4[3].len == 5
keys_4 := items_4.keys()
assert keys_4.contains(1)
assert keys_4.contains(2)
assert keys_4.contains(3)
assert '${items_4}' == "{49: 'one', 50: 'two', 51: 'three'}"
// map[rune]int
mut items_5 := {
`!`: 2
`%`: 3
}
assert typeof(m).name == 'map[rune]int'
assert m[`!`] == 2
m[`@`] = 7
assert m.len == 3
println(m)
assert '${m}' == '{`!`: 2, `%`: 3, `@`: 7}'
assert typeof(items_5).name == 'map[rune]int'
assert items_5[`!`] == 2
items_5[`@`] = 7
assert items_5.len == 3
keys_5 := items_5.keys()
assert keys_5.contains(`!`)
assert keys_5.contains(`%`)
assert keys_5.contains(`@`)
assert '${items_5}' == '{`!`: 2, `%`: 3, `@`: 7}'
// map[sum-type]string
mut items_6 := {
T1(T0(1)): 'one'
T0('2'): 'two'
}
items_6[`!`] = 'exclamation'
assert items_6[`!`].len == 11
keys_6 := items_6.keys()
assert keys_6.contains(T0(1))
assert keys_6.contains(T0('2'))
assert keys_6.contains(`!`)
// map[enum-type]string
mut items_7 := {
Colors.red: 'red'
.green: 'green'
}
items_7[.blue] = 'blue'
assert items_7[.blue].len == 4
keys_7 := items_7.keys()
keys_7.contains(.red)
keys_7.contains(.green)
keys_7.contains(.blue)
}
fn main() {
@ -246,5 +349,5 @@ fn main() {
test_keys_method_with_generic_constraints()
test_direct_map_access()
test_map_len()
test_rune_keys()
test_map_with_different_key_types()
}