Skip to content

Commit 1868799

Browse files
committed
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 abc106c gopls/integration/govim: build gopls using go1.18rc1 + 2022-02-28 c2ddf3d internal/lsp: add quick fix for unsupported feature + 2022-02-28 0e44f7a gopls/doc/advanced.md: correct commands for unstable version build + 2022-02-25 acdddf6 go/ssa: allows right operand of a shift to be signed. + 2022-02-25 9ffa3ad internal/lsp: Provide completions for test function definitions + 2022-02-24 b7525f4 internal/lsp: hash go version into package key + 2022-02-24 5210e0c gopls: wire in LangVersion and ModulePath for gofumpt formatting + 2022-02-24 e6ef770 go/types/typeutil: don't recurse into constraints when hashing tparams + 2022-02-23 258e473 internal/lsp/source: disable the useany analyzer by default + 2022-02-23 b7d2949 internal/lsp: don't store diagnostics for builtin.go + 2022-02-23 4f21f7a gopls: update gofumpt to v0.3.0 + 2022-02-22 3e31058 internal/imports: update to permit multiple main modules + 2022-02-22 43f084e internal/typesinternal: update typesinternal for 1.18 + 2022-02-18 897bd77 internal/gocommand: remove support for -workfile + 2022-02-17 e6a7e13 go/analysis/tools/internal/checker: add support for RunDespiteError Change-Id: I4ca5a581cb276b904f4a9d73d686aaa7cb0c6093
2 parents f1bc086 + abc106c commit 1868799

File tree

37 files changed

+1177
-85
lines changed

37 files changed

+1177
-85
lines changed

cmd/godoc/main.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,21 +207,21 @@ func main() {
207207
fmt.Printf("using module mode; GOMOD=%s\n", goModFile)
208208

209209
// Detect whether to use vendor mode or not.
210-
mainMod, vendorEnabled, err := gocommand.VendorEnabled(context.Background(), gocommand.Invocation{}, &gocommand.Runner{})
210+
vendorEnabled, mainModVendor, err := gocommand.VendorEnabled(context.Background(), gocommand.Invocation{}, &gocommand.Runner{})
211211
if err != nil {
212212
fmt.Fprintf(os.Stderr, "failed to determine if vendoring is enabled: %v", err)
213213
os.Exit(1)
214214
}
215215
if vendorEnabled {
216216
// Bind the root directory of the main module.
217-
fs.Bind(path.Join("/src", mainMod.Path), gatefs.New(vfs.OS(mainMod.Dir), fsGate), "/", vfs.BindAfter)
217+
fs.Bind(path.Join("/src", mainModVendor.Path), gatefs.New(vfs.OS(mainModVendor.Dir), fsGate), "/", vfs.BindAfter)
218218

219219
// Bind the vendor directory.
220220
//
221221
// Note that in module mode, vendor directories in locations
222222
// other than the main module's root directory are ignored.
223223
// See https://golang.org/ref/mod#vendoring.
224-
vendorDir := filepath.Join(mainMod.Dir, "vendor")
224+
vendorDir := filepath.Join(mainModVendor.Dir, "vendor")
225225
fs.Bind("/src", gatefs.New(vfs.OS(vendorDir), fsGate), "/", vfs.BindAfter)
226226

227227
} else {

go/analysis/internal/checker/checker.go

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ package checker
1111
import (
1212
"bytes"
1313
"encoding/gob"
14+
"errors"
1415
"flag"
1516
"fmt"
1617
"go/format"
@@ -129,8 +130,13 @@ func Run(args []string, analyzers []*analysis.Analyzer) (exitcode int) {
129130
allSyntax := needFacts(analyzers)
130131
initial, err := load(args, allSyntax)
131132
if err != nil {
132-
log.Print(err)
133-
return 1 // load errors
133+
if _, ok := err.(typeParseError); !ok {
134+
// Fail when some of the errors are not
135+
// related to parsing nor typing.
136+
log.Print(err)
137+
return 1
138+
}
139+
// TODO: filter analyzers based on RunDespiteError?
134140
}
135141

136142
// Print the results.
@@ -139,11 +145,17 @@ func Run(args []string, analyzers []*analysis.Analyzer) (exitcode int) {
139145
if Fix {
140146
applyFixes(roots)
141147
}
142-
143148
return printDiagnostics(roots)
144149
}
145150

146-
// load loads the initial packages.
151+
// typeParseError represents a package load error
152+
// that is related to typing and parsing.
153+
type typeParseError struct {
154+
error
155+
}
156+
157+
// load loads the initial packages. If all loading issues are related to
158+
// typing and parsing, the returned error is of type typeParseError.
147159
func load(patterns []string, allSyntax bool) ([]*packages.Package, error) {
148160
mode := packages.LoadSyntax
149161
if allSyntax {
@@ -155,18 +167,43 @@ func load(patterns []string, allSyntax bool) ([]*packages.Package, error) {
155167
}
156168
initial, err := packages.Load(&conf, patterns...)
157169
if err == nil {
158-
if n := packages.PrintErrors(initial); n > 1 {
159-
err = fmt.Errorf("%d errors during loading", n)
160-
} else if n == 1 {
161-
err = fmt.Errorf("error during loading")
162-
} else if len(initial) == 0 {
170+
if len(initial) == 0 {
163171
err = fmt.Errorf("%s matched no packages", strings.Join(patterns, " "))
172+
} else {
173+
err = loadingError(initial)
164174
}
165175
}
166-
167176
return initial, err
168177
}
169178

179+
// loadingError checks for issues during the loading of initial
180+
// packages. Returns nil if there are no issues. Returns error
181+
// of type typeParseError if all errors, including those in
182+
// dependencies, are related to typing or parsing. Otherwise,
183+
// a plain error is returned with an appropriate message.
184+
func loadingError(initial []*packages.Package) error {
185+
var err error
186+
if n := packages.PrintErrors(initial); n > 1 {
187+
err = fmt.Errorf("%d errors during loading", n)
188+
} else if n == 1 {
189+
err = errors.New("error during loading")
190+
} else {
191+
// no errors
192+
return nil
193+
}
194+
all := true
195+
packages.Visit(initial, nil, func(pkg *packages.Package) {
196+
for _, err := range pkg.Errors {
197+
typeOrParse := err.Kind == packages.TypeError || err.Kind == packages.ParseError
198+
all = all && typeOrParse
199+
}
200+
})
201+
if all {
202+
return typeParseError{err}
203+
}
204+
return err
205+
}
206+
170207
// TestAnalyzer applies an analysis to a set of packages (and their
171208
// dependencies if necessary) and returns the results.
172209
//

go/analysis/internal/checker/checker_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,62 @@ func run(pass *analysis.Pass) (interface{}, error) {
9999

100100
return nil, nil
101101
}
102+
103+
func TestRunDespiteErrors(t *testing.T) {
104+
testenv.NeedsGoPackages(t)
105+
106+
files := map[string]string{
107+
"rderr/test.go": `package rderr
108+
109+
// Foo deliberately has a type error
110+
func Foo(s string) int {
111+
return s + 1
112+
}
113+
`}
114+
115+
testdata, cleanup, err := analysistest.WriteFiles(files)
116+
if err != nil {
117+
t.Fatal(err)
118+
}
119+
path := filepath.Join(testdata, "src/rderr/test.go")
120+
121+
// A no-op analyzer that should finish regardless of
122+
// parse or type errors in the code.
123+
noop := &analysis.Analyzer{
124+
Name: "noop",
125+
Requires: []*analysis.Analyzer{inspect.Analyzer},
126+
Run: func(pass *analysis.Pass) (interface{}, error) {
127+
return nil, nil
128+
},
129+
RunDespiteErrors: true,
130+
}
131+
132+
for _, test := range []struct {
133+
name string
134+
pattern []string
135+
analyzers []*analysis.Analyzer
136+
code int
137+
}{
138+
// parse/type errors
139+
{name: "skip-error", pattern: []string{"file=" + path}, analyzers: []*analysis.Analyzer{analyzer}, code: 1},
140+
{name: "despite-error", pattern: []string{"file=" + path}, analyzers: []*analysis.Analyzer{noop}, code: 0},
141+
// combination of parse/type errors and no errors
142+
{name: "despite-error-and-no-error", pattern: []string{"file=" + path, "sort"}, analyzers: []*analysis.Analyzer{analyzer, noop}, code: 1},
143+
// non-existing package error
144+
{name: "no-package", pattern: []string{"xyz"}, analyzers: []*analysis.Analyzer{analyzer}, code: 1},
145+
{name: "no-package-despite-error", pattern: []string{"abc"}, analyzers: []*analysis.Analyzer{noop}, code: 1},
146+
{name: "no-multi-package-despite-error", pattern: []string{"xyz", "abc"}, analyzers: []*analysis.Analyzer{noop}, code: 1},
147+
// combination of type/parsing and different errors
148+
{name: "different-errors", pattern: []string{"file=" + path, "xyz"}, analyzers: []*analysis.Analyzer{analyzer, noop}, code: 1},
149+
// non existing dir error
150+
{name: "no-match-dir", pattern: []string{"file=non/existing/dir"}, analyzers: []*analysis.Analyzer{analyzer, noop}, code: 1},
151+
// no errors
152+
{name: "no-errors", pattern: []string{"sort"}, analyzers: []*analysis.Analyzer{analyzer, noop}, code: 0},
153+
} {
154+
if got := checker.Run(test.pattern, test.analyzers); got != test.code {
155+
t.Errorf("got incorrect exit code %d for test %s; want %d", got, test.name, test.code)
156+
}
157+
}
158+
159+
defer cleanup()
160+
}

go/ssa/emit.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,16 @@ func emitArith(f *Function, op token.Token, x, y Value, t types.Type, pos token.
7474
case token.SHL, token.SHR:
7575
x = emitConv(f, x, t)
7676
// y may be signed or an 'untyped' constant.
77-
// TODO(adonovan): whence signed values?
78-
if b, ok := y.Type().Underlying().(*types.Basic); ok && b.Info()&types.IsUnsigned == 0 {
79-
y = emitConv(f, y, types.Typ[types.Uint64])
77+
78+
// There is a runtime panic if y is signed and <0. Instead of inserting a check for y<0
79+
// and converting to an unsigned value (like the compiler) leave y as is.
80+
81+
if b, ok := y.Type().Underlying().(*types.Basic); ok && b.Info()&types.IsUntyped != 0 {
82+
// Untyped conversion:
83+
// Spec https://go.dev/ref/spec#Operators:
84+
// The right operand in a shift expression must have integer type or be an untyped constant
85+
// representable by a value of type uint.
86+
y = emitConv(f, y, types.Typ[types.Uint])
8087
}
8188

8289
case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:

go/ssa/interp/interp_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ var gorootTestTests = []string{
109109
var testdataTests = []string{
110110
"boundmeth.go",
111111
"complit.go",
112+
"convert.go",
112113
"coverage.go",
113114
"defer.go",
114115
"fieldprom.go",

go/ssa/interp/ops.go

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,26 @@ func asUint64(x value) uint64 {
137137
panic(fmt.Sprintf("cannot convert %T to uint64", x))
138138
}
139139

140+
// asUnsigned returns the value of x, which must be an integer type, as its equivalent unsigned type,
141+
// and returns true if x is non-negative.
142+
func asUnsigned(x value) (value, bool) {
143+
switch x := x.(type) {
144+
case int:
145+
return uint(x), x >= 0
146+
case int8:
147+
return uint8(x), x >= 0
148+
case int16:
149+
return uint16(x), x >= 0
150+
case int32:
151+
return uint32(x), x >= 0
152+
case int64:
153+
return uint64(x), x >= 0
154+
case uint, uint8, uint32, uint64, uintptr:
155+
return x, true
156+
}
157+
panic(fmt.Sprintf("cannot convert %T to unsigned", x))
158+
}
159+
140160
// zero returns a new "zero" value of the specified type.
141161
func zero(t types.Type) value {
142162
switch t := t.(type) {
@@ -576,7 +596,11 @@ func binop(op token.Token, t types.Type, x, y value) value {
576596
}
577597

578598
case token.SHL:
579-
y := asUint64(y)
599+
u, ok := asUnsigned(y)
600+
if !ok {
601+
panic("negative shift amount")
602+
}
603+
y := asUint64(u)
580604
switch x.(type) {
581605
case int:
582606
return x.(int) << y
@@ -603,7 +627,11 @@ func binop(op token.Token, t types.Type, x, y value) value {
603627
}
604628

605629
case token.SHR:
606-
y := asUint64(y)
630+
u, ok := asUnsigned(y)
631+
if !ok {
632+
panic("negative shift amount")
633+
}
634+
y := asUint64(u)
607635
switch x.(type) {
608636
case int:
609637
return x.(int) >> y

go/ssa/interp/testdata/convert.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Test conversion operations.
6+
7+
package main
8+
9+
func left(x int) { _ = 1 << x }
10+
func right(x int) { _ = 1 >> x }
11+
12+
func main() {
13+
wantPanic(
14+
func() {
15+
left(-1)
16+
},
17+
"runtime error: negative shift amount",
18+
)
19+
wantPanic(
20+
func() {
21+
right(-1)
22+
},
23+
"runtime error: negative shift amount",
24+
)
25+
}
26+
27+
func wantPanic(fn func(), s string) {
28+
defer func() {
29+
err := recover()
30+
if err == nil {
31+
panic("expected panic")
32+
}
33+
if got := err.(error).Error(); got != s {
34+
panic("expected panic " + s + " got " + got)
35+
}
36+
}()
37+
fn()
38+
}

go/types/typeutil/map.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ func (h Hasher) hashFor(t types.Type) uint32 {
379379
func (h Hasher) hashTuple(tuple *types.Tuple) uint32 {
380380
// See go/types.identicalTypes for rationale.
381381
n := tuple.Len()
382-
var hash uint32 = 9137 + 2*uint32(n)
382+
hash := 9137 + 2*uint32(n)
383383
for i := 0; i < n; i++ {
384384
hash += 3 * h.Hash(tuple.At(i).Type())
385385
}
@@ -398,7 +398,7 @@ func (h Hasher) hashUnion(t *typeparams.Union) uint32 {
398398
}
399399

400400
func (h Hasher) hashTermSet(terms []*typeparams.Term) uint32 {
401-
var hash uint32 = 9157 + 2*uint32(len(terms))
401+
hash := 9157 + 2*uint32(len(terms))
402402
for _, term := range terms {
403403
// term order is not significant.
404404
termHash := h.Hash(term.Type())
@@ -416,14 +416,16 @@ func (h Hasher) hashTermSet(terms []*typeparams.Term) uint32 {
416416
// If h.sigTParams is set and contains t, then we are in the process of hashing
417417
// a signature, and the hash value of t must depend only on t's index and
418418
// constraint: signatures are considered identical modulo type parameter
419-
// renaming.
419+
// renaming. To avoid infinite recursion, we only hash the type parameter
420+
// index, and rely on types.Identical to handle signatures where constraints
421+
// are not identical.
420422
//
421423
// Otherwise the hash of t depends only on t's pointer identity.
422424
func (h Hasher) hashTypeParam(t *typeparams.TypeParam) uint32 {
423425
if h.sigTParams != nil {
424426
i := t.Index()
425427
if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) {
426-
return 9173 + 2*h.Hash(t.Constraint()) + 3*uint32(i)
428+
return 9173 + 3*uint32(i)
427429
}
428430
}
429431
return h.hashPtr(t.Obj())

go/types/typeutil/map_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,17 @@ var ME2 = G2[int].M
233233
234234
// ME1Type should have identical type as ME1.
235235
var ME1Type func(G1[int], G1[int], G2[int])
236+
237+
// Examples from issue #51314
238+
type Constraint[T any] interface{}
239+
func Foo[T Constraint[T]]() {}
240+
func Fn[T1 ~*T2, T2 ~*T1](t1 T1, t2 T2) {}
241+
242+
// Bar and Baz are identical to Foo.
243+
func Bar[P Constraint[P]]() {}
244+
func Baz[Q any]() {} // The underlying type of Constraint[P] is any.
245+
// But Quux is not.
246+
func Quux[Q interface{ quux() }]() {}
236247
`
237248

238249
fset := token.NewFileSet()
@@ -284,6 +295,13 @@ var ME1Type func(G1[int], G1[int], G2[int])
284295
ME1 = scope.Lookup("ME1").Type()
285296
ME1Type = scope.Lookup("ME1Type").Type()
286297
ME2 = scope.Lookup("ME2").Type()
298+
299+
Constraint = scope.Lookup("Constraint").Type()
300+
Foo = scope.Lookup("Foo").Type()
301+
Fn = scope.Lookup("Fn").Type()
302+
Bar = scope.Lookup("Foo").Type()
303+
Baz = scope.Lookup("Foo").Type()
304+
Quux = scope.Lookup("Quux").Type()
287305
)
288306

289307
tmap := new(typeutil.Map)
@@ -345,6 +363,14 @@ var ME1Type func(G1[int], G1[int], G2[int])
345363
{ME1, "ME1", true},
346364
{ME1Type, "ME1Type", false},
347365
{ME2, "ME2", true},
366+
367+
// See golang/go#51314: avoid infinite recursion on cyclic type constraints.
368+
{Constraint, "Constraint", true},
369+
{Foo, "Foo", true},
370+
{Fn, "Fn", true},
371+
{Bar, "Bar", false},
372+
{Baz, "Baz", false},
373+
{Quux, "Quux", true},
348374
}
349375

350376
for _, step := range steps {

0 commit comments

Comments
 (0)