1// Copyright 2010 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package runtime
6
7import "unsafe"
8
9// The Error interface identifies a run time error.
10type Error interface {
11	error
12
13	// RuntimeError is a no-op function but
14	// serves to distinguish types that are run time
15	// errors from ordinary errors: a type is a
16	// run time error if it has a RuntimeError method.
17	RuntimeError()
18}
19
20// A TypeAssertionError explains a failed type assertion.
21type TypeAssertionError struct {
22	_interface    *_type
23	concrete      *_type
24	asserted      *_type
25	missingMethod string // one method needed by Interface, missing from Concrete
26}
27
28func (*TypeAssertionError) RuntimeError() {}
29
30func (e *TypeAssertionError) Error() string {
31	inter := "interface"
32	if e._interface != nil {
33		inter = e._interface.string()
34	}
35	as := e.asserted.string()
36	if e.concrete == nil {
37		return "interface conversion: " + inter + " is nil, not " + as
38	}
39	cs := e.concrete.string()
40	if e.missingMethod == "" {
41		msg := "interface conversion: " + inter + " is " + cs + ", not " + as
42		if cs == as {
43			// provide slightly clearer error message
44			if e.concrete.pkgpath() != e.asserted.pkgpath() {
45				msg += " (types from different packages)"
46			} else {
47				msg += " (types from different scopes)"
48			}
49		}
50		return msg
51	}
52	return "interface conversion: " + cs + " is not " + as +
53		": missing method " + e.missingMethod
54}
55
56// Remove quoted strings from gccgo reflection strings.
57func unquote(s string) string {
58	ls := len(s)
59	var i int
60	for i = 0; i < ls; i++ {
61		if s[i] == '\t' {
62			break
63		}
64	}
65	if i == ls {
66		return s
67	}
68	var q bool
69	r := make([]byte, len(s))
70	j := 0
71	for i = 0; i < ls; i++ {
72		if s[i] == '\t' {
73			q = !q
74		} else if !q {
75			r[j] = s[i]
76			j++
77		}
78	}
79	return string(r[:j])
80}
81
82//go:nosplit
83// itoa converts val to a decimal representation. The result is
84// written somewhere within buf and the location of the result is returned.
85// buf must be at least 20 bytes.
86func itoa(buf []byte, val uint64) []byte {
87	i := len(buf) - 1
88	for val >= 10 {
89		buf[i] = byte(val%10 + '0')
90		i--
91		val /= 10
92	}
93	buf[i] = byte(val + '0')
94	return buf[i:]
95}
96
97// An errorString represents a runtime error described by a single string.
98type errorString string
99
100func (e errorString) RuntimeError() {}
101
102func (e errorString) Error() string {
103	return "runtime error: " + string(e)
104}
105
106// An errorCString represents a runtime error described by a single C string.
107// Not "type errorCString uintptr" because of http://golang.org/issue/7084.
108type errorCString struct{ cstr uintptr }
109
110func (e errorCString) RuntimeError() {}
111
112func (e errorCString) Error() string {
113	return "runtime error: " + gostringnocopy((*byte)(unsafe.Pointer(e.cstr)))
114}
115
116// For calling from C.
117func NewErrorCString(s uintptr, ret *interface{}) {
118	*ret = errorCString{s}
119}
120
121// plainError represents a runtime error described a string without
122// the prefix "runtime error: " after invoking errorString.Error().
123// See Issue #14965.
124type plainError string
125
126func (e plainError) RuntimeError() {}
127
128func (e plainError) Error() string {
129	return string(e)
130}
131
132// A boundsError represents an indexing or slicing operation gone wrong.
133type boundsError struct {
134	x int64
135	y int
136	// Values in an index or slice expression can be signed or unsigned.
137	// That means we'd need 65 bits to encode all possible indexes, from -2^63 to 2^64-1.
138	// Instead, we keep track of whether x should be interpreted as signed or unsigned.
139	// y is known to be nonnegative and to fit in an int.
140	signed bool
141	code   boundsErrorCode
142}
143
144type boundsErrorCode uint8
145
146const (
147	boundsIndex boundsErrorCode = iota // s[x], 0 <= x < len(s) failed
148
149	boundsSliceAlen // s[?:x], 0 <= x <= len(s) failed
150	boundsSliceAcap // s[?:x], 0 <= x <= cap(s) failed
151	boundsSliceB    // s[x:y], 0 <= x <= y failed (but boundsSliceA didn't happen)
152
153	boundsSlice3Alen // s[?:?:x], 0 <= x <= len(s) failed
154	boundsSlice3Acap // s[?:?:x], 0 <= x <= cap(s) failed
155	boundsSlice3B    // s[?:x:y], 0 <= x <= y failed (but boundsSlice3A didn't happen)
156	boundsSlice3C    // s[x:y:?], 0 <= x <= y failed (but boundsSlice3A/B didn't happen)
157
158	// Note: in the above, len(s) and cap(s) are stored in y
159)
160
161// boundsErrorFmts provide error text for various out-of-bounds panics.
162// Note: if you change these strings, you should adjust the size of the buffer
163// in boundsError.Error below as well.
164var boundsErrorFmts = [...]string{
165	boundsIndex:      "index out of range [%x] with length %y",
166	boundsSliceAlen:  "slice bounds out of range [:%x] with length %y",
167	boundsSliceAcap:  "slice bounds out of range [:%x] with capacity %y",
168	boundsSliceB:     "slice bounds out of range [%x:%y]",
169	boundsSlice3Alen: "slice bounds out of range [::%x] with length %y",
170	boundsSlice3Acap: "slice bounds out of range [::%x] with capacity %y",
171	boundsSlice3B:    "slice bounds out of range [:%x:%y]",
172	boundsSlice3C:    "slice bounds out of range [%x:%y:]",
173}
174
175// boundsNegErrorFmts are overriding formats if x is negative. In this case there's no need to report y.
176var boundsNegErrorFmts = [...]string{
177	boundsIndex:      "index out of range [%x]",
178	boundsSliceAlen:  "slice bounds out of range [:%x]",
179	boundsSliceAcap:  "slice bounds out of range [:%x]",
180	boundsSliceB:     "slice bounds out of range [%x:]",
181	boundsSlice3Alen: "slice bounds out of range [::%x]",
182	boundsSlice3Acap: "slice bounds out of range [::%x]",
183	boundsSlice3B:    "slice bounds out of range [:%x:]",
184	boundsSlice3C:    "slice bounds out of range [%x::]",
185}
186
187func (e boundsError) RuntimeError() {}
188
189func appendIntStr(b []byte, v int64, signed bool) []byte {
190	if signed && v < 0 {
191		b = append(b, '-')
192		v = -v
193	}
194	var buf [20]byte
195	b = append(b, itoa(buf[:], uint64(v))...)
196	return b
197}
198
199func (e boundsError) Error() string {
200	fmt := boundsErrorFmts[e.code]
201	if e.signed && e.x < 0 {
202		fmt = boundsNegErrorFmts[e.code]
203	}
204	// max message length is 99: "runtime error: slice bounds out of range [::%x] with capacity %y"
205	// x can be at most 20 characters. y can be at most 19.
206	b := make([]byte, 0, 100)
207	b = append(b, "runtime error: "...)
208	for i := 0; i < len(fmt); i++ {
209		c := fmt[i]
210		if c != '%' {
211			b = append(b, c)
212			continue
213		}
214		i++
215		switch fmt[i] {
216		case 'x':
217			b = appendIntStr(b, e.x, e.signed)
218		case 'y':
219			b = appendIntStr(b, int64(e.y), true)
220		}
221	}
222	return string(b)
223}
224
225type stringer interface {
226	String() string
227}
228
229func typestring(x interface{}) string {
230	e := efaceOf(&x)
231	return e._type.string()
232}
233
234// printany prints an argument passed to panic.
235// If panic is called with a value that has a String or Error method,
236// it has already been converted into a string by preprintpanics.
237func printany(i interface{}) {
238	switch v := i.(type) {
239	case nil:
240		print("nil")
241	case bool:
242		print(v)
243	case int:
244		print(v)
245	case int8:
246		print(v)
247	case int16:
248		print(v)
249	case int32:
250		print(v)
251	case int64:
252		print(v)
253	case uint:
254		print(v)
255	case uint8:
256		print(v)
257	case uint16:
258		print(v)
259	case uint32:
260		print(v)
261	case uint64:
262		print(v)
263	case uintptr:
264		print(v)
265	case float32:
266		print(v)
267	case float64:
268		print(v)
269	case complex64:
270		print(v)
271	case complex128:
272		print(v)
273	case string:
274		print(v)
275	default:
276		print("(", typestring(i), ") ", i)
277	}
278}
279