go.tools/ssa: clarify spec of (*builder).complit().
Added test for []*map composite literals containing nested
literal subelements. This required implementing
(reflect.Value).Map{Keys,Index} in ssa/interp.
Plus two minor fixes in ssa/interp.
R=gri
CC=golang-dev
https://golang.org/cl/20470043
This commit is contained in:
parent
fb0632eb7d
commit
74b761d099
|
|
@ -386,7 +386,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
|
||||||
v = fn.addLocal(t, e.Lbrace)
|
v = fn.addLocal(t, e.Lbrace)
|
||||||
}
|
}
|
||||||
v.Comment = "complit"
|
v.Comment = "complit"
|
||||||
b.compLit(fn, v, e, t) // initialize in place
|
b.compLit(fn, v, e) // initialize in place
|
||||||
return &address{addr: v, expr: e}
|
return &address{addr: v, expr: e}
|
||||||
|
|
||||||
case *ast.ParenExpr:
|
case *ast.ParenExpr:
|
||||||
|
|
@ -470,14 +470,13 @@ func (b *builder) exprInPlace(fn *Function, loc lvalue, e ast.Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := loc.(*address); ok {
|
if _, ok := loc.(*address); ok {
|
||||||
typ := loc.typ()
|
if _, ok := loc.typ().Underlying().(*types.Interface); ok {
|
||||||
if _, ok := typ.Underlying().(*types.Interface); ok {
|
|
||||||
// e.g. var x interface{} = T{...}
|
// e.g. var x interface{} = T{...}
|
||||||
// Can't in-place initialize an interface value.
|
// Can't in-place initialize an interface value.
|
||||||
// Fall back to copying.
|
// Fall back to copying.
|
||||||
} else {
|
} else {
|
||||||
addr := loc.address(fn)
|
addr := loc.address(fn)
|
||||||
b.compLit(fn, addr, e, typ) // in place
|
b.compLit(fn, addr, e) // in place
|
||||||
emitDebugRef(fn, e, addr, true)
|
emitDebugRef(fn, e, addr, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -1184,10 +1183,13 @@ func (b *builder) arrayLen(fn *Function, elts []ast.Expr) int64 {
|
||||||
// Nested composite literals are recursively initialized in place
|
// Nested composite literals are recursively initialized in place
|
||||||
// where possible.
|
// where possible.
|
||||||
//
|
//
|
||||||
func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, typ types.Type) {
|
// A CompositeLit may have pointer type only in the recursive (nested)
|
||||||
// TODO(adonovan): document how and why typ ever differs from
|
// case when the type name is implicit. e.g. in []*T{{}}, the inner
|
||||||
// fn.Pkg.typeOf(e).
|
// literal has type *T behaves like &T{}.
|
||||||
|
// In that case, addr must hold a T, not a *T.
|
||||||
|
//
|
||||||
|
func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit) {
|
||||||
|
typ := deref(fn.Pkg.typeOf(e))
|
||||||
switch t := typ.Underlying().(type) {
|
switch t := typ.Underlying().(type) {
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
for i, e := range e.Elts {
|
for i, e := range e.Elts {
|
||||||
|
|
@ -1250,7 +1252,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, typ typ
|
||||||
if t != at { // slice
|
if t != at { // slice
|
||||||
s := &Slice{X: array}
|
s := &Slice{X: array}
|
||||||
s.setPos(e.Lbrace)
|
s.setPos(e.Lbrace)
|
||||||
s.setType(t)
|
s.setType(typ)
|
||||||
emitStore(fn, addr, fn.emit(s))
|
emitStore(fn, addr, fn.emit(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1270,12 +1272,6 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, typ typ
|
||||||
b.exprInPlace(fn, loc, e.Value)
|
b.exprInPlace(fn, loc, e.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *types.Pointer:
|
|
||||||
// Pointers can only occur in the recursive case; we
|
|
||||||
// strip them off in addr() before calling compLit
|
|
||||||
// again, so that we allocate space for a T not a *T.
|
|
||||||
panic("compLit(fn, addr, e, *types.Pointer")
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("unexpected CompositeLit type: " + t.String())
|
panic("unexpected CompositeLit type: " + t.String())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ var externals = map[string]externalFn{
|
||||||
"(reflect.Value).IsValid": ext۰reflect۰Value۰IsValid,
|
"(reflect.Value).IsValid": ext۰reflect۰Value۰IsValid,
|
||||||
"(reflect.Value).Kind": ext۰reflect۰Value۰Kind,
|
"(reflect.Value).Kind": ext۰reflect۰Value۰Kind,
|
||||||
"(reflect.Value).Len": ext۰reflect۰Value۰Len,
|
"(reflect.Value).Len": ext۰reflect۰Value۰Len,
|
||||||
|
"(reflect.Value).MapIndex": ext۰reflect۰Value۰MapIndex,
|
||||||
|
"(reflect.Value).MapKeys": ext۰reflect۰Value۰MapKeys,
|
||||||
"(reflect.Value).NumField": ext۰reflect۰Value۰NumField,
|
"(reflect.Value).NumField": ext۰reflect۰Value۰NumField,
|
||||||
"(reflect.Value).NumMethod": ext۰reflect۰Value۰NumMethod,
|
"(reflect.Value).NumMethod": ext۰reflect۰Value۰NumMethod,
|
||||||
"(reflect.Value).Pointer": ext۰reflect۰Value۰Pointer,
|
"(reflect.Value).Pointer": ext۰reflect۰Value۰Pointer,
|
||||||
|
|
|
||||||
|
|
@ -546,6 +546,9 @@ func runFrame(fr *frame) {
|
||||||
}
|
}
|
||||||
fr.panicking = true
|
fr.panicking = true
|
||||||
fr.panic = recover()
|
fr.panic = recover()
|
||||||
|
if fr.i.mode&EnableTracing != 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Panicking: %s.\n", fr.panic)
|
||||||
|
}
|
||||||
fr.runDefers()
|
fr.runDefers()
|
||||||
fr.block = fr.fn.Recover // recovered panic
|
fr.block = fr.fn.Recover // recovered panic
|
||||||
}()
|
}()
|
||||||
|
|
|
||||||
|
|
@ -306,6 +306,50 @@ func ext۰reflect۰Value۰Len(fn *ssa.Function, args []value) value {
|
||||||
return nil // unreachable
|
return nil // unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ext۰reflect۰Value۰MapIndex(fn *ssa.Function, args []value) value {
|
||||||
|
// Signature: func (reflect.Value) Value
|
||||||
|
tValue := rV2T(args[0]).t.Underlying().(*types.Map).Key()
|
||||||
|
k := rV2V(args[1])
|
||||||
|
switch m := rV2V(args[0]).(type) {
|
||||||
|
case map[value]value:
|
||||||
|
if v, ok := m[k]; ok {
|
||||||
|
return makeReflectValue(tValue, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
case *hashmap:
|
||||||
|
if v := m.lookup(k.(hashable)); v != nil {
|
||||||
|
return makeReflectValue(tValue, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("(reflect.Value).MapIndex(%T, %T)", m, k))
|
||||||
|
}
|
||||||
|
return makeReflectValue(nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰reflect۰Value۰MapKeys(fn *ssa.Function, args []value) value {
|
||||||
|
// Signature: func (reflect.Value) []Value
|
||||||
|
var keys []value
|
||||||
|
tKey := rV2T(args[0]).t.Underlying().(*types.Map).Key()
|
||||||
|
switch v := rV2V(args[0]).(type) {
|
||||||
|
case map[value]value:
|
||||||
|
for k := range v {
|
||||||
|
keys = append(keys, makeReflectValue(tKey, k))
|
||||||
|
}
|
||||||
|
|
||||||
|
case *hashmap:
|
||||||
|
for _, e := range v.table {
|
||||||
|
for ; e != nil; e = e.next {
|
||||||
|
keys = append(keys, makeReflectValue(tKey, e.key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("(reflect.Value).MapKeys(%T)", v))
|
||||||
|
}
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
func ext۰reflect۰Value۰NumField(fn *ssa.Function, args []value) value {
|
func ext۰reflect۰Value۰NumField(fn *ssa.Function, args []value) value {
|
||||||
// Signature: func (reflect.Value) int
|
// Signature: func (reflect.Value) int
|
||||||
return len(rV2V(args[0]).(structure))
|
return len(rV2V(args[0]).(structure))
|
||||||
|
|
|
||||||
|
|
@ -543,3 +543,18 @@ func init() {
|
||||||
}()
|
}()
|
||||||
_ = i == j // interface comparison recurses on types
|
_ = i == j // interface comparison recurses on types
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Composite literals
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
type M map[int]int
|
||||||
|
m1 := []*M{{1: 1}, &M{2: 2}}
|
||||||
|
want := "map[1:1] map[2:2]"
|
||||||
|
if got := fmt.Sprint(*m1[0], *m1[1]); got != want {
|
||||||
|
panic(got)
|
||||||
|
}
|
||||||
|
m2 := []M{{1: 1}, M{2: 2}}
|
||||||
|
if got := fmt.Sprint(m2[0], m2[1]); got != want {
|
||||||
|
panic(got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -359,7 +359,7 @@ func toWriter(w io.Writer, v value) {
|
||||||
|
|
||||||
case map[value]value:
|
case map[value]value:
|
||||||
io.WriteString(w, "map[")
|
io.WriteString(w, "map[")
|
||||||
sep := " "
|
sep := ""
|
||||||
for k, e := range v {
|
for k, e := range v {
|
||||||
io.WriteString(w, sep)
|
io.WriteString(w, sep)
|
||||||
sep = " "
|
sep = " "
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue