1
2
3
4
5 package typeparams
6
7 import (
8 "errors"
9 "fmt"
10 "go/types"
11 "os"
12 "strings"
13 )
14
15
16
17 const debug = false
18
19 var ErrEmptyTypeSet = errors.New("empty type set")
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 func StructuralTerms(tparam *TypeParam) ([]*Term, error) {
64 constraint := tparam.Constraint()
65 if constraint == nil {
66 return nil, fmt.Errorf("%s has nil constraint", tparam)
67 }
68 iface, _ := constraint.Underlying().(*types.Interface)
69 if iface == nil {
70 return nil, fmt.Errorf("constraint is %T, not *types.Interface", constraint.Underlying())
71 }
72 return InterfaceTermSet(iface)
73 }
74
75
76
77
78
79
80
81 func InterfaceTermSet(iface *types.Interface) ([]*Term, error) {
82 return computeTermSet(iface)
83 }
84
85
86
87
88
89
90
91 func UnionTermSet(union *Union) ([]*Term, error) {
92 return computeTermSet(union)
93 }
94
95 func computeTermSet(typ types.Type) ([]*Term, error) {
96 tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0)
97 if err != nil {
98 return nil, err
99 }
100 if tset.terms.isEmpty() {
101 return nil, ErrEmptyTypeSet
102 }
103 if tset.terms.isAll() {
104 return nil, nil
105 }
106 var terms []*Term
107 for _, term := range tset.terms {
108 terms = append(terms, NewTerm(term.tilde, term.typ))
109 }
110 return terms, nil
111 }
112
113
114
115
116
117
118 type termSet struct {
119 complete bool
120 terms termlist
121 }
122
123 func indentf(depth int, format string, args ...interface{}) {
124 fmt.Fprintf(os.Stderr, strings.Repeat(".", depth)+format+"\n", args...)
125 }
126
127 func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) {
128 if t == nil {
129 panic("nil type")
130 }
131
132 if debug {
133 indentf(depth, "%s", t.String())
134 defer func() {
135 if err != nil {
136 indentf(depth, "=> %s", err)
137 } else {
138 indentf(depth, "=> %s", res.terms.String())
139 }
140 }()
141 }
142
143 const maxTermCount = 100
144 if tset, ok := seen[t]; ok {
145 if !tset.complete {
146 return nil, fmt.Errorf("cycle detected in the declaration of %s", t)
147 }
148 return tset, nil
149 }
150
151
152 tset := new(termSet)
153 defer func() {
154 tset.complete = true
155 }()
156 seen[t] = tset
157
158 switch u := t.Underlying().(type) {
159 case *types.Interface:
160
161
162 tset.terms = allTermlist
163 for i := 0; i < u.NumEmbeddeds(); i++ {
164 embedded := u.EmbeddedType(i)
165 if _, ok := embedded.Underlying().(*TypeParam); ok {
166 return nil, fmt.Errorf("invalid embedded type %T", embedded)
167 }
168 tset2, err := computeTermSetInternal(embedded, seen, depth+1)
169 if err != nil {
170 return nil, err
171 }
172 tset.terms = tset.terms.intersect(tset2.terms)
173 }
174 case *Union:
175
176 tset.terms = nil
177 for i := 0; i < u.Len(); i++ {
178 t := u.Term(i)
179 var terms termlist
180 switch t.Type().Underlying().(type) {
181 case *types.Interface:
182 tset2, err := computeTermSetInternal(t.Type(), seen, depth+1)
183 if err != nil {
184 return nil, err
185 }
186 terms = tset2.terms
187 case *TypeParam, *Union:
188
189
190 return nil, fmt.Errorf("invalid union term %T", t)
191 default:
192 if t.Type() == types.Typ[types.Invalid] {
193 continue
194 }
195 terms = termlist{{t.Tilde(), t.Type()}}
196 }
197 tset.terms = tset.terms.union(terms)
198 if len(tset.terms) > maxTermCount {
199 return nil, fmt.Errorf("exceeded max term count %d", maxTermCount)
200 }
201 }
202 case *TypeParam:
203 panic("unreachable")
204 default:
205
206
207 if u != types.Typ[types.Invalid] {
208 tset.terms = termlist{{false, t}}
209 }
210 }
211 return tset, nil
212 }
213
214
215
216 func under(t types.Type) types.Type {
217 return t.Underlying()
218 }
219
View as plain text