]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: introduce the error_ type to match types2
authorRobert Findley <rfindley@google.com>
Mon, 18 Apr 2022 21:54:40 +0000 (17:54 -0400)
committerRobert Findley <rfindley@google.com>
Fri, 22 Apr 2022 15:46:52 +0000 (15:46 +0000)
To begin aligning with types2 error reporting, use an error_ type to
hold unevaluated error information, to report via Checker.report.

Change-Id: Ic5ac515759961e55b81acc9eeaac4db25b61804c
Reviewed-on: https://go-review.googlesource.com/c/go/+/400824
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
src/go/types/errors.go
src/go/types/errors_test.go

index c40a8436c5180c1c7f4a77892c24449949254d91..0dc0bc8799102910b8fe188621d33f9d0541ab86 100644 (file)
@@ -25,6 +25,64 @@ func unreachable() {
        panic("unreachable")
 }
 
+// An error_ represents a type-checking error.
+// To report an error_, call Checker.report.
+type error_ struct {
+       desc []errorDesc
+       code errorCode
+       soft bool // TODO(gri) eventually determine this from an error code
+}
+
+// An errorDesc describes part of a type-checking error.
+type errorDesc struct {
+       posn   positioner
+       format string
+       args   []interface{}
+}
+
+func (err *error_) empty() bool {
+       return err.desc == nil
+}
+
+func (err *error_) pos() token.Pos {
+       if err.empty() {
+               return token.NoPos
+       }
+       return err.desc[0].posn.Pos()
+}
+
+func (err *error_) msg(fset *token.FileSet, qf Qualifier) string {
+       if err.empty() {
+               return "no error"
+       }
+       var buf bytes.Buffer
+       for i := range err.desc {
+               p := &err.desc[i]
+               if i > 0 {
+                       fmt.Fprint(&buf, "\n\t")
+                       if p.posn.Pos().IsValid() {
+                               fmt.Fprintf(&buf, "%s: ", fset.Position(p.posn.Pos()))
+                       }
+               }
+               buf.WriteString(sprintf(fset, qf, false, p.format, p.args...))
+       }
+       return buf.String()
+}
+
+// String is for testing.
+func (err *error_) String() string {
+       if err.empty() {
+               return "no error"
+       }
+       return fmt.Sprintf("%d: %s", err.pos(), err.msg(nil, nil))
+}
+
+// errorf adds formatted error information to err.
+// It may be called multiple times to provide additional information.
+func (err *error_) errorf(at token.Pos, format string, args ...interface{}) {
+       err.desc = append(err.desc, errorDesc{atPos(at), format, args})
+}
+
 func (check *Checker) qualifier(pkg *Package) string {
        // Qualify the package unless it's the package being type-checked.
        if pkg != check.pkg {
@@ -141,8 +199,22 @@ func (check *Checker) dump(format string, args ...any) {
 
 // Report records the error pointed to by errp, setting check.firstError if
 // necessary.
-func (check *Checker) report(errp *Error) {
-       e := *errp
+func (check *Checker) report(errp *error_) {
+       if errp.empty() {
+               panic("empty error details")
+       }
+
+       span := spanOf(errp.desc[0].posn)
+       e := Error{
+               Fset:       check.fset,
+               Pos:        span.pos,
+               Msg:        errp.msg(check.fset, check.qualifier),
+               Soft:       errp.soft,
+               go116code:  errp.code,
+               go116start: span.start,
+               go116end:   span.end,
+       }
+
        // Cheap trick: Don't report errors with messages containing
        // "invalid operand" or "invalid type" as those tend to be
        // follow-on errors which don't add useful information. Only
@@ -183,35 +255,26 @@ func (check *Checker) report(errp *Error) {
        f(err)
 }
 
-func (check *Checker) newError(at positioner, code errorCode, soft bool, msg string) *Error {
-       span := spanOf(at)
-       return &Error{
-               Fset:       check.fset,
-               Pos:        span.pos,
-               Msg:        msg,
-               Soft:       soft,
-               go116code:  code,
-               go116start: span.start,
-               go116end:   span.end,
+// newErrorf creates a new error_ for later reporting with check.report.
+func newErrorf(at positioner, code errorCode, format string, args ...any) *error_ {
+       return &error_{
+               desc: []errorDesc{{at, format, args}},
+               code: code,
        }
 }
 
-// newErrorf creates a new Error, but does not handle it.
-func (check *Checker) newErrorf(at positioner, code errorCode, soft bool, format string, args ...any) *Error {
-       msg := check.sprintf(format, args...)
-       return check.newError(at, code, soft, msg)
-}
-
 func (check *Checker) error(at positioner, code errorCode, msg string) {
-       check.report(check.newError(at, code, false, msg))
+       check.report(newErrorf(at, code, msg))
 }
 
 func (check *Checker) errorf(at positioner, code errorCode, format string, args ...any) {
-       check.error(at, code, check.sprintf(format, args...))
+       check.report(newErrorf(at, code, format, args...))
 }
 
 func (check *Checker) softErrorf(at positioner, code errorCode, format string, args ...any) {
-       check.report(check.newErrorf(at, code, true, format, args...))
+       err := newErrorf(at, code, format, args...)
+       err.soft = true
+       check.report(err)
 }
 
 func (check *Checker) invalidAST(at positioner, format string, args ...any) {
index 942a9fdd4c2579fe7d2572e5cf900671dfdeb1df..4b5dab68e4e0c7a457ea12b4b53dedeb26237d22 100644 (file)
@@ -4,7 +4,30 @@
 
 package types
 
-import "testing"
+import (
+       "go/token"
+       "testing"
+)
+
+func TestError(t *testing.T) {
+       var err error_
+       want := "no error"
+       if got := err.String(); got != want {
+               t.Errorf("empty error: got %q, want %q", got, want)
+       }
+
+       want = "0: foo 42"
+       err.errorf(token.NoPos, "foo %d", 42)
+       if got := err.String(); got != want {
+               t.Errorf("simple error: got %q, want %q", got, want)
+       }
+
+       want = "0: foo 42\n\tbar 43"
+       err.errorf(token.NoPos, "bar %d", 43)
+       if got := err.String(); got != want {
+               t.Errorf("simple error: got %q, want %q", got, want)
+       }
+}
 
 func TestStripAnnotations(t *testing.T) {
        for _, test := range []struct {