1package main 2 3type Thing struct { 4 name string 5} 6 7type ThingOption func(*Thing) 8 9func WithName(name string) ThingOption { 10 return func(t *Thing) { 11 t.name = name 12 } 13} 14 15func NewThing(opts ...ThingOption) *Thing { 16 t := &Thing{} 17 for _, opt := range opts { 18 opt(t) 19 } 20 return t 21} 22 23func (t Thing) String() string { 24 return t.name 25} 26 27func (t Thing) Print(arg string) { 28 println("Thing.Print:", t.name, "arg:", arg) 29} 30 31type Printer interface { 32 Print(string) 33} 34 35func 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 testDeferBuiltin() 76} 77 78func runFunc(f func(int), arg int) { 79 f(arg) 80} 81 82func hello(n int) { 83 println("hello from function pointer:", n) 84} 85 86func testDefer() { 87 defer exportedDefer() 88 89 i := 1 90 defer deferred("...run as defer", i) 91 i++ 92 defer func() { 93 println("...run closure deferred:", i) 94 }() 95 i++ 96 defer deferred("...run as defer", i) 97 i++ 98 99 var t Printer = &Thing{"foo"} 100 defer t.Print("bar") 101 102 println("deferring...") 103 d := dumb{} 104 defer d.Value(0) 105} 106 107func testDeferLoop() { 108 for j := 0; j < 4; j++ { 109 defer deferred("loop", j) 110 } 111} 112 113func testDeferFuncVar() { 114 dummy, f := deferFunc() 115 dummy++ 116 defer f(1) 117} 118 119func testMultiFuncVar() { 120 f := multiFuncDefer() 121 defer f(1) 122} 123 124func testDeferBuiltin() { 125 i := make(chan int) 126 defer close(i) 127} 128 129type dumb struct { 130 131} 132 133func (*dumb) Value(key interface{}) interface{} { 134 return nil 135} 136 137func deferred(msg string, i int) { 138 println(msg, i) 139} 140 141//export __exportedDefer 142func exportedDefer() { 143 println("...exported defer") 144} 145 146func deferFunc() (int, func(int)) { 147 return 0, func(i int){println("...extracted defer func ", i)} 148} 149 150func multiFuncDefer() func(int) { 151 i := 0 152 153 if i > 0 { 154 return func(i int){println("Should not have gotten here. i = ", i)} 155 } 156 157 return func(i int){println("Called the correct function. i = ", i)} 158} 159 160func testBound(f func() string) { 161 println("bound method:", f()) 162} 163 164// regression1033 is a regression test for https://github.com/tinygo-org/tinygo/issues/1033. 165// In previous versions of the compiler, a deferred call to an interface would create an instruction that did not dominate its uses. 166func regression1033() { 167 foo(&Bar{}) 168} 169 170type Bar struct { 171 empty bool 172} 173 174func (b *Bar) Close() error { 175 return nil 176} 177 178type Closer interface { 179 Close() error 180} 181 182func foo(bar *Bar) error { 183 var a int 184 if !bar.empty { 185 a = 10 186 if a != 5 { 187 return nil 188 } 189 } 190 191 var c Closer = bar 192 defer c.Close() 193 194 return nil 195} 196