/
identical.go
149 lines (131 loc) · 4.71 KB
/
identical.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package typemap
import (
"go/types"
)
// Unlike types.Identical, receivers of Signature types are not ignored.
// Unlike types.Identical, interfaces are compared via pointer equality (except for the empty interface, which gets deduplicated).
// Unlike types.Identical, structs are compared via pointer equality.
func identical0(x, y types.Type) bool {
if x == y {
return true
}
switch x := x.(type) {
case *types.Basic:
// Basic types are singletons except for the rune and byte
// aliases, thus we cannot solely rely on the x == y check
// above. See also comment in TypeName.IsAlias.
if y, ok := y.(*types.Basic); ok {
return x.Kind() == y.Kind()
}
case *types.Array:
// Two array types are identical if they have identical element types
// and the same array length.
if y, ok := y.(*types.Array); ok {
// If one or both array lengths are unknown (< 0) due to some error,
// assume they are the same to avoid spurious follow-on errors.
return (x.Len() < 0 || y.Len() < 0 || x.Len() == y.Len()) && identical0(x.Elem(), y.Elem())
}
case *types.Slice:
// Two slice types are identical if they have identical element types.
if y, ok := y.(*types.Slice); ok {
return identical0(x.Elem(), y.Elem())
}
case *types.Struct:
if y, ok := y.(*types.Struct); ok {
return x == y
}
case *types.Pointer:
// Two pointer types are identical if they have identical base types.
if y, ok := y.(*types.Pointer); ok {
return identical0(x.Elem(), y.Elem())
}
case *types.Tuple:
// Two tuples types are identical if they have the same number of elements
// and corresponding elements have identical types.
if y, ok := y.(*types.Tuple); ok {
if x.Len() == y.Len() {
if x != nil {
for i := 0; i < x.Len(); i++ {
v := x.At(i)
w := y.At(i)
if !identical0(v.Type(), w.Type()) {
return false
}
}
}
return true
}
}
case *types.Signature:
// Two function types are identical if they have the same number of parameters
// and result values, corresponding parameter and result types are identical,
// and either both functions are variadic or neither is. Parameter and result
// names are not required to match.
if y, ok := y.(*types.Signature); ok {
return x.Variadic() == y.Variadic() &&
identical0(x.Params(), y.Params()) &&
identical0(x.Results(), y.Results()) &&
(x.Recv() != nil && y.Recv() != nil && identical0(x.Recv().Type(), y.Recv().Type()) || x.Recv() == nil && y.Recv() == nil)
}
case *types.Interface:
// The issue with interfaces, typeutil.Map and types.Identical
//
// types.Identical, when comparing two interfaces, only looks at the set
// of all methods, not differentiating between implicit (embedded) and
// explicit methods.
//
// When we see the following two types, in source order
//
// type I1 interface { foo() }
// type I2 interface { I1 }
//
// then we will first correctly process I1 and its underlying type. When
// we get to I2, we will see that its underlying type is identical to
// that of I1 and not process it again. This, however, means that we will
// not record the fact that I2 embeds I1. If only I2 is reachable via the
// graph root, then I1 will not be considered used.
//
// We choose to be lazy and compare interfaces by their
// pointers. This will obviously miss identical interfaces,
// but this only has a runtime cost, it doesn't affect
// correctness.
if y, ok := y.(*types.Interface); ok {
if x.NumEmbeddeds() == 0 &&
y.NumEmbeddeds() == 0 &&
x.NumMethods() == 0 &&
y.NumMethods() == 0 {
// all truly empty interfaces are the same
return true
}
return x == y
}
case *types.Map:
// Two map types are identical if they have identical key and value types.
if y, ok := y.(*types.Map); ok {
return identical0(x.Key(), y.Key()) && identical0(x.Elem(), y.Elem())
}
case *types.Chan:
// Two channel types are identical if they have identical value types
// and the same direction.
if y, ok := y.(*types.Chan); ok {
return x.Dir() == y.Dir() && identical0(x.Elem(), y.Elem())
}
case *types.Named:
// Two named types are identical if their type names originate
// in the same type declaration.
if y, ok := y.(*types.Named); ok {
return x.Obj() == y.Obj()
}
case nil:
default:
panic("unreachable")
}
return false
}
// Identical reports whether x and y are identical types.
// Unlike types.Identical, receivers of Signature types are not ignored.
// Unlike types.Identical, interfaces are compared via pointer equality (except for the empty interface, which gets deduplicated).
// Unlike types.Identical, structs are compared via pointer equality.
func Identical(x, y types.Type) (ret bool) {
return identical0(x, y)
}