1 package code
2
3 import (
4 "fmt"
5 "go/types"
6 )
7
8
9 func CompatibleTypes(expected, actual types.Type) error {
10
11 {
12 expectedPtr, expectedIsPtr := expected.(*types.Pointer)
13 actualPtr, actualIsPtr := actual.(*types.Pointer)
14
15 if expectedIsPtr && actualIsPtr {
16 return CompatibleTypes(expectedPtr.Elem(), actualPtr.Elem())
17 }
18 if expectedIsPtr && !actualIsPtr {
19 return CompatibleTypes(expectedPtr.Elem(), actual)
20 }
21 if !expectedIsPtr && actualIsPtr {
22 return CompatibleTypes(expected, actualPtr.Elem())
23 }
24 }
25
26 switch expected := expected.(type) {
27 case *types.Slice:
28 if actual, ok := actual.(*types.Slice); ok {
29 return CompatibleTypes(expected.Elem(), actual.Elem())
30 }
31
32 case *types.Array:
33 if actual, ok := actual.(*types.Array); ok {
34 if expected.Len() != actual.Len() {
35 return fmt.Errorf("array length differs")
36 }
37
38 return CompatibleTypes(expected.Elem(), actual.Elem())
39 }
40
41 case *types.Basic:
42 if actual, ok := actual.(*types.Basic); ok {
43 if actual.Kind() != expected.Kind() {
44 return fmt.Errorf("basic kind differs, %s != %s", expected.Name(), actual.Name())
45 }
46
47 return nil
48 }
49
50 case *types.Struct:
51 if actual, ok := actual.(*types.Struct); ok {
52 if expected.NumFields() != actual.NumFields() {
53 return fmt.Errorf("number of struct fields differ")
54 }
55
56 for i := 0; i < expected.NumFields(); i++ {
57 if expected.Field(i).Name() != actual.Field(i).Name() {
58 return fmt.Errorf("struct field %d name differs, %s != %s", i, expected.Field(i).Name(), actual.Field(i).Name())
59 }
60 if err := CompatibleTypes(expected.Field(i).Type(), actual.Field(i).Type()); err != nil {
61 return err
62 }
63 }
64 return nil
65 }
66
67 case *types.Tuple:
68 if actual, ok := actual.(*types.Tuple); ok {
69 if expected.Len() != actual.Len() {
70 return fmt.Errorf("tuple length differs, %d != %d", expected.Len(), actual.Len())
71 }
72
73 for i := 0; i < expected.Len(); i++ {
74 if err := CompatibleTypes(expected.At(i).Type(), actual.At(i).Type()); err != nil {
75 return err
76 }
77 }
78
79 return nil
80 }
81
82 case *types.Signature:
83 if actual, ok := actual.(*types.Signature); ok {
84 if err := CompatibleTypes(expected.Params(), actual.Params()); err != nil {
85 return err
86 }
87 err := CompatibleTypes(expected.Results(), actual.Results())
88 return err
89 }
90 case *types.Interface:
91 if actual, ok := actual.(*types.Interface); ok {
92 if expected.NumMethods() != actual.NumMethods() {
93 return fmt.Errorf("interface method count differs, %d != %d", expected.NumMethods(), actual.NumMethods())
94 }
95
96 for i := 0; i < expected.NumMethods(); i++ {
97 if expected.Method(i).Name() != actual.Method(i).Name() {
98 return fmt.Errorf("interface method %d name differs, %s != %s", i, expected.Method(i).Name(), actual.Method(i).Name())
99 }
100 if err := CompatibleTypes(expected.Method(i).Type(), actual.Method(i).Type()); err != nil {
101 return err
102 }
103 }
104
105 return nil
106 }
107
108 case *types.Map:
109 if actual, ok := actual.(*types.Map); ok {
110 if err := CompatibleTypes(expected.Key(), actual.Key()); err != nil {
111 return err
112 }
113
114 err := CompatibleTypes(expected.Elem(), actual.Elem())
115 return err
116 }
117
118 case *types.Chan:
119 if actual, ok := actual.(*types.Chan); ok {
120 return CompatibleTypes(expected.Elem(), actual.Elem())
121 }
122
123 case *types.Named:
124 if actual, ok := actual.(*types.Named); ok {
125 if NormalizeVendor(expected.Obj().Pkg().Path()) != NormalizeVendor(actual.Obj().Pkg().Path()) {
126 return fmt.Errorf(
127 "package name of named type differs, %s != %s",
128 NormalizeVendor(expected.Obj().Pkg().Path()),
129 NormalizeVendor(actual.Obj().Pkg().Path()),
130 )
131 }
132
133 if expected.Obj().Name() != actual.Obj().Name() {
134 return fmt.Errorf(
135 "named type name differs, %s != %s",
136 NormalizeVendor(expected.Obj().Name()),
137 NormalizeVendor(actual.Obj().Name()),
138 )
139 }
140
141 return nil
142 }
143
144
145
146 if actual, ok := actual.(*types.Basic); ok && actual.Kind() == types.Invalid {
147 return nil
148 }
149
150 default:
151 return fmt.Errorf("missing support for %T", expected)
152 }
153
154 return fmt.Errorf("type mismatch %T != %T", expected, actual)
155 }
156
View as plain text