aboutsummaryrefslogtreecommitdiff
path: root/src/go
diff options
context:
space:
mode:
Diffstat (limited to 'src/go')
-rw-r--r--src/go/build/build.go9
-rw-r--r--src/go/format/format.go2
-rw-r--r--src/go/internal/srcimporter/srcimporter.go8
-rw-r--r--src/go/types/api.go6
-rw-r--r--src/go/types/assignments.go10
-rw-r--r--src/go/types/call.go9
-rw-r--r--src/go/types/conversions.go5
-rw-r--r--src/go/types/errors.go140
-rw-r--r--src/go/types/errors_test.go25
-rw-r--r--src/go/types/expr.go12
-rw-r--r--src/go/types/sizes.go7
-rw-r--r--src/go/types/testdata/check/const0.go19
-rw-r--r--src/go/types/testdata/fixedbugs/issue52401.go11
13 files changed, 183 insertions, 80 deletions
diff --git a/src/go/build/build.go b/src/go/build/build.go
index c67d6d0cdc2..f40b4866350 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -1185,20 +1185,13 @@ func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode)
if ctxt.CgoEnabled {
cgo = "1"
}
- cmd.Env = append(os.Environ(),
+ cmd.Env = append(cmd.Environ(),
"GOOS="+ctxt.GOOS,
"GOARCH="+ctxt.GOARCH,
"GOROOT="+ctxt.GOROOT,
"GOPATH="+ctxt.GOPATH,
"CGO_ENABLED="+cgo,
)
- if cmd.Dir != "" {
- // If possible, set PWD: if an error occurs and PWD includes a symlink, we
- // want the error to refer to Dir, not some other name for it.
- if abs, err := filepath.Abs(cmd.Dir); err == nil {
- cmd.Env = append(cmd.Env, "PWD="+abs)
- }
- }
if err := cmd.Run(); err != nil {
return fmt.Errorf("go/build: go list %s: %v\n%s\n", path, err, stderr.String())
diff --git a/src/go/format/format.go b/src/go/format/format.go
index fb87e84a4eb..3837cb46170 100644
--- a/src/go/format/format.go
+++ b/src/go/format/format.go
@@ -38,7 +38,7 @@ const (
var config = printer.Config{Mode: printerMode, Tabwidth: tabWidth}
-const parserMode = parser.ParseComments
+const parserMode = parser.ParseComments | parser.SkipObjectResolution
// Node formats node in canonical gofmt style and writes the result to dst.
//
diff --git a/src/go/internal/srcimporter/srcimporter.go b/src/go/internal/srcimporter/srcimporter.go
index d7ec6691bc7..ea6f01280a7 100644
--- a/src/go/internal/srcimporter/srcimporter.go
+++ b/src/go/internal/srcimporter/srcimporter.go
@@ -136,7 +136,7 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type
setUsesCgo(&conf)
file, err := p.cgo(bp)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("error processing cgo for package %q: %w", bp.ImportPath, err)
}
files = append(files, file)
}
@@ -223,9 +223,9 @@ func (p *Importer) cgo(bp *build.Package) (*ast.File, error) {
args = append(args, bp.CgoCPPFLAGS...)
if len(bp.CgoPkgConfig) > 0 {
cmd := exec.Command("pkg-config", append([]string{"--cflags"}, bp.CgoPkgConfig...)...)
- out, err := cmd.CombinedOutput()
+ out, err := cmd.Output()
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("pkg-config --cflags: %w", err)
}
args = append(args, strings.Fields(string(out))...)
}
@@ -237,7 +237,7 @@ func (p *Importer) cgo(bp *build.Package) (*ast.File, error) {
cmd := exec.Command(args[0], args[1:]...)
cmd.Dir = bp.Dir
if err := cmd.Run(); err != nil {
- return nil, err
+ return nil, fmt.Errorf("go tool cgo: %w", err)
}
return parser.ParseFile(p.fset, filepath.Join(tmpdir, "_cgo_gotypes.go"), nil, 0)
diff --git a/src/go/types/api.go b/src/go/types/api.go
index 4f63d627130..0915d6a6eee 100644
--- a/src/go/types/api.go
+++ b/src/go/types/api.go
@@ -414,9 +414,9 @@ func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, i
// AssertableTo reports whether a value of type V can be asserted to have type T.
//
// The behavior of AssertableTo is undefined in two cases:
-// - if V is a generalized interface; i.e., an interface that may only be used
-// as a type constraint in Go code
-// - if T is an uninstantiated generic type
+// - if V is a generalized interface; i.e., an interface that may only be used
+// as a type constraint in Go code
+// - if T is an uninstantiated generic type
func AssertableTo(V *Interface, T Type) bool {
// Checker.newAssertableTo suppresses errors for invalid types, so we need special
// handling here.
diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go
index 101e868d82f..98d75630efe 100644
--- a/src/go/types/assignments.go
+++ b/src/go/types/assignments.go
@@ -9,6 +9,7 @@ package types
import (
"fmt"
"go/ast"
+ "go/token"
"strings"
)
@@ -339,11 +340,10 @@ func (check *Checker) initVars(lhs []*Var, origRHS []ast.Expr, returnStmt ast.St
} else if len(rhs) > 0 {
at = rhs[len(rhs)-1].expr // report at last value
}
- check.errorf(at, _WrongResultCount, "%s return values\n\thave %s\n\twant %s",
- qualifier,
- check.typesSummary(operandTypes(rhs), false),
- check.typesSummary(varTypes(lhs), false),
- )
+ err := newErrorf(at, _WrongResultCount, "%s return values", qualifier)
+ err.errorf(token.NoPos, "have %s", check.typesSummary(operandTypes(rhs), false))
+ err.errorf(token.NoPos, "want %s", check.typesSummary(varTypes(lhs), false))
+ check.report(err)
return
}
if compilerErrorMessages {
diff --git a/src/go/types/call.go b/src/go/types/call.go
index 51603170a60..3c7c3226f62 100644
--- a/src/go/types/call.go
+++ b/src/go/types/call.go
@@ -368,11 +368,10 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type
if sig.params != nil {
params = sig.params.vars
}
- check.errorf(at, _WrongArgCount, "%s arguments in call to %s\n\thave %s\n\twant %s",
- qualifier, call.Fun,
- check.typesSummary(operandTypes(args), false),
- check.typesSummary(varTypes(params), sig.variadic),
- )
+ err := newErrorf(at, _WrongArgCount, "%s arguments in call to %s", qualifier, call.Fun)
+ err.errorf(token.NoPos, "have %s", check.typesSummary(operandTypes(args), false))
+ err.errorf(token.NoPos, "want %s", check.typesSummary(varTypes(params), sig.variadic))
+ check.report(err)
return
}
diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go
index 65691cf4550..362c8fdbac9 100644
--- a/src/go/types/conversions.go
+++ b/src/go/types/conversions.go
@@ -8,6 +8,7 @@ package types
import (
"go/constant"
+ "go/token"
"unicode"
)
@@ -74,7 +75,9 @@ func (check *Checker) conversion(x *operand, T Type) {
if compilerErrorMessages {
if cause != "" {
// Add colon at end of line if we have a following cause.
- check.errorf(x, _InvalidConversion, "cannot convert %s to type %s:\n\t%s", x, T, cause)
+ err := newErrorf(x, _InvalidConversion, "cannot convert %s to type %s:", x, T)
+ err.errorf(token.NoPos, cause)
+ check.report(err)
} else {
check.errorf(x, _InvalidConversion, "cannot convert %s to type %s", x, T)
}
diff --git a/src/go/types/errors.go b/src/go/types/errors.go
index fade8630e09..0dc0bc87991 100644
--- a/src/go/types/errors.go
+++ b/src/go/types/errors.go
@@ -8,7 +8,6 @@ package types
import (
"bytes"
- "errors"
"fmt"
"go/ast"
"go/token"
@@ -26,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 {
@@ -140,36 +197,46 @@ func (check *Checker) dump(format string, args ...any) {
fmt.Println(sprintf(check.fset, check.qualifier, true, format, args...))
}
-func (check *Checker) err(err error) {
- if err == nil {
- return
+// Report records the error pointed to by errp, setting check.firstError if
+// necessary.
+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,
}
- var e Error
- isInternal := errors.As(err, &e)
+
// 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
// exclude them if these strings are not at the beginning,
// and only if we have at least one error already reported.
- isInvalidErr := isInternal && (strings.Index(e.Msg, "invalid operand") > 0 || strings.Index(e.Msg, "invalid type") > 0)
+ isInvalidErr := strings.Index(e.Msg, "invalid operand") > 0 || strings.Index(e.Msg, "invalid type") > 0
if check.firstErr != nil && isInvalidErr {
return
}
- if isInternal {
- e.Msg = stripAnnotations(e.Msg)
- if check.errpos != nil {
- // If we have an internal error and the errpos override is set, use it to
- // augment our error positioning.
- // TODO(rFindley) we may also want to augment the error message and refer
- // to the position (pos) in the original expression.
- span := spanOf(check.errpos)
- e.Pos = span.pos
- e.go116start = span.start
- e.go116end = span.end
- }
- err = e
+ e.Msg = stripAnnotations(e.Msg)
+ if check.errpos != nil {
+ // If we have an internal error and the errpos override is set, use it to
+ // augment our error positioning.
+ // TODO(rFindley) we may also want to augment the error message and refer
+ // to the position (pos) in the original expression.
+ span := spanOf(check.errpos)
+ e.Pos = span.pos
+ e.go116start = span.start
+ e.go116end = span.end
}
+ err := e
if check.firstErr == nil {
check.firstErr = err
@@ -178,10 +245,6 @@ func (check *Checker) err(err error) {
if trace {
pos := e.Pos
msg := e.Msg
- if !isInternal {
- msg = err.Error()
- pos = token.NoPos
- }
check.trace(pos, "ERROR: %s", msg)
}
@@ -192,35 +255,26 @@ func (check *Checker) err(err 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.err(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.err(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) {
diff --git a/src/go/types/errors_test.go b/src/go/types/errors_test.go
index 942a9fdd4c2..4b5dab68e4e 100644
--- a/src/go/types/errors_test.go
+++ b/src/go/types/errors_test.go
@@ -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 {
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index 977153512f9..70914d54852 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -87,7 +87,7 @@ func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
// overflow checks that the constant x is representable by its type.
// For untyped constants, it checks that the value doesn't become
// arbitrarily large.
-func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) {
+func (check *Checker) overflow(x *operand, opPos token.Pos) {
assert(x.mode == constant_)
if x.val.Kind() == constant.Unknown {
@@ -115,8 +115,8 @@ func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) {
}
}
-// opName returns the name of an operation, or the empty string.
-// Only operations that might overflow are handled.
+// opName returns the name of the operation if x is an operation
+// that might overflow; otherwise it returns the empty string.
func opName(e ast.Expr) string {
switch e := e.(type) {
case *ast.BinaryExpr:
@@ -213,7 +213,7 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
}
x.val = constant.UnaryOp(e.Op, x.val, prec)
x.expr = e
- check.overflow(x, e.Op, x.Pos())
+ check.overflow(x, x.Pos())
return
}
@@ -991,7 +991,7 @@ func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) {
if b, _ := e.(*ast.BinaryExpr); b != nil {
opPos = b.OpPos
}
- check.overflow(x, op, opPos)
+ check.overflow(x, opPos)
return
}
@@ -1171,7 +1171,7 @@ func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token
}
x.val = constant.BinaryOp(x.val, op, y.val)
x.expr = e
- check.overflow(x, op, opPos)
+ check.overflow(x, opPos)
return
}
diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go
index 494e0454770..7b67dca2b8b 100644
--- a/src/go/types/sizes.go
+++ b/src/go/types/sizes.go
@@ -166,10 +166,11 @@ func (s *StdSizes) Sizeof(T Type) int64 {
// common architecture word sizes and alignments
var gcArchSizes = map[string]*StdSizes{
"386": {4, 4},
- "arm": {4, 4},
- "arm64": {8, 8},
"amd64": {8, 8},
"amd64p32": {4, 8},
+ "arm": {4, 4},
+ "arm64": {8, 8},
+ "loong64": {8, 8},
"mips": {4, 4},
"mipsle": {4, 4},
"mips64": {8, 8},
@@ -188,7 +189,7 @@ var gcArchSizes = map[string]*StdSizes{
// The result is nil if a compiler/architecture pair is not known.
//
// Supported architectures for compiler "gc":
-// "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle",
+// "386", "amd64", "amd64p32", "arm", "arm64", "loong64", "mips", "mipsle",
// "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "sparc64", "wasm".
func SizesFor(compiler, arch string) Sizes {
var m map[string]*StdSizes
diff --git a/src/go/types/testdata/check/const0.go b/src/go/types/testdata/check/const0.go
index 3cffdf904c8..229c248643d 100644
--- a/src/go/types/testdata/check/const0.go
+++ b/src/go/types/testdata/check/const0.go
@@ -349,6 +349,25 @@ const _ = unsafe.Sizeof(func() {
assert(iota == 0)
})
+// issue #52438
+const i1 = iota
+const i2 = iota
+const i3 = iota
+
+func _() {
+ assert(i1 == 0)
+ assert(i2 == 0)
+ assert(i3 == 0)
+
+ const i4 = iota
+ const i5 = iota
+ const i6 = iota
+
+ assert(i4 == 0)
+ assert(i5 == 0)
+ assert(i6 == 0)
+}
+
// untyped constants must not get arbitrarily large
const prec = 512 // internal maximum precision for integers
const maxInt = (1<<(prec/2) - 1) * (1<<(prec/2) + 1) // == 1<<prec - 1
diff --git a/src/go/types/testdata/fixedbugs/issue52401.go b/src/go/types/testdata/fixedbugs/issue52401.go
new file mode 100644
index 00000000000..c7efd8c7180
--- /dev/null
+++ b/src/go/types/testdata/fixedbugs/issue52401.go
@@ -0,0 +1,11 @@
+// Copyright 2022 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.
+
+package p
+
+func _() {
+ const x = 0
+ x /* ERROR cannot assign to x */ += 1
+ x /* ERROR cannot assign to x */ ++
+}