compiler: implement operations on nil hashmaps
* comparing a map against nil * getting the length of a nil map
Этот коммит содержится в:
родитель
c84fc6a670
коммит
436901dc49
4 изменённых файлов: 31 добавлений и 7 удалений
|
@ -1870,12 +1870,7 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string)
|
|||
// string or slice
|
||||
llvmLen = c.builder.CreateExtractValue(value, 1, "len")
|
||||
case *types.Map:
|
||||
indices := []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
||||
llvm.ConstInt(c.ctx.Int32Type(), 2, false), // hashmap.count
|
||||
}
|
||||
ptr := c.builder.CreateGEP(value, indices, "lenptr")
|
||||
llvmLen = c.builder.CreateLoad(ptr, "len")
|
||||
llvmLen = c.createRuntimeCall("hashmapLen", []llvm.Value{value}, "len")
|
||||
default:
|
||||
return llvm.Value{}, errors.New("todo: len: unknown type")
|
||||
}
|
||||
|
@ -3053,7 +3048,10 @@ func (c *Compiler) parseBinOp(op token.Token, typ types.Type, x, y llvm.Value) (
|
|||
default:
|
||||
return llvm.Value{}, errors.New("binop on interface: " + op.String())
|
||||
}
|
||||
case *types.Pointer:
|
||||
case *types.Map, *types.Pointer:
|
||||
// Maps are in general not comparable, but can be compared against nil
|
||||
// (which is a nil pointer). This means they can be trivially compared
|
||||
// by treating them as a pointer.
|
||||
switch op {
|
||||
case token.EQL: // ==
|
||||
return c.builder.CreateICmp(llvm.IntEQ, x, y, ""), nil
|
||||
|
@ -3212,6 +3210,16 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
|
|||
llvmLen, // cap
|
||||
}, false)
|
||||
return slice, nil
|
||||
case *types.Map:
|
||||
if !expr.IsNil() {
|
||||
// I believe this is not allowed by the Go spec.
|
||||
panic("non-nil map constant")
|
||||
}
|
||||
llvmType, err := c.getLLVMType(typ)
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
return c.getZeroValue(llvmType)
|
||||
default:
|
||||
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String())
|
||||
}
|
||||
|
|
|
@ -71,6 +71,15 @@ func hashmapMake(keySize, valueSize uint8) *hashmap {
|
|||
}
|
||||
}
|
||||
|
||||
// Return the number of entries in this hashmap, called from the len builtin.
|
||||
// A nil hashmap is defined as having length 0.
|
||||
func hashmapLen(m *hashmap) int {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
return int(m.count)
|
||||
}
|
||||
|
||||
// Set a specified key to a given value. Grow the map if necessary.
|
||||
//go:nobounds
|
||||
func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) {
|
||||
|
|
5
testdata/map.go
предоставленный
5
testdata/map.go
предоставленный
|
@ -26,6 +26,11 @@ func main() {
|
|||
readMap(testmap2, "seven")
|
||||
lookup(testmap2, "eight")
|
||||
lookup(testmap2, "nokey")
|
||||
|
||||
// operations on nil maps
|
||||
var nilmap map[string]int
|
||||
println(m == nil, m != nil, len(m))
|
||||
println(nilmap == nil, nilmap != nil, len(nilmap))
|
||||
}
|
||||
|
||||
func readMap(m map[string]int, key string) {
|
||||
|
|
2
testdata/map.txt
предоставленный
2
testdata/map.txt
предоставленный
|
@ -48,3 +48,5 @@ map read: seven = 7
|
|||
twelve = 12
|
||||
lookup with comma-ok: eight 8 true
|
||||
lookup with comma-ok: nokey 0 false
|
||||
false true 2
|
||||
true false 0
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче