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.
7 import "internal/bytealg"
9 // The Error interface identifies a run time error.
10 type Error interface {
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.
20 // A TypeAssertionError explains a failed type assertion.
21 type TypeAssertionError struct {
25 missingMethod string // one method needed by Interface, missing from Concrete
28 func (*TypeAssertionError) RuntimeError() {}
30 func (e *TypeAssertionError) Error() string {
32 if e._interface != nil {
33 inter = toRType(e._interface).string()
35 as := toRType(e.asserted).string()
36 if e.concrete == nil {
37 return "interface conversion: " + inter + " is nil, not " + as
39 cs := toRType(e.concrete).string()
40 if e.missingMethod == "" {
41 msg := "interface conversion: " + inter + " is " + cs + ", not " + as
43 // provide slightly clearer error message
44 if toRType(e.concrete).pkgpath() != toRType(e.asserted).pkgpath() {
45 msg += " (types from different packages)"
47 msg += " (types from different scopes)"
52 return "interface conversion: " + cs + " is not " + as +
53 ": missing method " + e.missingMethod
56 // itoa converts val to a decimal representation. The result is
57 // written somewhere within buf and the location of the result is returned.
58 // buf must be at least 20 bytes.
61 func itoa(buf []byte, val uint64) []byte {
64 buf[i] = byte(val%10 + '0')
68 buf[i] = byte(val + '0')
72 // An errorString represents a runtime error described by a single string.
73 type errorString string
75 func (e errorString) RuntimeError() {}
77 func (e errorString) Error() string {
78 return "runtime error: " + string(e)
81 type errorAddressString struct {
82 msg string // error message
83 addr uintptr // memory address where the error occurred
86 func (e errorAddressString) RuntimeError() {}
88 func (e errorAddressString) Error() string {
89 return "runtime error: " + e.msg
92 // Addr returns the memory address where a fault occurred.
93 // The address provided is best-effort.
94 // The veracity of the result may depend on the platform.
95 // Errors providing this method will only be returned as
96 // a result of using runtime/debug.SetPanicOnFault.
97 func (e errorAddressString) Addr() uintptr {
101 // plainError represents a runtime error described a string without
102 // the prefix "runtime error: " after invoking errorString.Error().
104 type plainError string
106 func (e plainError) RuntimeError() {}
108 func (e plainError) Error() string {
112 // A boundsError represents an indexing or slicing operation gone wrong.
113 type boundsError struct {
116 // Values in an index or slice expression can be signed or unsigned.
117 // That means we'd need 65 bits to encode all possible indexes, from -2^63 to 2^64-1.
118 // Instead, we keep track of whether x should be interpreted as signed or unsigned.
119 // y is known to be nonnegative and to fit in an int.
124 type boundsErrorCode uint8
127 boundsIndex boundsErrorCode = iota // s[x], 0 <= x < len(s) failed
129 boundsSliceAlen // s[?:x], 0 <= x <= len(s) failed
130 boundsSliceAcap // s[?:x], 0 <= x <= cap(s) failed
131 boundsSliceB // s[x:y], 0 <= x <= y failed (but boundsSliceA didn't happen)
133 boundsSlice3Alen // s[?:?:x], 0 <= x <= len(s) failed
134 boundsSlice3Acap // s[?:?:x], 0 <= x <= cap(s) failed
135 boundsSlice3B // s[?:x:y], 0 <= x <= y failed (but boundsSlice3A didn't happen)
136 boundsSlice3C // s[x:y:?], 0 <= x <= y failed (but boundsSlice3A/B didn't happen)
138 boundsConvert // (*[x]T)(s), 0 <= x <= len(s) failed
139 // Note: in the above, len(s) and cap(s) are stored in y
142 // boundsErrorFmts provide error text for various out-of-bounds panics.
143 // Note: if you change these strings, you should adjust the size of the buffer
144 // in boundsError.Error below as well.
145 var boundsErrorFmts = [...]string{
146 boundsIndex: "index out of range [%x] with length %y",
147 boundsSliceAlen: "slice bounds out of range [:%x] with length %y",
148 boundsSliceAcap: "slice bounds out of range [:%x] with capacity %y",
149 boundsSliceB: "slice bounds out of range [%x:%y]",
150 boundsSlice3Alen: "slice bounds out of range [::%x] with length %y",
151 boundsSlice3Acap: "slice bounds out of range [::%x] with capacity %y",
152 boundsSlice3B: "slice bounds out of range [:%x:%y]",
153 boundsSlice3C: "slice bounds out of range [%x:%y:]",
154 boundsConvert: "cannot convert slice with length %y to array or pointer to array with length %x",
157 // boundsNegErrorFmts are overriding formats if x is negative. In this case there's no need to report y.
158 var boundsNegErrorFmts = [...]string{
159 boundsIndex: "index out of range [%x]",
160 boundsSliceAlen: "slice bounds out of range [:%x]",
161 boundsSliceAcap: "slice bounds out of range [:%x]",
162 boundsSliceB: "slice bounds out of range [%x:]",
163 boundsSlice3Alen: "slice bounds out of range [::%x]",
164 boundsSlice3Acap: "slice bounds out of range [::%x]",
165 boundsSlice3B: "slice bounds out of range [:%x:]",
166 boundsSlice3C: "slice bounds out of range [%x::]",
169 func (e boundsError) RuntimeError() {}
171 func appendIntStr(b []byte, v int64, signed bool) []byte {
177 b = append(b, itoa(buf[:], uint64(v))...)
181 func (e boundsError) Error() string {
182 fmt := boundsErrorFmts[e.code]
183 if e.signed && e.x < 0 {
184 fmt = boundsNegErrorFmts[e.code]
186 // max message length is 99: "runtime error: slice bounds out of range [::%x] with capacity %y"
187 // x can be at most 20 characters. y can be at most 19.
188 b := make([]byte, 0, 100)
189 b = append(b, "runtime error: "...)
190 for i := 0; i < len(fmt); i++ {
199 b = appendIntStr(b, e.x, e.signed)
201 b = appendIntStr(b, int64(e.y), true)
207 type stringer interface {
211 // printany prints an argument passed to panic.
212 // If panic is called with a value that has a String or Error method,
213 // it has already been converted into a string by preprintpanics.
214 func printany(i any) {
215 switch v := i.(type) {
253 printanycustomtype(i)
257 func printanycustomtype(i any) {
259 typestring := toRType(eface._type).string()
261 switch eface._type.Kind_ {
263 print(typestring, `("`, *(*string)(eface.data), `")`)
265 print(typestring, "(", *(*bool)(eface.data), ")")
267 print(typestring, "(", *(*int)(eface.data), ")")
269 print(typestring, "(", *(*int8)(eface.data), ")")
271 print(typestring, "(", *(*int16)(eface.data), ")")
273 print(typestring, "(", *(*int32)(eface.data), ")")
275 print(typestring, "(", *(*int64)(eface.data), ")")
277 print(typestring, "(", *(*uint)(eface.data), ")")
279 print(typestring, "(", *(*uint8)(eface.data), ")")
281 print(typestring, "(", *(*uint16)(eface.data), ")")
283 print(typestring, "(", *(*uint32)(eface.data), ")")
285 print(typestring, "(", *(*uint64)(eface.data), ")")
287 print(typestring, "(", *(*uintptr)(eface.data), ")")
289 print(typestring, "(", *(*float32)(eface.data), ")")
291 print(typestring, "(", *(*float64)(eface.data), ")")
293 print(typestring, *(*complex64)(eface.data))
295 print(typestring, *(*complex128)(eface.data))
297 print("(", typestring, ") ", eface.data)
301 // panicwrap generates a panic for a call to a wrapped value method
302 // with a nil pointer receiver.
304 // It is called from the generated wrapper code.
307 name := funcNameForPrint(funcname(findfunc(pc)))
308 // name is something like "main.(*T).F".
309 // We want to extract pkg ("main"), typ ("T"), and meth ("F").
310 // Do it by finding the parens.
311 i := bytealg.IndexByteString(name, '(')
313 throw("panicwrap: no ( in " + name)
316 if i+2 >= len(name) || name[i-1:i+2] != ".(*" {
317 throw("panicwrap: unexpected string after package name: " + name)
320 i = bytealg.IndexByteString(name, ')')
322 throw("panicwrap: no ) in " + name)
324 if i+2 >= len(name) || name[i:i+2] != ")." {
325 throw("panicwrap: unexpected string after type name: " + name)
329 panic(plainError("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer"))