Merge pull request #1425 from nspcc-dev/compiler/byteslice

Support variables in slice literals.
This commit is contained in:
Roman Khimov 2020-09-25 16:25:14 +03:00 committed by GitHub
commit 4b0008708b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 2 deletions

View file

@ -1594,13 +1594,24 @@ func (c *codegen) emitConvert(typ stackitem.Type) {
func (c *codegen) convertByteArray(lit *ast.CompositeLit) { func (c *codegen) convertByteArray(lit *ast.CompositeLit) {
buf := make([]byte, len(lit.Elts)) buf := make([]byte, len(lit.Elts))
varIndices := []int{}
for i := 0; i < len(lit.Elts); i++ { for i := 0; i < len(lit.Elts); i++ {
t := c.typeAndValueOf(lit.Elts[i]) t := c.typeAndValueOf(lit.Elts[i])
if t.Value != nil {
val, _ := constant.Int64Val(t.Value) val, _ := constant.Int64Val(t.Value)
buf[i] = byte(val) buf[i] = byte(val)
} else {
varIndices = append(varIndices, i)
}
} }
emit.Bytes(c.prog.BinWriter, buf) emit.Bytes(c.prog.BinWriter, buf)
c.emitConvert(stackitem.BufferT) c.emitConvert(stackitem.BufferT)
for _, i := range varIndices {
emit.Opcode(c.prog.BinWriter, opcode.DUP)
emit.Int(c.prog.BinWriter, int64(i))
ast.Walk(c, lit.Elts[i])
emit.Opcode(c.prog.BinWriter, opcode.SETITEM)
}
} }
func (c *codegen) convertMap(lit *ast.CompositeLit) { func (c *codegen) convertMap(lit *ast.CompositeLit) {

View file

@ -136,6 +136,18 @@ func (c *funcScope) analyzeVoidCalls(node ast.Node) bool {
c.voidCalls[n] = true c.voidCalls[n] = true
} }
return false return false
case *ast.CompositeLit:
for _, e := range n.Elts {
switch val := e.(type) {
case *ast.CallExpr: // slice
c.voidCalls[val] = false
case *ast.KeyValueExpr: // struct and map
ce, ok := val.Value.(*ast.CallExpr)
if ok {
c.voidCalls[ce] = false
}
}
}
} }
return true return true
} }

View file

@ -310,6 +310,26 @@ var sliceTestCases = []testCase{
`, `,
big.NewInt(2), big.NewInt(2),
}, },
{
"literal byte-slice with variable values",
`package foo
const sym1 = 's'
func Main() []byte {
sym2 := byte('t')
sym4 := byte('i')
return []byte{sym1, sym2, 'r', sym4, 'n', 'g'}
}`,
[]byte("string"),
},
{
"literal slice with function call",
`package foo
func fn() byte { return 't' }
func Main() []byte {
return []byte{'s', fn(), 'r'}
}`,
[]byte("str"),
},
} }
func TestSliceOperations(t *testing.T) { func TestSliceOperations(t *testing.T) {

View file

@ -29,6 +29,19 @@ var structTestCases = []testCase{
`, `,
big.NewInt(2), big.NewInt(2),
}, },
{
"struct field from func result",
`
package foo
type S struct { x int }
func fn() int { return 2 }
func Main() int {
t := S{x: fn()}
return t.x
}
`,
big.NewInt(2),
},
{ {
"struct field return", "struct field return",
` `