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.
5 // This file implements various error reporters.
11 "cmd/compile/internal/syntax"
13 . "internal/types/errors"
21 msg := "assertion failed"
22 // Include information about the assertion location. Due to panic recovery,
23 // this location is otherwise buried in the middle of the panicking stack.
24 if _, file, line, ok := runtime.Caller(1); ok {
25 msg = fmt.Sprintf("%s:%d: %s", file, line, msg)
35 // An error_ represents a type-checking error.
36 // To report an error_, call Checker.report.
40 soft bool // TODO(gri) eventually determine this from an error code
43 // An errorDesc describes part of a type-checking error.
44 type errorDesc struct {
50 func (err *error_) empty() bool {
51 return err.desc == nil
54 func (err *error_) pos() syntax.Pos {
58 return err.desc[0].pos
61 func (err *error_) msg(qf Qualifier) string {
65 var buf strings.Builder
66 for i := range err.desc {
69 fmt.Fprint(&buf, "\n\t")
71 fmt.Fprintf(&buf, "%s: ", p.pos)
74 buf.WriteString(sprintf(qf, false, p.format, p.args...))
79 // String is for testing.
80 func (err *error_) String() string {
84 return fmt.Sprintf("%s: %s", err.pos(), err.msg(nil))
87 // errorf adds formatted error information to err.
88 // It may be called multiple times to provide additional information.
89 func (err *error_) errorf(at poser, format string, args ...interface{}) {
90 err.desc = append(err.desc, errorDesc{atPos(at), format, args})
93 func sprintf(qf Qualifier, tpSubscripts bool, format string, args ...interface{}) string {
94 for i, arg := range args {
95 switch a := arg.(type) {
99 panic("got operand instead of *operand")
101 arg = operandString(a, qf)
105 arg = syntax.String(a)
107 var buf strings.Builder
109 for i, x := range a {
111 buf.WriteString(", ")
113 buf.WriteString(syntax.String(x))
118 arg = ObjectString(a, qf)
121 w := newTypeWriter(&buf, qf)
122 w.tpSubscripts = tpSubscripts
127 w := newTypeWriter(&buf, qf)
128 w.tpSubscripts = tpSubscripts
130 for i, x := range a {
132 buf.WriteString(", ")
140 w := newTypeWriter(&buf, qf)
141 w.tpSubscripts = tpSubscripts
143 for i, x := range a {
145 buf.WriteString(", ")
154 return fmt.Sprintf(format, args...)
157 func (check *Checker) qualifier(pkg *Package) string {
158 // Qualify the package unless it's the package being type-checked.
159 if pkg != check.pkg {
160 if check.pkgPathMap == nil {
161 check.pkgPathMap = make(map[string]map[string]bool)
162 check.seenPkgMap = make(map[*Package]bool)
163 check.markImports(check.pkg)
165 // If the same package name was used by multiple packages, display the full path.
166 if len(check.pkgPathMap[pkg.name]) > 1 {
167 return strconv.Quote(pkg.path)
174 // markImports recursively walks pkg and its imports, to record unique import
175 // paths in pkgPathMap.
176 func (check *Checker) markImports(pkg *Package) {
177 if check.seenPkgMap[pkg] {
180 check.seenPkgMap[pkg] = true
182 forName, ok := check.pkgPathMap[pkg.name]
184 forName = make(map[string]bool)
185 check.pkgPathMap[pkg.name] = forName
187 forName[pkg.path] = true
189 for _, imp := range pkg.imports {
190 check.markImports(imp)
195 func (check *Checker) sprintf(format string, args ...interface{}) string {
200 return sprintf(qf, false, format, args...)
203 func (check *Checker) report(err *error_) {
205 panic("no error to report")
207 check.err(err.pos(), err.code, err.msg(check.qualifier), err.soft)
210 func (check *Checker) trace(pos syntax.Pos, format string, args ...interface{}) {
211 fmt.Printf("%s:\t%s%s\n",
213 strings.Repeat(". ", check.indent),
214 sprintf(check.qualifier, true, format, args...),
218 // dump is only needed for debugging
219 func (check *Checker) dump(format string, args ...interface{}) {
220 fmt.Println(sprintf(check.qualifier, true, format, args...))
223 func (check *Checker) err(at poser, code Code, msg string, soft bool) {
225 case InvalidSyntaxTree:
226 msg = "invalid syntax tree: " + msg
228 panic("no error code provided")
231 // Cheap trick: Don't report errors with messages containing
232 // "invalid operand" or "invalid type" as those tend to be
233 // follow-on errors which don't add useful information. Only
234 // exclude them if these strings are not at the beginning,
235 // and only if we have at least one error already reported.
236 if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) {
242 // If we are encountering an error while evaluating an inherited
243 // constant initialization expression, pos is the position of in
244 // the original expression, and not of the currently declared
245 // constant identifier. Use the provided errpos instead.
246 // TODO(gri) We may also want to augment the error message and
247 // refer to the position (pos) in the original expression.
248 if check.errpos.IsKnown() {
249 assert(check.iota != nil)
253 // If we have a URL for error codes, add a link to the first line.
254 if code != 0 && check.conf.ErrorURL != "" {
255 u := fmt.Sprintf(check.conf.ErrorURL, code)
256 if i := strings.Index(msg, "\n"); i >= 0 {
257 msg = msg[:i] + u + msg[i:]
263 err := Error{pos, stripAnnotations(msg), msg, soft, code}
264 if check.firstErr == nil {
268 if check.conf.Trace {
269 check.trace(pos, "ERROR: %s", msg)
272 f := check.conf.Error
274 panic(bailout{}) // report only first error
280 invalidArg = "invalid argument: "
281 invalidOp = "invalid operation: "
284 type poser interface {
288 func (check *Checker) error(at poser, code Code, msg string) {
289 check.err(at, code, msg, false)
292 func (check *Checker) errorf(at poser, code Code, format string, args ...interface{}) {
293 check.err(at, code, check.sprintf(format, args...), false)
296 func (check *Checker) softErrorf(at poser, code Code, format string, args ...interface{}) {
297 check.err(at, code, check.sprintf(format, args...), true)
300 func (check *Checker) versionErrorf(at poser, v goVersion, format string, args ...interface{}) {
301 msg := check.sprintf(format, args...)
302 msg = fmt.Sprintf("%s requires %s or later", msg, v)
303 check.err(at, UnsupportedFeature, msg, true)
306 // atPos reports the left (= start) position of at.
307 func atPos(at poser) syntax.Pos {
308 switch x := at.(type) {
311 return syntax.StartPos(x.expr)
314 return syntax.StartPos(x)
319 // stripAnnotations removes internal (type) annotations from s.
320 func stripAnnotations(s string) string {
321 var buf strings.Builder
322 for _, r := range s {
323 // strip #'s and subscript digits
324 if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
328 if buf.Len() < len(s) {