Source file src/cmd/compile/internal/types2/errors.go

     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 types2
     8  
     9  import (
    10  	"bytes"
    11  	"cmd/compile/internal/syntax"
    12  	"fmt"
    13  	"strconv"
    14  	"strings"
    15  )
    16  
    17  func unimplemented() {
    18  	panic("unimplemented")
    19  }
    20  
    21  func assert(p bool) {
    22  	if !p {
    23  		panic("assertion failed")
    24  	}
    25  }
    26  
    27  func unreachable() {
    28  	panic("unreachable")
    29  }
    30  
    31  // An error_ represents a type-checking error.
    32  // To report an error_, call Checker.report.
    33  type error_ struct {
    34  	desc []errorDesc
    35  	soft bool // TODO(gri) eventually determine this from an error code
    36  }
    37  
    38  // An errorDesc describes part of a type-checking error.
    39  type errorDesc struct {
    40  	pos    syntax.Pos
    41  	format string
    42  	args   []interface{}
    43  }
    44  
    45  func (err *error_) empty() bool {
    46  	return err.desc == nil
    47  }
    48  
    49  func (err *error_) pos() syntax.Pos {
    50  	if err.empty() {
    51  		return nopos
    52  	}
    53  	return err.desc[0].pos
    54  }
    55  
    56  func (err *error_) msg(qf Qualifier) string {
    57  	if err.empty() {
    58  		return "no error"
    59  	}
    60  	var buf bytes.Buffer
    61  	for i := range err.desc {
    62  		p := &err.desc[i]
    63  		if i > 0 {
    64  			fmt.Fprint(&buf, "\n\t")
    65  			if p.pos.IsKnown() {
    66  				fmt.Fprintf(&buf, "%s: ", p.pos)
    67  			}
    68  		}
    69  		buf.WriteString(sprintf(qf, false, p.format, p.args...))
    70  	}
    71  	return buf.String()
    72  }
    73  
    74  // String is for testing.
    75  func (err *error_) String() string {
    76  	if err.empty() {
    77  		return "no error"
    78  	}
    79  	return fmt.Sprintf("%s: %s", err.pos(), err.msg(nil))
    80  }
    81  
    82  // errorf adds formatted error information to err.
    83  // It may be called multiple times to provide additional information.
    84  func (err *error_) errorf(at poser, format string, args ...interface{}) {
    85  	err.desc = append(err.desc, errorDesc{posFor(at), format, args})
    86  }
    87  
    88  func sprintf(qf Qualifier, debug bool, format string, args ...interface{}) string {
    89  	for i, arg := range args {
    90  		switch a := arg.(type) {
    91  		case nil:
    92  			arg = "<nil>"
    93  		case operand:
    94  			panic("got operand instead of *operand")
    95  		case *operand:
    96  			arg = operandString(a, qf)
    97  		case syntax.Pos:
    98  			arg = a.String()
    99  		case syntax.Expr:
   100  			arg = syntax.String(a)
   101  		case []syntax.Expr:
   102  			var buf bytes.Buffer
   103  			buf.WriteByte('[')
   104  			for i, x := range a {
   105  				if i > 0 {
   106  					buf.WriteString(", ")
   107  				}
   108  				buf.WriteString(syntax.String(x))
   109  			}
   110  			buf.WriteByte(']')
   111  			arg = buf.String()
   112  		case Object:
   113  			arg = ObjectString(a, qf)
   114  		case Type:
   115  			arg = typeString(a, qf, debug)
   116  		case []Type:
   117  			var buf bytes.Buffer
   118  			buf.WriteByte('[')
   119  			for i, x := range a {
   120  				if i > 0 {
   121  					buf.WriteString(", ")
   122  				}
   123  				buf.WriteString(typeString(x, qf, debug))
   124  			}
   125  			buf.WriteByte(']')
   126  			arg = buf.String()
   127  		case []*TypeParam:
   128  			var buf bytes.Buffer
   129  			buf.WriteByte('[')
   130  			for i, x := range a {
   131  				if i > 0 {
   132  					buf.WriteString(", ")
   133  				}
   134  				buf.WriteString(typeString(x, qf, debug)) // use typeString so we get subscripts when debugging
   135  			}
   136  			buf.WriteByte(']')
   137  			arg = buf.String()
   138  		}
   139  		args[i] = arg
   140  	}
   141  	return fmt.Sprintf(format, args...)
   142  }
   143  
   144  func (check *Checker) qualifier(pkg *Package) string {
   145  	// Qualify the package unless it's the package being type-checked.
   146  	if pkg != check.pkg {
   147  		if check.pkgPathMap == nil {
   148  			check.pkgPathMap = make(map[string]map[string]bool)
   149  			check.seenPkgMap = make(map[*Package]bool)
   150  			check.markImports(check.pkg)
   151  		}
   152  		// If the same package name was used by multiple packages, display the full path.
   153  		if len(check.pkgPathMap[pkg.name]) > 1 {
   154  			return strconv.Quote(pkg.path)
   155  		}
   156  		return pkg.name
   157  	}
   158  	return ""
   159  }
   160  
   161  // markImports recursively walks pkg and its imports, to record unique import
   162  // paths in pkgPathMap.
   163  func (check *Checker) markImports(pkg *Package) {
   164  	if check.seenPkgMap[pkg] {
   165  		return
   166  	}
   167  	check.seenPkgMap[pkg] = true
   168  
   169  	forName, ok := check.pkgPathMap[pkg.name]
   170  	if !ok {
   171  		forName = make(map[string]bool)
   172  		check.pkgPathMap[pkg.name] = forName
   173  	}
   174  	forName[pkg.path] = true
   175  
   176  	for _, imp := range pkg.imports {
   177  		check.markImports(imp)
   178  	}
   179  }
   180  
   181  // check may be nil.
   182  func (check *Checker) sprintf(format string, args ...interface{}) string {
   183  	var qf Qualifier
   184  	if check != nil {
   185  		qf = check.qualifier
   186  	}
   187  	return sprintf(qf, false, format, args...)
   188  }
   189  
   190  func (check *Checker) report(err *error_) {
   191  	if err.empty() {
   192  		panic("no error to report")
   193  	}
   194  	check.err(err.pos(), err.msg(check.qualifier), err.soft)
   195  }
   196  
   197  func (check *Checker) trace(pos syntax.Pos, format string, args ...interface{}) {
   198  	fmt.Printf("%s:\t%s%s\n",
   199  		pos,
   200  		strings.Repeat(".  ", check.indent),
   201  		sprintf(check.qualifier, true, format, args...),
   202  	)
   203  }
   204  
   205  // dump is only needed for debugging
   206  func (check *Checker) dump(format string, args ...interface{}) {
   207  	fmt.Println(sprintf(check.qualifier, true, format, args...))
   208  }
   209  
   210  func (check *Checker) err(at poser, msg string, soft bool) {
   211  	// Cheap trick: Don't report errors with messages containing
   212  	// "invalid operand" or "invalid type" as those tend to be
   213  	// follow-on errors which don't add useful information. Only
   214  	// exclude them if these strings are not at the beginning,
   215  	// and only if we have at least one error already reported.
   216  	if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) {
   217  		return
   218  	}
   219  
   220  	pos := posFor(at)
   221  
   222  	// If we are encountering an error while evaluating an inherited
   223  	// constant initialization expression, pos is the position of in
   224  	// the original expression, and not of the currently declared
   225  	// constant identifier. Use the provided errpos instead.
   226  	// TODO(gri) We may also want to augment the error message and
   227  	// refer to the position (pos) in the original expression.
   228  	if check.errpos.IsKnown() {
   229  		assert(check.iota != nil)
   230  		pos = check.errpos
   231  	}
   232  
   233  	err := Error{pos, stripAnnotations(msg), msg, soft}
   234  	if check.firstErr == nil {
   235  		check.firstErr = err
   236  	}
   237  
   238  	if check.conf.Trace {
   239  		check.trace(pos, "ERROR: %s", msg)
   240  	}
   241  
   242  	f := check.conf.Error
   243  	if f == nil {
   244  		panic(bailout{}) // report only first error
   245  	}
   246  	f(err)
   247  }
   248  
   249  const (
   250  	invalidAST = "invalid AST: "
   251  	invalidArg = "invalid argument: "
   252  	invalidOp  = "invalid operation: "
   253  )
   254  
   255  type poser interface {
   256  	Pos() syntax.Pos
   257  }
   258  
   259  func (check *Checker) error(at poser, msg string) {
   260  	check.err(at, msg, false)
   261  }
   262  
   263  func (check *Checker) errorf(at poser, format string, args ...interface{}) {
   264  	check.err(at, check.sprintf(format, args...), false)
   265  }
   266  
   267  func (check *Checker) softErrorf(at poser, format string, args ...interface{}) {
   268  	check.err(at, check.sprintf(format, args...), true)
   269  }
   270  
   271  func (check *Checker) versionErrorf(at poser, goVersion string, format string, args ...interface{}) {
   272  	msg := check.sprintf(format, args...)
   273  	if check.conf.CompilerErrorMessages {
   274  		msg = fmt.Sprintf("%s requires %s or later (-lang was set to %s; check go.mod)", msg, goVersion, check.conf.GoVersion)
   275  	} else {
   276  		msg = fmt.Sprintf("%s requires %s or later", msg, goVersion)
   277  	}
   278  	check.err(at, msg, true)
   279  }
   280  
   281  // posFor reports the left (= start) position of at.
   282  func posFor(at poser) syntax.Pos {
   283  	switch x := at.(type) {
   284  	case *operand:
   285  		if x.expr != nil {
   286  			return syntax.StartPos(x.expr)
   287  		}
   288  	case syntax.Node:
   289  		return syntax.StartPos(x)
   290  	}
   291  	return at.Pos()
   292  }
   293  
   294  // stripAnnotations removes internal (type) annotations from s.
   295  func stripAnnotations(s string) string {
   296  	// Would like to use strings.Builder but it's not available in Go 1.4.
   297  	var b bytes.Buffer
   298  	for _, r := range s {
   299  		// strip #'s and subscript digits
   300  		if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
   301  			b.WriteRune(r)
   302  		}
   303  	}
   304  	if b.Len() < len(s) {
   305  		return b.String()
   306  	}
   307  	return s
   308  }
   309  

View as plain text