Updates for go1.18beta1 (#2831)
* go.mod: update golang.org/x/tools to v0.1.8 Fixes TestGeneratedDoc on go1.18 * TeamCity: bump test matrix Add 1.18 to test matrix. Remove 1.15 from test matrix and from support range. * proc,tests: update for regabi on arm64 and 386 Make sure that stacktrace registers always contain the PC register of the current frame, even though the debug_frame rules might not specify it on architectures that use a link register. The PC register is needed to look up loclist entries for variable evaluation. * goversion: bump maximum supported Go version to 1.18 * proc: disable asyncpreempt on linux/arm64 Asyncpreempt on linux/arm64 can sometimes restart a sequence of instructions which will make breakpoint appear to be hit twice in some cases.
This commit is contained in:
parent
07bcf0cb13
commit
4a94b3eff2
12
.teamcity/settings.kts
vendored
12
.teamcity/settings.kts
vendored
@ -35,23 +35,23 @@ To debug in IntelliJ Idea, open the 'Maven Projects' tool window (View
|
|||||||
version = "2020.2"
|
version = "2020.2"
|
||||||
|
|
||||||
val targets = arrayOf(
|
val targets = arrayOf(
|
||||||
"linux/amd64/1.15",
|
|
||||||
"linux/amd64/1.16",
|
"linux/amd64/1.16",
|
||||||
"linux/amd64/1.17",
|
"linux/amd64/1.17",
|
||||||
|
"linux/amd64/1.18",
|
||||||
"linux/amd64/tip",
|
"linux/amd64/tip",
|
||||||
|
|
||||||
"linux/386/1.17",
|
"linux/386/1.18",
|
||||||
|
|
||||||
"linux/arm64/1.17",
|
"linux/arm64/1.18",
|
||||||
"linux/arm64/tip",
|
"linux/arm64/tip",
|
||||||
|
|
||||||
"windows/amd64/1.17",
|
"windows/amd64/1.18",
|
||||||
"windows/amd64/tip",
|
"windows/amd64/tip",
|
||||||
|
|
||||||
"mac/amd64/1.17",
|
"mac/amd64/1.18",
|
||||||
"mac/amd64/tip",
|
"mac/amd64/tip",
|
||||||
|
|
||||||
"mac/arm64/1.17",
|
"mac/arm64/1.18",
|
||||||
"mac/arm64/tip"
|
"mac/arm64/tip"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,10 +21,6 @@ function getgo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if [ "$version" = "gotip" ]; then
|
if [ "$version" = "gotip" ]; then
|
||||||
# TODO: remove this
|
|
||||||
if [ "$arch" != "amd64" ]; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
echo Building Go from tip
|
echo Building Go from tip
|
||||||
getgo $(curl https://go.dev/VERSION?m=text)
|
getgo $(curl https://go.dev/VERSION?m=text)
|
||||||
export GOROOT_BOOTSTRAP=$GOROOT
|
export GOROOT_BOOTSTRAP=$GOROOT
|
||||||
|
@ -8,10 +8,6 @@ ARCH=$2
|
|||||||
TMPDIR=$3
|
TMPDIR=$3
|
||||||
|
|
||||||
if [ "$GOVERSION" = "gotip" ]; then
|
if [ "$GOVERSION" = "gotip" ]; then
|
||||||
# TODO: remove this
|
|
||||||
if [ "$arch" != "amd64" ]; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
bootstrapver=$(curl https://go.dev/VERSION?m=text)
|
bootstrapver=$(curl https://go.dev/VERSION?m=text)
|
||||||
cd $TMPDIR
|
cd $TMPDIR
|
||||||
curl -sSL "https://storage.googleapis.com/golang/$bootstrapver.darwin-$ARCH.tar.gz" | tar -xz
|
curl -sSL "https://storage.googleapis.com/golang/$bootstrapver.darwin-$ARCH.tar.gz" | tar -xz
|
||||||
|
@ -34,7 +34,7 @@ function GetGo($version) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($version -eq "gotip") {
|
if ($version -eq "gotip") {
|
||||||
Exit 0
|
#Exit 0
|
||||||
$latest = Invoke-WebRequest -Uri https://golang.org/VERSION?m=text -UseBasicParsing | Select-Object -ExpandProperty Content
|
$latest = Invoke-WebRequest -Uri https://golang.org/VERSION?m=text -UseBasicParsing | Select-Object -ExpandProperty Content
|
||||||
GetGo $latest
|
GetGo $latest
|
||||||
$env:GOROOT_BOOTSTRAP = $env:GOROOT
|
$env:GOROOT_BOOTSTRAP = $env:GOROOT
|
||||||
|
2
go.mod
2
go.mod
@ -18,6 +18,6 @@ require (
|
|||||||
go.starlark.net v0.0.0-20200821142938-949cc6f4b097
|
go.starlark.net v0.0.0-20200821142938-949cc6f4b097
|
||||||
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4
|
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4
|
||||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654
|
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
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
)
|
)
|
||||||
|
2
go.sum
2
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.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 h1:cw6nUxdoEN5iEIWYD8aAsTZ8iYjLVNiHAb7xz/80WO4=
|
||||||
golang.org/x/tools v0.1.8-0.20211028023602-8de2a7fd1736/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
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-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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
MinSupportedVersionOfGoMajor = 1
|
MinSupportedVersionOfGoMajor = 1
|
||||||
MinSupportedVersionOfGoMinor = 15
|
MinSupportedVersionOfGoMinor = 16
|
||||||
MaxSupportedVersionOfGoMajor = 1
|
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)
|
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)
|
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)
|
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)
|
||||||
|
@ -266,11 +266,23 @@ func (dbp *nativeProcess) initialize(path string, debugInfoDirs []string) (*proc
|
|||||||
stopReason = proc.StopAttached
|
stopReason = proc.StopAttached
|
||||||
}
|
}
|
||||||
tgt, err := proc.NewTarget(dbp, dbp.pid, dbp.memthread, proc.NewTargetConfig{
|
tgt, err := proc.NewTarget(dbp, dbp.pid, dbp.memthread, proc.NewTargetConfig{
|
||||||
Path: path,
|
Path: path,
|
||||||
DebugInfoDirs: debugInfoDirs,
|
DebugInfoDirs: debugInfoDirs,
|
||||||
DisableAsyncPreempt: runtime.GOOS == "windows" || runtime.GOOS == "freebsd",
|
|
||||||
StopReason: stopReason,
|
// We disable asyncpreempt for the following reasons:
|
||||||
CanDump: runtime.GOOS == "linux"})
|
// - 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1335,6 +1335,10 @@ func TestFrameEvaluation(t *testing.T) {
|
|||||||
g, err := proc.GetG(p.CurrentThread())
|
g, err := proc.GetG(p.CurrentThread())
|
||||||
assertNoError(err, t, "GetG()")
|
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++ {
|
for i := 0; i <= 3; i++ {
|
||||||
scope, err := proc.ConvertEvalScope(p, g.ID, i+1, 0)
|
scope, err := proc.ConvertEvalScope(p, g.ID, i+1, 0)
|
||||||
assertNoError(err, t, fmt.Sprintf("ConvertEvalScope() on frame %d", i+1))
|
assertNoError(err, t, fmt.Sprintf("ConvertEvalScope() on frame %d", i+1))
|
||||||
|
@ -276,6 +276,9 @@ func (it *stackIterator) newStackframe(ret, retaddr uint64) Stackframe {
|
|||||||
it.regs.FrameBase = it.frameBase(fn)
|
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}
|
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
|
r.Call = r.Current
|
||||||
if !it.top && r.Current.Fn != nil && it.pc != r.Current.Fn.Entry {
|
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
|
// if the return address is the entry point of the function that
|
||||||
|
@ -383,11 +383,11 @@ func MustHaveCgo(t *testing.T) {
|
|||||||
func RegabiSupported() bool {
|
func RegabiSupported() bool {
|
||||||
// Tracks regabiSupported variable in ParseGOEXPERIMENT internal/buildcfg/exp.go
|
// Tracks regabiSupported variable in ParseGOEXPERIMENT internal/buildcfg/exp.go
|
||||||
switch {
|
switch {
|
||||||
case !goversion.VersionAfterOrEqual(runtime.Version(), 1, 17): // < 1.17
|
case goversion.VersionAfterOrEqual(runtime.Version(), 1, 18):
|
||||||
return false
|
return runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "ppc64"
|
||||||
case goversion.VersionAfterOrEqual(runtime.Version(), 1, 17):
|
case goversion.VersionAfterOrEqual(runtime.Version(), 1, 17):
|
||||||
return runtime.GOARCH == "amd64" && (runtime.GOOS == "android" || runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows")
|
return runtime.GOARCH == "amd64" && (runtime.GOOS == "android" || runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows")
|
||||||
default: // >= 1.18
|
default:
|
||||||
return runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64"
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2387,6 +2387,11 @@ func TestGlobalScopeAndVariables(t *testing.T) {
|
|||||||
[]onBreakpoint{{
|
[]onBreakpoint{{
|
||||||
// Stop at line 36
|
// Stop at line 36
|
||||||
execute: func() {
|
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)
|
client.StackTraceRequest(1, 0, 20)
|
||||||
stack := client.ExpectStackTraceResponse(t)
|
stack := client.ExpectStackTraceResponse(t)
|
||||||
checkStackFramesExact(t, stack, "main.main", 36, 1000, 3, 3)
|
checkStackFramesExact(t, stack, "main.main", 36, 1000, 3, 3)
|
||||||
@ -2454,6 +2459,12 @@ func TestRegistersScopeAndVariables(t *testing.T) {
|
|||||||
[]onBreakpoint{{
|
[]onBreakpoint{{
|
||||||
// Stop at line 36
|
// Stop at line 36
|
||||||
execute: func() {
|
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)
|
client.StackTraceRequest(1, 0, 20)
|
||||||
stack := client.ExpectStackTraceResponse(t)
|
stack := client.ExpectStackTraceResponse(t)
|
||||||
checkStackFramesExact(t, stack, "main.main", 36, 1000, 3, 3)
|
checkStackFramesExact(t, stack, "main.main", 36, 1000, 3, 3)
|
||||||
|
22
vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go
generated
vendored
22
vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go
generated
vendored
@ -331,7 +331,7 @@ func (p *iimporter) pkgAt(off uint64) *types.Package {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *iimporter) typAt(off uint64, base *types.Named) types.Type {
|
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
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,12 +343,30 @@ func (p *iimporter) typAt(off uint64, base *types.Named) types.Type {
|
|||||||
r.declReader.Reset(p.declData[off-predeclReserved:])
|
r.declReader.Reset(p.declData[off-predeclReserved:])
|
||||||
t := r.doType(base)
|
t := r.doType(base)
|
||||||
|
|
||||||
if base == nil || !isInterface(t) {
|
if canReuse(base, t) {
|
||||||
p.typCache[off] = t
|
p.typCache[off] = t
|
||||||
}
|
}
|
||||||
return 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 {
|
type importReader struct {
|
||||||
p *iimporter
|
p *iimporter
|
||||||
declReader bytes.Reader
|
declReader bytes.Reader
|
||||||
|
3
vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go
generated
vendored
3
vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go
generated
vendored
@ -16,5 +16,8 @@ func additionalPredeclared() []types.Type {
|
|||||||
return []types.Type{
|
return []types.Type{
|
||||||
// comparable
|
// comparable
|
||||||
types.Universe.Lookup("comparable").Type(),
|
types.Universe.Lookup("comparable").Type(),
|
||||||
|
|
||||||
|
// any
|
||||||
|
types.Universe.Lookup("any").Type(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
vendor/golang.org/x/tools/internal/typeparams/common.go
generated
vendored
7
vendor/golang.org/x/tools/internal/typeparams/common.go
generated
vendored
@ -13,6 +13,7 @@ package typeparams
|
|||||||
import (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"go/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A IndexExprData holds data from both ast.IndexExpr and the new
|
// A IndexExprData holds data from both ast.IndexExpr and the new
|
||||||
@ -23,3 +24,9 @@ type IndexExprData struct {
|
|||||||
Indices []ast.Expr // index expressions
|
Indices []ast.Expr // index expressions
|
||||||
Rbrack token.Pos // position of "]"
|
Rbrack token.Pos // position of "]"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsTypeParam reports whether t is a type parameter.
|
||||||
|
func IsTypeParam(t types.Type) bool {
|
||||||
|
_, ok := t.(*TypeParam)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
164
vendor/golang.org/x/tools/internal/typeparams/normalize.go
generated
vendored
164
vendor/golang.org/x/tools/internal/typeparams/normalize.go
generated
vendored
@ -16,92 +16,96 @@ import (
|
|||||||
|
|
||||||
const debug = false
|
const debug = false
|
||||||
|
|
||||||
// NormalizeInterface returns the normal form of the interface iface, or nil if iface
|
var ErrEmptyTypeSet = errors.New("empty type set")
|
||||||
// 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.
|
// 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
|
// Structural type restrictions of a type parameter are created via
|
||||||
// reasonably normalize (for example, contains unions with more than a hundred
|
// non-interface types embedded in its constraint interface (directly, or via a
|
||||||
// terms).
|
// 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:
|
// With interface embedding and unions, the specification of structural type
|
||||||
// - it has 0 or 1 embedded types.
|
// restrictions may be arbitrarily complex. For example, consider the
|
||||||
// - its embedded type is either a types.Union or has a concrete
|
// following:
|
||||||
// (non-interface) underlying type
|
//
|
||||||
// - if the embedded type is a union, each term of the union has a concrete
|
// type A interface{ ~string|~[]byte }
|
||||||
// underlying type, and no terms may be removed without changing the type set
|
//
|
||||||
// of the interface
|
// type B interface{ int|string }
|
||||||
func NormalizeInterface(iface *types.Interface) (*types.Interface, error) {
|
//
|
||||||
var methods []*types.Func
|
// type C interface { ~string|~int }
|
||||||
for i := 0; i < iface.NumMethods(); i++ {
|
//
|
||||||
methods = append(methods, iface.Method(i))
|
// 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
|
iface, _ := constraint.Underlying().(*types.Interface)
|
||||||
tset, err := computeTermSet(iface, make(map[types.Type]*termSet), 0)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch {
|
if tset.terms.isEmpty() {
|
||||||
case tset.terms.isEmpty():
|
return nil, ErrEmptyTypeSet
|
||||||
// Special case: as documented
|
}
|
||||||
|
if tset.terms.isAll() {
|
||||||
return nil, nil
|
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))
|
|
||||||
}
|
}
|
||||||
|
var terms []*Term
|
||||||
return types.NewInterfaceType(methods, embeddeds), nil
|
for _, term := range tset.terms {
|
||||||
}
|
terms = append(terms, NewTerm(term.tilde, term.typ))
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
return terms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// A termSet holds the normalized set of terms for a given type.
|
// 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...)
|
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 {
|
if t == nil {
|
||||||
panic("nil type")
|
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 {
|
if _, ok := embedded.Underlying().(*TypeParam); ok {
|
||||||
return nil, fmt.Errorf("invalid embedded type %T", embedded)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -173,7 +177,7 @@ func computeTermSet(t types.Type, seen map[types.Type]*termSet, depth int) (res
|
|||||||
var terms termlist
|
var terms termlist
|
||||||
switch t.Type().Underlying().(type) {
|
switch t.Type().Underlying().(type) {
|
||||||
case *types.Interface:
|
case *types.Interface:
|
||||||
tset2, err := computeTermSet(t.Type(), seen, depth+1)
|
tset2, err := computeTermSetInternal(t.Type(), seen, depth+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
1
vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go
generated
vendored
1
vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go
generated
vendored
@ -75,6 +75,7 @@ func ForFuncType(*ast.FuncType) *ast.FieldList {
|
|||||||
// this Go version. Its methods panic on use.
|
// this Go version. Its methods panic on use.
|
||||||
type TypeParam struct{ types.Type }
|
type TypeParam struct{ types.Type }
|
||||||
|
|
||||||
|
func (*TypeParam) Index() int { unsupported(); return 0 }
|
||||||
func (*TypeParam) Constraint() types.Type { unsupported(); return nil }
|
func (*TypeParam) Constraint() types.Type { unsupported(); return nil }
|
||||||
func (*TypeParam) Obj() *types.TypeName { unsupported(); return nil }
|
func (*TypeParam) Obj() *types.TypeName { unsupported(); return nil }
|
||||||
|
|
||||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -73,7 +73,7 @@ golang.org/x/sys/execabs
|
|||||||
golang.org/x/sys/internal/unsafeheader
|
golang.org/x/sys/internal/unsafeheader
|
||||||
golang.org/x/sys/unix
|
golang.org/x/sys/unix
|
||||||
golang.org/x/sys/windows
|
golang.org/x/sys/windows
|
||||||
# golang.org/x/tools v0.1.8-0.20211028023602-8de2a7fd1736
|
# golang.org/x/tools v0.1.8
|
||||||
## explicit
|
## explicit
|
||||||
golang.org/x/tools/go/gcexportdata
|
golang.org/x/tools/go/gcexportdata
|
||||||
golang.org/x/tools/go/internal/gcimporter
|
golang.org/x/tools/go/internal/gcimporter
|
||||||
|
Loading…
Reference in New Issue
Block a user