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 / expr.go
1 package main
2
3 import (
4         "bytes"
5         "fmt"
6 )
7
8 func (smith *Smith) initExpressions() {
9         smith.expressions = []func(res *Type) string{
10                 smith.exprLiteral,
11                 smith.exprVar,
12                 smith.exprFunc,
13                 smith.exprSelectorField,
14                 smith.exprRecv,
15                 smith.exprArith,
16                 smith.exprEqual,
17                 smith.exprOrder,
18                 smith.exprCall,
19                 smith.exprCallBuiltin,
20                 smith.exprAddress,
21                 smith.exprDeref,
22                 smith.exprSlice,
23                 smith.exprIndexSlice,
24                 smith.exprIndexArray,
25                 smith.exprIndexString,
26                 smith.exprIndexMap,
27                 smith.exprConversion,
28         }
29 }
30
31 func (smith *Smith) expression(res *Type) string {
32         smith.exprCount++
33         smith.totalExprCount++
34         if smith.exprDepth >= NExprDepth || smith.exprCount >= NExprCount || smith.totalExprCount >= NTotalExprCount {
35                 return res.literal()
36         }
37         for {
38                 smith.exprDepth++
39                 s := smith.expressions[smith.rnd(len(smith.expressions))](res)
40                 smith.exprDepth--
41                 if s != "" {
42                         return s
43                 }
44         }
45 }
46
47 func (smith *Smith) rvalue(t *Type) string {
48         return smith.expression(t)
49 }
50
51 // rvalue, but not a const
52 // used to index arrays and strings
53 func (smith *Smith) nonconstRvalue(t *Type) string {
54         if t.class != ClassNumeric {
55                 panic("bad")
56         }
57 trying:
58         for {
59                 res := ""
60                 switch smith.choice("lvalue", "call", "len", "selector", "recv", "arith", "indexMap", "conv") {
61                 case "lvalue":
62                         res = smith.lvalue(t)
63                 case "call":
64                         res = smith.exprCall(t)
65                 case "len":
66                         tt := smith.atype(TraitLenCapable)
67                         fn := smith.choice("len", "cap")
68                         if (tt.class == ClassString || tt.class == ClassMap) && fn == "cap" {
69                                 break
70                         }
71                         if tt.class == ClassArray {
72                                 // len/cap are const
73                                 break
74                         }
75                         res = F("(%v)((%v)(%v))", t.id, fn, smith.lvalue(tt))
76                 case "selector":
77                         res = smith.exprSelectorField(t)
78                 case "recv":
79                         res = smith.exprRecv(t)
80                 case "arith":
81                         res = F("(%v) %v (%v)", smith.lvalue(t), smith.choice("+", "-"), smith.rvalue(t))
82                 case "indexMap":
83                         res = smith.exprIndexMap(t)
84                 case "conv":
85                         res = F("(%v)(%v %v)", t.id, smith.lvalue(smith.atype(ClassNumeric)), smith.choice("", ","))
86                 default:
87                         panic("bad")
88                 }
89                 if res == "" {
90                         continue trying
91                 }
92                 return res
93         }
94 }
95
96 func (smith *Smith) lvalue(t *Type) string {
97         for {
98                 switch smith.choice("var", "indexSlice", "indexArray", "selector", "deref") {
99                 case "var":
100                         return smith.exprVar(t)
101                 case "indexSlice":
102                         return smith.exprIndexSlice(t)
103                 case "indexArray":
104                         return F("(%v)[%v]", smith.lvalue(smith.arrayOf(t)), smith.nonconstRvalue(smith.intType))
105                 case "selector":
106                         for i := 0; i < 10; i++ {
107                                 st := smith.atype(ClassStruct)
108                                 for _, e := range st.elems {
109                                         if e.typ == t {
110                                                 return F("(%v).%v", smith.lvalue(st), e.id)
111                                         }
112                                 }
113                         }
114                         continue
115                 case "deref":
116                         return smith.exprDeref(t)
117                 default:
118                         panic("bad")
119                 }
120         }
121 }
122
123 func (smith *Smith) lvalueOrBlank(t *Type) string {
124         for {
125                 switch smith.choice("lvalue", "map", "blank") {
126                 case "lvalue":
127                         return smith.lvalue(t)
128                 case "map":
129                         if e := smith.exprIndexMap(t); e != "" {
130                                 return e
131                         }
132                 case "blank":
133                         return "_"
134                 default:
135                         panic("bad")
136                 }
137         }
138 }
139
140 func (smith *Smith) lvalueOrMapIndex(t *Type) string {
141         for {
142                 switch smith.choice("lvalue", "map") {
143                 case "lvalue":
144                         return smith.lvalue(t)
145                 case "map":
146                         if e := smith.exprIndexMap(t); e != "" {
147                                 return e
148                         }
149                 default:
150                         panic("bad")
151                 }
152         }
153 }
154
155 func (smith *Smith) fmtRvalueList(list []*Type) string {
156         var buf bytes.Buffer
157         for i, t := range list {
158                 if i != 0 {
159                         buf.Write([]byte{','})
160                 }
161                 fmt.Fprintf(&buf, "%v", smith.rvalue(t))
162         }
163         return buf.String()
164 }
165
166 func (smith *Smith) fmtLvalueList(list []*Type) string {
167         var buf bytes.Buffer
168         for i, t := range list {
169                 if i != 0 {
170                         buf.Write([]byte{','})
171                 }
172                 buf.WriteString(smith.lvalueOrBlank(t))
173         }
174         return buf.String()
175 }
176
177 func (smith *Smith) fmtOasVarList(list []*Type) (str string, newVars []*Var) {
178         allVars := smith.vars()
179         var buf bytes.Buffer
180         for i, t := range list {
181                 expr := "_"
182                 // First, try to find an existing var in the same scope.
183                 if smith.rndBool() {
184                         for i, v := range allVars {
185                                 if v.typ == t && v.block == smith.curBlock {
186                                         allVars[i] = allVars[len(allVars)-1]
187                                         allVars = allVars[:len(allVars)-1]
188                                         expr = v.id
189                                         break
190                                 }
191                         }
192                 }
193                 if smith.rndBool() || (i == len(list)-1 && len(newVars) == 0) {
194                         expr = smith.newId("Var")
195                         newVars = append(newVars, &Var{id: expr, typ: t})
196                 }
197
198                 if i != 0 {
199                         buf.WriteString(", ")
200                 }
201                 buf.WriteString(expr)
202         }
203         return buf.String(), newVars
204 }
205
206 func (smith *Smith) exprLiteral(res *Type) string {
207         if res.complexLiteral != nil {
208                 return res.complexLiteral()
209         }
210         return res.literal()
211 }
212
213 func (smith *Smith) exprVar(res *Type) string {
214         for _, v := range smith.vars() {
215                 if v.typ == res {
216                         return v.id
217                 }
218         }
219         return smith.materializeVar(res)
220 }
221
222 func (smith *Smith) exprSelectorField(res *Type) string {
223         for i := 0; i < 10; i++ {
224                 st := smith.atype(ClassStruct)
225                 for _, e := range st.elems {
226                         if e.typ == res {
227                                 return F("(%v).%v", smith.rvalue(st), e.id)
228                         }
229                 }
230         }
231         return ""
232 }
233
234 func (smith *Smith) exprFunc(res *Type) string {
235         if !smith.satisfiesTrait(res, TraitGlobal) {
236                 return ""
237         }
238         var f *Func
239         for _, f1 := range smith.packages[smith.curPackage].toplevFuncs {
240                 if len(f1.rets) == 1 && f1.rets[0] == res {
241                         f = f1
242                         break
243                 }
244         }
245         if f == nil {
246                 f = smith.materializeFunc([]*Type{res})
247         }
248         if smith.rndBool() {
249                 return F("%v(%v)", f.name, smith.fmtRvalueList(f.args))
250         } else {
251                 var f0 *Func
252         loop:
253                 for _, f1 := range smith.packages[smith.curPackage].toplevFuncs {
254                         if len(f1.rets) == len(f.args) {
255                                 for i := range f.args {
256                                         // TODO: check assignability
257                                         if f1.rets[i] != f.args[i] {
258                                                 continue loop
259                                         }
260                                 }
261                                 f0 = f1
262                                 break
263                         }
264                 }
265                 if f0 == nil {
266                         f0 = smith.materializeFunc(f.args)
267                 }
268                 return F("%v(%v(%v))", f.name, f0.name, smith.fmtRvalueList(f0.args))
269         }
270 }
271
272 func (smith *Smith) exprAddress(res *Type) string {
273         if res.class != ClassPointer {
274                 return ""
275         }
276         if res.ktyp.class == ClassStruct && smith.rndBool() {
277                 return F("&%v", res.ktyp.complexLiteral())
278         }
279         return F("(%v)(&(%v))", res.id, smith.lvalue(res.ktyp))
280 }
281
282 func (smith *Smith) exprDeref(res *Type) string {
283         return F("(*(%v))", smith.lvalue(pointerTo(res)))
284 }
285
286 func (smith *Smith) exprRecv(res *Type) string {
287         t := smith.chanOf(res)
288         return F("(<- %v)", smith.rvalue(t))
289 }
290
291 func (smith *Smith) exprArith(res *Type) string {
292         if res.class != ClassNumeric && res.class != ClassComplex {
293                 return ""
294         }
295         // "/" causes division by zero
296         // "*" causes generation of -1 index in int(real(1i * 1i))
297         return F("(%v) + (%v)", smith.rvalue(res), smith.rvalue(res))
298 }
299
300 func (smith *Smith) exprEqual(res *Type) string {
301         if res != smith.boolType {
302                 return ""
303         }
304         t := smith.atype(TraitComparable)
305         return F("(%v) %v (%v)", smith.rvalue(t), smith.choice("==", "!="), smith.rvalue(t))
306 }
307
308 func (smith *Smith) exprOrder(res *Type) string {
309         if res != smith.boolType {
310                 return ""
311         }
312         t := smith.atype(TraitOrdered)
313         return F("(%v) %v (%v)", smith.rvalue(t), smith.choice("<", "<=", ">", ">="), smith.rvalue(t))
314
315 }
316
317 func (smith *Smith) exprCall(ret *Type) string {
318         t := smith.funcOf(smith.atypeList(TraitAny), []*Type{ret})
319         return F("%v(%v)", smith.rvalue(t), smith.fmtRvalueList(t.styp))
320 }
321
322 func (smith *Smith) exprCallBuiltin(ret *Type) string {
323         switch fn := smith.choice("append", "cap", "complex", "copy", "imag", "len", "make", "new", "real", "recover"); fn {
324         case "append":
325                 if ret.class != ClassSlice {
326                         return ""
327                 }
328                 switch smith.choice("one", "two", "slice") {
329                 case "one":
330                         return F("%v(%v, %v)", fn, smith.rvalue(ret), smith.rvalue(ret.ktyp))
331                 case "two":
332                         return F("%v(%v, %v, %v)", fn, smith.rvalue(ret), smith.rvalue(ret.ktyp), smith.rvalue(ret.ktyp))
333                 case "slice":
334                         return F("%v(%v, %v...)", fn, smith.rvalue(ret), smith.rvalue(ret))
335                 default:
336                         panic("bad")
337                 }
338         case "len", "cap":
339                 if ret != smith.intType { // TODO: must be convertable
340                         return ""
341                 }
342                 t := smith.atype(TraitLenCapable)
343                 if (t.class == ClassString || t.class == ClassMap) && fn == "cap" {
344                         return ""
345
346                 }
347                 return F("%v(%v)", fn, smith.rvalue(t))
348         case "copy":
349                 if ret != smith.intType {
350                         return ""
351                 }
352                 return F("%v", smith.exprCopySlice())
353         case "make":
354                 if ret.class != ClassSlice && ret.class != ClassMap && ret.class != ClassChan {
355                         return ""
356                 }
357                 cap := ""
358                 if ret.class == ClassSlice {
359                         if smith.rndBool() {
360                                 cap = F(", %v", smith.rvalue(smith.intType))
361                         } else {
362                                 // Careful to not generate "len larger than cap".
363                                 cap = F(", 0, %v", smith.rvalue(smith.intType))
364                         }
365                 } else if smith.rndBool() {
366                         cap = F(", %v", smith.rvalue(smith.intType))
367                 }
368                 return F("make(%v %v)", ret.id, cap)
369         case "new":
370                 if ret.class != ClassPointer {
371                         return ""
372                 }
373                 return F("new(%v)", ret.ktyp.id)
374         case "recover":
375                 if ret != smith.efaceType {
376                         return ""
377                 }
378                 return "recover()"
379         case "real", "imag":
380                 if ret == smith.float32Type {
381                         return F("real(%v)", smith.rvalue(smith.complex64Type))
382                 }
383                 if ret == smith.float64Type {
384                         return F("real(%v)", smith.rvalue(smith.complex128Type))
385                 }
386                 return ""
387         case "complex":
388                 if ret == smith.complex64Type {
389                         return F("complex(%v, %v)", smith.rvalue(smith.float32Type), smith.rvalue(smith.float32Type))
390                 }
391                 if ret == smith.complex128Type {
392                         return F("complex(%v, %v)", smith.rvalue(smith.float64Type), smith.rvalue(smith.float64Type))
393                 }
394                 return ""
395         default:
396                 panic("bad")
397         }
398 }
399
400 func (smith *Smith) exprCopySlice() string {
401         if smith.rndBool() {
402                 t := smith.atype(ClassSlice)
403                 return F("copy(%v, %v)", smith.rvalue(t), smith.rvalue(t))
404         } else {
405                 return F("copy(%v, %v)", smith.rvalue(smith.sliceOf(smith.byteType)), smith.rvalue(smith.stringType))
406         }
407 }
408
409 func (smith *Smith) exprSlice(ret *Type) string {
410         if ret.class != ClassSlice {
411                 return ""
412         }
413         i0 := ""
414         if smith.rndBool() {
415                 i0 = smith.nonconstRvalue(smith.intType)
416         }
417         i2 := ""
418         if smith.rndBool() {
419                 i2 = ":" + smith.nonconstRvalue(smith.intType)
420         }
421         i1 := ":"
422         if smith.rndBool() || i2 != "" {
423                 i1 = ":" + smith.nonconstRvalue(smith.intType)
424         }
425         return F("(%v)[%v%v%v]", smith.rvalue(ret), i0, i1, i2)
426 }
427
428 func (smith *Smith) exprIndexSlice(ret *Type) string {
429         return F("(%v)[%v]", smith.rvalue(smith.sliceOf(ret)), smith.nonconstRvalue(smith.intType))
430 }
431
432 func (smith *Smith) exprIndexString(ret *Type) string {
433         if ret != smith.byteType {
434                 return ""
435         }
436         return F("(%v)[%v]", smith.rvalue(smith.stringType), smith.nonconstRvalue(smith.intType))
437 }
438
439 func (smith *Smith) exprIndexArray(ret *Type) string {
440         // TODO: also handle indexing of pointers to arrays
441         return F("(%v)[%v]", smith.rvalue(smith.arrayOf(ret)), smith.nonconstRvalue(smith.intType))
442 }
443
444 func (smith *Smith) exprIndexMap(ret *Type) string {
445         // TODO: figure out something better
446         for i := 0; i < 10; i++ {
447                 t := smith.atype(ClassMap)
448                 if t.vtyp == ret {
449                         return F("(%v)[%v]", smith.rvalue(t), smith.rvalue(t.ktyp))
450                 }
451         }
452         return ""
453 }
454
455 func (smith *Smith) exprConversion(ret *Type) string {
456         if ret.class == ClassNumeric {
457                 return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.atype(ClassNumeric)), smith.choice("", ","))
458         }
459         if ret.class == ClassComplex {
460                 return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.atype(ClassComplex)), smith.choice("", ","))
461         }
462         if ret == smith.stringType {
463                 switch smith.choice("int", "byteSlice", "runeSlice") {
464                 case "int":
465                         // We produce a string of length at least 3, to not produce
466                         // "invalid string index 1 (out of bounds for 1-byte string)"
467                         return F("(%v)((%v) + (1<<24) %v)", ret.id, smith.rvalue(smith.intType), smith.choice("", ","))
468                 case "byteSlice":
469                         return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.sliceOf(smith.byteType)), smith.choice("", ","))
470                 case "runeSlice":
471                         return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.sliceOf(smith.runeType)), smith.choice("", ","))
472                 default:
473                         panic("bad")
474                 }
475         }
476         if ret.class == ClassSlice && (ret.ktyp == smith.byteType || ret.ktyp == smith.runeType) {
477                 return F("(%v)(%v %v)", ret.id, smith.rvalue(smith.stringType), smith.choice("", ","))
478         }
479         // TODO: handle "x is assignable to T"
480         // TODO: handle "x's type and T have identical underlying types"
481         // TODO: handle "x's type and T are unnamed pointer types and their pointer base types have identical underlying types"
482         return ""
483 }