...

Source file src/go/types/errors.go

Documentation: go/types

		 1  // Copyright 2012 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  // This file implements various error reporters.
		 6  
		 7  package types
		 8  
		 9  import (
		10  	"errors"
		11  	"fmt"
		12  	"go/ast"
		13  	"go/token"
		14  	"strconv"
		15  	"strings"
		16  )
		17  
		18  func assert(p bool) {
		19  	if !p {
		20  		panic("assertion failed")
		21  	}
		22  }
		23  
		24  func unreachable() {
		25  	panic("unreachable")
		26  }
		27  
		28  func (check *Checker) qualifier(pkg *Package) string {
		29  	// Qualify the package unless it's the package being type-checked.
		30  	if pkg != check.pkg {
		31  		if check.pkgPathMap == nil {
		32  			check.pkgPathMap = make(map[string]map[string]bool)
		33  			check.seenPkgMap = make(map[*Package]bool)
		34  			check.markImports(check.pkg)
		35  		}
		36  		// If the same package name was used by multiple packages, display the full path.
		37  		if len(check.pkgPathMap[pkg.name]) > 1 {
		38  			return strconv.Quote(pkg.path)
		39  		}
		40  		return pkg.name
		41  	}
		42  	return ""
		43  }
		44  
		45  // markImports recursively walks pkg and its imports, to record unique import
		46  // paths in pkgPathMap.
		47  func (check *Checker) markImports(pkg *Package) {
		48  	if check.seenPkgMap[pkg] {
		49  		return
		50  	}
		51  	check.seenPkgMap[pkg] = true
		52  
		53  	forName, ok := check.pkgPathMap[pkg.name]
		54  	if !ok {
		55  		forName = make(map[string]bool)
		56  		check.pkgPathMap[pkg.name] = forName
		57  	}
		58  	forName[pkg.path] = true
		59  
		60  	for _, imp := range pkg.imports {
		61  		check.markImports(imp)
		62  	}
		63  }
		64  
		65  func (check *Checker) sprintf(format string, args ...interface{}) string {
		66  	for i, arg := range args {
		67  		switch a := arg.(type) {
		68  		case nil:
		69  			arg = "<nil>"
		70  		case operand:
		71  			panic("internal error: should always pass *operand")
		72  		case *operand:
		73  			arg = operandString(a, check.qualifier)
		74  		case token.Pos:
		75  			arg = check.fset.Position(a).String()
		76  		case ast.Expr:
		77  			arg = ExprString(a)
		78  		case Object:
		79  			arg = ObjectString(a, check.qualifier)
		80  		case Type:
		81  			arg = TypeString(a, check.qualifier)
		82  		}
		83  		args[i] = arg
		84  	}
		85  	return fmt.Sprintf(format, args...)
		86  }
		87  
		88  func (check *Checker) trace(pos token.Pos, format string, args ...interface{}) {
		89  	fmt.Printf("%s:\t%s%s\n",
		90  		check.fset.Position(pos),
		91  		strings.Repeat(".	", check.indent),
		92  		check.sprintf(format, args...),
		93  	)
		94  }
		95  
		96  // dump is only needed for debugging
		97  func (check *Checker) dump(format string, args ...interface{}) {
		98  	fmt.Println(check.sprintf(format, args...))
		99  }
	 100  
	 101  func (check *Checker) err(err error) {
	 102  	if err == nil {
	 103  		return
	 104  	}
	 105  	var e Error
	 106  	isInternal := errors.As(err, &e)
	 107  	// Cheap trick: Don't report errors with messages containing
	 108  	// "invalid operand" or "invalid type" as those tend to be
	 109  	// follow-on errors which don't add useful information. Only
	 110  	// exclude them if these strings are not at the beginning,
	 111  	// and only if we have at least one error already reported.
	 112  	isInvalidErr := isInternal && (strings.Index(e.Msg, "invalid operand") > 0 || strings.Index(e.Msg, "invalid type") > 0)
	 113  	if check.firstErr != nil && isInvalidErr {
	 114  		return
	 115  	}
	 116  
	 117  	if isInternal {
	 118  		e.Msg = stripAnnotations(e.Msg)
	 119  		if check.errpos != nil {
	 120  			// If we have an internal error and the errpos override is set, use it to
	 121  			// augment our error positioning.
	 122  			// TODO(rFindley) we may also want to augment the error message and refer
	 123  			// to the position (pos) in the original expression.
	 124  			span := spanOf(check.errpos)
	 125  			e.Pos = span.pos
	 126  			e.go116start = span.start
	 127  			e.go116end = span.end
	 128  		}
	 129  		err = e
	 130  	}
	 131  
	 132  	if check.firstErr == nil {
	 133  		check.firstErr = err
	 134  	}
	 135  
	 136  	if trace {
	 137  		pos := e.Pos
	 138  		msg := e.Msg
	 139  		if !isInternal {
	 140  			msg = err.Error()
	 141  			pos = token.NoPos
	 142  		}
	 143  		check.trace(pos, "ERROR: %s", msg)
	 144  	}
	 145  
	 146  	f := check.conf.Error
	 147  	if f == nil {
	 148  		panic(bailout{}) // report only first error
	 149  	}
	 150  	f(err)
	 151  }
	 152  
	 153  func (check *Checker) newError(at positioner, code errorCode, soft bool, msg string) error {
	 154  	span := spanOf(at)
	 155  	return Error{
	 156  		Fset:			 check.fset,
	 157  		Pos:				span.pos,
	 158  		Msg:				msg,
	 159  		Soft:			 soft,
	 160  		go116code:	code,
	 161  		go116start: span.start,
	 162  		go116end:	 span.end,
	 163  	}
	 164  }
	 165  
	 166  // newErrorf creates a new Error, but does not handle it.
	 167  func (check *Checker) newErrorf(at positioner, code errorCode, soft bool, format string, args ...interface{}) error {
	 168  	msg := check.sprintf(format, args...)
	 169  	return check.newError(at, code, soft, msg)
	 170  }
	 171  
	 172  func (check *Checker) error(at positioner, code errorCode, msg string) {
	 173  	check.err(check.newError(at, code, false, msg))
	 174  }
	 175  
	 176  func (check *Checker) errorf(at positioner, code errorCode, format string, args ...interface{}) {
	 177  	check.error(at, code, check.sprintf(format, args...))
	 178  }
	 179  
	 180  func (check *Checker) softErrorf(at positioner, code errorCode, format string, args ...interface{}) {
	 181  	check.err(check.newErrorf(at, code, true, format, args...))
	 182  }
	 183  
	 184  func (check *Checker) invalidAST(at positioner, format string, args ...interface{}) {
	 185  	check.errorf(at, 0, "invalid AST: "+format, args...)
	 186  }
	 187  
	 188  func (check *Checker) invalidArg(at positioner, code errorCode, format string, args ...interface{}) {
	 189  	check.errorf(at, code, "invalid argument: "+format, args...)
	 190  }
	 191  
	 192  func (check *Checker) invalidOp(at positioner, code errorCode, format string, args ...interface{}) {
	 193  	check.errorf(at, code, "invalid operation: "+format, args...)
	 194  }
	 195  
	 196  // The positioner interface is used to extract the position of type-checker
	 197  // errors.
	 198  type positioner interface {
	 199  	Pos() token.Pos
	 200  }
	 201  
	 202  // posSpan holds a position range along with a highlighted position within that
	 203  // range. This is used for positioning errors, with pos by convention being the
	 204  // first position in the source where the error is known to exist, and start
	 205  // and end defining the full span of syntax being considered when the error was
	 206  // detected. Invariant: start <= pos < end || start == pos == end.
	 207  type posSpan struct {
	 208  	start, pos, end token.Pos
	 209  }
	 210  
	 211  func (e posSpan) Pos() token.Pos {
	 212  	return e.pos
	 213  }
	 214  
	 215  // inNode creates a posSpan for the given node.
	 216  // Invariant: node.Pos() <= pos < node.End() (node.End() is the position of the
	 217  // first byte after node within the source).
	 218  func inNode(node ast.Node, pos token.Pos) posSpan {
	 219  	start, end := node.Pos(), node.End()
	 220  	if debug {
	 221  		assert(start <= pos && pos < end)
	 222  	}
	 223  	return posSpan{start, pos, end}
	 224  }
	 225  
	 226  // atPos wraps a token.Pos to implement the positioner interface.
	 227  type atPos token.Pos
	 228  
	 229  func (s atPos) Pos() token.Pos {
	 230  	return token.Pos(s)
	 231  }
	 232  
	 233  // spanOf extracts an error span from the given positioner. By default this is
	 234  // the trivial span starting and ending at pos, but this span is expanded when
	 235  // the argument naturally corresponds to a span of source code.
	 236  func spanOf(at positioner) posSpan {
	 237  	switch x := at.(type) {
	 238  	case nil:
	 239  		panic("internal error: nil")
	 240  	case posSpan:
	 241  		return x
	 242  	case ast.Node:
	 243  		pos := x.Pos()
	 244  		return posSpan{pos, pos, x.End()}
	 245  	case *operand:
	 246  		if x.expr != nil {
	 247  			pos := x.Pos()
	 248  			return posSpan{pos, pos, x.expr.End()}
	 249  		}
	 250  		return posSpan{token.NoPos, token.NoPos, token.NoPos}
	 251  	default:
	 252  		pos := at.Pos()
	 253  		return posSpan{pos, pos, pos}
	 254  	}
	 255  }
	 256  
	 257  // stripAnnotations removes internal (type) annotations from s.
	 258  func stripAnnotations(s string) string {
	 259  	var b strings.Builder
	 260  	for _, r := range s {
	 261  		// strip #'s and subscript digits
	 262  		if r != instanceMarker && !('₀' <= r && r < '₀'+10) { // '₀' == U+2080
	 263  			b.WriteRune(r)
	 264  		}
	 265  	}
	 266  	if b.Len() < len(s) {
	 267  		return b.String()
	 268  	}
	 269  	return s
	 270  }
	 271  

View as plain text