Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.0.1-2020.1.5 / internal / gosmith / type.go
1 package main
2
3 import (
4         "bufio"
5         "bytes"
6         "fmt"
7 )
8
9 type TypeClass int
10
11 const (
12         ClassBoolean TypeClass = iota
13         ClassNumeric
14         ClassComplex
15         ClassString
16         ClassArray
17         ClassSlice
18         ClassStruct
19         ClassPointer
20         ClassFunction
21         ClassInterface
22         ClassMap
23         ClassChan
24
25         TraitAny
26         TraitOrdered
27         TraitComparable
28         TraitIndexable
29         TraitReceivable
30         TraitSendable
31         TraitHashable
32         TraitPrintable
33         TraitLenCapable
34         TraitGlobal
35 )
36
37 type Type struct {
38         id             string
39         class          TypeClass
40         namedUserType  bool
41         ktyp           *Type   // map key, chan elem, array elem, slice elem, pointee type
42         vtyp           *Type   // map val
43         utyp           *Type   // underlying type
44         styp           []*Type // function arguments
45         rtyp           []*Type // function return values
46         elems          []*Var  // struct fileds and interface methods
47         literal        func() string
48         complexLiteral func() string
49
50         // TODO: cache types
51         // pointerTo *Type
52 }
53
54 func (smith *Smith) initTypes() {
55         smith.predefinedTypes = []*Type{
56                 {id: "string", class: ClassString, literal: func() string { return "\"foo\"" }},
57                 {id: "bool", class: ClassBoolean, literal: func() string { return "false" }},
58                 {id: "int", class: ClassNumeric, literal: func() string { return "1" }},
59                 {id: "byte", class: ClassNumeric, literal: func() string { return "byte(0)" }},
60                 {id: "interface{}", class: ClassInterface, literal: func() string { return "interface{}(nil)" }},
61                 {id: "rune", class: ClassNumeric, literal: func() string { return "rune(0)" }},
62                 {id: "float32", class: ClassNumeric, literal: func() string { return "float32(1.0)" }},
63                 {id: "float64", class: ClassNumeric, literal: func() string { return "1.0" }},
64                 {id: "complex64", class: ClassComplex, literal: func() string { return "complex64(1i)" }},
65                 {id: "complex128", class: ClassComplex, literal: func() string { return "1i" }},
66
67                 {id: "uint", class: ClassNumeric, literal: func() string { return "uint(1)" }},
68                 {id: "uintptr", class: ClassNumeric, literal: func() string { return "uintptr(0)" }},
69                 {id: "int16", class: ClassNumeric, literal: func() string { return "int16(1)" }},
70                 {id: "error", class: ClassInterface, literal: func() string { return "error(nil)" }},
71         }
72         for _, t := range smith.predefinedTypes {
73                 t.utyp = t
74         }
75
76         smith.stringType = smith.predefinedTypes[0]
77         smith.boolType = smith.predefinedTypes[1]
78         smith.intType = smith.predefinedTypes[2]
79         smith.byteType = smith.predefinedTypes[3]
80         smith.efaceType = smith.predefinedTypes[4]
81         smith.runeType = smith.predefinedTypes[5]
82         smith.float32Type = smith.predefinedTypes[6]
83         smith.float64Type = smith.predefinedTypes[7]
84         smith.complex64Type = smith.predefinedTypes[8]
85         smith.complex128Type = smith.predefinedTypes[9]
86
87         smith.stringType.complexLiteral = func() string {
88                 if smith.rndBool() {
89                         return `"ab\x0acd"`
90                 }
91                 return "`abc\\x0acd`"
92         }
93 }
94
95 func fmtTypeList(list []*Type, parens bool) string {
96         var buf bytes.Buffer
97         if parens || len(list) > 1 {
98                 buf.Write([]byte{'('})
99         }
100         for i, t := range list {
101                 if i != 0 {
102                         buf.Write([]byte{','})
103                 }
104                 fmt.Fprintf(&buf, "%v", t.id)
105         }
106         if parens || len(list) > 1 {
107                 buf.Write([]byte{')'})
108         }
109         return buf.String()
110 }
111
112 func (smith *Smith) atype(trait TypeClass) *Type {
113         smith.typeDepth++
114         defer func() {
115                 smith.typeDepth--
116         }()
117         for {
118                 if smith.typeDepth >= 3 || smith.rndBool() {
119                         var cand []*Type
120                         for _, t := range smith.types() {
121                                 if smith.satisfiesTrait(t, trait) {
122                                         cand = append(cand, t)
123                                 }
124                         }
125                         if len(cand) > 0 {
126                                 return cand[smith.rnd(len(cand))]
127                         }
128                 }
129                 t := smith.typeLit()
130                 if t != nil && smith.satisfiesTrait(t, trait) {
131                         return t
132                 }
133         }
134 }
135
136 func (smith *Smith) typeLit() *Type {
137         switch smith.choice("array", "chan", "struct", "pointer", "interface", "slice", "function", "map") {
138         case "array":
139                 return smith.arrayOf(smith.atype(TraitAny))
140         case "chan":
141                 return smith.chanOf(smith.atype(TraitAny))
142         case "struct":
143                 var elems []*Var
144                 var buf bytes.Buffer
145                 fmt.Fprintf(&buf, "struct { ")
146                 for smith.rndBool() {
147                         e := &Var{id: smith.newId("Field"), typ: smith.atype(TraitAny)}
148                         elems = append(elems, e)
149                         fmt.Fprintf(&buf, "%v %v\n", e.id, e.typ.id)
150                 }
151                 fmt.Fprintf(&buf, "}")
152                 id := buf.String()
153                 return &Type{
154                         id:    id,
155                         class: ClassStruct,
156                         elems: elems,
157                         literal: func() string {
158                                 return F("(%v{})", id)
159                         },
160                         complexLiteral: func() string {
161                                 if smith.rndBool() {
162                                         // unnamed
163                                         var buf bytes.Buffer
164                                         fmt.Fprintf(&buf, "(%v{", id)
165                                         for i := 0; i < len(elems); i++ {
166                                                 fmt.Fprintf(&buf, "%v, ", smith.rvalue(elems[i].typ))
167                                         }
168                                         fmt.Fprintf(&buf, "})")
169                                         return buf.String()
170                                 } else {
171                                         // named
172                                         var buf bytes.Buffer
173                                         fmt.Fprintf(&buf, "(%v{", id)
174                                         for i := 0; i < len(elems); i++ {
175                                                 if smith.rndBool() {
176                                                         fmt.Fprintf(&buf, "%v: %v, ", elems[i].id, smith.rvalue(elems[i].typ))
177                                                 }
178                                         }
179                                         fmt.Fprintf(&buf, "})")
180                                         return buf.String()
181                                 }
182                         },
183                 }
184         case "pointer":
185                 return pointerTo(smith.atype(TraitAny))
186         case "interface":
187                 var buf bytes.Buffer
188                 fmt.Fprintf(&buf, "interface { ")
189                 for smith.rndBool() {
190                         fmt.Fprintf(&buf, " %v %v %v\n", smith.newId("Method"),
191                                 fmtTypeList(smith.atypeList(TraitAny), true),
192                                 fmtTypeList(smith.atypeList(TraitAny), false))
193                 }
194                 fmt.Fprintf(&buf, "}")
195                 return &Type{
196                         id:    buf.String(),
197                         class: ClassInterface,
198                         literal: func() string {
199                                 return F("%v(nil)", buf.String())
200                         },
201                 }
202         case "slice":
203                 return smith.sliceOf(smith.atype(TraitAny))
204         case "function":
205                 return smith.funcOf(smith.atypeList(TraitAny), smith.atypeList(TraitAny))
206         case "map":
207                 ktyp := smith.atype(TraitHashable)
208                 vtyp := smith.atype(TraitAny)
209                 return &Type{
210                         id:    F("map[%v]%v", ktyp.id, vtyp.id),
211                         class: ClassMap,
212                         ktyp:  ktyp,
213                         vtyp:  vtyp,
214                         literal: func() string {
215                                 if smith.rndBool() {
216                                         cap := ""
217                                         if smith.rndBool() {
218                                                 cap = "," + smith.rvalue(smith.intType)
219                                         }
220                                         return F("make(map[%v]%v %v)", ktyp.id, vtyp.id, cap)
221                                 } else {
222                                         return F("map[%v]%v{}", ktyp.id, vtyp.id)
223                                 }
224                         },
225                 }
226         default:
227                 panic("bad")
228         }
229 }
230
231 func (smith *Smith) satisfiesTrait(t *Type, trait TypeClass) bool {
232         if trait < TraitAny {
233                 return t.class == trait
234         }
235
236         switch trait {
237         case TraitAny:
238                 return true
239         case TraitOrdered:
240                 return t.class == ClassNumeric || t.class == ClassString
241         case TraitComparable:
242                 return t.class == ClassBoolean || t.class == ClassNumeric || t.class == ClassString ||
243                         t.class == ClassPointer || t.class == ClassChan || t.class == ClassInterface
244         case TraitIndexable:
245                 return t.class == ClassArray || t.class == ClassSlice || t.class == ClassString ||
246                         t.class == ClassMap
247         case TraitReceivable:
248                 return t.class == ClassChan
249         case TraitSendable:
250                 return t.class == ClassChan
251         case TraitHashable:
252                 if t.class == ClassFunction || t.class == ClassMap || t.class == ClassSlice {
253                         return false
254                 }
255                 if t.class == ClassArray && !smith.satisfiesTrait(t.ktyp, TraitHashable) {
256                         return false
257                 }
258                 if t.class == ClassStruct {
259                         for _, e := range t.elems {
260                                 if !smith.satisfiesTrait(e.typ, TraitHashable) {
261                                         return false
262                                 }
263                         }
264                 }
265                 return true
266         case TraitPrintable:
267                 return t.class == ClassBoolean || t.class == ClassNumeric || t.class == ClassString ||
268                         t.class == ClassPointer || t.class == ClassInterface
269         case TraitLenCapable:
270                 return t.class == ClassString || t.class == ClassSlice || t.class == ClassArray ||
271                         t.class == ClassMap || t.class == ClassChan
272         case TraitGlobal:
273                 for _, t1 := range smith.predefinedTypes {
274                         if t == t1 {
275                                 return true
276                         }
277                 }
278                 return false
279         default:
280                 panic("bad")
281         }
282 }
283
284 func (smith *Smith) atypeList(trait TypeClass) []*Type {
285         n := smith.rnd(4) + 1
286         list := make([]*Type, n)
287         for i := 0; i < n; i++ {
288                 list[i] = smith.atype(trait)
289         }
290         return list
291 }
292
293 func typeList(t *Type, n int) []*Type {
294         list := make([]*Type, n)
295         for i := 0; i < n; i++ {
296                 list[i] = t
297         }
298         return list
299 }
300
301 func pointerTo(elem *Type) *Type {
302         return &Type{
303                 id:    F("*%v", elem.id),
304                 class: ClassPointer,
305                 ktyp:  elem,
306                 literal: func() string {
307                         return F("(*%v)(nil)", elem.id)
308                 }}
309 }
310
311 func (smith *Smith) chanOf(elem *Type) *Type {
312         return &Type{
313                 id:    F("chan %v", elem.id),
314                 class: ClassChan,
315                 ktyp:  elem,
316                 literal: func() string {
317                         cap := ""
318                         if smith.rndBool() {
319                                 cap = "," + smith.rvalue(smith.intType)
320                         }
321                         return F("make(chan %v %v)", elem.id, cap)
322                 },
323         }
324 }
325
326 func (smith *Smith) sliceOf(elem *Type) *Type {
327         return &Type{
328                 id:    F("[]%v", elem.id),
329                 class: ClassSlice,
330                 ktyp:  elem,
331                 literal: func() string {
332                         return F("[]%v{}", elem.id)
333                 },
334                 complexLiteral: func() string {
335                         switch smith.choice("normal", "keyed") {
336                         case "normal":
337                                 return F("[]%v{%v}", elem.id, smith.fmtRvalueList(typeList(elem, smith.rnd(3))))
338                         case "keyed":
339                                 n := smith.rnd(3)
340                                 var indexes []int
341                         loop:
342                                 for len(indexes) < n {
343                                         i := smith.rnd(10)
344                                         for _, i1 := range indexes {
345                                                 if i1 == i {
346                                                         continue loop
347                                                 }
348                                         }
349                                         indexes = append(indexes, i)
350                                 }
351                                 var buf bytes.Buffer
352                                 fmt.Fprintf(&buf, "[]%v{", elem.id)
353                                 for i, idx := range indexes {
354                                         if i != 0 {
355                                                 fmt.Fprintf(&buf, ",")
356                                         }
357                                         fmt.Fprintf(&buf, "%v: %v", idx, smith.rvalue(elem))
358                                 }
359                                 fmt.Fprintf(&buf, "}")
360                                 return buf.String()
361                         default:
362                                 panic("bad")
363                         }
364                 },
365         }
366 }
367
368 func (smith *Smith) arrayOf(elem *Type) *Type {
369         size := smith.rnd(3)
370         return &Type{
371                 id:    F("[%v]%v", size, elem.id),
372                 class: ClassArray,
373                 ktyp:  elem,
374                 literal: func() string {
375                         return F("[%v]%v{}", size, elem.id)
376                 },
377                 complexLiteral: func() string {
378                         switch smith.choice("normal", "keyed") {
379                         case "normal":
380                                 return F("[%v]%v{%v}", smith.choice(F("%v", size), "..."), elem.id, smith.fmtRvalueList(typeList(elem, size)))
381                         case "keyed":
382                                 var buf bytes.Buffer
383                                 fmt.Fprintf(&buf, "[%v]%v{", size, elem.id)
384                                 for i := 0; i < size; i++ {
385                                         if i != 0 {
386                                                 fmt.Fprintf(&buf, ",")
387                                         }
388                                         fmt.Fprintf(&buf, "%v: %v", i, smith.rvalue(elem))
389                                 }
390                                 fmt.Fprintf(&buf, "}")
391                                 return buf.String()
392                         default:
393                                 panic("bad")
394                         }
395                 },
396         }
397 }
398
399 func (smith *Smith) funcOf(alist, rlist []*Type) *Type {
400         t := &Type{
401                 id:    F("func%v %v", fmtTypeList(alist, true), fmtTypeList(rlist, false)),
402                 class: ClassFunction,
403                 styp:  alist,
404                 rtyp:  rlist,
405         }
406         t.literal = func() string {
407                 return F("((func%v %v)(nil))", fmtTypeList(alist, true), fmtTypeList(rlist, false))
408         }
409         t.complexLiteral = func() string {
410                 return smith.genFuncLit(t)
411         }
412         return t
413 }
414
415 func (smith *Smith) genFuncLit(ft *Type) string {
416         //return F("((func%v %v)(nil))", fmtTypeList(ft.styp, true), fmtTypeList(ft.rtyp, false))
417
418         if smith.curBlockPos == -1 {
419                 smith.line("")
420         }
421
422         f := &Func{args: ft.styp, rets: ft.rtyp}
423         curFunc0 := smith.curFunc
424         smith.curFunc = f
425         curBlock0 := smith.curBlock
426         curBlockPos0 := smith.curBlockPos
427         curBlockLen0 := len(smith.curBlock.sub)
428         exprDepth0 := smith.exprDepth
429         exprCount0 := smith.exprCount
430         smith.exprDepth = 0
431         smith.exprCount = 0
432         defer func() {
433                 smith.curBlock = curBlock0
434                 smith.curFunc = curFunc0
435                 smith.exprDepth = exprDepth0
436                 smith.exprCount = exprCount0
437                 smith.curBlockPos = curBlockPos0 + (len(smith.curBlock.sub) - curBlockLen0)
438         }()
439
440         fb := &Block{parent: smith.curBlock, subBlock: smith.curBlock.sub[smith.curBlockPos]}
441         smith.curBlock = fb
442         smith.enterBlock(true)
443         smith.enterBlock(true)
444         argIds := make([]string, len(f.args))
445         argStr := ""
446         for i, a := range f.args {
447                 argIds[i] = smith.newId("Param")
448                 if i != 0 {
449                         argStr += ", "
450                 }
451                 argStr += argIds[i] + " " + a.id
452         }
453         smith.line("func(%v)%v {", argStr, fmtTypeList(f.rets, false))
454         for i, a := range f.args {
455                 smith.defineVar(argIds[i], a)
456         }
457         smith.curBlock.funcBoundary = true
458         smith.genBlock()
459         smith.leaveBlock()
460         smith.stmtReturn()
461         smith.line("}")
462         smith.leaveBlock()
463
464         //b := curBlock.sub[curBlockPos]
465         //copy(curBlock.sub[curBlockPos:], curBlock.sub[curBlockPos+1:])
466         //curBlock.sub = curBlock.sub[:len(curBlock.sub)-1]
467
468         var buf bytes.Buffer
469         w := bufio.NewWriter(&buf)
470         serializeBlock(w, fb, 0)
471         w.Flush()
472         s := buf.String()
473         //fmt.Printf("GEN FUNC:\n%v\n", s)
474         return s[:len(s)-1]
475 }
476
477 func dependsOn(t, t0 *Type) bool {
478         if t == nil {
479                 return false
480         }
481         if t.class == ClassInterface {
482                 // We don't know how to walk all types referenced by an interface yet.
483                 return true
484         }
485         if t0 == nil && t.namedUserType {
486                 return true
487         }
488         if t == t0 {
489                 return true
490         }
491         if dependsOn(t.ktyp, t0) {
492                 return true
493         }
494         if dependsOn(t.vtyp, t0) {
495                 return true
496         }
497         if dependsOn(t.ktyp, t0) {
498                 return true
499         }
500         for _, t1 := range t.styp {
501                 if dependsOn(t1, t0) {
502                         return true
503                 }
504         }
505         for _, t1 := range t.rtyp {
506                 if dependsOn(t1, t0) {
507                         return true
508                 }
509         }
510         for _, e := range t.elems {
511                 if dependsOn(e.typ, t0) {
512                         return true
513                 }
514         }
515         return false
516 }