...

Source file 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 = 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	//go:nosplit
    57	// itoa converts val to a decimal representation. The result is
    58	// written somewhere within buf and the location of the result is returned.
    59	// buf must be at least 20 bytes.
    60	func itoa(buf []byte, val uint64) []byte {
    61		i := len(buf) - 1
    62		for val >= 10 {
    63			buf[i] = byte(val%10 + '0')
    64			i--
    65			val /= 10
    66		}
    67		buf[i] = byte(val + '0')
    68		return buf[i:]
    69	}
    70	
    71	// An errorString represents a runtime error described by a single string.
    72	type errorString string
    73	
    74	func (e errorString) RuntimeError() {}
    75	
    76	func (e errorString) Error() string {
    77		return "runtime error: " + string(e)
    78	}
    79	
    80	// plainError represents a runtime error described a string without
    81	// the prefix "runtime error: " after invoking errorString.Error().
    82	// See Issue #14965.
    83	type plainError string
    84	
    85	func (e plainError) RuntimeError() {}
    86	
    87	func (e plainError) Error() string {
    88		return string(e)
    89	}
    90	
    91	// An boundsError represents a an indexing or slicing operation gone wrong.
    92	type boundsError struct {
    93		x int64
    94		y int
    95		// Values in an index or slice expression can be signed or unsigned.
    96		// That means we'd need 65 bits to encode all possible indexes, from -2^63 to 2^64-1.
    97		// Instead, we keep track of whether x should be interpreted as signed or unsigned.
    98		// y is known to be nonnegative and to fit in an int.
    99		signed bool
   100		code   boundsErrorCode
   101	}
   102	
   103	type boundsErrorCode uint8
   104	
   105	const (
   106		boundsIndex boundsErrorCode = iota // s[x], 0 <= x < len(s) failed
   107	
   108		boundsSliceAlen // s[?:x], 0 <= x <= len(s) failed
   109		boundsSliceAcap // s[?:x], 0 <= x <= cap(s) failed
   110		boundsSliceB    // s[x:y], 0 <= x <= y failed (but boundsSliceA didn't happen)
   111	
   112		boundsSlice3Alen // s[?:?:x], 0 <= x <= len(s) failed
   113		boundsSlice3Acap // s[?:?:x], 0 <= x <= cap(s) failed
   114		boundsSlice3B    // s[?:x:y], 0 <= x <= y failed (but boundsSlice3A didn't happen)
   115		boundsSlice3C    // s[x:y:?], 0 <= x <= y failed (but boundsSlice3A/B didn't happen)
   116	
   117		// Note: in the above, len(s) and cap(s) are stored in y
   118	)
   119	
   120	// boundsErrorFmts provide error text for various out-of-bounds panics.
   121	// Note: if you change these strings, you should adjust the size of the buffer
   122	// in boundsError.Error below as well.
   123	var boundsErrorFmts = [...]string{
   124		boundsIndex:      "index out of range [%x] with length %y",
   125		boundsSliceAlen:  "slice bounds out of range [:%x] with length %y",
   126		boundsSliceAcap:  "slice bounds out of range [:%x] with capacity %y",
   127		boundsSliceB:     "slice bounds out of range [%x:%y]",
   128		boundsSlice3Alen: "slice bounds out of range [::%x] with length %y",
   129		boundsSlice3Acap: "slice bounds out of range [::%x] with capacity %y",
   130		boundsSlice3B:    "slice bounds out of range [:%x:%y]",
   131		boundsSlice3C:    "slice bounds out of range [%x:%y:]",
   132	}
   133	
   134	// boundsNegErrorFmts are overriding formats if x is negative. In this case there's no need to report y.
   135	var boundsNegErrorFmts = [...]string{
   136		boundsIndex:      "index out of range [%x]",
   137		boundsSliceAlen:  "slice bounds out of range [:%x]",
   138		boundsSliceAcap:  "slice bounds out of range [:%x]",
   139		boundsSliceB:     "slice bounds out of range [%x:]",
   140		boundsSlice3Alen: "slice bounds out of range [::%x]",
   141		boundsSlice3Acap: "slice bounds out of range [::%x]",
   142		boundsSlice3B:    "slice bounds out of range [:%x:]",
   143		boundsSlice3C:    "slice bounds out of range [%x::]",
   144	}
   145	
   146	func (e boundsError) RuntimeError() {}
   147	
   148	func appendIntStr(b []byte, v int64, signed bool) []byte {
   149		if signed && v < 0 {
   150			b = append(b, '-')
   151			v = -v
   152		}
   153		var buf [20]byte
   154		b = append(b, itoa(buf[:], uint64(v))...)
   155		return b
   156	}
   157	
   158	func (e boundsError) Error() string {
   159		fmt := boundsErrorFmts[e.code]
   160		if e.signed && e.x < 0 {
   161			fmt = boundsNegErrorFmts[e.code]
   162		}
   163		// max message length is 99: "runtime error: slice bounds out of range [::%x] with capacity %y"
   164		// x can be at most 20 characters. y can be at most 19.
   165		b := make([]byte, 0, 100)
   166		b = append(b, "runtime error: "...)
   167		for i := 0; i < len(fmt); i++ {
   168			c := fmt[i]
   169			if c != '%' {
   170				b = append(b, c)
   171				continue
   172			}
   173			i++
   174			switch fmt[i] {
   175			case 'x':
   176				b = appendIntStr(b, e.x, e.signed)
   177			case 'y':
   178				b = appendIntStr(b, int64(e.y), true)
   179			}
   180		}
   181		return string(b)
   182	}
   183	
   184	type stringer interface {
   185		String() string
   186	}
   187	
   188	func typestring(x interface{}) string {
   189		e := efaceOf(&x)
   190		return e._type.string()
   191	}
   192	
   193	// printany prints an argument passed to panic.
   194	// If panic is called with a value that has a String or Error method,
   195	// it has already been converted into a string by preprintpanics.
   196	func printany(i interface{}) {
   197		switch v := i.(type) {
   198		case nil:
   199			print("nil")
   200		case bool:
   201			print(v)
   202		case int:
   203			print(v)
   204		case int8:
   205			print(v)
   206		case int16:
   207			print(v)
   208		case int32:
   209			print(v)
   210		case int64:
   211			print(v)
   212		case uint:
   213			print(v)
   214		case uint8:
   215			print(v)
   216		case uint16:
   217			print(v)
   218		case uint32:
   219			print(v)
   220		case uint64:
   221			print(v)
   222		case uintptr:
   223			print(v)
   224		case float32:
   225			print(v)
   226		case float64:
   227			print(v)
   228		case complex64:
   229			print(v)
   230		case complex128:
   231			print(v)
   232		case string:
   233			print(v)
   234		default:
   235			print("(", typestring(i), ") ", i)
   236		}
   237	}
   238	
   239	// panicwrap generates a panic for a call to a wrapped value method
   240	// with a nil pointer receiver.
   241	//
   242	// It is called from the generated wrapper code.
   243	func panicwrap() {
   244		pc := getcallerpc()
   245		name := funcname(findfunc(pc))
   246		// name is something like "main.(*T).F".
   247		// We want to extract pkg ("main"), typ ("T"), and meth ("F").
   248		// Do it by finding the parens.
   249		i := bytealg.IndexByteString(name, '(')
   250		if i < 0 {
   251			throw("panicwrap: no ( in " + name)
   252		}
   253		pkg := name[:i-1]
   254		if i+2 >= len(name) || name[i-1:i+2] != ".(*" {
   255			throw("panicwrap: unexpected string after package name: " + name)
   256		}
   257		name = name[i+2:]
   258		i = bytealg.IndexByteString(name, ')')
   259		if i < 0 {
   260			throw("panicwrap: no ) in " + name)
   261		}
   262		if i+2 >= len(name) || name[i:i+2] != ")." {
   263			throw("panicwrap: unexpected string after type name: " + name)
   264		}
   265		typ := name[:i]
   266		meth := name[i+2:]
   267		panic(plainError("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer"))
   268	}
   269	

View as plain text