aboutsummaryrefslogtreecommitdiff
path: root/go/ssa/interp/testdata/boundmeth.go
blob: 47b94068591abd378a2a9892e06cb87142871fad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Tests of bound method closures.

package main

import (
	"errors"
	"fmt"
)

func assert(b bool) {
	if !b {
		panic("oops")
	}
}

type I int

func (i I) add(x int) int {
	return int(i) + x
}

func valueReceiver() {
	var three I = 3
	assert(three.add(5) == 8)
	var add3 func(int) int = three.add
	assert(add3(5) == 8)
}

type S struct{ x int }

func (s *S) incr() {
	s.x++
}

func (s *S) get() int {
	return s.x
}

func pointerReceiver() {
	ps := new(S)
	incr := ps.incr
	get := ps.get
	assert(get() == 0)
	incr()
	incr()
	incr()
	assert(get() == 3)
}

func addressibleValuePointerReceiver() {
	var s S
	incr := s.incr
	get := s.get
	assert(get() == 0)
	incr()
	incr()
	incr()
	assert(get() == 3)
}

type S2 struct {
	S
}

func promotedReceiver() {
	var s2 S2
	incr := s2.incr
	get := s2.get
	assert(get() == 0)
	incr()
	incr()
	incr()
	assert(get() == 3)
}

func anonStruct() {
	var s struct{ S }
	incr := s.incr
	get := s.get
	assert(get() == 0)
	incr()
	incr()
	incr()
	assert(get() == 3)
}

func typeCheck() {
	var i interface{}
	i = (*S).incr
	_ = i.(func(*S)) // type assertion: receiver type prepended to params

	var s S
	i = s.incr
	_ = i.(func()) // type assertion: receiver type disappears
}

type errString string

func (err errString) Error() string {
	return string(err)
}

// Regression test for a builder crash.
func regress1(x error) func() string {
	return x.Error
}

// Regression test for b/7269:
// taking the value of an interface method performs a nil check.
func nilInterfaceMethodValue() {
	err := errors.New("ok")
	f := err.Error
	if got := f(); got != "ok" {
		panic(got)
	}

	err = nil
	if got := f(); got != "ok" {
		panic(got)
	}

	defer func() {
		r := fmt.Sprint(recover())
		// runtime panic string varies across toolchains
		if r != "interface conversion: interface is nil, not error" &&
			r != "runtime error: invalid memory address or nil pointer dereference" &&
			r != "method value: interface is nil" {
			panic("want runtime panic from nil interface method value, got " + r)
		}
	}()
	f = err.Error // runtime panic: err is nil
	panic("unreachable")
}

func main() {
	valueReceiver()
	pointerReceiver()
	addressibleValuePointerReceiver()
	promotedReceiver()
	anonStruct()
	typeCheck()

	if e := regress1(errString("hi"))(); e != "hi" {
		panic(e)
	}

	nilInterfaceMethodValue()
}