@@ -14,8 +14,20 @@ import (
14
14
// initializing an appropriately sized object.
15
15
func (c * Compiler ) emitMakeMap (frame * Frame , expr * ssa.MakeMap ) (llvm.Value , error ) {
16
16
mapType := expr .Type ().Underlying ().(* types.Map )
17
- llvmKeyType := c . getLLVMType ( mapType .Key ().Underlying () )
17
+ keyType := mapType .Key ().Underlying ()
18
18
llvmValueType := c .getLLVMType (mapType .Elem ().Underlying ())
19
+ var llvmKeyType llvm.Type
20
+ if t , ok := keyType .(* types.Basic ); ok && t .Info ()& types .IsString != 0 {
21
+ // String keys.
22
+ llvmKeyType = c .getLLVMType (keyType )
23
+ } else if hashmapIsBinaryKey (keyType ) {
24
+ // Trivially comparable keys.
25
+ llvmKeyType = c .getLLVMType (keyType )
26
+ } else {
27
+ // All other keys. Implemented as map[interface{}]valueType for ease of
28
+ // implementation.
29
+ llvmKeyType = c .getLLVMRuntimeType ("_interface" )
30
+ }
19
31
keySize := c .targetData .TypeAllocSize (llvmKeyType )
20
32
valueSize := c .targetData .TypeAllocSize (llvmValueType )
21
33
llvmKeySize := llvm .ConstInt (c .ctx .Int8Type (), keySize , false )
@@ -43,6 +55,7 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu
43
55
44
56
// Do the lookup. How it is done depends on the key type.
45
57
var commaOkValue llvm.Value
58
+ keyType = keyType .Underlying ()
46
59
if t , ok := keyType .(* types.Basic ); ok && t .Info ()& types .IsString != 0 {
47
60
// key is a string
48
61
params := []llvm.Value {m , key , mapValuePtr }
@@ -58,8 +71,14 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu
58
71
commaOkValue = c .createRuntimeCall ("hashmapBinaryGet" , params , "" )
59
72
c .emitLifetimeEnd (mapKeyPtr , mapKeySize )
60
73
} else {
61
- // Not trivially comparable using memcmp.
62
- return llvm.Value {}, c .makeError (pos , "only strings, bools, ints, pointers or structs of bools/ints are supported as map keys, but got: " + keyType .String ())
74
+ // Not trivially comparable using memcmp. Make it an interface instead.
75
+ itfKey := key
76
+ if _ , ok := keyType .(* types.Interface ); ! ok {
77
+ // Not already an interface, so convert it to an interface now.
78
+ itfKey = c .parseMakeInterface (key , keyType , pos )
79
+ }
80
+ params := []llvm.Value {m , itfKey , mapValuePtr }
81
+ commaOkValue = c .createRuntimeCall ("hashmapInterfaceGet" , params , "" )
63
82
}
64
83
65
84
// Load the resulting value from the hashmap. The value is set to the zero
@@ -93,7 +112,14 @@ func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value, p
93
112
c .createRuntimeCall ("hashmapBinarySet" , params , "" )
94
113
c .emitLifetimeEnd (keyPtr , keySize )
95
114
} else {
96
- c .addError (pos , "only strings, bools, ints, pointers or structs of bools/ints are supported as map keys, but got: " + keyType .String ())
115
+ // Key is not trivially comparable, so compare it as an interface instead.
116
+ itfKey := key
117
+ if _ , ok := keyType .(* types.Interface ); ! ok {
118
+ // Not already an interface, so convert it to an interface first.
119
+ itfKey = c .parseMakeInterface (key , keyType , pos )
120
+ }
121
+ params := []llvm.Value {m , itfKey , valuePtr }
122
+ c .createRuntimeCall ("hashmapInterfaceSet" , params , "" )
97
123
}
98
124
c .emitLifetimeEnd (valuePtr , valueSize )
99
125
}
@@ -113,7 +139,16 @@ func (c *Compiler) emitMapDelete(keyType types.Type, m, key llvm.Value, pos toke
113
139
c .emitLifetimeEnd (keyPtr , keySize )
114
140
return nil
115
141
} else {
116
- return c .makeError (pos , "only strings, bools, ints, pointers or structs of bools/ints are supported as map keys, but got: " + keyType .String ())
142
+ // Key is not trivially comparable, so compare it as an interface
143
+ // instead.
144
+ itfKey := key
145
+ if _ , ok := keyType .(* types.Interface ); ! ok {
146
+ // Not already an interface, so convert it to an interface first.
147
+ itfKey = c .parseMakeInterface (key , keyType , pos )
148
+ }
149
+ params := []llvm.Value {m , itfKey }
150
+ c .createRuntimeCall ("hashmapInterfaceDelete" , params , "" )
151
+ return nil
117
152
}
118
153
}
119
154
0 commit comments