github.com/jd-ly/tools@v0.5.7/go/ssa/interp/testdata/boundmeth.go (about)

     1  // Tests of bound method closures.
     2  
     3  package main
     4  
     5  import (
     6  	"errors"
     7  	"fmt"
     8  )
     9  
    10  func assert(b bool) {
    11  	if !b {
    12  		panic("oops")
    13  	}
    14  }
    15  
    16  type I int
    17  
    18  func (i I) add(x int) int {
    19  	return int(i) + x
    20  }
    21  
    22  func valueReceiver() {
    23  	var three I = 3
    24  	assert(three.add(5) == 8)
    25  	var add3 func(int) int = three.add
    26  	assert(add3(5) == 8)
    27  }
    28  
    29  type S struct{ x int }
    30  
    31  func (s *S) incr() {
    32  	s.x++
    33  }
    34  
    35  func (s *S) get() int {
    36  	return s.x
    37  }
    38  
    39  func pointerReceiver() {
    40  	ps := new(S)
    41  	incr := ps.incr
    42  	get := ps.get
    43  	assert(get() == 0)
    44  	incr()
    45  	incr()
    46  	incr()
    47  	assert(get() == 3)
    48  }
    49  
    50  func addressibleValuePointerReceiver() {
    51  	var s S
    52  	incr := s.incr
    53  	get := s.get
    54  	assert(get() == 0)
    55  	incr()
    56  	incr()
    57  	incr()
    58  	assert(get() == 3)
    59  }
    60  
    61  type S2 struct {
    62  	S
    63  }
    64  
    65  func promotedReceiver() {
    66  	var s2 S2
    67  	incr := s2.incr
    68  	get := s2.get
    69  	assert(get() == 0)
    70  	incr()
    71  	incr()
    72  	incr()
    73  	assert(get() == 3)
    74  }
    75  
    76  func anonStruct() {
    77  	var s struct{ S }
    78  	incr := s.incr
    79  	get := s.get
    80  	assert(get() == 0)
    81  	incr()
    82  	incr()
    83  	incr()
    84  	assert(get() == 3)
    85  }
    86  
    87  func typeCheck() {
    88  	var i interface{}
    89  	i = (*S).incr
    90  	_ = i.(func(*S)) // type assertion: receiver type prepended to params
    91  
    92  	var s S
    93  	i = s.incr
    94  	_ = i.(func()) // type assertion: receiver type disappears
    95  }
    96  
    97  type errString string
    98  
    99  func (err errString) Error() string {
   100  	return string(err)
   101  }
   102  
   103  // Regression test for a builder crash.
   104  func regress1(x error) func() string {
   105  	return x.Error
   106  }
   107  
   108  // Regression test for b/7269:
   109  // taking the value of an interface method performs a nil check.
   110  func nilInterfaceMethodValue() {
   111  	err := errors.New("ok")
   112  	f := err.Error
   113  	if got := f(); got != "ok" {
   114  		panic(got)
   115  	}
   116  
   117  	err = nil
   118  	if got := f(); got != "ok" {
   119  		panic(got)
   120  	}
   121  
   122  	defer func() {
   123  		r := fmt.Sprint(recover())
   124  		// runtime panic string varies across toolchains
   125  		if r != "interface conversion: interface is nil, not error" &&
   126  			r != "runtime error: invalid memory address or nil pointer dereference" {
   127  			panic("want runtime panic from nil interface method value, got " + r)
   128  		}
   129  	}()
   130  	f = err.Error // runtime panic: err is nil
   131  	panic("unreachable")
   132  }
   133  
   134  func main() {
   135  	valueReceiver()
   136  	pointerReceiver()
   137  	addressibleValuePointerReceiver()
   138  	promotedReceiver()
   139  	anonStruct()
   140  	typeCheck()
   141  
   142  	if e := regress1(errString("hi"))(); e != "hi" {
   143  		panic(e)
   144  	}
   145  
   146  	nilInterfaceMethodValue()
   147  }