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()} return kvType{typ, intType, slicetyp.Elem()}
} }
func (m *marshalMethod) loopConv(from, to Expression, fromTyp, toTyp kvType) []Statement { func (m *marshalMethod) loopConv(from, to Expression, fromTyp, toTyp kvType) (conv []Statement) {
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)}, Assign{Lhs: to, Rhs: makeExpr(toTyp.Type, from, m.scope.parent.qualify)},
Range{ Range{
Key: m.iterKey, 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 // Preserve nil maps and slices when marshaling. This is not required for unmarshaling
// methods because the field is already nil-checked earlier. // methods because the field is already nil-checked earlier.
if !m.isUnmarshal { if !m.isUnmarshal {
conv = []Statement{If{ inner = []Statement{If{
Condition: NotEqual{Lhs: from, Rhs: NIL}, 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 { 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 { type stringLit struct {
V string V string
} }

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

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

Loading…
Cancel
Save