mirror of https://github.com/tinygo-org/tinygo.git
wasmstm32webassemblymicrocontrollerarmavrspiwasiadafruitarduinocircuitplayground-expressgpioi2cllvmmicrobitnrf51nrf52nrf52840samd21tinygo
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
250 lines
4.2 KiB
250 lines
4.2 KiB
package main
|
|
|
|
type Thing struct {
|
|
name string
|
|
}
|
|
|
|
type ThingOption func(*Thing)
|
|
|
|
func WithName(name string) ThingOption {
|
|
return func(t *Thing) {
|
|
t.name = name
|
|
}
|
|
}
|
|
|
|
func NewThing(opts ...ThingOption) *Thing {
|
|
t := &Thing{}
|
|
for _, opt := range opts {
|
|
opt(t)
|
|
}
|
|
return t
|
|
}
|
|
|
|
func (t Thing) String() string {
|
|
return t.name
|
|
}
|
|
|
|
func (t Thing) Print(arg string) {
|
|
println("Thing.Print:", t.name, "arg:", arg)
|
|
}
|
|
|
|
type Printer interface {
|
|
Print(string)
|
|
}
|
|
|
|
func main() {
|
|
thing := &Thing{"foo"}
|
|
|
|
// function pointers
|
|
runFunc(hello, 5) // must be indirect to avoid obvious inlining
|
|
|
|
// deferred functions
|
|
testDefer()
|
|
|
|
// defers in loop
|
|
testDeferLoop()
|
|
|
|
//defer func variable call
|
|
testDeferFuncVar()
|
|
|
|
//More complicated func variable call
|
|
testMultiFuncVar()
|
|
|
|
// Take a bound method and use it as a function pointer.
|
|
// This function pointer needs a context pointer.
|
|
testBound(thing.String)
|
|
|
|
// closures
|
|
func() {
|
|
println("thing inside closure:", thing.String())
|
|
}()
|
|
runFunc(func(i int) {
|
|
println("inside fp closure:", thing.String(), i)
|
|
}, 3)
|
|
|
|
// functional arguments
|
|
thingFunctionalArgs1 := NewThing()
|
|
thingFunctionalArgs1.Print("functional args 1")
|
|
thingFunctionalArgs2 := NewThing(WithName("named thing"))
|
|
thingFunctionalArgs2.Print("functional args 2")
|
|
|
|
// regression testing
|
|
regression1033()
|
|
|
|
//Test deferred builtins
|
|
testDeferBuiltinClose()
|
|
testDeferBuiltinDelete()
|
|
|
|
// Check for issue 1304.
|
|
// There are two fields in this struct, one of which is zero-length so the
|
|
// other covers the entire struct. This led to a verification error for
|
|
// debug info, which used DW_OP_LLVM_fragment for a field that practically
|
|
// covered the entire variable.
|
|
var x issue1304
|
|
x.call()
|
|
|
|
if testDeferElse(false) != 0 {
|
|
println("else defer returned wrong value")
|
|
}
|
|
}
|
|
|
|
func runFunc(f func(int), arg int) {
|
|
f(arg)
|
|
}
|
|
|
|
func hello(n int) {
|
|
println("hello from function pointer:", n)
|
|
}
|
|
|
|
func testDefer() {
|
|
defer exportedDefer()
|
|
|
|
i := 1
|
|
defer deferred("...run as defer", i)
|
|
i++
|
|
defer func() {
|
|
println("...run closure deferred:", i)
|
|
}()
|
|
i++
|
|
defer deferred("...run as defer", i)
|
|
i++
|
|
|
|
var t Printer = &Thing{"foo"}
|
|
defer t.Print("bar")
|
|
|
|
println("deferring...")
|
|
d := dumb{}
|
|
defer d.Value(0)
|
|
}
|
|
|
|
func testDeferLoop() {
|
|
for j := 0; j < 4; j++ {
|
|
defer deferred("loop", j)
|
|
}
|
|
}
|
|
|
|
func testDeferFuncVar() {
|
|
dummy, f := deferFunc()
|
|
dummy++
|
|
defer f(1)
|
|
}
|
|
|
|
func testMultiFuncVar() {
|
|
f := multiFuncDefer()
|
|
defer f(1)
|
|
}
|
|
|
|
func testDeferBuiltinClose() {
|
|
i := make(chan int)
|
|
func() {
|
|
defer close(i)
|
|
}()
|
|
if n, ok := <-i; n != 0 || ok {
|
|
println("expected to read 0 from closed channel")
|
|
}
|
|
}
|
|
|
|
func testDeferBuiltinDelete() {
|
|
m := map[int]int{3: 30, 5: 50}
|
|
func() {
|
|
defer delete(m, 3)
|
|
if m[3] != 30 {
|
|
println("expected m[3] to be 30")
|
|
}
|
|
}()
|
|
if m[3] != 0 {
|
|
println("expected m[3] to be 0")
|
|
}
|
|
}
|
|
|
|
type dumb struct {
|
|
}
|
|
|
|
func (*dumb) Value(key interface{}) interface{} {
|
|
return nil
|
|
}
|
|
|
|
func deferred(msg string, i int) {
|
|
println(msg, i)
|
|
}
|
|
|
|
//export __exportedDefer
|
|
func exportedDefer() {
|
|
println("...exported defer")
|
|
}
|
|
|
|
func deferFunc() (int, func(int)) {
|
|
return 0, func(i int) { println("...extracted defer func ", i) }
|
|
}
|
|
|
|
func multiFuncDefer() func(int) {
|
|
i := 0
|
|
|
|
if i > 0 {
|
|
return func(i int) { println("Should not have gotten here. i = ", i) }
|
|
}
|
|
|
|
return func(i int) { println("Called the correct function. i = ", i) }
|
|
}
|
|
|
|
func testBound(f func() string) {
|
|
println("bound method:", f())
|
|
}
|
|
|
|
// regression1033 is a regression test for https://github.com/tinygo-org/tinygo/issues/1033.
|
|
// In previous versions of the compiler, a deferred call to an interface would create an instruction that did not dominate its uses.
|
|
func regression1033() {
|
|
foo(&Bar{})
|
|
}
|
|
|
|
type Bar struct {
|
|
empty bool
|
|
}
|
|
|
|
func (b *Bar) Close() error {
|
|
return nil
|
|
}
|
|
|
|
type Closer interface {
|
|
Close() error
|
|
}
|
|
|
|
func foo(bar *Bar) error {
|
|
var a int
|
|
if !bar.empty {
|
|
a = 10
|
|
if a != 5 {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
var c Closer = bar
|
|
defer c.Close()
|
|
|
|
return nil
|
|
}
|
|
|
|
type issue1304 struct {
|
|
a [0]int // zero-length field
|
|
b int // field 'b' covers entire struct
|
|
}
|
|
|
|
func (x issue1304) call() {
|
|
// nothing to do
|
|
}
|
|
|
|
type recursiveFuncType func(recursiveFuncType)
|
|
|
|
var recursiveFunction recursiveFuncType
|
|
|
|
//go:noinline
|
|
func testDeferElse(b bool) (r int) {
|
|
if !b {
|
|
defer func() {
|
|
r = 0
|
|
|
|
}()
|
|
}
|
|
|
|
return 1
|
|
}
|
|
|