1
2
3
4
5 package types
6
7
8
9
10
11
12
13
14
15
16
17
18
19 type term struct {
20 tilde bool
21 typ *Type
22 }
23
24
25
26 func (t *Type) StructuralType() *Type {
27 sts, _ := specificTypes(t)
28 var su *Type
29 for _, st := range sts {
30 u := st.typ.Underlying()
31 if su != nil {
32 u = match(su, u)
33 if u == nil {
34 return nil
35 }
36 }
37
38 su = u
39 }
40 return su
41 }
42
43
44
45
46
47
48
49 func match(x, y *Type) *Type {
50 if IdenticalStrict(x, y) {
51 return x
52 }
53
54 if x.IsChan() && y.IsChan() && IdenticalStrict(x.Elem(), y.Elem()) {
55
56
57
58 switch {
59 case x.ChanDir().CanSend() && x.ChanDir().CanRecv():
60 return y
61 case y.ChanDir().CanSend() && y.ChanDir().CanRecv():
62 return x
63 }
64 }
65 return nil
66 }
67
68
69
70
71
72 func specificTypes(t *Type) (list []term, inf bool) {
73 t.wantEtype(TINTER)
74
75
76
77 inf = true
78 for _, m := range t.Methods().Slice() {
79 var r2 []term
80 inf2 := false
81
82 switch {
83 case m.IsMethod():
84 inf2 = true
85
86 case m.Type.IsUnion():
87 nt := m.Type.NumTerms()
88 for i := 0; i < nt; i++ {
89 t, tilde := m.Type.Term(i)
90 if t.IsInterface() {
91 r3, r3inf := specificTypes(t)
92 if r3inf {
93
94
95 r2 = nil
96 inf2 = true
97 break
98 }
99
100 for _, r3e := range r3 {
101 r2 = insertType(r2, r3e)
102 }
103 } else {
104 r2 = insertType(r2, term{tilde, t})
105 }
106 }
107
108 case m.Type.IsInterface():
109 r2, inf2 = specificTypes(m.Type)
110
111 default:
112
113
114 r2 = []term{{false, m.Type}}
115 }
116
117 if inf2 {
118
119
120 continue
121 }
122
123 if inf {
124
125 list = r2
126 inf = false
127 continue
128 }
129
130
131 var r3 []term
132 for _, re := range list {
133 for _, r2e := range r2 {
134 if tm := intersect(re, r2e); tm.typ != nil {
135 r3 = append(r3, tm)
136 }
137 }
138 }
139 list = r3
140 }
141 return
142 }
143
144
145 func insertType(list []term, tm term) []term {
146 for i, elt := range list {
147 if new := union(elt, tm); new.typ != nil {
148
149 list[i] = new
150 return list
151 }
152 }
153 return append(list, tm)
154 }
155
156
157
158
159 func union(x, y term) term {
160 if disjoint(x, y) {
161 return term{false, nil}
162 }
163 if x.tilde || !y.tilde {
164 return x
165 }
166 return y
167 }
168
169
170 func intersect(x, y term) term {
171 if disjoint(x, y) {
172 return term{false, nil}
173 }
174 if !x.tilde || y.tilde {
175 return x
176 }
177 return y
178 }
179
180
181 func disjoint(x, y term) bool {
182 ux := x.typ
183 if y.tilde {
184 ux = ux.Underlying()
185 }
186 uy := y.typ
187 if x.tilde {
188 uy = uy.Underlying()
189 }
190 return !IdenticalStrict(ux, uy)
191 }
192
View as plain text