use a temp variable for loop conversions on function calls

This avoids calling the function more than once.
master
Felix Lange 8 years ago
parent f1b18f569a
commit 8b5010f571
  1. 32
      genmethod.go
  2. 21
      internal/tests/mapconv/output.go
  3. 21
      internal/tests/sliceconv/output.go

@ -286,8 +286,14 @@ func sliceKV(typ types.Type) kvType {
return kvType{typ, intType, slicetyp.Elem()}
}
func (m *marshalMethod) loopConv(from, to Expression, fromTyp, toTyp kvType) []Statement {
conv := []Statement{
func (m *marshalMethod) loopConv(from, to Expression, fromTyp, toTyp kvType) (conv []Statement) {
if hasSideEffects(from) {
orig := from
from = Name(m.scope.newIdent("tmp"))
conv = []Statement{DeclareAndAssign{Lhs: from, Rhs: orig}}
}
// The actual conversion is a loop that assigns each element.
inner := []Statement{
Assign{Lhs: to, Rhs: makeExpr(toTyp.Type, from, m.scope.parent.qualify)},
Range{
Key: m.iterKey,
@ -302,12 +308,12 @@ func (m *marshalMethod) loopConv(from, to Expression, fromTyp, toTyp kvType) []S
// Preserve nil maps and slices when marshaling. This is not required for unmarshaling
// methods because the field is already nil-checked earlier.
if !m.isUnmarshal {
conv = []Statement{If{
inner = []Statement{If{
Condition: NotEqual{Lhs: from, Rhs: NIL},
Body: conv,
Body: inner,
}}
}
return conv
return append(conv, inner...)
}
func simpleConv(from Expression, fromtyp, totyp types.Type, qf types.Qualifier) Expression {
@ -344,6 +350,22 @@ func errCheck(expr Expression) If {
}
}
// hasSideEffects returns whether an expression may have side effects.
func hasSideEffects(expr Expression) bool {
switch expr := expr.(type) {
case Var:
return false
case Dotted:
return hasSideEffects(expr.Receiver)
case Star:
return hasSideEffects(expr.Value)
case Index:
return hasSideEffects(expr.Index) && hasSideEffects(expr.Value)
default:
return true
}
}
type stringLit struct {
V string
}

@ -29,9 +29,10 @@ func (x X) MarshalJSON() ([]byte, error) {
}
enc.NoConv = x.NoConv
enc.NoConvNamed = x.NoConvNamed
if x.Func() != nil {
enc.Func = make(map[replacedString]replacedInt, len(x.Func()))
for k, v := range x.Func() {
tmp := x.Func()
if tmp != nil {
enc.Func = make(map[replacedString]replacedInt, len(tmp))
for k, v := range tmp {
enc.Func[replacedString(k)] = replacedInt(v)
}
}
@ -93,9 +94,10 @@ func (x X) MarshalYAML() (interface{}, error) {
}
enc.NoConv = x.NoConv
enc.NoConvNamed = x.NoConvNamed
if x.Func() != nil {
enc.Func = make(map[replacedString]replacedInt, len(x.Func()))
for k, v := range x.Func() {
tmp := x.Func()
if tmp != nil {
enc.Func = make(map[replacedString]replacedInt, len(tmp))
for k, v := range tmp {
enc.Func[replacedString(k)] = replacedInt(v)
}
}
@ -157,9 +159,10 @@ func (x X) MarshalTOML() (interface{}, error) {
}
enc.NoConv = x.NoConv
enc.NoConvNamed = x.NoConvNamed
if x.Func() != nil {
enc.Func = make(map[replacedString]replacedInt, len(x.Func()))
for k, v := range x.Func() {
tmp := x.Func()
if tmp != nil {
enc.Func = make(map[replacedString]replacedInt, len(tmp))
for k, v := range tmp {
enc.Func[replacedString(k)] = replacedInt(v)
}
}

@ -31,9 +31,10 @@ func (x X) MarshalJSON() ([]byte, error) {
enc.ByteString = []byte(x.ByteString)
enc.NoConv = x.NoConv
enc.NoConvNamed = x.NoConvNamed
if x.Func() != nil {
enc.Func = make([]replacedInt, len(x.Func()))
for k, v := range x.Func() {
tmp := x.Func()
if tmp != nil {
enc.Func = make([]replacedInt, len(tmp))
for k, v := range tmp {
enc.Func[k] = replacedInt(v)
}
}
@ -101,9 +102,10 @@ func (x X) MarshalYAML() (interface{}, error) {
enc.ByteString = []byte(x.ByteString)
enc.NoConv = x.NoConv
enc.NoConvNamed = x.NoConvNamed
if x.Func() != nil {
enc.Func = make([]replacedInt, len(x.Func()))
for k, v := range x.Func() {
tmp := x.Func()
if tmp != nil {
enc.Func = make([]replacedInt, len(tmp))
for k, v := range tmp {
enc.Func[k] = replacedInt(v)
}
}
@ -171,9 +173,10 @@ func (x X) MarshalTOML() (interface{}, error) {
enc.ByteString = []byte(x.ByteString)
enc.NoConv = x.NoConv
enc.NoConvNamed = x.NoConvNamed
if x.Func() != nil {
enc.Func = make([]replacedInt, len(x.Func()))
for k, v := range x.Func() {
tmp := x.Func()
if tmp != nil {
enc.Func = make([]replacedInt, len(tmp))
for k, v := range tmp {
enc.Func[k] = replacedInt(v)
}
}

Loading…
Cancel
Save