From 5e3c4016a436c357a57a6f7870913c6911c6904e Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 23 Feb 2024 14:40:37 -0800 Subject: [PATCH] go/types, types2: separate formatting from error handling functions This change moves formatting-specific functionality into a new file format.go and rearranges the code in the errors.go files to be in the same order for go/types and types2, making them more similar. No functionality change. This is a pure code reordering. Change-Id: Ibd818792397be146ad510a6c7308c85d3bb65956 Reviewed-on: https://go-review.googlesource.com/c/go/+/566555 LUCI-TryBot-Result: Go LUCI Auto-Submit: Robert Griesemer Reviewed-by: Robert Findley Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/errors.go | 163 ++------------------ src/cmd/compile/internal/types2/format.go | 153 +++++++++++++++++++ src/go/types/errors.go | 178 +++------------------- src/go/types/format.go | 153 +++++++++++++++++++ 4 files changed, 337 insertions(+), 310 deletions(-) create mode 100644 src/cmd/compile/internal/types2/format.go create mode 100644 src/go/types/format.go diff --git a/src/cmd/compile/internal/types2/errors.go b/src/cmd/compile/internal/types2/errors.go index f65c1b5377..ea4a69b300 100644 --- a/src/cmd/compile/internal/types2/errors.go +++ b/src/cmd/compile/internal/types2/errors.go @@ -2,17 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file implements various error reporters. +// This file implements error reporting. package types2 import ( - "bytes" "cmd/compile/internal/syntax" "fmt" . "internal/types/errors" "runtime" - "strconv" "strings" ) @@ -52,6 +50,16 @@ func (check *Checker) newError(code Code) *error_ { return &error_{check: check, code: code} } +// addf adds formatted error information to err. +// It may be called multiple times to provide additional information. +// The position of the first call to addf determines the position of the reported Error. +// Subsequent calls to addf provide additional information in the form of additional lines +// in the error message (types2) or continuation errors identified by a tab-indented error +// message (go/types). +func (err *error_) addf(at poser, format string, args ...interface{}) { + err.desc = append(err.desc, errorDesc{atPos(at), err.check.sprintf(format, args...)}) +} + func (err *error_) empty() bool { return err.desc == nil } @@ -83,139 +91,6 @@ func (err *error_) msg() string { return buf.String() } -// addf adds formatted error information to err. -// It may be called multiple times to provide additional information. -// The position of the first call to addf determines the position of the reported Error. -// Subsequent calls to addf provide additional information in the form of additional lines -// in the error message (types2) or continuation errors identified by a tab-indented error -// message (go/types). -func (err *error_) addf(at poser, format string, args ...interface{}) { - err.desc = append(err.desc, errorDesc{atPos(at), err.check.sprintf(format, args...)}) -} - -func sprintf(qf Qualifier, tpSubscripts bool, format string, args ...any) string { - for i, arg := range args { - switch a := arg.(type) { - case nil: - arg = "" - case operand: - panic("got operand instead of *operand") - case *operand: - arg = operandString(a, qf) - case syntax.Pos: - arg = a.String() - case syntax.Expr: - arg = ExprString(a) - case []syntax.Expr: - var buf strings.Builder - buf.WriteByte('[') - for i, x := range a { - if i > 0 { - buf.WriteString(", ") - } - buf.WriteString(ExprString(x)) - } - buf.WriteByte(']') - arg = buf.String() - case Object: - arg = ObjectString(a, qf) - case Type: - var buf bytes.Buffer - w := newTypeWriter(&buf, qf) - w.tpSubscripts = tpSubscripts - w.typ(a) - arg = buf.String() - case []Type: - var buf bytes.Buffer - w := newTypeWriter(&buf, qf) - w.tpSubscripts = tpSubscripts - buf.WriteByte('[') - for i, x := range a { - if i > 0 { - buf.WriteString(", ") - } - w.typ(x) - } - buf.WriteByte(']') - arg = buf.String() - case []*TypeParam: - var buf bytes.Buffer - w := newTypeWriter(&buf, qf) - w.tpSubscripts = tpSubscripts - buf.WriteByte('[') - for i, x := range a { - if i > 0 { - buf.WriteString(", ") - } - w.typ(x) - } - buf.WriteByte(']') - arg = buf.String() - } - args[i] = arg - } - return fmt.Sprintf(format, args...) -} - -func (check *Checker) qualifier(pkg *Package) string { - // Qualify the package unless it's the package being type-checked. - if pkg != check.pkg { - if check.pkgPathMap == nil { - check.pkgPathMap = make(map[string]map[string]bool) - check.seenPkgMap = make(map[*Package]bool) - check.markImports(check.pkg) - } - // If the same package name was used by multiple packages, display the full path. - if len(check.pkgPathMap[pkg.name]) > 1 { - return strconv.Quote(pkg.path) - } - return pkg.name - } - return "" -} - -// markImports recursively walks pkg and its imports, to record unique import -// paths in pkgPathMap. -func (check *Checker) markImports(pkg *Package) { - if check.seenPkgMap[pkg] { - return - } - check.seenPkgMap[pkg] = true - - forName, ok := check.pkgPathMap[pkg.name] - if !ok { - forName = make(map[string]bool) - check.pkgPathMap[pkg.name] = forName - } - forName[pkg.path] = true - - for _, imp := range pkg.imports { - check.markImports(imp) - } -} - -// check may be nil. -func (check *Checker) sprintf(format string, args ...any) string { - var qf Qualifier - if check != nil { - qf = check.qualifier - } - return sprintf(qf, false, format, args...) -} - -func (check *Checker) trace(pos syntax.Pos, format string, args ...any) { - fmt.Printf("%s:\t%s%s\n", - pos, - strings.Repeat(". ", check.indent), - sprintf(check.qualifier, true, format, args...), - ) -} - -// dump is only needed for debugging -func (check *Checker) dump(format string, args ...any) { - fmt.Println(sprintf(check.qualifier, true, format, args...)) -} - // report reports the error err, setting check.firstError if necessary. func (err *error_) report() { if err.empty() { @@ -323,6 +198,7 @@ const ( invalidOp = "invalid operation: " ) +// The poser interface is used to extract the position of type-checker errors. type poser interface { Pos() syntax.Pos } @@ -365,18 +241,3 @@ func atPos(at poser) syntax.Pos { } return at.Pos() } - -// stripAnnotations removes internal (type) annotations from s. -func stripAnnotations(s string) string { - var buf strings.Builder - for _, r := range s { - // strip #'s and subscript digits - if r < '₀' || '₀'+10 <= r { // '₀' == U+2080 - buf.WriteRune(r) - } - } - if buf.Len() < len(s) { - return buf.String() - } - return s -} diff --git a/src/cmd/compile/internal/types2/format.go b/src/cmd/compile/internal/types2/format.go new file mode 100644 index 0000000000..442d219d1a --- /dev/null +++ b/src/cmd/compile/internal/types2/format.go @@ -0,0 +1,153 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements (error and trace) message formatting support. + +package types2 + +import ( + "bytes" + "cmd/compile/internal/syntax" + "fmt" + "strconv" + "strings" +) + +func sprintf(qf Qualifier, tpSubscripts bool, format string, args ...any) string { + for i, arg := range args { + switch a := arg.(type) { + case nil: + arg = "" + case operand: + panic("got operand instead of *operand") + case *operand: + arg = operandString(a, qf) + case syntax.Pos: + arg = a.String() + case syntax.Expr: + arg = ExprString(a) + case []syntax.Expr: + var buf strings.Builder + buf.WriteByte('[') + for i, x := range a { + if i > 0 { + buf.WriteString(", ") + } + buf.WriteString(ExprString(x)) + } + buf.WriteByte(']') + arg = buf.String() + case Object: + arg = ObjectString(a, qf) + case Type: + var buf bytes.Buffer + w := newTypeWriter(&buf, qf) + w.tpSubscripts = tpSubscripts + w.typ(a) + arg = buf.String() + case []Type: + var buf bytes.Buffer + w := newTypeWriter(&buf, qf) + w.tpSubscripts = tpSubscripts + buf.WriteByte('[') + for i, x := range a { + if i > 0 { + buf.WriteString(", ") + } + w.typ(x) + } + buf.WriteByte(']') + arg = buf.String() + case []*TypeParam: + var buf bytes.Buffer + w := newTypeWriter(&buf, qf) + w.tpSubscripts = tpSubscripts + buf.WriteByte('[') + for i, x := range a { + if i > 0 { + buf.WriteString(", ") + } + w.typ(x) + } + buf.WriteByte(']') + arg = buf.String() + } + args[i] = arg + } + return fmt.Sprintf(format, args...) +} + +// check may be nil. +func (check *Checker) sprintf(format string, args ...any) string { + var qf Qualifier + if check != nil { + qf = check.qualifier + } + return sprintf(qf, false, format, args...) +} + +func (check *Checker) trace(pos syntax.Pos, format string, args ...any) { + fmt.Printf("%s:\t%s%s\n", + pos, + strings.Repeat(". ", check.indent), + sprintf(check.qualifier, true, format, args...), + ) +} + +// dump is only needed for debugging +func (check *Checker) dump(format string, args ...any) { + fmt.Println(sprintf(check.qualifier, true, format, args...)) +} + +func (check *Checker) qualifier(pkg *Package) string { + // Qualify the package unless it's the package being type-checked. + if pkg != check.pkg { + if check.pkgPathMap == nil { + check.pkgPathMap = make(map[string]map[string]bool) + check.seenPkgMap = make(map[*Package]bool) + check.markImports(check.pkg) + } + // If the same package name was used by multiple packages, display the full path. + if len(check.pkgPathMap[pkg.name]) > 1 { + return strconv.Quote(pkg.path) + } + return pkg.name + } + return "" +} + +// markImports recursively walks pkg and its imports, to record unique import +// paths in pkgPathMap. +func (check *Checker) markImports(pkg *Package) { + if check.seenPkgMap[pkg] { + return + } + check.seenPkgMap[pkg] = true + + forName, ok := check.pkgPathMap[pkg.name] + if !ok { + forName = make(map[string]bool) + check.pkgPathMap[pkg.name] = forName + } + forName[pkg.path] = true + + for _, imp := range pkg.imports { + check.markImports(imp) + } +} + +// stripAnnotations removes internal (type) annotations from s. +func stripAnnotations(s string) string { + var buf strings.Builder + for _, r := range s { + // strip #'s and subscript digits + if r < '₀' || '₀'+10 <= r { // '₀' == U+2080 + buf.WriteRune(r) + } + } + if buf.Len() < len(s) { + return buf.String() + } + return s +} diff --git a/src/go/types/errors.go b/src/go/types/errors.go index 1abceb5ccf..878a81cd1a 100644 --- a/src/go/types/errors.go +++ b/src/go/types/errors.go @@ -2,18 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file implements various error reporters. +// This file implements error reporting. package types import ( - "bytes" "fmt" "go/ast" "go/token" . "internal/types/errors" "runtime" - "strconv" "strings" ) @@ -53,6 +51,16 @@ func (check *Checker) newError(code Code) *error_ { return &error_{check: check, code: code} } +// addf adds formatted error information to err. +// It may be called multiple times to provide additional information. +// The position of the first call to addf determines the position of the reported Error. +// Subsequent calls to addf provide additional information in the form of additional lines +// in the error message (types2) or continuation errors identified by a tab-indented error +// message (go/types). +func (err *error_) addf(at positioner, format string, args ...interface{}) { + err.desc = append(err.desc, errorDesc{at, err.check.sprintf(format, args...)}) +} + func (err *error_) empty() bool { return err.desc == nil } @@ -84,138 +92,6 @@ func (err *error_) msg() string { return buf.String() } -// addf adds formatted error information to err. -// It may be called multiple times to provide additional information. -// The position of the first call to addf determines the position of the reported Error. -// Subsequent calls to addf provide additional information in the form of additional lines -// in the error message (types2) or continuation errors identified by a tab-indented error -// message (go/types). -func (err *error_) addf(at positioner, format string, args ...interface{}) { - err.desc = append(err.desc, errorDesc{at, err.check.sprintf(format, args...)}) -} - -func (check *Checker) qualifier(pkg *Package) string { - // Qualify the package unless it's the package being type-checked. - if pkg != check.pkg { - if check.pkgPathMap == nil { - check.pkgPathMap = make(map[string]map[string]bool) - check.seenPkgMap = make(map[*Package]bool) - check.markImports(check.pkg) - } - // If the same package name was used by multiple packages, display the full path. - if len(check.pkgPathMap[pkg.name]) > 1 { - return strconv.Quote(pkg.path) - } - return pkg.name - } - return "" -} - -// markImports recursively walks pkg and its imports, to record unique import -// paths in pkgPathMap. -func (check *Checker) markImports(pkg *Package) { - if check.seenPkgMap[pkg] { - return - } - check.seenPkgMap[pkg] = true - - forName, ok := check.pkgPathMap[pkg.name] - if !ok { - forName = make(map[string]bool) - check.pkgPathMap[pkg.name] = forName - } - forName[pkg.path] = true - - for _, imp := range pkg.imports { - check.markImports(imp) - } -} - -// check may be nil. -func (check *Checker) sprintf(format string, args ...any) string { - var fset *token.FileSet - var qf Qualifier - if check != nil { - fset = check.fset - qf = check.qualifier - } - return sprintf(fset, qf, false, format, args...) -} - -func sprintf(fset *token.FileSet, qf Qualifier, tpSubscripts bool, format string, args ...any) string { - for i, arg := range args { - switch a := arg.(type) { - case nil: - arg = "" - case operand: - panic("got operand instead of *operand") - case *operand: - arg = operandString(a, qf) - case token.Pos: - if fset != nil { - arg = fset.Position(a).String() - } - case ast.Expr: - arg = ExprString(a) - case []ast.Expr: - var buf bytes.Buffer - buf.WriteByte('[') - writeExprList(&buf, a) - buf.WriteByte(']') - arg = buf.String() - case Object: - arg = ObjectString(a, qf) - case Type: - var buf bytes.Buffer - w := newTypeWriter(&buf, qf) - w.tpSubscripts = tpSubscripts - w.typ(a) - arg = buf.String() - case []Type: - var buf bytes.Buffer - w := newTypeWriter(&buf, qf) - w.tpSubscripts = tpSubscripts - buf.WriteByte('[') - for i, x := range a { - if i > 0 { - buf.WriteString(", ") - } - w.typ(x) - } - buf.WriteByte(']') - arg = buf.String() - case []*TypeParam: - var buf bytes.Buffer - w := newTypeWriter(&buf, qf) - w.tpSubscripts = tpSubscripts - buf.WriteByte('[') - for i, x := range a { - if i > 0 { - buf.WriteString(", ") - } - w.typ(x) - } - buf.WriteByte(']') - arg = buf.String() - } - args[i] = arg - } - return fmt.Sprintf(format, args...) -} - -func (check *Checker) trace(pos token.Pos, format string, args ...any) { - fmt.Printf("%s:\t%s%s\n", - check.fset.Position(pos), - strings.Repeat(". ", check.indent), - sprintf(check.fset, check.qualifier, true, format, args...), - ) -} - -// dump is only needed for debugging -func (check *Checker) dump(format string, args ...any) { - fmt.Println(sprintf(check.fset, check.qualifier, true, format, args...)) -} - // report reports the error err, setting check.firstError if necessary. func (err *error_) report() { if err.empty() { @@ -337,8 +213,7 @@ const ( invalidOp = "invalid operation: " ) -// The positioner interface is used to extract the position of type-checker -// errors. +// The positioner interface is used to extract the position of type-checker errors. type positioner interface { Pos() token.Pos } @@ -369,6 +244,13 @@ func (check *Checker) versionErrorf(at positioner, v goVersion, format string, a err.report() } +// atPos wraps a token.Pos to implement the positioner interface. +type atPos token.Pos + +func (s atPos) Pos() token.Pos { + return token.Pos(s) +} + // posSpan holds a position range along with a highlighted position within that // range. This is used for positioning errors, with pos by convention being the // first position in the source where the error is known to exist, and start @@ -393,13 +275,6 @@ func inNode(node ast.Node, pos token.Pos) posSpan { return posSpan{start, pos, end} } -// atPos wraps a token.Pos to implement the positioner interface. -type atPos token.Pos - -func (s atPos) Pos() token.Pos { - return token.Pos(s) -} - // spanOf extracts an error span from the given positioner. By default this is // the trivial span starting and ending at pos, but this span is expanded when // the argument naturally corresponds to a span of source code. @@ -423,18 +298,3 @@ func spanOf(at positioner) posSpan { return posSpan{pos, pos, pos} } } - -// stripAnnotations removes internal (type) annotations from s. -func stripAnnotations(s string) string { - var buf strings.Builder - for _, r := range s { - // strip #'s and subscript digits - if r < '₀' || '₀'+10 <= r { // '₀' == U+2080 - buf.WriteRune(r) - } - } - if buf.Len() < len(s) { - return buf.String() - } - return s -} diff --git a/src/go/types/format.go b/src/go/types/format.go new file mode 100644 index 0000000000..09e599c3c3 --- /dev/null +++ b/src/go/types/format.go @@ -0,0 +1,153 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements (error and trace) message formatting support. + +package types + +import ( + "bytes" + "fmt" + "go/ast" + "go/token" + "strconv" + "strings" +) + +func sprintf(fset *token.FileSet, qf Qualifier, tpSubscripts bool, format string, args ...any) string { + for i, arg := range args { + switch a := arg.(type) { + case nil: + arg = "" + case operand: + panic("got operand instead of *operand") + case *operand: + arg = operandString(a, qf) + case token.Pos: + if fset != nil { + arg = fset.Position(a).String() + } + case ast.Expr: + arg = ExprString(a) + case []ast.Expr: + var buf bytes.Buffer + buf.WriteByte('[') + writeExprList(&buf, a) + buf.WriteByte(']') + arg = buf.String() + case Object: + arg = ObjectString(a, qf) + case Type: + var buf bytes.Buffer + w := newTypeWriter(&buf, qf) + w.tpSubscripts = tpSubscripts + w.typ(a) + arg = buf.String() + case []Type: + var buf bytes.Buffer + w := newTypeWriter(&buf, qf) + w.tpSubscripts = tpSubscripts + buf.WriteByte('[') + for i, x := range a { + if i > 0 { + buf.WriteString(", ") + } + w.typ(x) + } + buf.WriteByte(']') + arg = buf.String() + case []*TypeParam: + var buf bytes.Buffer + w := newTypeWriter(&buf, qf) + w.tpSubscripts = tpSubscripts + buf.WriteByte('[') + for i, x := range a { + if i > 0 { + buf.WriteString(", ") + } + w.typ(x) + } + buf.WriteByte(']') + arg = buf.String() + } + args[i] = arg + } + return fmt.Sprintf(format, args...) +} + +// check may be nil. +func (check *Checker) sprintf(format string, args ...any) string { + var fset *token.FileSet + var qf Qualifier + if check != nil { + fset = check.fset + qf = check.qualifier + } + return sprintf(fset, qf, false, format, args...) +} + +func (check *Checker) trace(pos token.Pos, format string, args ...any) { + fmt.Printf("%s:\t%s%s\n", + check.fset.Position(pos), + strings.Repeat(". ", check.indent), + sprintf(check.fset, check.qualifier, true, format, args...), + ) +} + +// dump is only needed for debugging +func (check *Checker) dump(format string, args ...any) { + fmt.Println(sprintf(check.fset, check.qualifier, true, format, args...)) +} + +func (check *Checker) qualifier(pkg *Package) string { + // Qualify the package unless it's the package being type-checked. + if pkg != check.pkg { + if check.pkgPathMap == nil { + check.pkgPathMap = make(map[string]map[string]bool) + check.seenPkgMap = make(map[*Package]bool) + check.markImports(check.pkg) + } + // If the same package name was used by multiple packages, display the full path. + if len(check.pkgPathMap[pkg.name]) > 1 { + return strconv.Quote(pkg.path) + } + return pkg.name + } + return "" +} + +// markImports recursively walks pkg and its imports, to record unique import +// paths in pkgPathMap. +func (check *Checker) markImports(pkg *Package) { + if check.seenPkgMap[pkg] { + return + } + check.seenPkgMap[pkg] = true + + forName, ok := check.pkgPathMap[pkg.name] + if !ok { + forName = make(map[string]bool) + check.pkgPathMap[pkg.name] = forName + } + forName[pkg.path] = true + + for _, imp := range pkg.imports { + check.markImports(imp) + } +} + +// stripAnnotations removes internal (type) annotations from s. +func stripAnnotations(s string) string { + var buf strings.Builder + for _, r := range s { + // strip #'s and subscript digits + if r < '₀' || '₀'+10 <= r { // '₀' == U+2080 + buf.WriteRune(r) + } + } + if buf.Len() < len(s) { + return buf.String() + } + return s +} -- 2.48.1