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  }