diff --git a/.teamcity/settings.kts b/.teamcity/settings.kts index 0db7f48c..e157212d 100644 --- a/.teamcity/settings.kts +++ b/.teamcity/settings.kts @@ -35,23 +35,23 @@ To debug in IntelliJ Idea, open the 'Maven Projects' tool window (View version = "2020.2" val targets = arrayOf( - "linux/amd64/1.15", "linux/amd64/1.16", "linux/amd64/1.17", + "linux/amd64/1.18", "linux/amd64/tip", - "linux/386/1.17", + "linux/386/1.18", - "linux/arm64/1.17", + "linux/arm64/1.18", "linux/arm64/tip", - "windows/amd64/1.17", + "windows/amd64/1.18", "windows/amd64/tip", - "mac/amd64/1.17", + "mac/amd64/1.18", "mac/amd64/tip", - "mac/arm64/1.17", + "mac/arm64/1.18", "mac/arm64/tip" ) diff --git a/_scripts/test_linux.sh b/_scripts/test_linux.sh index 846f733e..c37bae05 100755 --- a/_scripts/test_linux.sh +++ b/_scripts/test_linux.sh @@ -21,10 +21,6 @@ function getgo { } if [ "$version" = "gotip" ]; then - # TODO: remove this - if [ "$arch" != "amd64" ]; then - exit 0 - fi echo Building Go from tip getgo $(curl https://go.dev/VERSION?m=text) export GOROOT_BOOTSTRAP=$GOROOT diff --git a/_scripts/test_mac.sh b/_scripts/test_mac.sh index e48cbf0e..93af0c1f 100644 --- a/_scripts/test_mac.sh +++ b/_scripts/test_mac.sh @@ -8,10 +8,6 @@ ARCH=$2 TMPDIR=$3 if [ "$GOVERSION" = "gotip" ]; then - # TODO: remove this - if [ "$arch" != "amd64" ]; then - exit 0 - fi bootstrapver=$(curl https://go.dev/VERSION?m=text) cd $TMPDIR curl -sSL "https://storage.googleapis.com/golang/$bootstrapver.darwin-$ARCH.tar.gz" | tar -xz diff --git a/_scripts/test_windows.ps1 b/_scripts/test_windows.ps1 index 8d803d77..65b56fff 100644 --- a/_scripts/test_windows.ps1 +++ b/_scripts/test_windows.ps1 @@ -34,7 +34,7 @@ function GetGo($version) { } if ($version -eq "gotip") { - Exit 0 + #Exit 0 $latest = Invoke-WebRequest -Uri https://golang.org/VERSION?m=text -UseBasicParsing | Select-Object -ExpandProperty Content GetGo $latest $env:GOROOT_BOOTSTRAP = $env:GOROOT diff --git a/go.mod b/go.mod index 2c54543c..8eb5d769 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,6 @@ require ( go.starlark.net v0.0.0-20200821142938-949cc6f4b097 golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4 golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 - golang.org/x/tools v0.1.8-0.20211028023602-8de2a7fd1736 + golang.org/x/tools v0.1.8 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 21e7ad13..e79c3fd9 100644 --- a/go.sum +++ b/go.sum @@ -309,6 +309,8 @@ golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.8-0.20211028023602-8de2a7fd1736 h1:cw6nUxdoEN5iEIWYD8aAsTZ8iYjLVNiHAb7xz/80WO4= golang.org/x/tools v0.1.8-0.20211028023602-8de2a7fd1736/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/goversion/compat.go b/pkg/goversion/compat.go index 053ae138..83660564 100644 --- a/pkg/goversion/compat.go +++ b/pkg/goversion/compat.go @@ -8,9 +8,9 @@ import ( var ( MinSupportedVersionOfGoMajor = 1 - MinSupportedVersionOfGoMinor = 15 + MinSupportedVersionOfGoMinor = 16 MaxSupportedVersionOfGoMajor = 1 - MaxSupportedVersionOfGoMinor = 17 + MaxSupportedVersionOfGoMinor = 18 goTooOldErr = fmt.Sprintf("Go version %%s is too old for this version of Delve (minimum supported version %d.%d, suppress this error with --check-go-version=false)", MinSupportedVersionOfGoMajor, MinSupportedVersionOfGoMinor) goTooOldWarn = fmt.Sprintf("WARNING: undefined behavior - Go version %%s is too old for this version of Delve (minimum supported version %d.%d)", MinSupportedVersionOfGoMajor, MinSupportedVersionOfGoMinor) dlvTooOldErr = fmt.Sprintf("Version of Delve is too old for Go version %%s (maximum supported version %d.%d, suppress this error with --check-go-version=false)", MaxSupportedVersionOfGoMajor, MaxSupportedVersionOfGoMinor) diff --git a/pkg/proc/native/proc.go b/pkg/proc/native/proc.go index f5b25cb4..071cac7c 100644 --- a/pkg/proc/native/proc.go +++ b/pkg/proc/native/proc.go @@ -266,11 +266,23 @@ func (dbp *nativeProcess) initialize(path string, debugInfoDirs []string) (*proc stopReason = proc.StopAttached } tgt, err := proc.NewTarget(dbp, dbp.pid, dbp.memthread, proc.NewTargetConfig{ - Path: path, - DebugInfoDirs: debugInfoDirs, - DisableAsyncPreempt: runtime.GOOS == "windows" || runtime.GOOS == "freebsd", - StopReason: stopReason, - CanDump: runtime.GOOS == "linux"}) + Path: path, + DebugInfoDirs: debugInfoDirs, + + // We disable asyncpreempt for the following reasons: + // - on Windows asyncpreempt is incompatible with debuggers, see: + // https://github.com/golang/go/issues/36494 + // - freebsd's backend is generally broken and asyncpreempt makes it even more so, see: + // https://github.com/go-delve/delve/issues/1754 + // - on linux/arm64 asyncpreempt can sometimes restart a sequence of + // instructions, if the sequence happens to contain a breakpoint it will + // look like the breakpoint was hit twice when it was "logically" only + // executed once. + // See: https://go-review.googlesource.com/c/go/+/208126 + DisableAsyncPreempt: runtime.GOOS == "windows" || runtime.GOOS == "freebsd" || (runtime.GOOS == "linux" && runtime.GOARCH == "arm64"), + + StopReason: stopReason, + CanDump: runtime.GOOS == "linux"}) if err != nil { return nil, err } diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go index 8f39a82b..e7acf601 100644 --- a/pkg/proc/proc_test.go +++ b/pkg/proc/proc_test.go @@ -1335,6 +1335,10 @@ func TestFrameEvaluation(t *testing.T) { g, err := proc.GetG(p.CurrentThread()) assertNoError(err, t, "GetG()") + frames, err := g.Stacktrace(40, 0) + t.Logf("Goroutine %d %#v", g.ID, g.Thread) + logStacktrace(t, p, frames) + for i := 0; i <= 3; i++ { scope, err := proc.ConvertEvalScope(p, g.ID, i+1, 0) assertNoError(err, t, fmt.Sprintf("ConvertEvalScope() on frame %d", i+1)) diff --git a/pkg/proc/stack.go b/pkg/proc/stack.go index bcc2fe51..9d847f49 100644 --- a/pkg/proc/stack.go +++ b/pkg/proc/stack.go @@ -276,6 +276,9 @@ func (it *stackIterator) newStackframe(ret, retaddr uint64) Stackframe { it.regs.FrameBase = it.frameBase(fn) } r := Stackframe{Current: Location{PC: it.pc, File: f, Line: l, Fn: fn}, Regs: it.regs, Ret: ret, addrret: retaddr, stackHi: it.stackhi, SystemStack: it.systemstack, lastpc: it.pc} + if r.Regs.Reg(it.regs.PCRegNum) == nil { + r.Regs.AddReg(it.regs.PCRegNum, op.DwarfRegisterFromUint64(it.pc)) + } r.Call = r.Current if !it.top && r.Current.Fn != nil && it.pc != r.Current.Fn.Entry { // if the return address is the entry point of the function that diff --git a/pkg/proc/test/support.go b/pkg/proc/test/support.go index 5620dd5c..afaf2d2f 100644 --- a/pkg/proc/test/support.go +++ b/pkg/proc/test/support.go @@ -383,11 +383,11 @@ func MustHaveCgo(t *testing.T) { func RegabiSupported() bool { // Tracks regabiSupported variable in ParseGOEXPERIMENT internal/buildcfg/exp.go switch { - case !goversion.VersionAfterOrEqual(runtime.Version(), 1, 17): // < 1.17 - return false + case goversion.VersionAfterOrEqual(runtime.Version(), 1, 18): + return runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "ppc64" case goversion.VersionAfterOrEqual(runtime.Version(), 1, 17): return runtime.GOARCH == "amd64" && (runtime.GOOS == "android" || runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows") - default: // >= 1.18 - return runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" + default: + return false } } diff --git a/service/dap/server_test.go b/service/dap/server_test.go index 09a59154..e0088dfd 100644 --- a/service/dap/server_test.go +++ b/service/dap/server_test.go @@ -2387,6 +2387,11 @@ func TestGlobalScopeAndVariables(t *testing.T) { []onBreakpoint{{ // Stop at line 36 execute: func() { + if runtime.GOARCH == "386" && goversion.VersionAfterOrEqual(runtime.Version(), 1, 18) { + client.StepInRequest(1) + client.ExpectStepInResponse(t) + client.ExpectStoppedEvent(t) + } client.StackTraceRequest(1, 0, 20) stack := client.ExpectStackTraceResponse(t) checkStackFramesExact(t, stack, "main.main", 36, 1000, 3, 3) @@ -2454,6 +2459,12 @@ func TestRegistersScopeAndVariables(t *testing.T) { []onBreakpoint{{ // Stop at line 36 execute: func() { + if runtime.GOARCH == "386" && goversion.VersionAfterOrEqual(runtime.Version(), 1, 18) { + client.StepInRequest(1) + client.ExpectStepInResponse(t) + client.ExpectStoppedEvent(t) + } + client.StackTraceRequest(1, 0, 20) stack := client.ExpectStackTraceResponse(t) checkStackFramesExact(t, stack, "main.main", 36, 1000, 3, 3) diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go b/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go index 3e318749..cdb332cd 100644 --- a/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go @@ -331,7 +331,7 @@ func (p *iimporter) pkgAt(off uint64) *types.Package { } func (p *iimporter) typAt(off uint64, base *types.Named) types.Type { - if t, ok := p.typCache[off]; ok && (base == nil || !isInterface(t)) { + if t, ok := p.typCache[off]; ok && canReuse(base, t) { return t } @@ -343,12 +343,30 @@ func (p *iimporter) typAt(off uint64, base *types.Named) types.Type { r.declReader.Reset(p.declData[off-predeclReserved:]) t := r.doType(base) - if base == nil || !isInterface(t) { + if canReuse(base, t) { p.typCache[off] = t } return t } +// canReuse reports whether the type rhs on the RHS of the declaration for def +// may be re-used. +// +// Specifically, if def is non-nil and rhs is an interface type with methods, it +// may not be re-used because we have a convention of setting the receiver type +// for interface methods to def. +func canReuse(def *types.Named, rhs types.Type) bool { + if def == nil { + return true + } + iface, _ := rhs.(*types.Interface) + if iface == nil { + return true + } + // Don't use iface.Empty() here as iface may not be complete. + return iface.NumEmbeddeds() == 0 && iface.NumExplicitMethods() == 0 +} + type importReader struct { p *iimporter declReader bytes.Reader diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go b/vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go index 2c98f0ac..a9938432 100644 --- a/vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go @@ -16,5 +16,8 @@ func additionalPredeclared() []types.Type { return []types.Type{ // comparable types.Universe.Lookup("comparable").Type(), + + // any + types.Universe.Lookup("any").Type(), } } diff --git a/vendor/golang.org/x/tools/internal/typeparams/common.go b/vendor/golang.org/x/tools/internal/typeparams/common.go index 9fc6b4be..961d036f 100644 --- a/vendor/golang.org/x/tools/internal/typeparams/common.go +++ b/vendor/golang.org/x/tools/internal/typeparams/common.go @@ -13,6 +13,7 @@ package typeparams import ( "go/ast" "go/token" + "go/types" ) // A IndexExprData holds data from both ast.IndexExpr and the new @@ -23,3 +24,9 @@ type IndexExprData struct { Indices []ast.Expr // index expressions Rbrack token.Pos // position of "]" } + +// IsTypeParam reports whether t is a type parameter. +func IsTypeParam(t types.Type) bool { + _, ok := t.(*TypeParam) + return ok +} diff --git a/vendor/golang.org/x/tools/internal/typeparams/normalize.go b/vendor/golang.org/x/tools/internal/typeparams/normalize.go index 29373508..090f142a 100644 --- a/vendor/golang.org/x/tools/internal/typeparams/normalize.go +++ b/vendor/golang.org/x/tools/internal/typeparams/normalize.go @@ -16,92 +16,96 @@ import ( const debug = false -// NormalizeInterface returns the normal form of the interface iface, or nil if iface -// has an empty type set (i.e. there are no types that satisfy iface). If the -// resulting interface is non-nil, it will be identical to iface. +var ErrEmptyTypeSet = errors.New("empty type set") + +// StructuralTerms returns a slice of terms representing the normalized +// structural type restrictions of a type parameter, if any. // -// An error is returned if the interface type is invalid, or too complicated to -// reasonably normalize (for example, contains unions with more than a hundred -// terms). +// Structural type restrictions of a type parameter are created via +// non-interface types embedded in its constraint interface (directly, or via a +// chain of interface embeddings). For example, in the declaration +// type T[P interface{~int; m()}] int +// the structural restriction of the type parameter P is ~int. // -// An interface is in normal form if and only if: -// - it has 0 or 1 embedded types. -// - its embedded type is either a types.Union or has a concrete -// (non-interface) underlying type -// - if the embedded type is a union, each term of the union has a concrete -// underlying type, and no terms may be removed without changing the type set -// of the interface -func NormalizeInterface(iface *types.Interface) (*types.Interface, error) { - var methods []*types.Func - for i := 0; i < iface.NumMethods(); i++ { - methods = append(methods, iface.Method(i)) +// With interface embedding and unions, the specification of structural type +// restrictions may be arbitrarily complex. For example, consider the +// following: +// +// type A interface{ ~string|~[]byte } +// +// type B interface{ int|string } +// +// type C interface { ~string|~int } +// +// type T[P interface{ A|B; C }] int +// +// In this example, the structural type restriction of P is ~string|int: A|B +// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, +// which when intersected with C (~string|~int) yields ~string|int. +// +// StructuralTerms computes these expansions and reductions, producing a +// "normalized" form of the embeddings. A structural restriction is normalized +// if it is a single union containing no interface terms, and is minimal in the +// sense that removing any term changes the set of types satisfying the +// constraint. It is left as a proof for the reader that, modulo sorting, there +// is exactly one such normalized form. +// +// Because the minimal representation always takes this form, StructuralTerms +// returns a slice of tilde terms corresponding to the terms of the union in +// the normalized structural restriction. An error is returned if the +// constraint interface is invalid, exceeds complexity bounds, or has an empty +// type set. In the latter case, StructuralTerms returns ErrEmptyTypeSet. +// +// StructuralTerms makes no guarantees about the order of terms, except that it +// is deterministic. +func StructuralTerms(tparam *TypeParam) ([]*Term, error) { + constraint := tparam.Constraint() + if constraint == nil { + return nil, fmt.Errorf("%s has nil constraint", tparam) } - var embeddeds []types.Type - tset, err := computeTermSet(iface, make(map[types.Type]*termSet), 0) + iface, _ := constraint.Underlying().(*types.Interface) + if iface == nil { + return nil, fmt.Errorf("constraint is %T, not *types.Interface", constraint.Underlying()) + } + return InterfaceTermSet(iface) +} + +// InterfaceTermSet computes the normalized terms for a constraint interface, +// returning an error if the term set cannot be computed or is empty. In the +// latter case, the error will be ErrEmptyTypeSet. +// +// See the documentation of StructuralTerms for more information on +// normalization. +func InterfaceTermSet(iface *types.Interface) ([]*Term, error) { + return computeTermSet(iface) +} + +// UnionTermSet computes the normalized terms for a union, returning an error +// if the term set cannot be computed or is empty. In the latter case, the +// error will be ErrEmptyTypeSet. +// +// See the documentation of StructuralTerms for more information on +// normalization. +func UnionTermSet(union *Union) ([]*Term, error) { + return computeTermSet(union) +} + +func computeTermSet(typ types.Type) ([]*Term, error) { + tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0) if err != nil { return nil, err } - switch { - case tset.terms.isEmpty(): - // Special case: as documented + if tset.terms.isEmpty() { + return nil, ErrEmptyTypeSet + } + if tset.terms.isAll() { return nil, nil - - case tset.terms.isAll(): - // No embeddeds. - - case len(tset.terms) == 1: - if !tset.terms[0].tilde { - embeddeds = append(embeddeds, tset.terms[0].typ) - break - } - fallthrough - default: - var terms []*Term - for _, term := range tset.terms { - terms = append(terms, NewTerm(term.tilde, term.typ)) - } - embeddeds = append(embeddeds, NewUnion(terms)) } - - return types.NewInterfaceType(methods, embeddeds), nil -} - -var ErrEmptyTypeSet = errors.New("empty type set") - -// StructuralTerms returns the normalized structural type restrictions of a -// type, if any. For types that are not type parameters, it returns term slice -// containing a single non-tilde term holding the given type. For type -// parameters, it returns the normalized term list of the type parameter's -// constraint. See NormalizeInterface for more information on the normal form -// of a constraint interface. -// -// StructuralTerms returns an error if the structural term list cannot be -// computed. If the type set of typ is empty, it returns ErrEmptyTypeSet. -func StructuralTerms(typ types.Type) ([]*Term, error) { - switch typ := typ.(type) { - case *TypeParam: - iface, _ := typ.Constraint().(*types.Interface) - if iface == nil { - return nil, fmt.Errorf("constraint is %T, not *types.Interface", typ) - } - tset, err := computeTermSet(iface, make(map[types.Type]*termSet), 0) - if err != nil { - return nil, err - } - if tset.terms.isEmpty() { - return nil, ErrEmptyTypeSet - } - if tset.terms.isAll() { - return nil, nil - } - var terms []*Term - for _, term := range tset.terms { - terms = append(terms, NewTerm(term.tilde, term.typ)) - } - return terms, nil - default: - return []*Term{NewTerm(false, typ)}, nil + var terms []*Term + for _, term := range tset.terms { + terms = append(terms, NewTerm(term.tilde, term.typ)) } + return terms, nil } // A termSet holds the normalized set of terms for a given type. @@ -118,7 +122,7 @@ func indentf(depth int, format string, args ...interface{}) { fmt.Fprintf(os.Stderr, strings.Repeat(".", depth)+format+"\n", args...) } -func computeTermSet(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) { +func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) { if t == nil { panic("nil type") } @@ -159,7 +163,7 @@ func computeTermSet(t types.Type, seen map[types.Type]*termSet, depth int) (res if _, ok := embedded.Underlying().(*TypeParam); ok { return nil, fmt.Errorf("invalid embedded type %T", embedded) } - tset2, err := computeTermSet(embedded, seen, depth+1) + tset2, err := computeTermSetInternal(embedded, seen, depth+1) if err != nil { return nil, err } @@ -173,7 +177,7 @@ func computeTermSet(t types.Type, seen map[types.Type]*termSet, depth int) (res var terms termlist switch t.Type().Underlying().(type) { case *types.Interface: - tset2, err := computeTermSet(t.Type(), seen, depth+1) + tset2, err := computeTermSetInternal(t.Type(), seen, depth+1) if err != nil { return nil, err } diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go b/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go index 6ad3a43a..e509daf7 100644 --- a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go +++ b/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go @@ -75,6 +75,7 @@ func ForFuncType(*ast.FuncType) *ast.FieldList { // this Go version. Its methods panic on use. type TypeParam struct{ types.Type } +func (*TypeParam) Index() int { unsupported(); return 0 } func (*TypeParam) Constraint() types.Type { unsupported(); return nil } func (*TypeParam) Obj() *types.TypeName { unsupported(); return nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index c99bcb78..0c595f43 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -73,7 +73,7 @@ golang.org/x/sys/execabs golang.org/x/sys/internal/unsafeheader golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/tools v0.1.8-0.20211028023602-8de2a7fd1736 +# golang.org/x/tools v0.1.8 ## explicit golang.org/x/tools/go/gcexportdata golang.org/x/tools/go/internal/gcimporter