github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/types2/builtins_test.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package types2_test 6 7 import ( 8 "fmt" 9 "testing" 10 11 "github.com/go-asm/go/cmd/compile/syntax" 12 13 . "github.com/go-asm/go/cmd/compile/types2" 14 ) 15 16 var builtinCalls = []struct { 17 name, src, sig string 18 }{ 19 {"append", `var s []int; _ = append(s)`, `func([]int, ...int) []int`}, 20 {"append", `var s []int; _ = append(s, 0)`, `func([]int, ...int) []int`}, 21 {"append", `var s []int; _ = (append)(s, 0)`, `func([]int, ...int) []int`}, 22 {"append", `var s []byte; _ = ((append))(s, 0)`, `func([]byte, ...byte) []byte`}, 23 {"append", `var s []byte; _ = append(s, "foo"...)`, `func([]byte, string...) []byte`}, 24 {"append", `type T []byte; var s T; var str string; _ = append(s, str...)`, `func(p.T, string...) p.T`}, 25 {"append", `type T []byte; type U string; var s T; var str U; _ = append(s, str...)`, `func(p.T, p.U...) p.T`}, 26 27 {"cap", `var s [10]int; _ = cap(s)`, `invalid type`}, // constant 28 {"cap", `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant 29 {"cap", `var s []int64; _ = cap(s)`, `func([]int64) int`}, 30 {"cap", `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`}, 31 {"cap", `type S []byte; var s S; _ = cap(s)`, `func(p.S) int`}, 32 {"cap", `var s P; _ = cap(s)`, `func(P) int`}, 33 34 {"len", `_ = len("foo")`, `invalid type`}, // constant 35 {"len", `var s string; _ = len(s)`, `func(string) int`}, 36 {"len", `var s [10]int; _ = len(s)`, `invalid type`}, // constant 37 {"len", `var s [10]int; _ = len(&s)`, `invalid type`}, // constant 38 {"len", `var s []int64; _ = len(s)`, `func([]int64) int`}, 39 {"len", `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`}, 40 {"len", `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`}, 41 {"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`}, 42 {"len", `var s P; _ = len(s)`, `func(P) int`}, 43 44 {"clear", `var m map[float64]int; clear(m)`, `func(map[float64]int)`}, 45 {"clear", `var s []byte; clear(s)`, `func([]byte)`}, 46 47 {"close", `var c chan int; close(c)`, `func(chan int)`}, 48 {"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`}, 49 50 {"complex", `_ = complex(1, 0)`, `invalid type`}, // constant 51 {"complex", `var re float32; _ = complex(re, 1.0)`, `func(float32, float32) complex64`}, 52 {"complex", `var im float64; _ = complex(1, im)`, `func(float64, float64) complex128`}, 53 {"complex", `type F32 float32; var re, im F32; _ = complex(re, im)`, `func(p.F32, p.F32) complex64`}, 54 {"complex", `type F64 float64; var re, im F64; _ = complex(re, im)`, `func(p.F64, p.F64) complex128`}, 55 56 {"copy", `var src, dst []byte; copy(dst, src)`, `func([]byte, []byte) int`}, 57 {"copy", `type T [][]int; var src, dst T; _ = copy(dst, src)`, `func(p.T, p.T) int`}, 58 {"copy", `var src string; var dst []byte; copy(dst, src)`, `func([]byte, string) int`}, 59 {"copy", `type T string; type U []byte; var src T; var dst U; copy(dst, src)`, `func(p.U, p.T) int`}, 60 {"copy", `var dst []byte; copy(dst, "hello")`, `func([]byte, string) int`}, 61 62 {"delete", `var m map[string]bool; delete(m, "foo")`, `func(map[string]bool, string)`}, 63 {"delete", `type (K string; V int); var m map[K]V; delete(m, "foo")`, `func(map[p.K]p.V, p.K)`}, 64 65 {"imag", `_ = imag(1i)`, `invalid type`}, // constant 66 {"imag", `var c complex64; _ = imag(c)`, `func(complex64) float32`}, 67 {"imag", `var c complex128; _ = imag(c)`, `func(complex128) float64`}, 68 {"imag", `type C64 complex64; var c C64; _ = imag(c)`, `func(p.C64) float32`}, 69 {"imag", `type C128 complex128; var c C128; _ = imag(c)`, `func(p.C128) float64`}, 70 71 {"real", `_ = real(1i)`, `invalid type`}, // constant 72 {"real", `var c complex64; _ = real(c)`, `func(complex64) float32`}, 73 {"real", `var c complex128; _ = real(c)`, `func(complex128) float64`}, 74 {"real", `type C64 complex64; var c C64; _ = real(c)`, `func(p.C64) float32`}, 75 {"real", `type C128 complex128; var c C128; _ = real(c)`, `func(p.C128) float64`}, 76 77 {"make", `_ = make([]int, 10)`, `func([]int, int) []int`}, 78 {"make", `type T []byte; _ = make(T, 10, 20)`, `func(p.T, int, int) p.T`}, 79 80 // go.dev/issue/37349 81 {"make", ` _ = make([]int, 0 )`, `func([]int, int) []int`}, 82 {"make", `var l int; _ = make([]int, l )`, `func([]int, int) []int`}, 83 {"make", ` _ = make([]int, 0, 0)`, `func([]int, int, int) []int`}, 84 {"make", `var l int; _ = make([]int, l, 0)`, `func([]int, int, int) []int`}, 85 {"make", `var c int; _ = make([]int, 0, c)`, `func([]int, int, int) []int`}, 86 {"make", `var l, c int; _ = make([]int, l, c)`, `func([]int, int, int) []int`}, 87 88 // go.dev/issue/37393 89 {"make", ` _ = make([]int , 0 )`, `func([]int, int) []int`}, 90 {"make", `var l byte ; _ = make([]int8 , l )`, `func([]int8, byte) []int8`}, 91 {"make", ` _ = make([]int16 , 0, 0)`, `func([]int16, int, int) []int16`}, 92 {"make", `var l int16; _ = make([]string , l, 0)`, `func([]string, int16, int) []string`}, 93 {"make", `var c int32; _ = make([]float64 , 0, c)`, `func([]float64, int, int32) []float64`}, 94 {"make", `var l, c uint ; _ = make([]complex128, l, c)`, `func([]complex128, uint, uint) []complex128`}, 95 96 // go.dev/issue/45667 97 {"make", `const l uint = 1; _ = make([]int, l)`, `func([]int, uint) []int`}, 98 99 {"max", ` _ = max(0 )`, `invalid type`}, // constant 100 {"max", `var x int ; _ = max(x )`, `func(int) int`}, 101 {"max", `var x int ; _ = max(0, x )`, `func(int, int) int`}, 102 {"max", `var x string ; _ = max("a", x )`, `func(string, string) string`}, 103 {"max", `var x float32; _ = max(0, 1.0, x)`, `func(float32, float32, float32) float32`}, 104 105 {"min", ` _ = min(0 )`, `invalid type`}, // constant 106 {"min", `var x int ; _ = min(x )`, `func(int) int`}, 107 {"min", `var x int ; _ = min(0, x )`, `func(int, int) int`}, 108 {"min", `var x string ; _ = min("a", x )`, `func(string, string) string`}, 109 {"min", `var x float32; _ = min(0, 1.0, x)`, `func(float32, float32, float32) float32`}, 110 111 {"new", `_ = new(int)`, `func(int) *int`}, 112 {"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`}, 113 114 {"panic", `panic(0)`, `func(interface{})`}, 115 {"panic", `panic("foo")`, `func(interface{})`}, 116 117 {"print", `print()`, `func()`}, 118 {"print", `print(0)`, `func(int)`}, 119 {"print", `print(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`}, 120 121 {"println", `println()`, `func()`}, 122 {"println", `println(0)`, `func(int)`}, 123 {"println", `println(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`}, 124 125 {"recover", `recover()`, `func() interface{}`}, 126 {"recover", `_ = recover()`, `func() interface{}`}, 127 128 {"Add", `var p unsafe.Pointer; _ = unsafe.Add(p, -1.0)`, `func(unsafe.Pointer, int) unsafe.Pointer`}, 129 {"Add", `var p unsafe.Pointer; var n uintptr; _ = unsafe.Add(p, n)`, `func(unsafe.Pointer, uintptr) unsafe.Pointer`}, 130 {"Add", `_ = unsafe.Add(nil, 0)`, `func(unsafe.Pointer, int) unsafe.Pointer`}, 131 132 {"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`}, // constant 133 {"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant 134 {"Alignof", `var x P; _ = unsafe.Alignof(x)`, `func(P) uintptr`}, 135 136 {"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`}, // constant 137 {"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant 138 {"Offsetof", `var x struct{_ int; f P}; _ = unsafe.Offsetof((&x).f)`, `func(P) uintptr`}, 139 140 {"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`}, // constant 141 {"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant 142 {"Sizeof", `var x P; _ = unsafe.Sizeof(x)`, `func(P) uintptr`}, 143 144 {"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`}, 145 {"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`}, 146 {"Slice", `type B *byte; var b B; _ = unsafe.Slice(b, 0)`, `func(*byte, int) []byte`}, 147 148 {"SliceData", "var s []int; _ = unsafe.SliceData(s)", `func([]int) *int`}, 149 {"SliceData", "type S []int; var s S; _ = unsafe.SliceData(s)", `func([]int) *int`}, 150 151 {"String", `var p *byte; _ = unsafe.String(p, 1)`, `func(*byte, int) string`}, 152 {"String", `type B *byte; var b B; _ = unsafe.String(b, 0)`, `func(*byte, int) string`}, 153 154 {"StringData", `var s string; _ = unsafe.StringData(s)`, `func(string) *byte`}, 155 {"StringData", `_ = unsafe.StringData("foo")`, `func(string) *byte`}, 156 157 {"assert", `assert(true)`, `invalid type`}, // constant 158 {"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant 159 160 // no tests for trace since it produces output as a side-effect 161 } 162 163 func TestBuiltinSignatures(t *testing.T) { 164 DefPredeclaredTestFuncs() 165 166 seen := map[string]bool{"trace": true} // no test for trace built-in; add it manually 167 for _, call := range builtinCalls { 168 testBuiltinSignature(t, call.name, call.src, call.sig) 169 seen[call.name] = true 170 } 171 172 // make sure we didn't miss one 173 for _, name := range Universe.Names() { 174 if _, ok := Universe.Lookup(name).(*Builtin); ok && !seen[name] { 175 t.Errorf("missing test for %s", name) 176 } 177 } 178 for _, name := range Unsafe.Scope().Names() { 179 if _, ok := Unsafe.Scope().Lookup(name).(*Builtin); ok && !seen[name] { 180 t.Errorf("missing test for unsafe.%s", name) 181 } 182 } 183 } 184 185 func testBuiltinSignature(t *testing.T, name, src0, want string) { 186 src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _[P ~[]byte]() { %s }`, src0) 187 188 uses := make(map[*syntax.Name]Object) 189 types := make(map[syntax.Expr]TypeAndValue) 190 mustTypecheck(src, nil, &Info{Uses: uses, Types: types}) 191 192 // find called function 193 n := 0 194 var fun syntax.Expr 195 for x := range types { 196 if call, _ := x.(*syntax.CallExpr); call != nil { 197 fun = call.Fun 198 n++ 199 } 200 } 201 if n != 1 { 202 t.Errorf("%s: got %d CallExprs; want 1", src0, n) 203 return 204 } 205 206 // check recorded types for fun and descendents (may be parenthesized) 207 for { 208 // the recorded type for the built-in must match the wanted signature 209 typ := types[fun].Type 210 if typ == nil { 211 t.Errorf("%s: no type recorded for %s", src0, syntax.String(fun)) 212 return 213 } 214 if got := typ.String(); got != want { 215 t.Errorf("%s: got type %s; want %s", src0, got, want) 216 return 217 } 218 219 // called function must be a (possibly parenthesized, qualified) 220 // identifier denoting the expected built-in 221 switch p := fun.(type) { 222 case *syntax.Name: 223 obj := uses[p] 224 if obj == nil { 225 t.Errorf("%s: no object found for %s", src0, p.Value) 226 return 227 } 228 bin, _ := obj.(*Builtin) 229 if bin == nil { 230 t.Errorf("%s: %s does not denote a built-in", src0, p.Value) 231 return 232 } 233 if bin.Name() != name { 234 t.Errorf("%s: got built-in %s; want %s", src0, bin.Name(), name) 235 return 236 } 237 return // we're done 238 239 case *syntax.ParenExpr: 240 fun = p.X // unpack 241 242 case *syntax.SelectorExpr: 243 // built-in from package unsafe - ignore details 244 return // we're done 245 246 default: 247 t.Errorf("%s: invalid function call", src0) 248 return 249 } 250 } 251 }