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

     1  package main
     2  
     3  type Thing struct {
     4  	name string
     5  }
     6  
     7  type ThingOption func(*Thing)
     8  
     9  func WithName(name string) ThingOption {
    10  	return func(t *Thing) {
    11  		t.name = name
    12  	}
    13  }
    14  
    15  func NewThing(opts ...ThingOption) *Thing {
    16  	t := &Thing{}
    17  	for _, opt := range opts {
    18  		opt(t)
    19  	}
    20  	return t
    21  }
    22  
    23  func (t Thing) String() string {
    24  	return t.name
    25  }
    26  
    27  func (t Thing) Print(arg string) {
    28  	println("Thing.Print:", t.name, "arg:", arg)
    29  }
    30  
    31  type Printer interface {
    32  	Print(string)
    33  }
    34  
    35  func main() {
    36  	thing := &Thing{"foo"}
    37  
    38  	// function pointers
    39  	runFunc(hello, 5) // must be indirect to avoid obvious inlining
    40  
    41  	// deferred functions
    42  	testDefer()
    43  
    44  	// defers in loop
    45  	testDeferLoop()
    46  
    47  	//defer func variable call
    48  	testDeferFuncVar()
    49  
    50  	//More complicated func variable call
    51  	testMultiFuncVar()
    52  
    53  	// Take a bound method and use it as a function pointer.
    54  	// This function pointer needs a context pointer.
    55  	testBound(thing.String)
    56  
    57  	// closures
    58  	func() {
    59  		println("thing inside closure:", thing.String())
    60  	}()
    61  	runFunc(func(i int) {
    62  		println("inside fp closure:", thing.String(), i)
    63  	}, 3)
    64  
    65  	// functional arguments
    66  	thingFunctionalArgs1 := NewThing()
    67  	thingFunctionalArgs1.Print("functional args 1")
    68  	thingFunctionalArgs2 := NewThing(WithName("named thing"))
    69  	thingFunctionalArgs2.Print("functional args 2")
    70  
    71  	// regression testing
    72  	regression1033()
    73  
    74  	//Test deferred builtins
    75  	testDeferBuiltinClose()
    76  	testDeferBuiltinDelete()
    77  
    78  	// Check for issue 1304.
    79  	// There are two fields in this struct, one of which is zero-length so the
    80  	// other covers the entire struct. This led to a verification error for
    81  	// debug info, which used DW_OP_LLVM_fragment for a field that practically
    82  	// covered the entire variable.
    83  	var x issue1304
    84  	x.call()
    85  
    86  	if testDeferElse(false) != 0 {
    87  		println("else defer returned wrong value")
    88  	}
    89  }
    90  
    91  func runFunc(f func(int), arg int) {
    92  	f(arg)
    93  }
    94  
    95  func hello(n int) {
    96  	println("hello from function pointer:", n)
    97  }
    98  
    99  func testDefer() {
   100  	defer exportedDefer()
   101  
   102  	i := 1
   103  	defer deferred("...run as defer", i)
   104  	i++
   105  	defer func() {
   106  		println("...run closure deferred:", i)
   107  	}()
   108  	i++
   109  	defer deferred("...run as defer", i)
   110  	i++
   111  
   112  	var t Printer = &Thing{"foo"}
   113  	defer t.Print("bar")
   114  
   115  	println("deferring...")
   116  	d := dumb{}
   117  	defer d.Value(0)
   118  }
   119  
   120  func testDeferLoop() {
   121  	for j := 0; j < 4; j++ {
   122  		defer deferred("loop", j)
   123  	}
   124  }
   125  
   126  func testDeferFuncVar() {
   127  	dummy, f := deferFunc()
   128  	dummy++
   129  	defer f(1)
   130  }
   131  
   132  func testMultiFuncVar() {
   133  	f := multiFuncDefer()
   134  	defer f(1)
   135  }
   136  
   137  func testDeferBuiltinClose() {
   138  	i := make(chan int)
   139  	func() {
   140  		defer close(i)
   141  	}()
   142  	if n, ok := <-i; n != 0 || ok {
   143  		println("expected to read 0 from closed channel")
   144  	}
   145  }
   146  
   147  func testDeferBuiltinDelete() {
   148  	m := map[int]int{3: 30, 5: 50}
   149  	func() {
   150  		defer delete(m, 3)
   151  		if m[3] != 30 {
   152  			println("expected m[3] to be 30")
   153  		}
   154  	}()
   155  	if m[3] != 0 {
   156  		println("expected m[3] to be 0")
   157  	}
   158  }
   159  
   160  type dumb struct {
   161  }
   162  
   163  func (*dumb) Value(key interface{}) interface{} {
   164  	return nil
   165  }
   166  
   167  func deferred(msg string, i int) {
   168  	println(msg, i)
   169  }
   170  
   171  //export __exportedDefer
   172  func exportedDefer() {
   173  	println("...exported defer")
   174  }
   175  
   176  func deferFunc() (int, func(int)) {
   177  	return 0, func(i int) { println("...extracted defer func ", i) }
   178  }
   179  
   180  func multiFuncDefer() func(int) {
   181  	i := 0
   182  
   183  	if i > 0 {
   184  		return func(i int) { println("Should not have gotten here. i = ", i) }
   185  	}
   186  
   187  	return func(i int) { println("Called the correct function. i = ", i) }
   188  }
   189  
   190  func testBound(f func() string) {
   191  	println("bound method:", f())
   192  }
   193  
   194  // regression1033 is a regression test for https://github.com/tinygo-org/tinygo/issues/1033.
   195  // In previous versions of the compiler, a deferred call to an interface would create an instruction that did not dominate its uses.
   196  func regression1033() {
   197  	foo(&Bar{})
   198  }
   199  
   200  type Bar struct {
   201  	empty bool
   202  }
   203  
   204  func (b *Bar) Close() error {
   205  	return nil
   206  }
   207  
   208  type Closer interface {
   209  	Close() error
   210  }
   211  
   212  func foo(bar *Bar) error {
   213  	var a int
   214  	if !bar.empty {
   215  		a = 10
   216  		if a != 5 {
   217  			return nil
   218  		}
   219  	}
   220  
   221  	var c Closer = bar
   222  	defer c.Close()
   223  
   224  	return nil
   225  }
   226  
   227  type issue1304 struct {
   228  	a [0]int // zero-length field
   229  	b int    // field 'b' covers entire struct
   230  }
   231  
   232  func (x issue1304) call() {
   233  	// nothing to do
   234  }
   235  
   236  type recursiveFuncType func(recursiveFuncType)
   237  
   238  var recursiveFunction recursiveFuncType
   239  
   240  //go:noinline
   241  func testDeferElse(b bool) (r int) {
   242  	if !b {
   243  		defer func() {
   244  			r = 0
   245  
   246  		}()
   247  	}
   248  
   249  	return 1
   250  }