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"
18 func unimplemented() {
19 panic("unimplemented")
24 msg := "assertion failed"
25 // Include information about the assertion location. Due to panic recovery,
26 // this location is otherwise buried in the middle of the panicking stack.
27 if _, file, line, ok := runtime.Caller(1); ok {
28 msg = fmt.Sprintf("%s:%d: %s", file, line, msg)
38 // An error_ represents a type-checking error.
39 // To report an error_, call Checker.report.
43 soft bool // TODO(gri) eventually determine this from an error code
46 // An errorDesc describes part of a type-checking error.
47 type errorDesc struct {
53 func (err *error_) empty() bool {
54 return err.desc == nil
57 func (err *error_) pos() syntax.Pos {
61 return err.desc[0].pos
64 func (err *error_) msg(qf Qualifier) string {
68 var buf strings.Builder
69 for i := range err.desc {
72 fmt.Fprint(&buf, "\n\t")
74 fmt.Fprintf(&buf, "%s: ", p.pos)
77 buf.WriteString(sprintf(qf, false, p.format, p.args...))
82 // String is for testing.
83 func (err *error_) String() string {
87 return fmt.Sprintf("%s: %s", err.pos(), err.msg(nil))
90 // errorf adds formatted error information to err.
91 // It may be called multiple times to provide additional information.
92 func (err *error_) errorf(at poser, format string, args ...interface{}) {
93 err.desc = append(err.desc, errorDesc{posFor(at), format, args})
96 func sprintf(qf Qualifier, tpSubscripts bool, format string, args ...interface{}) string {
97 for i, arg := range args {
98 switch a := arg.(type) {
102 panic("got operand instead of *operand")
104 arg = operandString(a, qf)
108 arg = syntax.String(a)
110 var buf strings.Builder
112 for i, x := range a {
114 buf.WriteString(", ")
116 buf.WriteString(syntax.String(x))
121 arg = ObjectString(a, qf)
124 w := newTypeWriter(&buf, qf)
125 w.tpSubscripts = tpSubscripts
130 w := newTypeWriter(&buf, qf)
131 w.tpSubscripts = tpSubscripts
133 for i, x := range a {
135 buf.WriteString(", ")
143 w := newTypeWriter(&buf, qf)
144 w.tpSubscripts = tpSubscripts
146 for i, x := range a {
148 buf.WriteString(", ")
157 return fmt.Sprintf(format, args...)
160 func (check *Checker) qualifier(pkg *Package) string {
161 // Qualify the package unless it's the package being type-checked.
162 if pkg != check.pkg {
163 if check.pkgPathMap == nil {
164 check.pkgPathMap = make(map[string]map[string]bool)
165 check.seenPkgMap = make(map[*Package]bool)
166 check.markImports(check.pkg)
168 // If the same package name was used by multiple packages, display the full path.
169 if len(check.pkgPathMap[pkg.name]) > 1 {
170 return strconv.Quote(pkg.path)
177 // markImports recursively walks pkg and its imports, to record unique import
178 // paths in pkgPathMap.
179 func (check *Checker) markImports(pkg *Package) {
180 if check.seenPkgMap[pkg] {
183 check.seenPkgMap[pkg] = true
185 forName, ok := check.pkgPathMap[pkg.name]
187 forName = make(map[string]bool)
188 check.pkgPathMap[pkg.name] = forName
190 forName[pkg.path] = true
192 for _, imp := range pkg.imports {
193 check.markImports(imp)
198 func (check *Checker) sprintf(format string, args ...interface{}) string {
203 return sprintf(qf, false, format, args...)
206 func (check *Checker) report(err *error_) {
208 panic("no error to report")
210 check.err(err.pos(), err.code, err.msg(check.qualifier), err.soft)
213 func (check *Checker) trace(pos syntax.Pos, format string, args ...interface{}) {
214 fmt.Printf("%s:\t%s%s\n",
216 strings.Repeat(". ", check.indent),
217 sprintf(check.qualifier, true, format, args...),
221 // dump is only needed for debugging
222 func (check *Checker) dump(format string, args ...interface{}) {
223 fmt.Println(sprintf(check.qualifier, true, format, args...))
226 func (check *Checker) err(at poser, code errorCode, msg string, soft bool) {
227 // Cheap trick: Don't report errors with messages containing
228 // "invalid operand" or "invalid type" as those tend to be
229 // follow-on errors which don't add useful information. Only
230 // exclude them if these strings are not at the beginning,
231 // and only if we have at least one error already reported.
232 if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) {
238 // If we are encountering an error while evaluating an inherited
239 // constant initialization expression, pos is the position of in
240 // the original expression, and not of the currently declared
241 // constant identifier. Use the provided errpos instead.
242 // TODO(gri) We may also want to augment the error message and
243 // refer to the position (pos) in the original expression.
244 if check.errpos.IsKnown() {
245 assert(check.iota != nil)
249 err := Error{pos, stripAnnotations(msg), msg, soft}
250 if check.firstErr == nil {
254 if check.conf.Trace {
255 check.trace(pos, "ERROR: %s", msg)
258 f := check.conf.Error
260 panic(bailout{}) // report only first error
266 invalidAST = "invalid AST: "
267 invalidArg = "invalid argument: "
268 invalidOp = "invalid operation: "
271 type poser interface {
275 func (check *Checker) error(at poser, code errorCode, msg string) {
276 check.err(at, code, msg, false)
279 func (check *Checker) errorf(at poser, code errorCode, format string, args ...interface{}) {
280 check.err(at, code, check.sprintf(format, args...), false)
283 func (check *Checker) softErrorf(at poser, code errorCode, format string, args ...interface{}) {
284 check.err(at, code, check.sprintf(format, args...), true)
287 func (check *Checker) versionErrorf(at poser, goVersion string, format string, args ...interface{}) {
288 msg := check.sprintf(format, args...)
289 msg = fmt.Sprintf("%s requires %s or later", msg, goVersion)
290 check.err(at, _UnsupportedFeature, msg, true)
293 // posFor reports the left (= start) position of at.
294 func posFor(at poser) syntax.Pos {
295 switch x := at.(type) {
298 return syntax.StartPos(x.expr)
301 return syntax.StartPos(x)
306 // stripAnnotations removes internal (type) annotations from s.
307 func stripAnnotations(s string) string {
308 var buf strings.Builder
309 for _, r := range s {
310 // strip #'s and subscript digits
311 if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
315 if buf.Len() < len(s) {