Skip to content

Commit 6bb9208

Browse files
authored
Merge pull request #215 from jmattheis/nested-aliases
Don't see aliases as different types
2 parents 035de33 + be9d79b commit 6bb9208

File tree

9 files changed

+149
-27
lines changed

9 files changed

+149
-27
lines changed

builder/skipcopy.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package builder
22

33
import (
4+
"go/types"
5+
46
"github.com/dave/jennifer/jen"
57
"github.com/jmattheis/goverter/xtype"
68
)
@@ -10,7 +12,7 @@ type SkipCopy struct{}
1012

1113
// Matches returns true, if the builder can create handle the given types.
1214
func (*SkipCopy) Matches(ctx *MethodContext, source, target *xtype.Type) bool {
13-
return ctx.Conf.SkipCopySameType && source.String == target.String
15+
return ctx.Conf.SkipCopySameType && types.Identical(source.T, target.T)
1416
}
1517

1618
// Build creates conversion source code for the given source and target type.

docs/changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import GH from './GH.vue';
66

77
## unreleased
88

9+
- Fix comparison of signatures with aliases in
10+
[`extend`](./reference/extend.md) and conversion methods. <GH issue="213" pr="215"/>
11+
- This is a regression introduced in v1.9.1 due to the x/tools upgrade.
912
- Upgrade toolchain to go1.25. <GH pr="214"/>
1013

1114
## v1.9.1

generator/generator.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,8 @@ func (g *generator) shouldCreateSubMethod(ctx *builder.MethodContext, source, ta
496496
// *Source -> Target
497497
// Source -> *Target
498498
// *Source -> *Target
499-
isCurrentPointerStructMethod = ctx.Signature.Source == source.AsPointerType().String() ||
500-
ctx.Signature.Target == target.AsPointerType().String()
499+
isCurrentPointerStructMethod = types.Identical(ctx.Signature.Source, source.AsPointerType()) ||
500+
types.Identical(ctx.Signature.Target, target.AsPointerType())
501501
}
502502

503503
createSubMethod := false
@@ -516,7 +516,7 @@ func (g *generator) shouldCreateSubMethod(ctx *builder.MethodContext, source, ta
516516
case source.Enum(&ctx.Conf.Enum).OK && target.Enum(&ctx.Conf.Enum).OK:
517517
createSubMethod = true
518518
}
519-
if ctx.Conf.SkipCopySameType && source.String == target.String {
519+
if ctx.Conf.SkipCopySameType && types.Identical(source.T, target.T) {
520520
createSubMethod = false
521521
}
522522
}
@@ -569,7 +569,7 @@ func (g *generator) createSubMethod(ctx *builder.MethodContext, sourceID *xtype.
569569
}
570570

571571
func (g *generator) hasMethod(ctx *builder.MethodContext, source, target types.Type) bool {
572-
signature := xtype.Signature{Source: source.String(), Target: target.String()}
572+
signature := xtype.Signature{Source: source, Target: target}
573573
return g.extend.Has(signature) || g.lookup.Has(signature)
574574
}
575575

@@ -579,13 +579,13 @@ func (g *generator) getOverlappingStructDefinition(ctx *builder.MethodContext, s
579579
}
580580

581581
overlapping := []xtype.Signature{
582-
{Source: source.AsPointerType().String(), Target: target.String},
583-
{Source: source.AsPointerType().String(), Target: target.AsPointerType().String()},
584-
{Source: source.String, Target: target.AsPointerType().String()},
582+
{Source: source.AsPointerType(), Target: target.T},
583+
{Source: source.AsPointerType(), Target: target.AsPointerType()},
584+
{Source: source.T, Target: target.AsPointerType()},
585585
}
586586

587587
for _, sig := range overlapping {
588-
if ctx.Signature == sig {
588+
if ctx.Signature.Identical(sig) {
589589
continue
590590
}
591591
if def, _ := g.lookup.Get(sig, ctx.AvailableContext); def != nil && len(def.RawFieldSettings) > 0 {

generator/validate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
)
88

99
func validateMethods(lookup *method.Index[generatedMethod]) error {
10-
for _, hits := range lookup.Exact {
10+
for _, hits := range lookup.Exact.Values() {
1111
for _, entry := range hits {
1212
genMethod := entry.Item
1313

method/index.go

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,18 @@ type IndexID struct {
2121

2222
func NewIndex[T any]() *Index[T] {
2323
return &Index[T]{
24-
Exact: map[xtype.Signature][]IndexEntry[T]{},
24+
Exact: xtype.NewSignatureMap[[]IndexEntry[T]](),
2525
}
2626
}
2727

2828
type Index[T any] struct {
29-
Exact map[xtype.Signature][]IndexEntry[T]
29+
Exact *xtype.SignatureMap[[]IndexEntry[T]]
3030
Update []*T
3131
}
3232

3333
func (l *Index[T]) GetAll() []*T {
3434
items := []*T{}
35-
for _, exacts := range l.Exact {
35+
for _, exacts := range l.Exact.Values() {
3636
for _, exact := range exacts {
3737
items = append(items, exact.Item)
3838
}
@@ -42,14 +42,17 @@ func (l *Index[T]) GetAll() []*T {
4242

4343
func (l *Index[T]) RegisterOverrideOverlapping(t *T, def *Definition) {
4444
newEntry := IndexEntry[T]{Def: def, Item: t}
45-
for i, entry := range l.Exact[def.Signature] {
45+
entries, _ := l.Exact.At(def.Signature)
46+
for i, entry := range entries {
4647
if satisfiesContext(entry.Def.Context, def.Context) || satisfiesContext(def.Context, entry.Def.Context) {
47-
l.Exact[def.Signature][i] = newEntry
48+
entries[i] = newEntry
49+
l.Exact.Set(def.Signature, entries)
4850
return
4951
}
5052
}
5153

52-
l.Exact[def.Signature] = append(l.Exact[def.Signature], newEntry)
54+
entries = append(entries, newEntry)
55+
l.Exact.Set(def.Signature, entries)
5356
}
5457

5558
func (l *Index[T]) RegisterUpdate(t *T, def *Definition) (IndexID, error) {
@@ -58,7 +61,8 @@ func (l *Index[T]) RegisterUpdate(t *T, def *Definition) (IndexID, error) {
5861
}
5962

6063
func (l *Index[T]) Register(t *T, def *Definition) (IndexID, error) {
61-
for _, entry := range l.Exact[def.Signature] {
64+
entries, _ := l.Exact.At(def.Signature)
65+
for _, entry := range entries {
6266
if err := checkOverlap(entry.Def, def); err != nil {
6367
return IndexID{}, err
6468
}
@@ -68,8 +72,10 @@ func (l *Index[T]) Register(t *T, def *Definition) (IndexID, error) {
6872
}
6973

7074
newEntry := IndexEntry[T]{Def: def, Item: t}
71-
l.Exact[def.Signature] = append(l.Exact[def.Signature], newEntry)
72-
return IndexID{sig: def.Signature, idx: len(l.Exact[def.Signature]) - 1}, nil
75+
entries = append(entries, newEntry)
76+
l.Exact.Set(def.Signature, entries)
77+
78+
return IndexID{sig: def.Signature, idx: len(entries) - 1}, nil
7379
}
7480

7581
func checkOverlap(left, right *Definition) error {
@@ -83,16 +89,17 @@ func (l *Index[T]) ByID(id IndexID) *T {
8389
if id.update {
8490
return l.Update[id.idx]
8591
}
86-
return l.Exact[id.sig][id.idx].Item
92+
value, _ := l.Exact.At(id.sig)
93+
return value[id.idx].Item
8794
}
8895

8996
func (l *Index[T]) Has(sig xtype.Signature) bool {
90-
_, ok := l.Exact[sig]
97+
_, ok := l.Exact.At(sig)
9198
return ok
9299
}
93100

94101
func (l *Index[T]) Get(sig xtype.Signature, m map[string]*xtype.Type) (*T, error) {
95-
hits, ok := l.Exact[sig]
102+
hits, ok := l.Exact.At(sig)
96103
if !ok {
97104
return nil, nil
98105
}

method/parse.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func Parse(obj types.Object, opts *ParseOpts, localOpts LocalOpts) (*Definition,
106106
case methodDef.Source == nil:
107107
arg.Use = ArgUseSource
108108
methodDef.Source = arg.Type
109-
methodDef.Signature.Source = methodDef.Source.String
109+
methodDef.Signature.Source = methodDef.Source.T
110110
default:
111111
arg.Use = ArgUseMultiSource
112112
methodDef.MultiSources = append(methodDef.MultiSources, arg.Type)
@@ -146,7 +146,7 @@ func Parse(obj types.Object, opts *ParseOpts, localOpts LocalOpts) (*Definition,
146146
return nil, formatErr("must have only one source param")
147147
}
148148

149-
methodDef.Signature.Target = methodDef.Target.String
149+
methodDef.Signature.Target = methodDef.Target.T
150150

151151
return methodDef, nil
152152
}

scenario/extend_alias.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
input:
2+
input.go: |
3+
package alias
4+
5+
// goverter:converter
6+
// goverter:extend Conv
7+
type Converter interface {
8+
Convert(source Input) Output
9+
}
10+
11+
type InputAlias = Input
12+
type OutputAlias = Output
13+
14+
type ID = string
15+
16+
func Conv(i int) *string {
17+
return nil
18+
}
19+
20+
type Input struct { Name int }
21+
type Output struct { Name *ID }
22+
success:
23+
- generated/generated.go: |
24+
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
25+
26+
package generated
27+
28+
import execution "github.com/jmattheis/goverter/execution"
29+
30+
type ConverterImpl struct{}
31+
32+
func (c *ConverterImpl) Convert(source execution.Input) execution.Output {
33+
var aliasOutput execution.Output
34+
aliasOutput.Name = execution.Conv(source.Name)
35+
return aliasOutput
36+
}

xtype/map.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package xtype
2+
3+
import (
4+
"golang.org/x/tools/go/types/typeutil"
5+
)
6+
7+
func NewSignatureMap[T any]() *SignatureMap[T] {
8+
return &SignatureMap[T]{
9+
table: map[hashedSignature][]entry[T]{},
10+
}
11+
}
12+
13+
// Implements a hash map with a Signature key. Uses the hash of types.Type via typeutil.
14+
type SignatureMap[T any] struct {
15+
table map[hashedSignature][]entry[T]
16+
}
17+
18+
type entry[T any] struct {
19+
key Signature
20+
value T
21+
}
22+
23+
type hashedSignature struct {
24+
source uint32
25+
target uint32
26+
}
27+
28+
func (m *SignatureMap[T]) At(key Signature) (T, bool) {
29+
for _, entry := range m.table[hash(key)] {
30+
if key.Identical(entry.key) {
31+
return entry.value, true
32+
}
33+
}
34+
var empty T
35+
return empty, false
36+
}
37+
38+
func (m *SignatureMap[T]) Set(key Signature, value T) {
39+
hashed := hash(key)
40+
bucket := m.table[hashed]
41+
for i, entry := range bucket {
42+
if key.Identical(entry.key) {
43+
bucket[i].value = value
44+
return
45+
}
46+
}
47+
48+
m.table[hashed] = append(bucket, entry[T]{key: key, value: value})
49+
}
50+
51+
func (m *SignatureMap[T]) Values() []T {
52+
values := make([]T, 0, len(m.table))
53+
54+
for _, bucket := range m.table {
55+
for _, entry := range bucket {
56+
values = append(values, entry.value)
57+
}
58+
}
59+
60+
return values
61+
}
62+
63+
func hash(t Signature) hashedSignature {
64+
return hashedSignature{
65+
source: theHasher.Hash(t.Source),
66+
target: theHasher.Hash(t.Target),
67+
}
68+
}
69+
70+
var theHasher typeutil.Hasher

xtype/type.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@ const ThisVar = "c"
1313

1414
// Signature represents a signature for conversion.
1515
type Signature struct {
16-
Source string
17-
Target string
16+
Source types.Type
17+
Target types.Type
18+
}
19+
20+
func (s *Signature) Identical(other Signature) bool {
21+
return types.Identical(s.Source, other.Source) && types.Identical(s.Target, other.Target)
1822
}
1923

2024
func SignatureOf(source, target *Type) Signature {
21-
return Signature{Source: source.String, Target: target.String}
25+
return Signature{Source: source.T, Target: target.T}
2226
}
2327

2428
// Type is a helper wrapper for types.Type.

0 commit comments

Comments
 (0)