github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/testdata/reflect.go (about) 1 package main 2 3 import ( 4 "errors" 5 "reflect" 6 "strconv" 7 "unsafe" 8 ) 9 10 type ( 11 myint int 12 myslice []byte 13 myslice2 []myint 14 mychan chan int 15 myptr *int 16 point struct { 17 X int16 18 Y int16 19 } 20 mystruct struct { 21 n int `foo:"bar"` 22 some point "some\x00tag" 23 zero struct{} 24 buf []byte 25 Buf []byte 26 } 27 linkedList struct { 28 next *linkedList `description:"chain"` 29 foo int 30 } 31 selfref struct { 32 x *selfref 33 } 34 ) 35 36 var ( 37 errorValue = errors.New("test error") 38 errorType = reflect.TypeOf((*error)(nil)).Elem() 39 stringerType = reflect.TypeOf((*interface { 40 String() string 41 })(nil)).Elem() 42 ) 43 44 func main() { 45 println("matching types") 46 println(reflect.TypeOf(int(3)) == reflect.TypeOf(int(5))) 47 println(reflect.TypeOf(int(3)) == reflect.TypeOf(uint(5))) 48 println(reflect.TypeOf(myint(3)) == reflect.TypeOf(int(5))) 49 println(reflect.TypeOf(myslice{}) == reflect.TypeOf([]byte{})) 50 println(reflect.TypeOf(myslice2{}) == reflect.TypeOf([]myint{})) 51 println(reflect.TypeOf(myslice2{}) == reflect.TypeOf([]int{})) 52 53 println("\nvalues of interfaces") 54 var zeroSlice []byte 55 var zeroFunc func() 56 // by embedding a 0-array func type in your struct, it is not comparable 57 type doNotCompare [0]func() 58 type notComparable struct { 59 doNotCompare 60 data *int32 61 } 62 var zeroMap map[string]int 63 var zeroChan chan int 64 n := 42 65 for _, v := range []interface{}{ 66 // basic types 67 true, 68 false, 69 int(2000), 70 int(-2000), 71 uint(2000), 72 int8(-3), 73 int8(3), 74 uint8(200), 75 int16(-300), 76 int16(300), 77 uint16(50000), 78 int32(7 << 20), 79 int32(-7 << 20), 80 uint32(7 << 20), 81 int64(9 << 40), 82 int64(-9 << 40), 83 uint64(9 << 40), 84 uintptr(12345), 85 float32(3.14), 86 float64(3.14), 87 complex64(1.2 + 0.3i), 88 complex128(1.3 + 0.4i), 89 myint(32), 90 "foo", 91 unsafe.Pointer(new(int)), 92 // channels 93 zeroChan, 94 mychan(zeroChan), 95 // pointers 96 new(int), 97 new(error), 98 &n, 99 myptr(new(int)), 100 // slices 101 []byte{1, 2, 3}, 102 make([]uint8, 2, 5), 103 []rune{3, 5}, 104 []string{"xyz", "Z"}, 105 zeroSlice, 106 []byte{}, 107 []float32{1, 1.32}, 108 []float64{1, 1.64}, 109 []complex64{1, 1.64 + 0.3i}, 110 []complex128{1, 1.128 + 0.4i}, 111 myslice{5, 3, 11}, 112 // array 113 [3]int64{5, 8, 2}, 114 [2]uint8{3, 5}, 115 // functions 116 zeroFunc, 117 emptyFunc, 118 // maps 119 zeroMap, 120 map[string]int{}, 121 // structs 122 struct{}{}, 123 struct{ error }{}, 124 struct { 125 a uint8 126 b int16 127 c int8 128 }{42, 321, 123}, 129 mystruct{5, point{-5, 3}, struct{}{}, []byte{'G', 'o'}, []byte{'X'}}, 130 &linkedList{ 131 foo: 42, 132 }, 133 struct{ A, B uintptr }{2, 3}, 134 // interfaces 135 []interface{}{3, "str", -4 + 2.5i}, 136 } { 137 showValue(reflect.ValueOf(v), "") 138 } 139 140 // Test reflect.New(). 141 newInt8 := reflect.New(reflect.TypeOf(int8(0))) 142 newInt8.Elem().SetInt(5) 143 newInt16 := reflect.New(reflect.TypeOf(int16(0))) 144 newInt16.Elem().SetInt(-800) 145 newInt32 := reflect.New(reflect.TypeOf(int32(0))) 146 newInt32.Elem().SetInt(1e8) 147 newInt64 := reflect.New(reflect.TypeOf(int64(0))) 148 newInt64.Elem().SetInt(-1e12) 149 newComplex128 := reflect.New(reflect.TypeOf(0 + 0i)) 150 newComplex128.Elem().SetComplex(-8 - 20e5i) 151 for _, val := range []reflect.Value{newInt8, newInt16, newInt32, newInt64, newComplex128} { 152 showValue(val, "") 153 } 154 155 // test sizes 156 println("\nsizes:") 157 for _, tc := range []struct { 158 name string 159 rt reflect.Type 160 }{ 161 {"int8", reflect.TypeOf(int8(0))}, 162 {"int16", reflect.TypeOf(int16(0))}, 163 {"int32", reflect.TypeOf(int32(0))}, 164 {"int64", reflect.TypeOf(int64(0))}, 165 {"uint8", reflect.TypeOf(uint8(0))}, 166 {"uint16", reflect.TypeOf(uint16(0))}, 167 {"uint32", reflect.TypeOf(uint32(0))}, 168 {"uint64", reflect.TypeOf(uint64(0))}, 169 {"float32", reflect.TypeOf(float32(0))}, 170 {"float64", reflect.TypeOf(float64(0))}, 171 {"complex64", reflect.TypeOf(complex64(0))}, 172 {"complex128", reflect.TypeOf(complex128(0))}, 173 } { 174 println(tc.name, int(tc.rt.Size()), tc.rt.Bits()) 175 } 176 assertSize(reflect.TypeOf(uintptr(0)).Size() == unsafe.Sizeof(uintptr(0)), "uintptr") 177 assertSize(reflect.TypeOf("").Size() == unsafe.Sizeof(""), "string") 178 assertSize(reflect.TypeOf(new(int)).Size() == unsafe.Sizeof(new(int)), "*int") 179 assertSize(reflect.TypeOf(zeroFunc).Size() == unsafe.Sizeof(zeroFunc), "func()") 180 assertSize(reflect.TypeOf(zeroChan).Size() == unsafe.Sizeof(zeroChan), "chan int") 181 assertSize(reflect.TypeOf(zeroMap).Size() == unsafe.Sizeof(zeroMap), "map[string]int") 182 183 // make sure embedding a zero-sized "not comparable" struct does not add size to a struct 184 assertSize(reflect.TypeOf(doNotCompare{}).Size() == unsafe.Sizeof(doNotCompare{}), "[0]func()") 185 assertSize(unsafe.Sizeof(notComparable{}) == unsafe.Sizeof((*int32)(nil)), "struct{[0]func(); *int32}") 186 187 // Test that offset is correctly calculated. 188 // This doesn't just test reflect but also (indirectly) that unsafe.Alignof 189 // works correctly. 190 s := struct { 191 small1 byte 192 big1 int64 193 small2 byte 194 big2 int64 195 }{} 196 st := reflect.TypeOf(s) 197 println("offset for int64 matches:", st.Field(1).Offset-st.Field(0).Offset == uintptr(unsafe.Pointer(&s.big1))-uintptr(unsafe.Pointer(&s.small1))) 198 println("offset for complex128 matches:", st.Field(3).Offset-st.Field(2).Offset == uintptr(unsafe.Pointer(&s.big2))-uintptr(unsafe.Pointer(&s.small2))) 199 200 // SetBool 201 rv := reflect.ValueOf(new(bool)).Elem() 202 rv.SetBool(true) 203 if rv.Bool() != true { 204 panic("could not set bool with SetBool()") 205 } 206 207 // SetInt 208 for _, v := range []interface{}{ 209 new(int), 210 new(int8), 211 new(int16), 212 new(int32), 213 new(int64), 214 } { 215 rv := reflect.ValueOf(v).Elem() 216 rv.SetInt(99) 217 if rv.Int() != 99 { 218 panic("could not set integer with SetInt()") 219 } 220 } 221 222 // SetUint 223 for _, v := range []interface{}{ 224 new(uint), 225 new(uint8), 226 new(uint16), 227 new(uint32), 228 new(uint64), 229 new(uintptr), 230 } { 231 rv := reflect.ValueOf(v).Elem() 232 rv.SetUint(99) 233 if rv.Uint() != 99 { 234 panic("could not set integer with SetUint()") 235 } 236 } 237 238 // SetFloat 239 for _, v := range []interface{}{ 240 new(float32), 241 new(float64), 242 } { 243 rv := reflect.ValueOf(v).Elem() 244 rv.SetFloat(2.25) 245 if rv.Float() != 2.25 { 246 panic("could not set float with SetFloat()") 247 } 248 } 249 250 // SetComplex 251 for _, v := range []interface{}{ 252 new(complex64), 253 new(complex128), 254 } { 255 rv := reflect.ValueOf(v).Elem() 256 rv.SetComplex(3 + 2i) 257 if rv.Complex() != 3+2i { 258 panic("could not set complex with SetComplex()") 259 } 260 } 261 262 // SetString 263 rv = reflect.ValueOf(new(string)).Elem() 264 rv.SetString("foo") 265 if rv.String() != "foo" { 266 panic("could not set string with SetString()") 267 } 268 269 // Set int 270 rv = reflect.ValueOf(new(int)).Elem() 271 rv.SetInt(33) 272 rv.Set(reflect.ValueOf(22)) 273 if rv.Int() != 22 { 274 panic("could not set int with Set()") 275 } 276 277 // Set uint8 278 rv = reflect.ValueOf(new(uint8)).Elem() 279 rv.SetUint(33) 280 rv.Set(reflect.ValueOf(uint8(22))) 281 if rv.Uint() != 22 { 282 panic("could not set uint8 with Set()") 283 } 284 285 // Set string 286 rv = reflect.ValueOf(new(string)).Elem() 287 rv.SetString("foo") 288 rv.Set(reflect.ValueOf("bar")) 289 if rv.String() != "bar" { 290 panic("could not set string with Set()") 291 } 292 293 // Set complex128 294 rv = reflect.ValueOf(new(complex128)).Elem() 295 rv.SetComplex(3 + 2i) 296 rv.Set(reflect.ValueOf(4 + 8i)) 297 if rv.Complex() != 4+8i { 298 panic("could not set complex128 with Set()") 299 } 300 301 // Set to slice 302 rv = reflect.ValueOf([]int{3, 5}) 303 rv.Index(1).SetInt(7) 304 if rv.Index(1).Int() != 7 { 305 panic("could not set int in slice") 306 } 307 rv.Index(1).Set(reflect.ValueOf(8)) 308 if rv.Index(1).Int() != 8 { 309 panic("could not set int in slice") 310 } 311 if rv.Len() != 2 || rv.Index(0).Int() != 3 { 312 panic("slice was changed while setting part of it") 313 } 314 315 testAppendSlice() 316 317 // Test types that are created in reflect and never created elsewhere in a 318 // value-to-interface conversion. 319 v := reflect.ValueOf(new(unreferencedType)) 320 switch v.Elem().Interface().(type) { 321 case unreferencedType: 322 println("type assertion succeeded for unreferenced type") 323 default: 324 println("type assertion failed (but should succeed)") 325 } 326 327 // Test type that is not referenced at all: not when creating the 328 // reflect.Value (except through the field) and not with a type assert. 329 // Previously this would result in a type assert failure because the Int() 330 // method wasn't picked up. 331 v = reflect.ValueOf(struct { 332 X totallyUnreferencedType 333 }{}) 334 if v.Field(0).Interface().(interface { 335 Int() int 336 }).Int() != 42 { 337 println("could not call method on totally unreferenced type") 338 } 339 340 if reflect.TypeOf(new(myint)) != reflect.PtrTo(reflect.TypeOf(myint(0))) { 341 println("PtrTo failed for type myint") 342 } 343 if reflect.TypeOf(new(myslice)) != reflect.PtrTo(reflect.TypeOf(make(myslice, 0))) { 344 println("PtrTo failed for type myslice") 345 } 346 347 if reflect.TypeOf(errorValue).Implements(errorType) != true { 348 println("errorValue.Implements(errorType) was false, expected true") 349 } 350 if reflect.TypeOf(errorValue).Implements(stringerType) != false { 351 println("errorValue.Implements(errorType) was true, expected false") 352 } 353 354 println("\nalignment / offset:") 355 v2 := struct { 356 noCompare [0]func() 357 data byte 358 }{} 359 println("struct{[0]func(); byte}:", unsafe.Offsetof(v2.data) == uintptr(unsafe.Pointer(&v2.data))-uintptr(unsafe.Pointer(&v2))) 360 361 println("\nstruct tags") 362 TestStructTag() 363 364 println("\nv.Interface() method") 365 testInterfaceMethod() 366 367 // Test reflect.DeepEqual. 368 var selfref1, selfref2 selfref 369 selfref1.x = &selfref1 370 selfref2.x = &selfref2 371 for i, tc := range []struct { 372 v1, v2 interface{} 373 equal bool 374 }{ 375 {int(5), int(5), true}, 376 {int(3), int(5), false}, 377 {int(5), uint(5), false}, 378 {struct { 379 a int 380 b string 381 }{3, "x"}, struct { 382 a int 383 b string 384 }{3, "x"}, true}, 385 {struct { 386 a int 387 b string 388 }{3, "x"}, struct { 389 a int 390 b string 391 }{3, "y"}, false}, 392 {selfref1, selfref2, true}, 393 } { 394 result := reflect.DeepEqual(tc.v1, tc.v2) 395 if result != tc.equal { 396 if tc.equal { 397 println("reflect.DeepEqual() test", i, "not equal while it should be") 398 } else { 399 println("reflect.DeepEqual() test", i, "equal while it should not be") 400 } 401 } 402 } 403 } 404 405 func emptyFunc() { 406 } 407 408 func showValue(rv reflect.Value, indent string) { 409 rt := rv.Type() 410 if rt.Kind() != rv.Kind() { 411 panic("type kind is different from value kind") 412 } 413 print(indent+"reflect type: ", rt.Kind().String()) 414 if rv.CanSet() { 415 print(" settable=true") 416 } 417 if rv.CanAddr() { 418 print(" addrable=true") 419 } 420 if !rv.CanInterface() { 421 print(" caninterface=false") 422 } 423 if !rt.Comparable() { 424 print(" comparable=false") 425 } 426 println() 427 switch rt.Kind() { 428 case reflect.Bool: 429 println(indent+" bool:", rv.Bool()) 430 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 431 println(indent+" int:", rv.Int()) 432 case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 433 println(indent+" uint:", rv.Uint()) 434 case reflect.Float32, reflect.Float64: 435 println(indent+" float:", rv.Float()) 436 case reflect.Complex64, reflect.Complex128: 437 println(indent+" complex:", rv.Complex()) 438 case reflect.String: 439 println(indent+" string:", rv.String(), rv.Len()) 440 for i := 0; i < rv.Len(); i++ { 441 showValue(rv.Index(i), indent+" ") 442 } 443 case reflect.UnsafePointer: 444 println(indent+" pointer:", rv.Pointer() != 0) 445 case reflect.Array: 446 println(indent+" array:", rt.Len(), rt.Elem().Kind().String(), int(rt.Size())) 447 for i := 0; i < rv.Len(); i++ { 448 showValue(rv.Index(i), indent+" ") 449 } 450 case reflect.Chan: 451 println(indent+" chan:", rt.Elem().Kind().String()) 452 println(indent+" nil:", rv.IsNil()) 453 case reflect.Func: 454 println(indent + " func") 455 println(indent+" nil:", rv.IsNil()) 456 case reflect.Interface: 457 println(indent + " interface") 458 println(indent+" nil:", rv.IsNil()) 459 if !rv.IsNil() { 460 showValue(rv.Elem(), indent+" ") 461 } 462 case reflect.Map: 463 println(indent + " map") 464 println(indent+" nil:", rv.IsNil()) 465 case reflect.Ptr: 466 println(indent+" pointer:", rv.Pointer() != 0, rt.Elem().Kind().String()) 467 println(indent+" nil:", rv.IsNil()) 468 if !rv.IsNil() { 469 showValue(rv.Elem(), indent+" ") 470 } 471 case reflect.Slice: 472 println(indent+" slice:", rt.Elem().Kind().String(), rv.Len(), rv.Cap()) 473 println(indent+" pointer:", rv.Pointer() != 0) 474 println(indent+" nil:", rv.IsNil()) 475 for i := 0; i < rv.Len(); i++ { 476 println(indent+" indexing:", i) 477 showValue(rv.Index(i), indent+" ") 478 } 479 case reflect.Struct: 480 println(indent+" struct:", rt.NumField()) 481 for i := 0; i < rv.NumField(); i++ { 482 field := rt.Field(i) 483 println(indent+" field:", i, field.Name) 484 println(indent+" pkg:", field.PkgPath) 485 println(indent+" tag:", strconv.Quote(string(field.Tag))) 486 println(indent+" embedded:", field.Anonymous) 487 println(indent+" exported:", field.IsExported()) 488 showValue(rv.Field(i), indent+" ") 489 } 490 default: 491 println(indent + " unknown type kind!") 492 } 493 } 494 495 func assertSize(ok bool, typ string) { 496 if !ok { 497 panic("size mismatch for type " + typ) 498 } 499 } 500 501 // Test whether appending to a slice is equivalent between reflect and native 502 // slice append. 503 func testAppendSlice() { 504 for i := 0; i < 100; i++ { 505 dst := makeRandomSlice(i) 506 src := makeRandomSlice(i) 507 result1 := append(dst, src...) 508 result2 := reflect.AppendSlice(reflect.ValueOf(dst), reflect.ValueOf(src)).Interface().([]uint32) 509 if !sliceEqual(result1, result2) { 510 println("slice: mismatch after runtime.SliceAppend with", len(dst), cap(dst), len(src), cap(src)) 511 } 512 } 513 } 514 515 func makeRandomSlice(max int) []uint32 { 516 cap := randuint32() % uint32(max+1) 517 len := randuint32() % (cap + 1) 518 s := make([]uint32, len, cap) 519 for i := uint32(0); i < len; i++ { 520 s[i] = randuint32() 521 } 522 return s 523 } 524 525 func sliceEqual(s1, s2 []uint32) bool { 526 if len(s1) != len(s2) { 527 return false 528 } 529 for i, val := range s1 { 530 if s2[i] != val { 531 return false 532 } 533 } 534 // Note: can't compare cap because the Go implementation has a different 535 // behavior between the built-in append function and 536 // reflect.AppendSlice. 537 return true 538 } 539 540 type unreferencedType int 541 542 type totallyUnreferencedType int 543 544 func (totallyUnreferencedType) Int() int { 545 return 42 546 } 547 548 func TestStructTag() { 549 type S struct { 550 F string `species:"gopher" color:"blue"` 551 } 552 553 s := S{} 554 st := reflect.TypeOf(s) 555 field := st.Field(0) 556 println(field.Tag.Get("color"), field.Tag.Get("species")) 557 } 558 559 // Test Interface() call: it should never return an interface itself. 560 func testInterfaceMethod() { 561 v := reflect.ValueOf(struct{ X interface{} }{X: 5}) 562 println("kind:", v.Field(0).Kind().String()) 563 itf := v.Field(0).Interface() 564 switch n := itf.(type) { 565 case int: 566 println("int", n) // correct 567 default: 568 println("something else") // incorrect 569 } 570 } 571 572 var xorshift32State uint32 = 1 573 574 func xorshift32(x uint32) uint32 { 575 // Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" 576 x ^= x << 13 577 x ^= x >> 17 578 x ^= x << 5 579 return x 580 } 581 582 func randuint32() uint32 { 583 xorshift32State = xorshift32(xorshift32State) 584 return xorshift32State 585 }