]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/error.go
log/slog: fix method name in docs
[gostls13.git] / src / runtime / error.go
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
5 package runtime
6
7 import "internal/bytealg"
8
9 // The Error interface identifies a run time error.
10 type 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.
21 type TypeAssertionError struct {
22         _interface    *_type
23         concrete      *_type
24         asserted      *_type
25         missingMethod string // one method needed by Interface, missing from Concrete
26 }
27
28 func (*TypeAssertionError) RuntimeError() {}
29
30 func (e *TypeAssertionError) Error() string {
31         inter := "interface"
32         if e._interface != nil {
33                 inter = toRType(e._interface).string()
34         }
35         as := toRType(e.asserted).string()
36         if e.concrete == nil {
37                 return "interface conversion: " + inter + " is nil, not " + as
38         }
39         cs := toRType(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 toRType(e.concrete).pkgpath() != toRType(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 // 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.
59 //
60 //go:nosplit
61 func itoa(buf []byte, val uint64) []byte {
62         i := len(buf) - 1
63         for val >= 10 {
64                 buf[i] = byte(val%10 + '0')
65                 i--
66                 val /= 10
67         }
68         buf[i] = byte(val + '0')
69         return buf[i:]
70 }
71
72 // An errorString represents a runtime error described by a single string.
73 type errorString string
74
75 func (e errorString) RuntimeError() {}
76
77 func (e errorString) Error() string {
78         return "runtime error: " + string(e)
79 }
80
81 type errorAddressString struct {
82         msg  string  // error message
83         addr uintptr // memory address where the error occurred
84 }
85
86 func (e errorAddressString) RuntimeError() {}
87
88 func (e errorAddressString) Error() string {
89         return "runtime error: " + e.msg
90 }
91
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 {
98         return e.addr
99 }
100
101 // plainError represents a runtime error described a string without
102 // the prefix "runtime error: " after invoking errorString.Error().
103 // See Issue #14965.
104 type plainError string
105
106 func (e plainError) RuntimeError() {}
107
108 func (e plainError) Error() string {
109         return string(e)
110 }
111
112 // A boundsError represents an indexing or slicing operation gone wrong.
113 type boundsError struct {
114         x int64
115         y int
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.
120         signed bool
121         code   boundsErrorCode
122 }
123
124 type boundsErrorCode uint8
125
126 const (
127         boundsIndex boundsErrorCode = iota // s[x], 0 <= x < len(s) failed
128
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)
132
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)
137
138         boundsConvert // (*[x]T)(s), 0 <= x <= len(s) failed
139         // Note: in the above, len(s) and cap(s) are stored in y
140 )
141
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",
155 }
156
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::]",
167 }
168
169 func (e boundsError) RuntimeError() {}
170
171 func appendIntStr(b []byte, v int64, signed bool) []byte {
172         if signed && v < 0 {
173                 b = append(b, '-')
174                 v = -v
175         }
176         var buf [20]byte
177         b = append(b, itoa(buf[:], uint64(v))...)
178         return b
179 }
180
181 func (e boundsError) Error() string {
182         fmt := boundsErrorFmts[e.code]
183         if e.signed && e.x < 0 {
184                 fmt = boundsNegErrorFmts[e.code]
185         }
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++ {
191                 c := fmt[i]
192                 if c != '%' {
193                         b = append(b, c)
194                         continue
195                 }
196                 i++
197                 switch fmt[i] {
198                 case 'x':
199                         b = appendIntStr(b, e.x, e.signed)
200                 case 'y':
201                         b = appendIntStr(b, int64(e.y), true)
202                 }
203         }
204         return string(b)
205 }
206
207 type stringer interface {
208         String() string
209 }
210
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) {
216         case nil:
217                 print("nil")
218         case bool:
219                 print(v)
220         case int:
221                 print(v)
222         case int8:
223                 print(v)
224         case int16:
225                 print(v)
226         case int32:
227                 print(v)
228         case int64:
229                 print(v)
230         case uint:
231                 print(v)
232         case uint8:
233                 print(v)
234         case uint16:
235                 print(v)
236         case uint32:
237                 print(v)
238         case uint64:
239                 print(v)
240         case uintptr:
241                 print(v)
242         case float32:
243                 print(v)
244         case float64:
245                 print(v)
246         case complex64:
247                 print(v)
248         case complex128:
249                 print(v)
250         case string:
251                 print(v)
252         default:
253                 printanycustomtype(i)
254         }
255 }
256
257 func printanycustomtype(i any) {
258         eface := efaceOf(&i)
259         typestring := toRType(eface._type).string()
260
261         switch eface._type.Kind_ {
262         case kindString:
263                 print(typestring, `("`, *(*string)(eface.data), `")`)
264         case kindBool:
265                 print(typestring, "(", *(*bool)(eface.data), ")")
266         case kindInt:
267                 print(typestring, "(", *(*int)(eface.data), ")")
268         case kindInt8:
269                 print(typestring, "(", *(*int8)(eface.data), ")")
270         case kindInt16:
271                 print(typestring, "(", *(*int16)(eface.data), ")")
272         case kindInt32:
273                 print(typestring, "(", *(*int32)(eface.data), ")")
274         case kindInt64:
275                 print(typestring, "(", *(*int64)(eface.data), ")")
276         case kindUint:
277                 print(typestring, "(", *(*uint)(eface.data), ")")
278         case kindUint8:
279                 print(typestring, "(", *(*uint8)(eface.data), ")")
280         case kindUint16:
281                 print(typestring, "(", *(*uint16)(eface.data), ")")
282         case kindUint32:
283                 print(typestring, "(", *(*uint32)(eface.data), ")")
284         case kindUint64:
285                 print(typestring, "(", *(*uint64)(eface.data), ")")
286         case kindUintptr:
287                 print(typestring, "(", *(*uintptr)(eface.data), ")")
288         case kindFloat32:
289                 print(typestring, "(", *(*float32)(eface.data), ")")
290         case kindFloat64:
291                 print(typestring, "(", *(*float64)(eface.data), ")")
292         case kindComplex64:
293                 print(typestring, *(*complex64)(eface.data))
294         case kindComplex128:
295                 print(typestring, *(*complex128)(eface.data))
296         default:
297                 print("(", typestring, ") ", eface.data)
298         }
299 }
300
301 // panicwrap generates a panic for a call to a wrapped value method
302 // with a nil pointer receiver.
303 //
304 // It is called from the generated wrapper code.
305 func panicwrap() {
306         pc := getcallerpc()
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, '(')
312         if i < 0 {
313                 throw("panicwrap: no ( in " + name)
314         }
315         pkg := name[:i-1]
316         if i+2 >= len(name) || name[i-1:i+2] != ".(*" {
317                 throw("panicwrap: unexpected string after package name: " + name)
318         }
319         name = name[i+2:]
320         i = bytealg.IndexByteString(name, ')')
321         if i < 0 {
322                 throw("panicwrap: no ) in " + name)
323         }
324         if i+2 >= len(name) || name[i:i+2] != ")." {
325                 throw("panicwrap: unexpected string after type name: " + name)
326         }
327         typ := name[:i]
328         meth := name[i+2:]
329         panic(plainError("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer"))
330 }