github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/testdata/interface.go (about)

     1  package main
     2  
     3  import "time"
     4  
     5  func main() {
     6  	thing := &Thing{"foo"}
     7  	println("thing:", thing.String())
     8  	thing.Print()
     9  	printItf(5)
    10  	printItf(byte('x'))
    11  	printItf("foo")
    12  	printItf(Foo(18))
    13  	printItf(*thing)
    14  	printItf(thing)
    15  	printItf(Stringer(thing))
    16  	printItf(struct{ n int }{})
    17  	printItf(struct {
    18  		n int `foo:"bar"`
    19  	}{})
    20  	printItf(Number(3))
    21  	array := Array([4]uint32{1, 7, 11, 13})
    22  	printItf(array)
    23  	printItf(ArrayStruct{3, array})
    24  	printItf(SmallPair{3, 5})
    25  	s := Stringer(thing)
    26  	println("Stringer.String():", s.String())
    27  	var itf interface{} = s
    28  	println("Stringer.(*Thing).String():", itf.(Stringer).String())
    29  	if s, ok := s.(interface{ String() string }); ok {
    30  		println("s has String() method:", s.String())
    31  	}
    32  
    33  	println("nested switch:", nestedSwitch('v', 3))
    34  
    35  	// Try putting a linked list in an interface:
    36  	// https://github.com/tinygo-org/tinygo/issues/309
    37  	itf = linkedList{}
    38  
    39  	// Test bugfix for assertion on named empty interface:
    40  	// https://github.com/tinygo-org/tinygo/issues/453
    41  	_, _ = itf.(Empty)
    42  
    43  	var v Byter = FooByte(3)
    44  	println("Byte(): ", v.Byte())
    45  
    46  	var n int
    47  	var f float32
    48  	var interfaceEqualTests = []struct {
    49  		equal bool
    50  		lhs   interface{}
    51  		rhs   interface{}
    52  	}{
    53  		{true, true, true},
    54  		{true, int(1), int(1)},
    55  		{true, int8(1), int8(1)},
    56  		{true, int16(1), int16(1)},
    57  		{true, int32(1), int32(1)},
    58  		{true, int64(1), int64(1)},
    59  		{true, uint(1), uint(1)},
    60  		{false, uint(1), uint(2)},
    61  		{true, uint8(1), uint8(1)},
    62  		{true, uint16(1), uint16(1)},
    63  		{true, uint32(1), uint32(1)},
    64  		{true, uint64(1), uint64(1)},
    65  		{true, uintptr(1), uintptr(1)},
    66  		{true, float32(1.1), float32(1.1)},
    67  		{true, float64(1.1), float64(1.1)},
    68  		{true, complex(100, 8), complex(100, 8)},
    69  		{false, complex(100, 8), complex(101, 8)},
    70  		{false, complex(100, 8), complex(100, 9)},
    71  		{true, complex64(8), complex64(8)},
    72  		{true, complex128(8), complex128(8)},
    73  		{true, "string", "string"},
    74  		{false, "string", "stringx"},
    75  		{true, [2]int16{-5, 201}, [2]int16{-5, 201}},
    76  		{false, [2]int16{-5, 201}, [2]int16{-5, 202}},
    77  		{false, [2]int16{-5, 201}, [2]int16{5, 201}},
    78  		{true, &n, &n},
    79  		{false, &n, new(int)},
    80  		{false, new(int), new(int)},
    81  		{false, &n, &f},
    82  		{true, struct {
    83  			a int
    84  			b int
    85  		}{3, 5}, struct {
    86  			a int
    87  			b int
    88  		}{3, 5}},
    89  		{false, struct {
    90  			a int
    91  			b int
    92  		}{3, 5}, struct {
    93  			a int
    94  			b int
    95  		}{3, 6}},
    96  		{true, named1(), named1()},
    97  		{true, named2(), named2()},
    98  		{false, named1(), named2()},
    99  		{false, named2(), named3()},
   100  		{true, namedptr1(), namedptr1()},
   101  		{false, namedptr1(), namedptr2()},
   102  	}
   103  	for i, tc := range interfaceEqualTests {
   104  		if (tc.lhs == tc.rhs) != tc.equal {
   105  			println("test", i, "of interfaceEqualTests failed")
   106  		}
   107  	}
   108  
   109  	// test interface blocking
   110  	blockDynamic(NonBlocker{})
   111  	println("non-blocking call on sometimes-blocking interface")
   112  	blockDynamic(SleepBlocker(time.Millisecond))
   113  	println("slept 1ms")
   114  	blockStatic(SleepBlocker(time.Millisecond))
   115  	println("slept 1ms")
   116  
   117  	// check that pointer-to-pointer type switches work
   118  	ptrptrswitch()
   119  
   120  	// check that type asserts to interfaces with no methods work
   121  	emptyintfcrash()
   122  }
   123  
   124  func printItf(val interface{}) {
   125  	switch val := val.(type) {
   126  	case Unmatched:
   127  		panic("matched the unmatchable")
   128  	case Doubler:
   129  		println("is Doubler:", val.Double())
   130  	case Tuple:
   131  		println("is Tuple:", val.Nth(0), val.Nth(1), val.Nth(2), val.Nth(3))
   132  		val.Print()
   133  	case int:
   134  		println("is int:", val)
   135  	case byte:
   136  		println("is byte:", val)
   137  	case string:
   138  		println("is string:", val)
   139  	case Thing:
   140  		println("is Thing:", val.String())
   141  	case *Thing:
   142  		println("is *Thing:", val.String())
   143  	case struct{ i int }:
   144  		println("is struct{i int}")
   145  	case struct{ n int }:
   146  		println("is struct{n int}")
   147  	case struct {
   148  		n int `foo:"bar"`
   149  	}:
   150  		println("is struct{n int `foo:\"bar\"`}")
   151  	case Foo:
   152  		println("is Foo:", val)
   153  	default:
   154  		println("is ?")
   155  	}
   156  }
   157  
   158  var (
   159  	// Test for type assert support in the interp package.
   160  	globalThing interface{} = Foo(3)
   161  	_                       = globalThing.(Foo)
   162  )
   163  
   164  func nestedSwitch(verb rune, arg interface{}) bool {
   165  	switch verb {
   166  	case 'v', 's':
   167  		switch arg.(type) {
   168  		case int:
   169  			return true
   170  		}
   171  	}
   172  	return false
   173  }
   174  
   175  func blockDynamic(blocker DynamicBlocker) {
   176  	blocker.Block()
   177  }
   178  
   179  func blockStatic(blocker StaticBlocker) {
   180  	blocker.Sleep()
   181  }
   182  
   183  type Thing struct {
   184  	name string
   185  }
   186  
   187  func (t Thing) String() string {
   188  	return t.name
   189  }
   190  
   191  func (t Thing) Print() {
   192  	println("Thing.Print:", t.name)
   193  }
   194  
   195  type Stringer interface {
   196  	String() string
   197  }
   198  
   199  type Foo int
   200  
   201  type Number int
   202  
   203  func (n Number) Double() int {
   204  	return int(n) * 2
   205  }
   206  
   207  type Doubler interface {
   208  	Double() int
   209  }
   210  
   211  type Tuple interface {
   212  	Nth(int) uint32
   213  	Print()
   214  }
   215  
   216  type Array [4]uint32
   217  
   218  func (a Array) Nth(n int) uint32 {
   219  	return a[n]
   220  }
   221  
   222  func (a Array) Print() {
   223  	println("Array len:", len(a))
   224  }
   225  
   226  type ArrayStruct struct {
   227  	n int
   228  	a Array
   229  }
   230  
   231  func (a ArrayStruct) Nth(n int) uint32 {
   232  	return a.a[n]
   233  }
   234  
   235  func (a ArrayStruct) Print() {
   236  	println("ArrayStruct.Print:", len(a.a), a.n)
   237  }
   238  
   239  type SmallPair struct {
   240  	a byte
   241  	b byte
   242  }
   243  
   244  func (p SmallPair) Nth(n int) uint32 {
   245  	return uint32(int(p.a)*n + int(p.b)*n)
   246  }
   247  
   248  func (p SmallPair) Print() {
   249  	println("SmallPair.Print:", p.a, p.b)
   250  }
   251  
   252  // There is no type that matches this method.
   253  type Unmatched interface {
   254  	NeverImplementedMethod()
   255  }
   256  
   257  type linkedList struct {
   258  	addr *linkedList
   259  }
   260  
   261  type DynamicBlocker interface {
   262  	Block()
   263  }
   264  
   265  type NonBlocker struct{}
   266  
   267  func (b NonBlocker) Block() {}
   268  
   269  type SleepBlocker time.Duration
   270  
   271  func (s SleepBlocker) Block() {
   272  	time.Sleep(time.Duration(s))
   273  }
   274  
   275  func (s SleepBlocker) Sleep() {
   276  	s.Block()
   277  }
   278  
   279  type StaticBlocker interface {
   280  	Sleep()
   281  }
   282  
   283  type Empty interface{}
   284  
   285  type FooByte int
   286  
   287  func (f FooByte) Byte() byte { return byte(f) }
   288  
   289  type Byter interface {
   290  	Byte() uint8
   291  }
   292  
   293  // Make sure that named types inside functions do not alias with any other named
   294  // functions.
   295  
   296  type named int
   297  
   298  func named1() any {
   299  	return named(0)
   300  }
   301  
   302  func named2() any {
   303  	type named int
   304  	return named(0)
   305  }
   306  
   307  func named3() any {
   308  	type named int
   309  	return named(0)
   310  }
   311  
   312  func namedptr1() interface{} {
   313  	type Test int
   314  	return (*Test)(nil)
   315  }
   316  
   317  func namedptr2() interface{} {
   318  	type Test byte
   319  	return (*Test)(nil)
   320  }
   321  
   322  func ptrptrswitch() {
   323  	identify(0)
   324  	identify(new(int))
   325  	identify(new(*int))
   326  }
   327  
   328  func identify(itf any) {
   329  	switch itf.(type) {
   330  	case int:
   331  		println("type is int")
   332  	case *int:
   333  		println("type is *int")
   334  	case **int:
   335  		println("type is **int")
   336  	default:
   337  		println("other type??")
   338  	}
   339  }
   340  
   341  func emptyintfcrash() {
   342  	if x, ok := any(5).(any); ok {
   343  		println("x is", x.(int))
   344  	}
   345  }