recognize named map and slice types

master
Felix Lange 8 years ago
parent 1fd1f70537
commit 788895d3d8
  1. 21
      genmethod.go
  2. 10
      internal/tests/mapconv/input.go
  3. 66
      internal/tests/mapconv/output.go
  4. 10
      internal/tests/sliceconv/input.go
  5. 66
      internal/tests/sliceconv/output.go
  6. 4
      main.go
  7. 56
      typeutil.go

@ -212,7 +212,7 @@ func (m *marshalMethod) marshalConversions(from, to Var, format string) (s []Sta
} }
func (m *marshalMethod) convert(from, to Expression, fromtyp, totyp types.Type) (s []Statement) { func (m *marshalMethod) convert(from, to Expression, fromtyp, totyp types.Type) (s []Statement) {
// Remove pointer introduced by ensurePointer during field building. // Remove pointer introduced by ensureNilCheckable during field building.
if isPointer(fromtyp) && !isPointer(totyp) { if isPointer(fromtyp) && !isPointer(totyp) {
from = Star{Value: from} from = Star{Value: from}
fromtyp = fromtyp.(*types.Pointer).Elem() fromtyp = fromtyp.(*types.Pointer).Elem()
@ -220,22 +220,20 @@ func (m *marshalMethod) convert(from, to Expression, fromtyp, totyp types.Type)
from = AddressOf{Value: from} from = AddressOf{Value: from}
fromtyp = types.NewPointer(fromtyp) fromtyp = types.NewPointer(fromtyp)
} }
// Generate the conversion. // Generate the conversion.
qf := m.mtyp.scope.qualify qf := m.mtyp.scope.qualify
switch { switch {
case types.ConvertibleTo(fromtyp, totyp): case types.ConvertibleTo(fromtyp, totyp):
s = append(s, Assign{Lhs: to, Rhs: simpleConv(from, fromtyp, totyp, qf)}) s = append(s, Assign{Lhs: to, Rhs: simpleConv(from, fromtyp, totyp, qf)})
case isSlice(fromtyp): case underlyingSlice(fromtyp) != nil:
fromElem := fromtyp.(*types.Slice).Elem() fromElem := underlyingSlice(fromtyp).Elem()
toElem := totyp.(*types.Slice).Elem() toElem := underlyingSlice(totyp).Elem()
s = append(s, Assign{Lhs: to, Rhs: makeExpr(totyp, from, qf)}) s = append(s, Assign{Lhs: to, Rhs: makeExpr(totyp, from, qf)})
s = append(s, m.loopConv(from, to, intType, intType, fromElem, toElem)) s = append(s, m.loopConv(from, to, intType, intType, fromElem, toElem))
case isMap(fromtyp): case underlyingMap(fromtyp) != nil:
fromKey, fromElem := fromtyp.(*types.Map).Key(), fromtyp.(*types.Map).Elem() fromMap, toMap := underlyingMap(fromtyp), underlyingMap(totyp)
toKey, toElem := totyp.(*types.Map).Key(), totyp.(*types.Map).Elem()
s = append(s, Assign{Lhs: to, Rhs: makeExpr(totyp, from, qf)}) s = append(s, Assign{Lhs: to, Rhs: makeExpr(totyp, from, qf)})
s = append(s, m.loopConv(from, to, fromKey, toKey, fromElem, toElem)) s = append(s, m.loopConv(from, to, fromMap.Key(), toMap.Key(), fromMap.Elem(), toMap.Elem()))
default: default:
invalidConv(fromtyp, totyp, qf) invalidConv(fromtyp, totyp, qf)
} }
@ -243,14 +241,13 @@ func (m *marshalMethod) convert(from, to Expression, fromtyp, totyp types.Type)
} }
func (m *marshalMethod) loopConv(from, to Expression, fromKey, toKey, fromElem, toElem types.Type) Statement { func (m *marshalMethod) loopConv(from, to Expression, fromKey, toKey, fromElem, toElem types.Type) Statement {
qf := m.scope.parent.qualify
return Range{ return Range{
Key: m.iterKey, Key: m.iterKey,
Value: m.iterVal, Value: m.iterVal,
RangeValue: from, RangeValue: from,
Body: []Statement{Assign{ Body: []Statement{Assign{
Lhs: Index{Value: to, Index: simpleConv(m.iterKey, fromKey, toKey, qf)}, Lhs: Index{Value: to, Index: simpleConv(m.iterKey, fromKey, toKey, m.scope.parent.qualify)},
Rhs: simpleConv(m.iterVal, fromElem, toElem, qf), Rhs: simpleConv(m.iterVal, fromElem, toElem, m.scope.parent.qualify),
}}, }},
} }
} }

@ -10,10 +10,16 @@ type replacedString string
type replacedInt int type replacedInt int
type namedMap map[string]int
type namedMap2 map[replacedString]replacedInt
type X struct { type X struct {
M map[string]int Map map[string]int
Named namedMap
} }
type Xo struct { type Xo struct {
M map[replacedString]replacedInt Map map[replacedString]replacedInt
Named namedMap2
} }

@ -9,31 +9,44 @@ import (
func (x *X) MarshalJSON() ([]byte, error) { func (x *X) MarshalJSON() ([]byte, error) {
type XJSON struct { type XJSON struct {
M map[replacedString]replacedInt Map map[replacedString]replacedInt
Named namedMap2
} }
var enc XJSON var enc XJSON
enc.M = make(map[replacedString]replacedInt, len(x.M)) enc.Map = make(map[replacedString]replacedInt, len(x.Map))
for k, v := range x.M { for k, v := range x.Map {
enc.M[replacedString(k)] = replacedInt(v) enc.Map[replacedString(k)] = replacedInt(v)
}
enc.Named = make(namedMap2, len(x.Named))
for k, v := range x.Named {
enc.Named[replacedString(k)] = replacedInt(v)
} }
return json.Marshal(&enc) return json.Marshal(&enc)
} }
func (x *X) UnmarshalJSON(input []byte) error { func (x *X) UnmarshalJSON(input []byte) error {
type XJSON struct { type XJSON struct {
M map[replacedString]replacedInt Map map[replacedString]replacedInt
Named namedMap2
} }
var dec XJSON var dec XJSON
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
return err return err
} }
var x0 X var x0 X
if dec.M == nil { if dec.Map == nil {
return errors.New("missing required field m for X") return errors.New("missing required field map for X")
}
x0.Map = make(map[string]int, len(dec.Map))
for k, v := range dec.Map {
x0.Map[string(k)] = int(v)
}
if dec.Named == nil {
return errors.New("missing required field named for X")
} }
x0.M = make(map[string]int, len(dec.M)) x0.Named = make(namedMap, len(dec.Named))
for k, v := range dec.M { for k, v := range dec.Named {
x0.M[string(k)] = int(v) x0.Named[string(k)] = int(v)
} }
*x = x0 *x = x0
return nil return nil
@ -41,31 +54,44 @@ func (x *X) UnmarshalJSON(input []byte) error {
func (x *X) MarshalYAML() (interface{}, error) { func (x *X) MarshalYAML() (interface{}, error) {
type XYAML struct { type XYAML struct {
M map[replacedString]replacedInt Map map[replacedString]replacedInt
Named namedMap2
} }
var enc XYAML var enc XYAML
enc.M = make(map[replacedString]replacedInt, len(x.M)) enc.Map = make(map[replacedString]replacedInt, len(x.Map))
for k, v := range x.M { for k, v := range x.Map {
enc.M[replacedString(k)] = replacedInt(v) enc.Map[replacedString(k)] = replacedInt(v)
}
enc.Named = make(namedMap2, len(x.Named))
for k, v := range x.Named {
enc.Named[replacedString(k)] = replacedInt(v)
} }
return &enc, nil return &enc, nil
} }
func (x *X) UnmarshalYAML(unmarshal func(interface{}) error) error { func (x *X) UnmarshalYAML(unmarshal func(interface{}) error) error {
type XYAML struct { type XYAML struct {
M map[replacedString]replacedInt Map map[replacedString]replacedInt
Named namedMap2
} }
var dec XYAML var dec XYAML
if err := unmarshal(&dec); err != nil { if err := unmarshal(&dec); err != nil {
return err return err
} }
var x0 X var x0 X
if dec.M == nil { if dec.Map == nil {
return errors.New("missing required field m for X") return errors.New("missing required field map for X")
}
x0.Map = make(map[string]int, len(dec.Map))
for k, v := range dec.Map {
x0.Map[string(k)] = int(v)
}
if dec.Named == nil {
return errors.New("missing required field named for X")
} }
x0.M = make(map[string]int, len(dec.M)) x0.Named = make(namedMap, len(dec.Named))
for k, v := range dec.M { for k, v := range dec.Named {
x0.M[string(k)] = int(v) x0.Named[string(k)] = int(v)
} }
*x = x0 *x = x0
return nil return nil

@ -8,10 +8,16 @@ package sliceconv
type replacedInt int type replacedInt int
type namedSlice []int
type namedSlice2 []replacedInt
type X struct { type X struct {
S []int Slice []int
Named namedSlice
} }
type Xo struct { type Xo struct {
S []replacedInt Slice []replacedInt
Named namedSlice2
} }

@ -9,31 +9,44 @@ import (
func (x *X) MarshalJSON() ([]byte, error) { func (x *X) MarshalJSON() ([]byte, error) {
type XJSON struct { type XJSON struct {
S []replacedInt Slice []replacedInt
Named namedSlice2
} }
var enc XJSON var enc XJSON
enc.S = make([]replacedInt, len(x.S)) enc.Slice = make([]replacedInt, len(x.Slice))
for k, v := range x.S { for k, v := range x.Slice {
enc.S[k] = replacedInt(v) enc.Slice[k] = replacedInt(v)
}
enc.Named = make(namedSlice2, len(x.Named))
for k, v := range x.Named {
enc.Named[k] = replacedInt(v)
} }
return json.Marshal(&enc) return json.Marshal(&enc)
} }
func (x *X) UnmarshalJSON(input []byte) error { func (x *X) UnmarshalJSON(input []byte) error {
type XJSON struct { type XJSON struct {
S []replacedInt Slice []replacedInt
Named namedSlice2
} }
var dec XJSON var dec XJSON
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
return err return err
} }
var x0 X var x0 X
if dec.S == nil { if dec.Slice == nil {
return errors.New("missing required field s for X") return errors.New("missing required field slice for X")
}
x0.Slice = make([]int, len(dec.Slice))
for k, v := range dec.Slice {
x0.Slice[k] = int(v)
}
if dec.Named == nil {
return errors.New("missing required field named for X")
} }
x0.S = make([]int, len(dec.S)) x0.Named = make(namedSlice, len(dec.Named))
for k, v := range dec.S { for k, v := range dec.Named {
x0.S[k] = int(v) x0.Named[k] = int(v)
} }
*x = x0 *x = x0
return nil return nil
@ -41,31 +54,44 @@ func (x *X) UnmarshalJSON(input []byte) error {
func (x *X) MarshalYAML() (interface{}, error) { func (x *X) MarshalYAML() (interface{}, error) {
type XYAML struct { type XYAML struct {
S []replacedInt Slice []replacedInt
Named namedSlice2
} }
var enc XYAML var enc XYAML
enc.S = make([]replacedInt, len(x.S)) enc.Slice = make([]replacedInt, len(x.Slice))
for k, v := range x.S { for k, v := range x.Slice {
enc.S[k] = replacedInt(v) enc.Slice[k] = replacedInt(v)
}
enc.Named = make(namedSlice2, len(x.Named))
for k, v := range x.Named {
enc.Named[k] = replacedInt(v)
} }
return &enc, nil return &enc, nil
} }
func (x *X) UnmarshalYAML(unmarshal func(interface{}) error) error { func (x *X) UnmarshalYAML(unmarshal func(interface{}) error) error {
type XYAML struct { type XYAML struct {
S []replacedInt Slice []replacedInt
Named namedSlice2
} }
var dec XYAML var dec XYAML
if err := unmarshal(&dec); err != nil { if err := unmarshal(&dec); err != nil {
return err return err
} }
var x0 X var x0 X
if dec.S == nil { if dec.Slice == nil {
return errors.New("missing required field s for X") return errors.New("missing required field slice for X")
}
x0.Slice = make([]int, len(dec.Slice))
for k, v := range dec.Slice {
x0.Slice[k] = int(v)
}
if dec.Named == nil {
return errors.New("missing required field named for X")
} }
x0.S = make([]int, len(dec.S)) x0.Named = make(namedSlice, len(dec.Named))
for k, v := range dec.S { for k, v := range dec.Named {
x0.S[k] = int(v) x0.Named[k] = int(v)
} }
*x = x0 *x = x0
return nil return nil

@ -284,7 +284,7 @@ func newMarshalerType(fs *token.FileSet, imp types.Importer, typ *types.Named) *
} }
mf := &marshalerField{ mf := &marshalerField{
name: f.Name(), name: f.Name(),
typ: ensurePointer(f.Type()), typ: ensureNilCheckable(f.Type()),
origTyp: f.Type(), origTyp: f.Type(),
tag: styp.Tag(i), tag: styp.Tag(i),
} }
@ -312,7 +312,7 @@ func (mtyp *marshalerType) loadOverrides(otypename string, otyp *types.Struct) e
if err := checkConvertible(of.Type(), f.origTyp); err != nil { if err := checkConvertible(of.Type(), f.origTyp); err != nil {
return fmt.Errorf("%v: invalid field override: %v", mtyp.fs.Position(of.Pos()), err) return fmt.Errorf("%v: invalid field override: %v", mtyp.fs.Position(of.Pos()), err)
} }
f.typ = ensurePointer(of.Type()) f.typ = ensureNilCheckable(of.Type())
} }
mtyp.scope.addReferences(otyp) mtyp.scope.addReferences(otyp)
return nil return nil

@ -66,42 +66,66 @@ func isPointer(typ types.Type) bool {
return ok return ok
} }
func isSlice(typ types.Type) bool { func underlyingSlice(typ types.Type) *types.Slice {
_, ok := typ.(*types.Slice) for {
return ok switch typ.(type) {
case *types.Named:
typ = typ.Underlying()
case *types.Slice:
return typ.(*types.Slice)
default:
return nil
}
}
} }
func isMap(typ types.Type) bool { func underlyingMap(typ types.Type) *types.Map {
_, ok := typ.(*types.Map) for {
return ok switch typ.(type) {
case *types.Named:
typ = typ.Underlying()
case *types.Map:
return typ.(*types.Map)
default:
return nil
}
}
} }
func ensurePointer(typ types.Type) types.Type { func ensureNilCheckable(typ types.Type) types.Type {
if isPointer(typ) || isSlice(typ) || isMap(typ) { orig := typ
return typ for {
switch typ.(type) {
case *types.Named:
typ = typ.Underlying()
case *types.Map, *types.Slice, *types.Pointer:
return orig
default:
return types.NewPointer(orig)
}
} }
return types.NewPointer(typ)
} }
// checkConvertible determines whether values of type from can be converted to type to. It // checkConvertible determines whether values of type from can be converted to type to. It
// returns nil if convertible and a descriptive error otherwise. // returns nil if convertible and a descriptive error otherwise.
// See package documentation for this definition of 'convertible'.
func checkConvertible(from, to types.Type) error { func checkConvertible(from, to types.Type) error {
if types.ConvertibleTo(from, to) { if types.ConvertibleTo(from, to) {
return nil return nil
} }
// Slices. // Slices.
sfrom, fromIsSlice := from.(*types.Slice) sfrom := underlyingSlice(from)
sto, toIsSlice := to.(*types.Slice) sto := underlyingSlice(to)
if fromIsSlice && toIsSlice { if sfrom != nil && sto != nil {
if !types.ConvertibleTo(sfrom.Elem(), sto.Elem()) { if !types.ConvertibleTo(sfrom.Elem(), sto.Elem()) {
return fmt.Errorf("slice element type %s is not convertible to %s", sfrom.Elem(), sto.Elem()) return fmt.Errorf("slice element type %s is not convertible to %s", sfrom.Elem(), sto.Elem())
} }
return nil return nil
} }
// Maps. // Maps.
mfrom, fromIsMap := from.(*types.Map) mfrom := underlyingMap(from)
mto, toIsMap := to.(*types.Map) mto := underlyingMap(to)
if fromIsMap && toIsMap { if mfrom != nil && mto != nil {
if !types.ConvertibleTo(mfrom.Key(), mto.Key()) { if !types.ConvertibleTo(mfrom.Key(), mto.Key()) {
return fmt.Errorf("map key type %s is not convertible to %s", mfrom.Key(), mto.Key()) return fmt.Errorf("map key type %s is not convertible to %s", mfrom.Key(), mto.Key())
} }

Loading…
Cancel
Save