all: merge master (abc106c) into gopls-release-branch.0.8
Also add a replace directive to gopls/go.mod.
Updates golang/go#51074
Conflicts:
- gopls/go.mod (due to gofumpt update)
Merge List:
+ 2022-02-28 abc106cd gopls/integration/govim: build gopls using go1.18rc1
+ 2022-02-28 c2ddf3dd internal/lsp: add quick fix for unsupported feature
+ 2022-02-28 0e44f7a8 gopls/doc/advanced.md: correct commands for unstable version build
+ 2022-02-25 acdddf67 go/ssa: allows right operand of a shift to be signed.
+ 2022-02-25 9ffa3ad3 internal/lsp: Provide completions for test function definitions
+ 2022-02-24 b7525f43 internal/lsp: hash go version into package key
+ 2022-02-24 5210e0ca gopls: wire in LangVersion and ModulePath for gofumpt formatting
+ 2022-02-24 e6ef7709 go/types/typeutil: don't recurse into constraints when hashing tparams
+ 2022-02-23 258e4730 internal/lsp/source: disable the useany analyzer by default
+ 2022-02-23 b7d29496 internal/lsp: don't store diagnostics for builtin.go
+ 2022-02-23 4f21f7a5 gopls: update gofumpt to v0.3.0
+ 2022-02-22 3e31058c internal/imports: update to permit multiple main modules
+ 2022-02-22 43f084e5 internal/typesinternal: update typesinternal for 1.18
+ 2022-02-18 897bd77c internal/gocommand: remove support for -workfile
+ 2022-02-17 e6a7e133 go/analysis/tools/internal/checker: add support for RunDespiteError
Change-Id: I4ca5a581cb276b904f4a9d73d686aaa7cb0c6093
diff --git a/cmd/godoc/main.go b/cmd/godoc/main.go
index 9d6ac86..352bb4b 100644
--- a/cmd/godoc/main.go
+++ b/cmd/godoc/main.go
@@ -207,21 +207,21 @@
fmt.Printf("using module mode; GOMOD=%s\n", goModFile)
// Detect whether to use vendor mode or not.
- mainMod, vendorEnabled, err := gocommand.VendorEnabled(context.Background(), gocommand.Invocation{}, &gocommand.Runner{})
+ vendorEnabled, mainModVendor, err := gocommand.VendorEnabled(context.Background(), gocommand.Invocation{}, &gocommand.Runner{})
if err != nil {
fmt.Fprintf(os.Stderr, "failed to determine if vendoring is enabled: %v", err)
os.Exit(1)
}
if vendorEnabled {
// Bind the root directory of the main module.
- fs.Bind(path.Join("/src", mainMod.Path), gatefs.New(vfs.OS(mainMod.Dir), fsGate), "/", vfs.BindAfter)
+ fs.Bind(path.Join("/src", mainModVendor.Path), gatefs.New(vfs.OS(mainModVendor.Dir), fsGate), "/", vfs.BindAfter)
// Bind the vendor directory.
//
// Note that in module mode, vendor directories in locations
// other than the main module's root directory are ignored.
// See https://golang.org/ref/mod#vendoring.
- vendorDir := filepath.Join(mainMod.Dir, "vendor")
+ vendorDir := filepath.Join(mainModVendor.Dir, "vendor")
fs.Bind("/src", gatefs.New(vfs.OS(vendorDir), fsGate), "/", vfs.BindAfter)
} else {
diff --git a/go/analysis/internal/checker/checker.go b/go/analysis/internal/checker/checker.go
index 8861393..e405a2a 100644
--- a/go/analysis/internal/checker/checker.go
+++ b/go/analysis/internal/checker/checker.go
@@ -11,6 +11,7 @@
import (
"bytes"
"encoding/gob"
+ "errors"
"flag"
"fmt"
"go/format"
@@ -129,8 +130,13 @@
allSyntax := needFacts(analyzers)
initial, err := load(args, allSyntax)
if err != nil {
- log.Print(err)
- return 1 // load errors
+ if _, ok := err.(typeParseError); !ok {
+ // Fail when some of the errors are not
+ // related to parsing nor typing.
+ log.Print(err)
+ return 1
+ }
+ // TODO: filter analyzers based on RunDespiteError?
}
// Print the results.
@@ -139,11 +145,17 @@
if Fix {
applyFixes(roots)
}
-
return printDiagnostics(roots)
}
-// load loads the initial packages.
+// typeParseError represents a package load error
+// that is related to typing and parsing.
+type typeParseError struct {
+ error
+}
+
+// load loads the initial packages. If all loading issues are related to
+// typing and parsing, the returned error is of type typeParseError.
func load(patterns []string, allSyntax bool) ([]*packages.Package, error) {
mode := packages.LoadSyntax
if allSyntax {
@@ -155,18 +167,43 @@
}
initial, err := packages.Load(&conf, patterns...)
if err == nil {
- if n := packages.PrintErrors(initial); n > 1 {
- err = fmt.Errorf("%d errors during loading", n)
- } else if n == 1 {
- err = fmt.Errorf("error during loading")
- } else if len(initial) == 0 {
+ if len(initial) == 0 {
err = fmt.Errorf("%s matched no packages", strings.Join(patterns, " "))
+ } else {
+ err = loadingError(initial)
}
}
-
return initial, err
}
+// loadingError checks for issues during the loading of initial
+// packages. Returns nil if there are no issues. Returns error
+// of type typeParseError if all errors, including those in
+// dependencies, are related to typing or parsing. Otherwise,
+// a plain error is returned with an appropriate message.
+func loadingError(initial []*packages.Package) error {
+ var err error
+ if n := packages.PrintErrors(initial); n > 1 {
+ err = fmt.Errorf("%d errors during loading", n)
+ } else if n == 1 {
+ err = errors.New("error during loading")
+ } else {
+ // no errors
+ return nil
+ }
+ all := true
+ packages.Visit(initial, nil, func(pkg *packages.Package) {
+ for _, err := range pkg.Errors {
+ typeOrParse := err.Kind == packages.TypeError || err.Kind == packages.ParseError
+ all = all && typeOrParse
+ }
+ })
+ if all {
+ return typeParseError{err}
+ }
+ return err
+}
+
// TestAnalyzer applies an analysis to a set of packages (and their
// dependencies if necessary) and returns the results.
//
diff --git a/go/analysis/internal/checker/checker_test.go b/go/analysis/internal/checker/checker_test.go
index 50c51a1..eee211c 100644
--- a/go/analysis/internal/checker/checker_test.go
+++ b/go/analysis/internal/checker/checker_test.go
@@ -99,3 +99,62 @@
return nil, nil
}
+
+func TestRunDespiteErrors(t *testing.T) {
+ testenv.NeedsGoPackages(t)
+
+ files := map[string]string{
+ "rderr/test.go": `package rderr
+
+// Foo deliberately has a type error
+func Foo(s string) int {
+ return s + 1
+}
+`}
+
+ testdata, cleanup, err := analysistest.WriteFiles(files)
+ if err != nil {
+ t.Fatal(err)
+ }
+ path := filepath.Join(testdata, "src/rderr/test.go")
+
+ // A no-op analyzer that should finish regardless of
+ // parse or type errors in the code.
+ noop := &analysis.Analyzer{
+ Name: "noop",
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ Run: func(pass *analysis.Pass) (interface{}, error) {
+ return nil, nil
+ },
+ RunDespiteErrors: true,
+ }
+
+ for _, test := range []struct {
+ name string
+ pattern []string
+ analyzers []*analysis.Analyzer
+ code int
+ }{
+ // parse/type errors
+ {name: "skip-error", pattern: []string{"file=" + path}, analyzers: []*analysis.Analyzer{analyzer}, code: 1},
+ {name: "despite-error", pattern: []string{"file=" + path}, analyzers: []*analysis.Analyzer{noop}, code: 0},
+ // combination of parse/type errors and no errors
+ {name: "despite-error-and-no-error", pattern: []string{"file=" + path, "sort"}, analyzers: []*analysis.Analyzer{analyzer, noop}, code: 1},
+ // non-existing package error
+ {name: "no-package", pattern: []string{"xyz"}, analyzers: []*analysis.Analyzer{analyzer}, code: 1},
+ {name: "no-package-despite-error", pattern: []string{"abc"}, analyzers: []*analysis.Analyzer{noop}, code: 1},
+ {name: "no-multi-package-despite-error", pattern: []string{"xyz", "abc"}, analyzers: []*analysis.Analyzer{noop}, code: 1},
+ // combination of type/parsing and different errors
+ {name: "different-errors", pattern: []string{"file=" + path, "xyz"}, analyzers: []*analysis.Analyzer{analyzer, noop}, code: 1},
+ // non existing dir error
+ {name: "no-match-dir", pattern: []string{"file=non/existing/dir"}, analyzers: []*analysis.Analyzer{analyzer, noop}, code: 1},
+ // no errors
+ {name: "no-errors", pattern: []string{"sort"}, analyzers: []*analysis.Analyzer{analyzer, noop}, code: 0},
+ } {
+ if got := checker.Run(test.pattern, test.analyzers); got != test.code {
+ t.Errorf("got incorrect exit code %d for test %s; want %d", got, test.name, test.code)
+ }
+ }
+
+ defer cleanup()
+}
diff --git a/go/ssa/emit.go b/go/ssa/emit.go
index 7c8cfdc..ff53705 100644
--- a/go/ssa/emit.go
+++ b/go/ssa/emit.go
@@ -74,9 +74,16 @@
case token.SHL, token.SHR:
x = emitConv(f, x, t)
// y may be signed or an 'untyped' constant.
- // TODO(adonovan): whence signed values?
- if b, ok := y.Type().Underlying().(*types.Basic); ok && b.Info()&types.IsUnsigned == 0 {
- y = emitConv(f, y, types.Typ[types.Uint64])
+
+ // There is a runtime panic if y is signed and <0. Instead of inserting a check for y<0
+ // and converting to an unsigned value (like the compiler) leave y as is.
+
+ if b, ok := y.Type().Underlying().(*types.Basic); ok && b.Info()&types.IsUntyped != 0 {
+ // Untyped conversion:
+ // Spec https://go.dev/ref/spec#Operators:
+ // The right operand in a shift expression must have integer type or be an untyped constant
+ // representable by a value of type uint.
+ y = emitConv(f, y, types.Typ[types.Uint])
}
case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
diff --git a/go/ssa/interp/interp_test.go b/go/ssa/interp/interp_test.go
index 28ebf5f..1b43742 100644
--- a/go/ssa/interp/interp_test.go
+++ b/go/ssa/interp/interp_test.go
@@ -109,6 +109,7 @@
var testdataTests = []string{
"boundmeth.go",
"complit.go",
+ "convert.go",
"coverage.go",
"defer.go",
"fieldprom.go",
diff --git a/go/ssa/interp/ops.go b/go/ssa/interp/ops.go
index 6af7847..3bc6a4e 100644
--- a/go/ssa/interp/ops.go
+++ b/go/ssa/interp/ops.go
@@ -137,6 +137,26 @@
panic(fmt.Sprintf("cannot convert %T to uint64", x))
}
+// asUnsigned returns the value of x, which must be an integer type, as its equivalent unsigned type,
+// and returns true if x is non-negative.
+func asUnsigned(x value) (value, bool) {
+ switch x := x.(type) {
+ case int:
+ return uint(x), x >= 0
+ case int8:
+ return uint8(x), x >= 0
+ case int16:
+ return uint16(x), x >= 0
+ case int32:
+ return uint32(x), x >= 0
+ case int64:
+ return uint64(x), x >= 0
+ case uint, uint8, uint32, uint64, uintptr:
+ return x, true
+ }
+ panic(fmt.Sprintf("cannot convert %T to unsigned", x))
+}
+
// zero returns a new "zero" value of the specified type.
func zero(t types.Type) value {
switch t := t.(type) {
@@ -576,7 +596,11 @@
}
case token.SHL:
- y := asUint64(y)
+ u, ok := asUnsigned(y)
+ if !ok {
+ panic("negative shift amount")
+ }
+ y := asUint64(u)
switch x.(type) {
case int:
return x.(int) << y
@@ -603,7 +627,11 @@
}
case token.SHR:
- y := asUint64(y)
+ u, ok := asUnsigned(y)
+ if !ok {
+ panic("negative shift amount")
+ }
+ y := asUint64(u)
switch x.(type) {
case int:
return x.(int) >> y
diff --git a/go/ssa/interp/testdata/convert.go b/go/ssa/interp/testdata/convert.go
new file mode 100644
index 0000000..0dcf13b
--- /dev/null
+++ b/go/ssa/interp/testdata/convert.go
@@ -0,0 +1,38 @@
+// 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.
+
+// Test conversion operations.
+
+package main
+
+func left(x int) { _ = 1 << x }
+func right(x int) { _ = 1 >> x }
+
+func main() {
+ wantPanic(
+ func() {
+ left(-1)
+ },
+ "runtime error: negative shift amount",
+ )
+ wantPanic(
+ func() {
+ right(-1)
+ },
+ "runtime error: negative shift amount",
+ )
+}
+
+func wantPanic(fn func(), s string) {
+ defer func() {
+ err := recover()
+ if err == nil {
+ panic("expected panic")
+ }
+ if got := err.(error).Error(); got != s {
+ panic("expected panic " + s + " got " + got)
+ }
+ }()
+ fn()
+}
diff --git a/go/types/typeutil/map.go b/go/types/typeutil/map.go
index 490ee90..c9f8f25 100644
--- a/go/types/typeutil/map.go
+++ b/go/types/typeutil/map.go
@@ -379,7 +379,7 @@
func (h Hasher) hashTuple(tuple *types.Tuple) uint32 {
// See go/types.identicalTypes for rationale.
n := tuple.Len()
- var hash uint32 = 9137 + 2*uint32(n)
+ hash := 9137 + 2*uint32(n)
for i := 0; i < n; i++ {
hash += 3 * h.Hash(tuple.At(i).Type())
}
@@ -398,7 +398,7 @@
}
func (h Hasher) hashTermSet(terms []*typeparams.Term) uint32 {
- var hash uint32 = 9157 + 2*uint32(len(terms))
+ hash := 9157 + 2*uint32(len(terms))
for _, term := range terms {
// term order is not significant.
termHash := h.Hash(term.Type())
@@ -416,14 +416,16 @@
// If h.sigTParams is set and contains t, then we are in the process of hashing
// a signature, and the hash value of t must depend only on t's index and
// constraint: signatures are considered identical modulo type parameter
-// renaming.
+// renaming. To avoid infinite recursion, we only hash the type parameter
+// index, and rely on types.Identical to handle signatures where constraints
+// are not identical.
//
// Otherwise the hash of t depends only on t's pointer identity.
func (h Hasher) hashTypeParam(t *typeparams.TypeParam) uint32 {
if h.sigTParams != nil {
i := t.Index()
if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) {
- return 9173 + 2*h.Hash(t.Constraint()) + 3*uint32(i)
+ return 9173 + 3*uint32(i)
}
}
return h.hashPtr(t.Obj())
diff --git a/go/types/typeutil/map_test.go b/go/types/typeutil/map_test.go
index 17f87ed..8cd643e 100644
--- a/go/types/typeutil/map_test.go
+++ b/go/types/typeutil/map_test.go
@@ -233,6 +233,17 @@
// ME1Type should have identical type as ME1.
var ME1Type func(G1[int], G1[int], G2[int])
+
+// Examples from issue #51314
+type Constraint[T any] interface{}
+func Foo[T Constraint[T]]() {}
+func Fn[T1 ~*T2, T2 ~*T1](t1 T1, t2 T2) {}
+
+// Bar and Baz are identical to Foo.
+func Bar[P Constraint[P]]() {}
+func Baz[Q any]() {} // The underlying type of Constraint[P] is any.
+// But Quux is not.
+func Quux[Q interface{ quux() }]() {}
`
fset := token.NewFileSet()
@@ -284,6 +295,13 @@
ME1 = scope.Lookup("ME1").Type()
ME1Type = scope.Lookup("ME1Type").Type()
ME2 = scope.Lookup("ME2").Type()
+
+ Constraint = scope.Lookup("Constraint").Type()
+ Foo = scope.Lookup("Foo").Type()
+ Fn = scope.Lookup("Fn").Type()
+ Bar = scope.Lookup("Foo").Type()
+ Baz = scope.Lookup("Foo").Type()
+ Quux = scope.Lookup("Quux").Type()
)
tmap := new(typeutil.Map)
@@ -345,6 +363,14 @@
{ME1, "ME1", true},
{ME1Type, "ME1Type", false},
{ME2, "ME2", true},
+
+ // See golang/go#51314: avoid infinite recursion on cyclic type constraints.
+ {Constraint, "Constraint", true},
+ {Foo, "Foo", true},
+ {Fn, "Fn", true},
+ {Bar, "Bar", false},
+ {Baz, "Baz", false},
+ {Quux, "Quux", true},
}
for _, step := range steps {
diff --git a/gopls/doc/advanced.md b/gopls/doc/advanced.md
index dfea673..c4e9eab 100644
--- a/gopls/doc/advanced.md
+++ b/gopls/doc/advanced.md
@@ -16,7 +16,8 @@
### Unstable versions
-To update `gopls` to the latest **unstable** version, use:
+To update `gopls` to the latest **unstable** version, use the following
+commands.
```sh
# Create an empty go.mod file, only for tracking requirements.
@@ -24,11 +25,8 @@
go mod init gopls-unstable
# Use 'go get' to add requirements and to ensure they work together.
-go get golang.org/x/tools/gopls@master golang.org/x/tools@master
+go get -d golang.org/x/tools/gopls@master golang.org/x/tools@master
-# For go1.17 or older, the above `go get` command will build and
-# install `gopls`. For go1.18+ or tip, run the following command to install
-# using selected versions in go.mod.
go install golang.org/x/tools/gopls
```
diff --git a/gopls/doc/analyzers.md b/gopls/doc/analyzers.md
index 121fa49..07f846d 100644
--- a/gopls/doc/analyzers.md
+++ b/gopls/doc/analyzers.md
@@ -574,7 +574,7 @@
check for constraints that could be simplified to "any"
-**Enabled by default.**
+**Disabled by default. Enable it by setting `"analyses": {"useany": true}`.**
## **fillreturns**
diff --git a/gopls/doc/commands.md b/gopls/doc/commands.md
index b70b0af..37a4ca4 100644
--- a/gopls/doc/commands.md
+++ b/gopls/doc/commands.md
@@ -84,6 +84,22 @@
}
```
+### **Run go mod edit -go=version**
+Identifier: `gopls.edit_go_directive`
+
+Runs `go mod edit -go=version` for a module.
+
+Args:
+
+```
+{
+ // Any document URI within the relevant module.
+ "URI": string,
+ // The version to pass to `go mod edit -go`.
+ "Version": string,
+}
+```
+
### **Toggle gc_details**
Identifier: `gopls.gc_details`
diff --git a/gopls/go.mod b/gopls/go.mod
index 8d28eb1..f31b95a 100644
--- a/gopls/go.mod
+++ b/gopls/go.mod
@@ -8,10 +8,10 @@
github.com/jba/templatecheck v0.6.0
github.com/sergi/go-diff v1.1.0
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3
- golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
+ golang.org/x/sys v0.0.0-20220209214540-3681064d5158
golang.org/x/tools v0.1.10-0.20220218151557-0d40b49f18b2
honnef.co/go/tools v0.2.2
- mvdan.cc/gofumpt v0.2.1
+ mvdan.cc/gofumpt v0.3.0
mvdan.cc/xurls/v2 v2.3.0
)
@@ -22,3 +22,5 @@
golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)
+
+replace golang.org/x/tools => ../
diff --git a/gopls/go.sum b/gopls/go.sum
index 19c76d9..74e0e84 100644
--- a/gopls/go.sum
+++ b/gopls/go.sum
@@ -5,9 +5,8 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
-github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
-github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns=
+github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/safehtml v0.0.2 h1:ZOt2VXg4x24bW0m2jtzAOkhoXV0iM8vNKc0paByCZqM=
@@ -62,9 +61,8 @@
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
-golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
+golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -91,7 +89,7 @@
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.2.2 h1:MNh1AVMyVX23VUHE2O27jm6lNj3vjO5DexS4A1xvnzk=
honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
-mvdan.cc/gofumpt v0.2.1 h1:7jakRGkQcLAJdT+C8Bwc9d0BANkVPSkHZkzNv07pJAs=
-mvdan.cc/gofumpt v0.2.1/go.mod h1:a/rvZPhsNaedOJBzqRD9omnwVwHZsBdJirXHa9Gh9Ig=
+mvdan.cc/gofumpt v0.3.0 h1:kTojdZo9AcEYbQYhGuLf/zszYthRdhDNDUi2JKTxas4=
+mvdan.cc/gofumpt v0.3.0/go.mod h1:0+VyGZWleeIj5oostkOex+nDBA0eyavuDnDusAJ8ylo=
mvdan.cc/xurls/v2 v2.3.0 h1:59Olnbt67UKpxF1EwVBopJvkSUBmgtb468E4GVWIZ1I=
mvdan.cc/xurls/v2 v2.3.0/go.mod h1:AjuTy7gEiUArFMjgBBDU4SMxlfUYsRokpJQgNWOt3e4=
diff --git a/gopls/integration/govim/run_local.sh b/gopls/integration/govim/run_local.sh
index b7aba5e..b5c284f 100755
--- a/gopls/integration/govim/run_local.sh
+++ b/gopls/integration/govim/run_local.sh
@@ -13,7 +13,7 @@
Args:
--sudo run docker with sudo
--short run `go test` with `-short`
- --version run on the specific tagged Go version (or latest) rather
+ --version run on the specific tagged govim version (or latest) rather
than the default branch
Run govim tests against HEAD using local docker.
@@ -71,7 +71,7 @@
${SUDO_IF_NEEDED}docker run --rm -t \
-v "${tools_dir}:/src/tools" \
-w "/src/tools/gopls" \
- golang:latest \
+ golang:rc \
go build -o $(basename ${temp_gopls})
# Build the test harness. Here we are careful to pass in a very limited build
diff --git a/gopls/internal/hooks/hooks.go b/gopls/internal/hooks/hooks.go
index 390967d..487fb60 100644
--- a/gopls/internal/hooks/hooks.go
+++ b/gopls/internal/hooks/hooks.go
@@ -22,8 +22,11 @@
options.ComputeEdits = ComputeEdits
}
options.URLRegexp = relaxedFullWord
- options.GofumptFormat = func(ctx context.Context, src []byte) ([]byte, error) {
- return format.Source(src, format.Options{})
+ options.GofumptFormat = func(ctx context.Context, langVersion, modulePath string, src []byte) ([]byte, error) {
+ return format.Source(src, format.Options{
+ LangVersion: langVersion,
+ ModulePath: modulePath,
+ })
}
updateAnalyzers(options)
}
diff --git a/gopls/internal/regtest/completion/completion_test.go b/gopls/internal/regtest/completion/completion_test.go
index 988d5c3..6abcd60 100644
--- a/gopls/internal/regtest/completion/completion_test.go
+++ b/gopls/internal/regtest/completion/completion_test.go
@@ -256,7 +256,7 @@
for i, v := range got {
if v != want[i] {
- return fmt.Sprintf("completion results are not the same: got %v, want %v", got, want)
+ return fmt.Sprintf("%d completion result not the same: got %q, want %q", i, v, want[i])
}
}
@@ -546,3 +546,56 @@
}
})
}
+
+func TestDefinition(t *testing.T) {
+ stuff := `
+-- go.mod --
+module mod.com
+
+go 1.18
+-- a_test.go --
+package foo
+func T()
+func TestG()
+func TestM()
+func TestMi()
+func Ben()
+func Fuz()
+func Testx()
+func TestMe(t *testing.T)
+func BenchmarkFoo()
+`
+ // All those parentheses are needed for the completion code to see
+ // later lines as being definitions
+ tests := []struct {
+ pat string
+ want []string
+ }{
+ {"T", []string{"TestXxx(t *testing.T)", "TestMain(m *testing.M)"}},
+ {"TestM", []string{"TestMain(m *testing.M)", "TestM(t *testing.T)"}},
+ {"TestMi", []string{"TestMi(t *testing.T)"}},
+ {"TestG", []string{"TestG(t *testing.T)"}},
+ {"B", []string{"BenchmarkXxx(b *testing.B)"}},
+ {"BenchmarkFoo", []string{"BenchmarkFoo(b *testing.B)"}},
+ {"F", []string{"FuzzXxx(f *testing.F)"}},
+ {"Testx", nil},
+ {"TestMe", []string{"TestMe"}},
+ }
+ fname := "a_test.go"
+ Run(t, stuff, func(t *testing.T, env *Env) {
+ env.OpenFile(fname)
+ env.Await(env.DoneWithOpen())
+ for _, tst := range tests {
+ pos := env.RegexpSearch(fname, tst.pat)
+ pos.Column += len(tst.pat)
+ completions := env.Completion(fname, pos)
+ result := compareCompletionResults(tst.want, completions.Items)
+ if result != "" {
+ t.Errorf("%s failed: %s:%q", tst.pat, result, tst.want)
+ for i, it := range completions.Items {
+ t.Errorf("%d got %q %q", i, it.Label, it.Detail)
+ }
+ }
+ }
+ })
+}
diff --git a/gopls/internal/regtest/misc/formatting_test.go b/gopls/internal/regtest/misc/formatting_test.go
index 67e7939..75d8f62 100644
--- a/gopls/internal/regtest/misc/formatting_test.go
+++ b/gopls/internal/regtest/misc/formatting_test.go
@@ -301,3 +301,69 @@
}
})
}
+
+func TestGofumptFormatting(t *testing.T) {
+
+ // Exercise some gofumpt formatting rules:
+ // - No empty lines following an assignment operator
+ // - Octal integer literals should use the 0o prefix on modules using Go
+ // 1.13 and later. Requires LangVersion to be correctly resolved.
+ // - std imports must be in a separate group at the top. Requires ModulePath
+ // to be correctly resolved.
+ const input = `
+-- go.mod --
+module foo
+
+go 1.17
+-- foo.go --
+package foo
+
+import (
+ "foo/bar"
+ "fmt"
+)
+
+const perm = 0755
+
+func foo() {
+ foo :=
+ "bar"
+ fmt.Println(foo, bar.Bar)
+}
+-- foo.go.formatted --
+package foo
+
+import (
+ "fmt"
+
+ "foo/bar"
+)
+
+const perm = 0o755
+
+func foo() {
+ foo := "bar"
+ fmt.Println(foo, bar.Bar)
+}
+-- bar/bar.go --
+package bar
+
+const Bar = 42
+`
+
+ WithOptions(
+ EditorConfig{
+ Settings: map[string]interface{}{
+ "gofumpt": true,
+ },
+ },
+ ).Run(t, input, func(t *testing.T, env *Env) {
+ env.OpenFile("foo.go")
+ env.FormatBuffer("foo.go")
+ got := env.Editor.BufferText("foo.go")
+ want := env.ReadWorkspaceFile("foo.go.formatted")
+ if got != want {
+ t.Errorf("unexpected formatting result:\n%s", tests.Diff(t, want, got))
+ }
+ })
+}
diff --git a/internal/gocommand/vendor.go b/internal/gocommand/vendor.go
index 5e75bd6..2d3d408 100644
--- a/internal/gocommand/vendor.go
+++ b/internal/gocommand/vendor.go
@@ -38,10 +38,10 @@
// with the supplied context.Context and Invocation. The Invocation can contain pre-defined fields,
// of which only Verb and Args are modified to run the appropriate Go command.
// Inspired by setDefaultBuildMod in modload/init.go
-func VendorEnabled(ctx context.Context, inv Invocation, r *Runner) (*ModuleJSON, bool, error) {
+func VendorEnabled(ctx context.Context, inv Invocation, r *Runner) (bool, *ModuleJSON, error) {
mainMod, go114, err := getMainModuleAnd114(ctx, inv, r)
if err != nil {
- return nil, false, err
+ return false, nil, err
}
// We check the GOFLAGS to see if there is anything overridden or not.
@@ -49,7 +49,7 @@
inv.Args = []string{"GOFLAGS"}
stdout, err := r.Run(ctx, inv)
if err != nil {
- return nil, false, err
+ return false, nil, err
}
goflags := string(bytes.TrimSpace(stdout.Bytes()))
matches := modFlagRegexp.FindStringSubmatch(goflags)
@@ -57,25 +57,27 @@
if len(matches) != 0 {
modFlag = matches[1]
}
- if modFlag != "" {
- // Don't override an explicit '-mod=' argument.
- return mainMod, modFlag == "vendor", nil
+ // Don't override an explicit '-mod=' argument.
+ if modFlag == "vendor" {
+ return true, mainMod, nil
+ } else if modFlag != "" {
+ return false, nil, nil
}
if mainMod == nil || !go114 {
- return mainMod, false, nil
+ return false, nil, nil
}
// Check 1.14's automatic vendor mode.
if fi, err := os.Stat(filepath.Join(mainMod.Dir, "vendor")); err == nil && fi.IsDir() {
if mainMod.GoVersion != "" && semver.Compare("v"+mainMod.GoVersion, "v1.14") >= 0 {
// The Go version is at least 1.14, and a vendor directory exists.
// Set -mod=vendor by default.
- return mainMod, true, nil
+ return true, mainMod, nil
}
}
- return mainMod, false, nil
+ return false, nil, nil
}
-// getMainModuleAnd114 gets the main module's information and whether the
+// getMainModuleAnd114 gets one of the main modules' information and whether the
// go command in use is 1.14+. This is the information needed to figure out
// if vendoring should be enabled.
func getMainModuleAnd114(ctx context.Context, inv Invocation, r *Runner) (*ModuleJSON, bool, error) {
diff --git a/internal/imports/mod.go b/internal/imports/mod.go
index dff6d55..2bcf41f 100644
--- a/internal/imports/mod.go
+++ b/internal/imports/mod.go
@@ -34,7 +34,8 @@
scannedRoots map[gopathwalk.Root]bool
initialized bool
- main *gocommand.ModuleJSON
+ mains []*gocommand.ModuleJSON
+ mainByDir map[string]*gocommand.ModuleJSON
modsByModPath []*gocommand.ModuleJSON // All modules, ordered by # of path components in module Path...
modsByDir []*gocommand.ModuleJSON // ...or Dir.
@@ -69,21 +70,21 @@
Logf: r.env.Logf,
WorkingDir: r.env.WorkingDir,
}
- mainMod, vendorEnabled, err := gocommand.VendorEnabled(context.TODO(), inv, r.env.GocmdRunner)
+ vendorEnabled, mainModVendor, err := gocommand.VendorEnabled(context.TODO(), inv, r.env.GocmdRunner)
if err != nil {
return err
}
- if mainMod != nil && vendorEnabled {
+ if mainModVendor != nil && vendorEnabled {
// Vendor mode is on, so all the non-Main modules are irrelevant,
// and we need to search /vendor for everything.
- r.main = mainMod
+ r.mains = []*gocommand.ModuleJSON{mainModVendor}
r.dummyVendorMod = &gocommand.ModuleJSON{
Path: "",
- Dir: filepath.Join(mainMod.Dir, "vendor"),
+ Dir: filepath.Join(mainModVendor.Dir, "vendor"),
}
- r.modsByModPath = []*gocommand.ModuleJSON{mainMod, r.dummyVendorMod}
- r.modsByDir = []*gocommand.ModuleJSON{mainMod, r.dummyVendorMod}
+ r.modsByModPath = []*gocommand.ModuleJSON{mainModVendor, r.dummyVendorMod}
+ r.modsByDir = []*gocommand.ModuleJSON{mainModVendor, r.dummyVendorMod}
} else {
// Vendor mode is off, so run go list -m ... to find everything.
err := r.initAllMods()
@@ -122,8 +123,10 @@
r.roots = []gopathwalk.Root{
{filepath.Join(goenv["GOROOT"], "/src"), gopathwalk.RootGOROOT},
}
- if r.main != nil {
- r.roots = append(r.roots, gopathwalk.Root{r.main.Dir, gopathwalk.RootCurrentModule})
+ r.mainByDir = make(map[string]*gocommand.ModuleJSON)
+ for _, main := range r.mains {
+ r.roots = append(r.roots, gopathwalk.Root{main.Dir, gopathwalk.RootCurrentModule})
+ r.mainByDir[main.Dir] = main
}
if vendorEnabled {
r.roots = append(r.roots, gopathwalk.Root{r.dummyVendorMod.Dir, gopathwalk.RootOther})
@@ -189,7 +192,7 @@
r.modsByModPath = append(r.modsByModPath, mod)
r.modsByDir = append(r.modsByDir, mod)
if mod.Main {
- r.main = mod
+ r.mains = append(r.mains, mod)
}
}
return nil
@@ -609,7 +612,7 @@
}
switch root.Type {
case gopathwalk.RootCurrentModule:
- importPath = path.Join(r.main.Path, filepath.ToSlash(subdir))
+ importPath = path.Join(r.mainByDir[root.Path].Path, filepath.ToSlash(subdir))
case gopathwalk.RootModuleCache:
matches := modCacheRegexp.FindStringSubmatch(subdir)
if len(matches) == 0 {
diff --git a/internal/imports/mod_test.go b/internal/imports/mod_test.go
index 51bc967..5f71805 100644
--- a/internal/imports/mod_test.go
+++ b/internal/imports/mod_test.go
@@ -552,6 +552,336 @@
mt.assertModuleFoundInDir("example.com/vv", "v", `main/v12$`)
}
+// Tests that go.work files are respected.
+func TestModWorkspace(t *testing.T) {
+ testenv.NeedsGo1Point(t, 18)
+
+ mt := setup(t, `
+-- go.work --
+go 1.18
+
+use (
+ ./a
+ ./b
+)
+-- a/go.mod --
+module example.com/a
+
+go 1.18
+-- a/a.go --
+package a
+-- b/go.mod --
+module example.com/b
+
+go 1.18
+-- b/b.go --
+package b
+`, "")
+ defer mt.cleanup()
+
+ mt.assertModuleFoundInDir("example.com/a", "a", `main/a$`)
+ mt.assertModuleFoundInDir("example.com/b", "b", `main/b$`)
+ mt.assertScanFinds("example.com/a", "a")
+ mt.assertScanFinds("example.com/b", "b")
+}
+
+// Tests replaces in workspaces. Uses the directory layout in the cmd/go
+// work_replace test. It tests both that replaces in go.work files are
+// respected and that a wildcard replace in go.work overrides a versioned replace
+// in go.mod.
+func TestModWorkspaceReplace(t *testing.T) {
+ testenv.NeedsGo1Point(t, 18)
+
+ mt := setup(t, `
+-- go.work --
+use m
+
+replace example.com/dep => ./dep
+replace example.com/other => ./other2
+
+-- m/go.mod --
+module example.com/m
+
+require example.com/dep v1.0.0
+require example.com/other v1.0.0
+
+replace example.com/other v1.0.0 => ./other
+-- m/m.go --
+package m
+
+import "example.com/dep"
+import "example.com/other"
+
+func F() {
+ dep.G()
+ other.H()
+}
+-- dep/go.mod --
+module example.com/dep
+-- dep/dep.go --
+package dep
+
+func G() {
+}
+-- other/go.mod --
+module example.com/other
+-- other/dep.go --
+package other
+
+func G() {
+}
+-- other2/go.mod --
+module example.com/other
+-- other2/dep.go --
+package other2
+
+func G() {
+}
+`, "")
+ defer mt.cleanup()
+
+ mt.assertScanFinds("example.com/m", "m")
+ mt.assertScanFinds("example.com/dep", "dep")
+ mt.assertModuleFoundInDir("example.com/other", "other2", "main/other2$")
+ mt.assertScanFinds("example.com/other", "other2")
+}
+
+// Tests a case where conflicting replaces are overridden by a replace
+// in the go.work file.
+func TestModWorkspaceReplaceOverride(t *testing.T) {
+ testenv.NeedsGo1Point(t, 18)
+
+ mt := setup(t, `-- go.work --
+use m
+use n
+replace example.com/dep => ./dep3
+-- m/go.mod --
+module example.com/m
+
+require example.com/dep v1.0.0
+replace example.com/dep => ./dep1
+-- m/m.go --
+package m
+
+import "example.com/dep"
+
+func F() {
+ dep.G()
+}
+-- n/go.mod --
+module example.com/n
+
+require example.com/dep v1.0.0
+replace example.com/dep => ./dep2
+-- n/n.go --
+package n
+
+import "example.com/dep"
+
+func F() {
+ dep.G()
+}
+-- dep1/go.mod --
+module example.com/dep
+-- dep1/dep.go --
+package dep
+
+func G() {
+}
+-- dep2/go.mod --
+module example.com/dep
+-- dep2/dep.go --
+package dep
+
+func G() {
+}
+-- dep3/go.mod --
+module example.com/dep
+-- dep3/dep.go --
+package dep
+
+func G() {
+}
+`, "")
+
+ mt.assertScanFinds("example.com/m", "m")
+ mt.assertScanFinds("example.com/n", "n")
+ mt.assertScanFinds("example.com/dep", "dep")
+ mt.assertModuleFoundInDir("example.com/dep", "dep", "main/dep3$")
+}
+
+// Tests that the correct versions of modules are found in
+// workspaces with module pruning. This is based on the
+// cmd/go mod_prune_all script test.
+func TestModWorkspacePrune(t *testing.T) {
+ testenv.NeedsGo1Point(t, 18)
+
+ mt := setup(t, `
+-- go.work --
+go 1.18
+
+use (
+ ./a
+ ./p
+)
+
+replace example.com/b v1.0.0 => ./b
+replace example.com/q v1.0.0 => ./q1_0_0
+replace example.com/q v1.0.5 => ./q1_0_5
+replace example.com/q v1.1.0 => ./q1_1_0
+replace example.com/r v1.0.0 => ./r
+replace example.com/w v1.0.0 => ./w
+replace example.com/x v1.0.0 => ./x
+replace example.com/y v1.0.0 => ./y
+replace example.com/z v1.0.0 => ./z1_0_0
+replace example.com/z v1.1.0 => ./z1_1_0
+
+-- a/go.mod --
+module example.com/a
+
+go 1.18
+
+require example.com/b v1.0.0
+require example.com/z v1.0.0
+-- a/foo.go --
+package main
+
+import "example.com/b"
+
+func main() {
+ b.B()
+}
+-- b/go.mod --
+module example.com/b
+
+go 1.18
+
+require example.com/q v1.1.0
+-- b/b.go --
+package b
+
+func B() {
+}
+-- p/go.mod --
+module example.com/p
+
+go 1.18
+
+require example.com/q v1.0.0
+
+replace example.com/q v1.0.0 => ../q1_0_0
+replace example.com/q v1.1.0 => ../q1_1_0
+-- p/main.go --
+package main
+
+import "example.com/q"
+
+func main() {
+ q.PrintVersion()
+}
+-- q1_0_0/go.mod --
+module example.com/q
+
+go 1.18
+-- q1_0_0/q.go --
+package q
+
+import "fmt"
+
+func PrintVersion() {
+ fmt.Println("version 1.0.0")
+}
+-- q1_0_5/go.mod --
+module example.com/q
+
+go 1.18
+
+require example.com/r v1.0.0
+-- q1_0_5/q.go --
+package q
+
+import _ "example.com/r"
+-- q1_1_0/go.mod --
+module example.com/q
+
+require example.com/w v1.0.0
+require example.com/z v1.1.0
+
+go 1.18
+-- q1_1_0/q.go --
+package q
+
+import _ "example.com/w"
+import _ "example.com/z"
+
+import "fmt"
+
+func PrintVersion() {
+ fmt.Println("version 1.1.0")
+}
+-- r/go.mod --
+module example.com/r
+
+go 1.18
+
+require example.com/r v1.0.0
+-- r/r.go --
+package r
+-- w/go.mod --
+module example.com/w
+
+go 1.18
+
+require example.com/x v1.0.0
+-- w/w.go --
+package w
+-- w/w_test.go --
+package w
+
+import _ "example.com/x"
+-- x/go.mod --
+module example.com/x
+
+go 1.18
+-- x/x.go --
+package x
+-- x/x_test.go --
+package x
+import _ "example.com/y"
+-- y/go.mod --
+module example.com/y
+
+go 1.18
+-- y/y.go --
+package y
+-- z1_0_0/go.mod --
+module example.com/z
+
+go 1.18
+
+require example.com/q v1.0.5
+-- z1_0_0/z.go --
+package z
+
+import _ "example.com/q"
+-- z1_1_0/go.mod --
+module example.com/z
+
+go 1.18
+-- z1_1_0/z.go --
+package z
+`, "")
+
+ mt.assertScanFinds("example.com/w", "w")
+ mt.assertScanFinds("example.com/q", "q")
+ mt.assertScanFinds("example.com/x", "x")
+ mt.assertScanFinds("example.com/z", "z")
+ mt.assertModuleFoundInDir("example.com/w", "w", "main/w$")
+ mt.assertModuleFoundInDir("example.com/q", "q", "main/q1_1_0$")
+ mt.assertModuleFoundInDir("example.com/x", "x", "main/x$")
+ mt.assertModuleFoundInDir("example.com/z", "z", "main/z1_1_0$")
+}
+
// Tests that we handle GO111MODULE=on with no go.mod file. See #30855.
func TestNoMainModule(t *testing.T) {
testenv.NeedsGo1Point(t, 12)
diff --git a/internal/lsp/cache/check.go b/internal/lsp/cache/check.go
index 6163816..f166863 100644
--- a/internal/lsp/cache/check.go
+++ b/internal/lsp/cache/check.go
@@ -194,7 +194,7 @@
depKeys = append(depKeys, depHandle.key)
}
experimentalKey := s.View().Options().ExperimentalPackageCacheKey
- ph.key = checkPackageKey(ph.m.ID, compiledGoFiles, m.Config, depKeys, mode, experimentalKey)
+ ph.key = checkPackageKey(ph.m.ID, compiledGoFiles, m, depKeys, mode, experimentalKey)
return ph, deps, nil
}
@@ -214,15 +214,18 @@
return source.ParseExported
}
-func checkPackageKey(id PackageID, pghs []*parseGoHandle, cfg *packages.Config, deps []packageHandleKey, mode source.ParseMode, experimentalKey bool) packageHandleKey {
+func checkPackageKey(id PackageID, pghs []*parseGoHandle, m *KnownMetadata, deps []packageHandleKey, mode source.ParseMode, experimentalKey bool) packageHandleKey {
b := bytes.NewBuffer(nil)
b.WriteString(string(id))
+ if m.Module != nil {
+ b.WriteString(m.Module.GoVersion) // go version affects type check errors.
+ }
if !experimentalKey {
// cfg was used to produce the other hashed inputs (package ID, parsed Go
// files, and deps). It should not otherwise affect the inputs to the type
// checker, so this experiment omits it. This should increase cache hits on
// the daemon as cfg contains the environment and working directory.
- b.WriteString(hashConfig(cfg))
+ b.WriteString(hashConfig(m.Config))
}
b.WriteByte(byte(mode))
for _, dep := range deps {
diff --git a/internal/lsp/cache/errors.go b/internal/lsp/cache/errors.go
index 6790938..155b7a4 100644
--- a/internal/lsp/cache/errors.go
+++ b/internal/lsp/cache/errors.go
@@ -101,6 +101,7 @@
}
var importErrorRe = regexp.MustCompile(`could not import ([^\s]+)`)
+var unsupportedFeatureRe = regexp.MustCompile(`.*require go(\d+\.\d+) or later`)
func typeErrorDiagnostics(snapshot *snapshot, pkg *pkg, e extendedError) ([]*source.Diagnostic, error) {
code, spn, err := typeErrorData(snapshot.FileSet(), pkg, e.primary)
@@ -145,6 +146,14 @@
return nil, err
}
}
+ if code == typesinternal.UnsupportedFeature {
+ if match := unsupportedFeatureRe.FindStringSubmatch(e.primary.Msg); match != nil {
+ diag.SuggestedFixes, err = editGoDirectiveQuickFix(snapshot, spn.URI(), match[1])
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
return []*source.Diagnostic{diag}, nil
}
@@ -165,6 +174,22 @@
return []source.SuggestedFix{source.SuggestedFixFromCommand(cmd, protocol.QuickFix)}, nil
}
+func editGoDirectiveQuickFix(snapshot *snapshot, uri span.URI, version string) ([]source.SuggestedFix, error) {
+ // Go mod edit only supports module mode.
+ if snapshot.workspaceMode()&moduleMode == 0 {
+ return nil, nil
+ }
+ title := fmt.Sprintf("go mod edit -go=%s", version)
+ cmd, err := command.NewEditGoDirectiveCommand(title, command.EditGoDirectiveArgs{
+ URI: protocol.URIFromSpanURI(uri),
+ Version: version,
+ })
+ if err != nil {
+ return nil, err
+ }
+ return []source.SuggestedFix{source.SuggestedFixFromCommand(cmd, protocol.QuickFix)}, nil
+}
+
func analysisDiagnosticDiagnostics(snapshot *snapshot, pkg *pkg, a *analysis.Analyzer, e *analysis.Diagnostic) ([]*source.Diagnostic, error) {
var srcAnalyzer *source.Analyzer
// Find the analyzer that generated this diagnostic.
diff --git a/internal/lsp/cache/metadata.go b/internal/lsp/cache/metadata.go
index bef7bf8..618578d 100644
--- a/internal/lsp/cache/metadata.go
+++ b/internal/lsp/cache/metadata.go
@@ -56,6 +56,11 @@
return string(m.PkgPath)
}
+// ModuleInfo implements the source.Metadata interface.
+func (m *Metadata) ModuleInfo() *packages.Module {
+ return m.Module
+}
+
// KnownMetadata is a wrapper around metadata that tracks its validity.
type KnownMetadata struct {
*Metadata
diff --git a/internal/lsp/cache/snapshot.go b/internal/lsp/cache/snapshot.go
index b9cd36c..e786c02 100644
--- a/internal/lsp/cache/snapshot.go
+++ b/internal/lsp/cache/snapshot.go
@@ -1025,7 +1025,11 @@
var mds []source.Metadata
for _, id := range knownIDs {
md := s.getMetadata(id)
- mds = append(mds, md)
+ // TODO(rfindley): knownIDs and metadata should be in sync, but existing
+ // code is defensive of nil metadata.
+ if md != nil {
+ mds = append(mds, md)
+ }
}
return mds, nil
}
diff --git a/internal/lsp/command.go b/internal/lsp/command.go
index d8f9d2c..e9d61d5 100644
--- a/internal/lsp/command.go
+++ b/internal/lsp/command.go
@@ -261,6 +261,20 @@
})
}
+func (c *commandHandler) EditGoDirective(ctx context.Context, args command.EditGoDirectiveArgs) error {
+ return c.run(ctx, commandConfig{
+ requireSave: true, // if go.mod isn't saved it could cause a problem
+ forURI: args.URI,
+ }, func(ctx context.Context, deps commandDeps) error {
+ _, err := deps.snapshot.RunGoCommandDirect(ctx, source.Normal, &gocommand.Invocation{
+ Verb: "mod",
+ Args: []string{"edit", "-go", args.Version},
+ WorkingDir: filepath.Dir(args.URI.SpanURI().Filename()),
+ })
+ return err
+ })
+}
+
func (c *commandHandler) RemoveDependency(ctx context.Context, args command.RemoveDependencyArgs) error {
return c.run(ctx, commandConfig{
progress: "Removing dependency",
diff --git a/internal/lsp/command/command_gen.go b/internal/lsp/command/command_gen.go
index c814bfe..5569693 100644
--- a/internal/lsp/command/command_gen.go
+++ b/internal/lsp/command/command_gen.go
@@ -23,6 +23,7 @@
AddImport Command = "add_import"
ApplyFix Command = "apply_fix"
CheckUpgrades Command = "check_upgrades"
+ EditGoDirective Command = "edit_go_directive"
GCDetails Command = "gc_details"
Generate Command = "generate"
GenerateGoplsMod Command = "generate_gopls_mod"
@@ -46,6 +47,7 @@
AddImport,
ApplyFix,
CheckUpgrades,
+ EditGoDirective,
GCDetails,
Generate,
GenerateGoplsMod,
@@ -90,6 +92,12 @@
return nil, err
}
return nil, s.CheckUpgrades(ctx, a0)
+ case "gopls.edit_go_directive":
+ var a0 EditGoDirectiveArgs
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ return nil, s.EditGoDirective(ctx, a0)
case "gopls.gc_details":
var a0 protocol.DocumentURI
if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
@@ -240,6 +248,18 @@
}, nil
}
+func NewEditGoDirectiveCommand(title string, a0 EditGoDirectiveArgs) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.edit_go_directive",
+ Arguments: args,
+ }, nil
+}
+
func NewGCDetailsCommand(title string, a0 protocol.DocumentURI) (protocol.Command, error) {
args, err := MarshalArgs(a0)
if err != nil {
diff --git a/internal/lsp/command/interface.go b/internal/lsp/command/interface.go
index d5f520d..6058c72 100644
--- a/internal/lsp/command/interface.go
+++ b/internal/lsp/command/interface.go
@@ -68,6 +68,11 @@
// Runs `go mod vendor` for a module.
Vendor(context.Context, URIArg) error
+ // EditGoDirective: Run go mod edit -go=version
+ //
+ // Runs `go mod edit -go=version` for a module.
+ EditGoDirective(context.Context, EditGoDirectiveArgs) error
+
// UpdateGoSum: Update go.sum
//
// Updates the go.sum file for a module.
@@ -204,6 +209,13 @@
OnlyDiagnostic bool
}
+type EditGoDirectiveArgs struct {
+ // Any document URI within the relevant module.
+ URI protocol.DocumentURI
+ // The version to pass to `go mod edit -go`.
+ Version string
+}
+
type GoGetPackageArgs struct {
// Any document URI within the relevant module.
URI protocol.DocumentURI
diff --git a/internal/lsp/diagnostics.go b/internal/lsp/diagnostics.go
index f4b0064..e352e4b 100644
--- a/internal/lsp/diagnostics.go
+++ b/internal/lsp/diagnostics.go
@@ -288,7 +288,11 @@
return
}
for _, cgf := range pkg.CompiledGoFiles() {
- s.storeDiagnostics(snapshot, cgf.URI, typeCheckSource, pkgDiagnostics[cgf.URI])
+ // builtin.go exists only for documentation purposes, and is not valid Go code.
+ // Don't report distracting errors
+ if !snapshot.IsBuiltin(ctx, cgf.URI) {
+ s.storeDiagnostics(snapshot, cgf.URI, typeCheckSource, pkgDiagnostics[cgf.URI])
+ }
}
if includeAnalysis && !pkg.HasListOrParseErrors() {
reports, err := source.Analyze(ctx, snapshot, pkg, false)
diff --git a/internal/lsp/source/api_json.go b/internal/lsp/source/api_json.go
index 4742fb1..f37cc80 100755
--- a/internal/lsp/source/api_json.go
+++ b/internal/lsp/source/api_json.go
@@ -406,7 +406,7 @@
{
Name: "\"useany\"",
Doc: "check for constraints that could be simplified to \"any\"",
- Default: "true",
+ Default: "false",
},
{
Name: "\"fillreturns\"",
@@ -604,6 +604,12 @@
ArgDoc: "{\n\t// The go.mod file URI.\n\t\"URI\": string,\n\t// The modules to check.\n\t\"Modules\": []string,\n}",
},
{
+ Command: "gopls.edit_go_directive",
+ Title: "Run go mod edit -go=version",
+ Doc: "Runs `go mod edit -go=version` for a module.",
+ ArgDoc: "{\n\t// Any document URI within the relevant module.\n\t\"URI\": string,\n\t// The version to pass to `go mod edit -go`.\n\t\"Version\": string,\n}",
+ },
+ {
Command: "gopls.gc_details",
Title: "Toggle gc_details",
Doc: "Toggle the calculation of gc annotations.",
@@ -922,9 +928,8 @@
Doc: "checks for unused writes\n\nThe analyzer reports instances of writes to struct fields and\narrays that are never read. Specifically, when a struct object\nor an array is copied, its elements are copied implicitly by\nthe compiler, and any element write to this copy does nothing\nwith the original object.\n\nFor example:\n\n\ttype T struct { x int }\n\tfunc f(input []T) {\n\t\tfor i, v := range input { // v is a copy\n\t\t\tv.x = i // unused write to field x\n\t\t}\n\t}\n\nAnother example is about non-pointer receiver:\n\n\ttype T struct { x int }\n\tfunc (t T) f() { // t is a copy\n\t\tt.x = i // unused write to field x\n\t}\n",
},
{
- Name: "useany",
- Doc: "check for constraints that could be simplified to \"any\"",
- Default: true,
+ Name: "useany",
+ Doc: "check for constraints that could be simplified to \"any\"",
},
{
Name: "fillreturns",
diff --git a/internal/lsp/source/completion/completion.go b/internal/lsp/source/completion/completion.go
index 94389c7..30d277f 100644
--- a/internal/lsp/source/completion/completion.go
+++ b/internal/lsp/source/completion/completion.go
@@ -485,6 +485,13 @@
qual := types.RelativeTo(pkg.GetTypes())
objStr = types.ObjectString(obj, qual)
}
+ ans, sel := definition(path, obj, snapshot.FileSet(), pgf.Mapper, fh)
+ if ans != nil {
+ sort.Slice(ans, func(i, j int) bool {
+ return ans[i].Score > ans[j].Score
+ })
+ return ans, sel, nil
+ }
return nil, nil, ErrIsDefinition{objStr: objStr}
}
}
diff --git a/internal/lsp/source/completion/definition.go b/internal/lsp/source/completion/definition.go
new file mode 100644
index 0000000..17b251c
--- /dev/null
+++ b/internal/lsp/source/completion/definition.go
@@ -0,0 +1,127 @@
+// 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 completion
+
+import (
+ "go/ast"
+ "go/token"
+ "go/types"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+
+ "golang.org/x/tools/internal/lsp/protocol"
+ "golang.org/x/tools/internal/lsp/snippet"
+ "golang.org/x/tools/internal/lsp/source"
+)
+
+// some definitions can be completed
+// So far, TestFoo(t *testing.T), TestMain(m *testing.M)
+// BenchmarkFoo(b *testing.B), FuzzFoo(f *testing.F)
+
+// path[0] is known to be *ast.Ident
+func definition(path []ast.Node, obj types.Object, fset *token.FileSet, mapper *protocol.ColumnMapper, fh source.FileHandle) ([]CompletionItem, *Selection) {
+ if _, ok := obj.(*types.Func); !ok {
+ return nil, nil // not a function at all
+ }
+ if !strings.HasSuffix(fh.URI().Filename(), "_test.go") {
+ return nil, nil
+ }
+
+ name := path[0].(*ast.Ident).Name
+ if len(name) == 0 {
+ // can't happen
+ return nil, nil
+ }
+ pos := path[0].Pos()
+ sel := &Selection{
+ content: "",
+ cursor: pos,
+ MappedRange: source.NewMappedRange(fset, mapper, pos, pos),
+ }
+ var ans []CompletionItem
+
+ // Always suggest TestMain, if possible
+ if strings.HasPrefix("TestMain", name) {
+ ans = []CompletionItem{defItem("TestMain(m *testing.M)", obj)}
+ }
+
+ // If a snippet is possible, suggest it
+ if strings.HasPrefix("Test", name) {
+ ans = append(ans, defSnippet("Test", "Xxx", "(t *testing.T)", obj))
+ return ans, sel
+ } else if strings.HasPrefix("Benchmark", name) {
+ ans = append(ans, defSnippet("Benchmark", "Xxx", "(b *testing.B)", obj))
+ return ans, sel
+ } else if strings.HasPrefix("Fuzz", name) {
+ ans = append(ans, defSnippet("Fuzz", "Xxx", "(f *testing.F)", obj))
+ return ans, sel
+ }
+
+ // Fill in the argument for what the user has already typed
+ if got := defMatches(name, "Test", path, "(t *testing.T)"); got != "" {
+ ans = append(ans, defItem(got, obj))
+ } else if got := defMatches(name, "Benchmark", path, "(b *testing.B)"); got != "" {
+ ans = append(ans, defItem(got, obj))
+ } else if got := defMatches(name, "Fuzz", path, "(f *testing.F)"); got != "" {
+ ans = append(ans, defItem(got, obj))
+ }
+ return ans, sel
+}
+
+func defMatches(name, pat string, path []ast.Node, arg string) string {
+ idx := strings.Index(name, pat)
+ if idx < 0 {
+ return ""
+ }
+ c, _ := utf8.DecodeRuneInString(name[len(pat):])
+ if unicode.IsLower(c) {
+ return ""
+ }
+ fd, ok := path[1].(*ast.FuncDecl)
+ if !ok {
+ // we don't know what's going on
+ return ""
+ }
+ fp := fd.Type.Params
+ if fp != nil && len(fp.List) > 0 {
+ // signature already there, minimal suggestion
+ return name
+ }
+ // suggesting signature too
+ return name + arg
+}
+
+func defSnippet(prefix, placeholder, suffix string, obj types.Object) CompletionItem {
+ var sn snippet.Builder
+ sn.WriteText(prefix)
+ if placeholder != "" {
+ sn.WritePlaceholder(func(b *snippet.Builder) { b.WriteText(placeholder) })
+ }
+ sn.WriteText(suffix + " {\n")
+ sn.WriteFinalTabstop()
+ sn.WriteText("\n}")
+ return CompletionItem{
+ Label: prefix + placeholder + suffix,
+ Detail: "tab, type the rest of the name, then tab",
+ Kind: protocol.FunctionCompletion,
+ Depth: 0,
+ Score: 10,
+ snippet: &sn,
+ Documentation: prefix + " test function",
+ obj: obj,
+ }
+}
+func defItem(val string, obj types.Object) CompletionItem {
+ return CompletionItem{
+ Label: val,
+ InsertText: val,
+ Kind: protocol.FunctionCompletion,
+ Depth: 0,
+ Score: 9, // prefer the snippets when available
+ Documentation: "complete the parameter",
+ obj: obj,
+ }
+}
diff --git a/internal/lsp/source/format.go b/internal/lsp/source/format.go
index 4f02e4f..79da0b3 100644
--- a/internal/lsp/source/format.go
+++ b/internal/lsp/source/format.go
@@ -63,8 +63,24 @@
// Apply additional formatting, if any is supported. Currently, the only
// supported additional formatter is gofumpt.
- if format := snapshot.View().Options().Hooks.GofumptFormat; snapshot.View().Options().Gofumpt && format != nil {
- b, err := format(ctx, buf.Bytes())
+ if format := snapshot.View().Options().GofumptFormat; snapshot.View().Options().Gofumpt && format != nil {
+ // gofumpt can customize formatting based on language version and module
+ // path, if available.
+ //
+ // Try to derive this information, but fall-back on the default behavior.
+ //
+ // TODO: under which circumstances can we fail to find module information?
+ // Can this, for example, result in inconsistent formatting across saves,
+ // due to pending calls to packages.Load?
+ var langVersion, modulePath string
+ mds, err := snapshot.MetadataForFile(ctx, fh.URI())
+ if err == nil && len(mds) > 0 {
+ if mi := mds[0].ModuleInfo(); mi != nil {
+ langVersion = mi.GoVersion
+ modulePath = mi.Path
+ }
+ }
+ b, err := format(ctx, langVersion, modulePath, buf.Bytes())
if err != nil {
return nil, err
}
diff --git a/internal/lsp/source/options.go b/internal/lsp/source/options.go
index 139ae70..b1df290 100644
--- a/internal/lsp/source/options.go
+++ b/internal/lsp/source/options.go
@@ -462,11 +462,16 @@
// Hooks contains configuration that is provided to the Gopls command by the
// main package.
type Hooks struct {
- LicensesText string
- GoDiff bool
- ComputeEdits diff.ComputeEdits
- URLRegexp *regexp.Regexp
- GofumptFormat func(ctx context.Context, src []byte) ([]byte, error)
+ LicensesText string
+ GoDiff bool
+ ComputeEdits diff.ComputeEdits
+ URLRegexp *regexp.Regexp
+
+ // GofumptFormat allows the gopls module to wire-in a call to
+ // gofumpt/format.Source. langVersion and modulePath are used for some
+ // Gofumpt formatting rules -- see the Gofumpt documentation for details.
+ GofumptFormat func(ctx context.Context, langVersion, modulePath string, src []byte) ([]byte, error)
+
DefaultAnalyzers map[string]*Analyzer
TypeErrorAnalyzers map[string]*Analyzer
ConvenienceAnalyzers map[string]*Analyzer
@@ -694,8 +699,8 @@
ClientOptions: o.ClientOptions,
InternalOptions: o.InternalOptions,
Hooks: Hooks{
- GoDiff: o.Hooks.GoDiff,
- ComputeEdits: o.Hooks.ComputeEdits,
+ GoDiff: o.GoDiff,
+ ComputeEdits: o.ComputeEdits,
GofumptFormat: o.GofumptFormat,
URLRegexp: o.URLRegexp,
},
@@ -1265,7 +1270,7 @@
testinggoroutine.Analyzer.Name: {Analyzer: testinggoroutine.Analyzer, Enabled: true},
unusedparams.Analyzer.Name: {Analyzer: unusedparams.Analyzer, Enabled: false},
unusedwrite.Analyzer.Name: {Analyzer: unusedwrite.Analyzer, Enabled: false},
- useany.Analyzer.Name: {Analyzer: useany.Analyzer, Enabled: true},
+ useany.Analyzer.Name: {Analyzer: useany.Analyzer, Enabled: false},
infertypeargs.Analyzer.Name: {Analyzer: infertypeargs.Analyzer, Enabled: true},
// gofmt -s suite:
diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go
index dba45f7..9e9b035 100644
--- a/internal/lsp/source/view.go
+++ b/internal/lsp/source/view.go
@@ -18,6 +18,7 @@
"golang.org/x/mod/modfile"
"golang.org/x/mod/module"
"golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/gocommand"
"golang.org/x/tools/internal/imports"
"golang.org/x/tools/internal/lsp/progress"
@@ -319,6 +320,9 @@
// PackagePath is the package path.
PackagePath() string
+
+ // ModuleInfo returns the go/packages module information for the given package.
+ ModuleInfo() *packages.Module
}
// Session represents a single connection from a client.
diff --git a/internal/typesinternal/errorcode.go b/internal/typesinternal/errorcode.go
index fa2834e..d38ee3c 100644
--- a/internal/typesinternal/errorcode.go
+++ b/internal/typesinternal/errorcode.go
@@ -1365,4 +1365,162 @@
// return i
// }
InvalidGo
+
+ // All codes below were added in Go 1.17.
+
+ /* decl */
+
+ // BadDecl occurs when a declaration has invalid syntax.
+ BadDecl
+
+ // RepeatedDecl occurs when an identifier occurs more than once on the left
+ // hand side of a short variable declaration.
+ //
+ // Example:
+ // func _() {
+ // x, y, y := 1, 2, 3
+ // }
+ RepeatedDecl
+
+ /* unsafe */
+
+ // InvalidUnsafeAdd occurs when unsafe.Add is called with a
+ // length argument that is not of integer type.
+ //
+ // Example:
+ // import "unsafe"
+ //
+ // var p unsafe.Pointer
+ // var _ = unsafe.Add(p, float64(1))
+ InvalidUnsafeAdd
+
+ // InvalidUnsafeSlice occurs when unsafe.Slice is called with a
+ // pointer argument that is not of pointer type or a length argument
+ // that is not of integer type, negative, or out of bounds.
+ //
+ // Example:
+ // import "unsafe"
+ //
+ // var x int
+ // var _ = unsafe.Slice(x, 1)
+ //
+ // Example:
+ // import "unsafe"
+ //
+ // var x int
+ // var _ = unsafe.Slice(&x, float64(1))
+ //
+ // Example:
+ // import "unsafe"
+ //
+ // var x int
+ // var _ = unsafe.Slice(&x, -1)
+ //
+ // Example:
+ // import "unsafe"
+ //
+ // var x int
+ // var _ = unsafe.Slice(&x, uint64(1) << 63)
+ InvalidUnsafeSlice
+
+ // All codes below were added in Go 1.18.
+
+ /* features */
+
+ // UnsupportedFeature occurs when a language feature is used that is not
+ // supported at this Go version.
+ UnsupportedFeature
+
+ /* type params */
+
+ // NotAGenericType occurs when a non-generic type is used where a generic
+ // type is expected: in type or function instantiation.
+ //
+ // Example:
+ // type T int
+ //
+ // var _ T[int]
+ NotAGenericType
+
+ // WrongTypeArgCount occurs when a type or function is instantiated with an
+ // incorrent number of type arguments, including when a generic type or
+ // function is used without instantiation.
+ //
+ // Errors inolving failed type inference are assigned other error codes.
+ //
+ // Example:
+ // type T[p any] int
+ //
+ // var _ T[int, string]
+ //
+ // Example:
+ // func f[T any]() {}
+ //
+ // var x = f
+ WrongTypeArgCount
+
+ // CannotInferTypeArgs occurs when type or function type argument inference
+ // fails to infer all type arguments.
+ //
+ // Example:
+ // func f[T any]() {}
+ //
+ // func _() {
+ // f()
+ // }
+ //
+ // Example:
+ // type N[P, Q any] struct{}
+ //
+ // var _ N[int]
+ CannotInferTypeArgs
+
+ // InvalidTypeArg occurs when a type argument does not satisfy its
+ // corresponding type parameter constraints.
+ //
+ // Example:
+ // type T[P ~int] struct{}
+ //
+ // var _ T[string]
+ InvalidTypeArg // arguments? InferenceFailed
+
+ // InvalidInstanceCycle occurs when an invalid cycle is detected
+ // within the instantiation graph.
+ //
+ // Example:
+ // func f[T any]() { f[*T]() }
+ InvalidInstanceCycle
+
+ // InvalidUnion occurs when an embedded union or approximation element is
+ // not valid.
+ //
+ // Example:
+ // type _ interface {
+ // ~int | interface{ m() }
+ // }
+ InvalidUnion
+
+ // MisplacedConstraintIface occurs when a constraint-type interface is used
+ // outside of constraint position.
+ //
+ // Example:
+ // type I interface { ~int }
+ //
+ // var _ I
+ MisplacedConstraintIface
+
+ // InvalidMethodTypeParams occurs when methods have type parameters.
+ //
+ // It cannot be encountered with an AST parsed using go/parser.
+ InvalidMethodTypeParams
+
+ // MisplacedTypeParam occurs when a type parameter is used in a place where
+ // it is not permitted.
+ //
+ // Example:
+ // type T[P any] P
+ //
+ // Example:
+ // type T[P any] struct{ *P }
+ MisplacedTypeParam
)
diff --git a/internal/typesinternal/errorcode_string.go b/internal/typesinternal/errorcode_string.go
index 3e5842a..de90e95 100644
--- a/internal/typesinternal/errorcode_string.go
+++ b/internal/typesinternal/errorcode_string.go
@@ -138,11 +138,25 @@
_ = x[UnusedResults-128]
_ = x[InvalidDefer-129]
_ = x[InvalidGo-130]
+ _ = x[BadDecl-131]
+ _ = x[RepeatedDecl-132]
+ _ = x[InvalidUnsafeAdd-133]
+ _ = x[InvalidUnsafeSlice-134]
+ _ = x[UnsupportedFeature-135]
+ _ = x[NotAGenericType-136]
+ _ = x[WrongTypeArgCount-137]
+ _ = x[CannotInferTypeArgs-138]
+ _ = x[InvalidTypeArg-139]
+ _ = x[InvalidInstanceCycle-140]
+ _ = x[InvalidUnion-141]
+ _ = x[MisplacedConstraintIface-142]
+ _ = x[InvalidMethodTypeParams-143]
+ _ = x[MisplacedTypeParam-144]
}
-const _ErrorCode_name = "TestBlankPkgNameMismatchedPkgNameInvalidPkgUseBadImportPathBrokenImportImportCRenamedUnusedImportInvalidInitCycleDuplicateDeclInvalidDeclCycleInvalidTypeCycleInvalidConstInitInvalidConstValInvalidConstTypeUntypedNilWrongAssignCountUnassignableOperandNoNewVarMultiValAssignOpInvalidIfaceAssignInvalidChanAssignIncompatibleAssignUnaddressableFieldAssignNotATypeInvalidArrayLenBlankIfaceMethodIncomparableMapKeyInvalidIfaceEmbedInvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDotInvalidDotDotDotOperandInvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDeclInvalidChanRangeInvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGo"
+const _ErrorCode_name = "TestBlankPkgNameMismatchedPkgNameInvalidPkgUseBadImportPathBrokenImportImportCRenamedUnusedImportInvalidInitCycleDuplicateDeclInvalidDeclCycleInvalidTypeCycleInvalidConstInitInvalidConstValInvalidConstTypeUntypedNilWrongAssignCountUnassignableOperandNoNewVarMultiValAssignOpInvalidIfaceAssignInvalidChanAssignIncompatibleAssignUnaddressableFieldAssignNotATypeInvalidArrayLenBlankIfaceMethodIncomparableMapKeyInvalidIfaceEmbedInvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDotInvalidDotDotDotOperandInvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDeclInvalidChanRangeInvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParam"
-var _ErrorCode_index = [...]uint16{0, 4, 16, 33, 46, 59, 71, 85, 97, 113, 126, 142, 158, 174, 189, 205, 215, 231, 250, 258, 274, 292, 309, 327, 351, 359, 374, 390, 408, 425, 440, 447, 458, 481, 496, 508, 519, 534, 548, 563, 578, 591, 600, 614, 629, 640, 655, 664, 680, 700, 718, 737, 749, 768, 787, 803, 820, 839, 853, 864, 879, 892, 907, 923, 937, 953, 968, 985, 1003, 1018, 1028, 1038, 1055, 1077, 1091, 1105, 1125, 1143, 1163, 1181, 1204, 1220, 1235, 1248, 1258, 1270, 1281, 1295, 1308, 1319, 1329, 1344, 1355, 1366, 1379, 1395, 1412, 1436, 1453, 1468, 1478, 1487, 1500, 1516, 1532, 1543, 1558, 1574, 1588, 1604, 1618, 1635, 1655, 1668, 1684, 1698, 1715, 1732, 1749, 1764, 1778, 1792, 1803, 1815, 1828, 1845, 1858, 1869, 1882, 1894, 1903}
+var _ErrorCode_index = [...]uint16{0, 4, 16, 33, 46, 59, 71, 85, 97, 113, 126, 142, 158, 174, 189, 205, 215, 231, 250, 258, 274, 292, 309, 327, 351, 359, 374, 390, 408, 425, 440, 447, 458, 481, 496, 508, 519, 534, 548, 563, 578, 591, 600, 614, 629, 640, 655, 664, 680, 700, 718, 737, 749, 768, 787, 803, 820, 839, 853, 864, 879, 892, 907, 923, 937, 953, 968, 985, 1003, 1018, 1028, 1038, 1055, 1077, 1091, 1105, 1125, 1143, 1163, 1181, 1204, 1220, 1235, 1248, 1258, 1270, 1281, 1295, 1308, 1319, 1329, 1344, 1355, 1366, 1379, 1395, 1412, 1436, 1453, 1468, 1478, 1487, 1500, 1516, 1532, 1543, 1558, 1574, 1588, 1604, 1618, 1635, 1655, 1668, 1684, 1698, 1715, 1732, 1749, 1764, 1778, 1792, 1803, 1815, 1828, 1845, 1858, 1869, 1882, 1894, 1903, 1910, 1922, 1938, 1956, 1974, 1989, 2006, 2025, 2039, 2059, 2071, 2095, 2118, 2136}
func (i ErrorCode) String() string {
i -= 1