pkg/terminal: support ctrlz for shell job control (#2806)

* pkg/terminal: support ctrlz for shell job control

This required forking peterh/liner under the go-delve org and using that
instead since upstream is not open to supporting this feature.

Fixes #2157

* Update liner

* Update liner but correctly this time

* upgrade golang.org/x/tools to 0.1.9
This commit is contained in:
Derek Parker 2022-02-10 09:50:55 -08:00 committed by GitHub
parent 9c18bb46dd
commit dee4437bd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 173 additions and 152 deletions

4
go.mod

@ -2,6 +2,8 @@ module github.com/go-delve/delve
go 1.16 go 1.16
replace github.com/peterh/liner v1.2.2 => github.com/go-delve/liner v1.2.2-1
require ( require (
github.com/cilium/ebpf v0.7.0 github.com/cilium/ebpf v0.7.0
github.com/cosiner/argv v0.1.0 github.com/cosiner/argv v0.1.0
@ -18,6 +20,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-20211117180635-dee7805ff2e1 golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1
golang.org/x/tools v0.1.8 golang.org/x/tools v0.1.9
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
) )

13
go.sum

@ -53,6 +53,8 @@ github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebP
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-delve/liner v1.2.2-1 h1:0hGpZh6vjI6LFTlXuHFCX9PebaluzDzps2owdMrrSuk=
github.com/go-delve/liner v1.2.2-1/go.mod h1:biJCRbqp51wS+I92HMqn5H8/A0PAhxn2vyOT+JqhiGI=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
@ -151,10 +153,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterh/liner v1.2.1 h1:O4BlKaq/LWu6VRWmol4ByWfzx6MfXc5Op5HETyIy5yg=
github.com/peterh/liner v1.2.1/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
github.com/peterh/liner v1.2.2 h1:aJ4AOodmL+JxOZZEL2u9iJf8omNRpqHc/EbrK+3mAXw=
github.com/peterh/liner v1.2.2/go.mod h1:xFwJyiKIXJZUKItq5dGHZSTBRAuG/CpeNpWLyiNRNwI=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -281,7 +279,6 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/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-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI= golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI=
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -311,10 +308,8 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/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.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.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
golang.org/x/tools v0.1.8-0.20211028023602-8de2a7fd1736/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.9/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=

@ -101,6 +101,7 @@ func New(client service.Client, conf *config.Config) *Term {
cmds: cmds, cmds: cmds,
stdout: &transcriptWriter{w: os.Stdout}, stdout: &transcriptWriter{w: os.Stdout},
} }
t.line.SetCtrlZStop(true)
if strings.ToLower(os.Getenv("TERM")) != "dumb" { if strings.ToLower(os.Getenv("TERM")) != "dumb" {
t.stdout.w = getColorableWriter() t.stdout.w = getColorableWriter()

@ -26,6 +26,7 @@ type commonState struct {
columns int columns int
killRing *ring.Ring killRing *ring.Ring
ctrlCAborts bool ctrlCAborts bool
ctrlZStop bool
r *bufio.Reader r *bufio.Reader
tabStyle TabStyle tabStyle TabStyle
multiLineMode bool multiLineMode bool
@ -229,6 +230,12 @@ func (s *State) SetCtrlCAborts(aborts bool) {
s.ctrlCAborts = aborts s.ctrlCAborts = aborts
} }
// SetCtrlZStop sets whether Prompt on a supported terminal will send
// SIGTSTP when Ctrl-Z is pressed. The default is false
func (s *State) SetCtrlZStop(stop bool) {
s.ctrlZStop = stop
}
// SetMultiLineMode sets whether line is auto-wrapped. The default is false (single line). // SetMultiLineMode sets whether line is auto-wrapped. The default is false (single line).
func (s *State) SetMultiLineMode(mlmode bool) { func (s *State) SetMultiLineMode(mlmode bool) {
s.multiLineMode = mlmode s.multiLineMode = mlmode

@ -1,4 +1,4 @@
module github.com/peterh/liner module github.com/go-delve/liner
require ( require (
github.com/mattn/go-runewidth v0.0.3 github.com/mattn/go-runewidth v0.0.3

@ -793,6 +793,10 @@ mainLoop:
pos = 0 pos = 0
fmt.Print(prompt) fmt.Print(prompt)
s.restartPrompt() s.restartPrompt()
case ctrlZ:
if s.ctrlZStop {
handleCtrlZ()
}
case ctrlH, bs: // Backspace case ctrlH, bs: // Backspace
if pos <= 0 { if pos <= 0 {
s.doBeep() s.doBeep()
@ -829,7 +833,7 @@ mainLoop:
case esc: case esc:
// DO NOTHING // DO NOTHING
// Unused keys // Unused keys
case ctrlG, ctrlO, ctrlQ, ctrlS, ctrlV, ctrlX, ctrlZ: case ctrlG, ctrlO, ctrlQ, ctrlS, ctrlV, ctrlX:
fallthrough fallthrough
// Catch unhandled control codes (anything <= 31) // Catch unhandled control codes (anything <= 31)
case 0, 28, 29, 30, 31: case 0, 28, 29, 30, 31:
@ -1090,9 +1094,13 @@ mainLoop:
pos = 0 pos = 0
fmt.Print(prompt) fmt.Print(prompt)
s.restartPrompt() s.restartPrompt()
case ctrlZ:
if s.ctrlZStop {
handleCtrlZ()
}
// Unused keys // Unused keys
case esc, tab, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlK, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS, case esc, tab, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlK, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS,
ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ: ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY:
fallthrough fallthrough
// Catch unhandled control codes (anything <= 31) // Catch unhandled control codes (anything <= 31)
case 0, 28, 29, 30, 31: case 0, 28, 29, 30, 31:

15
vendor/github.com/peterh/liner/signal_unix.go generated vendored Normal file

@ -0,0 +1,15 @@
// +build linux darwin openbsd freebsd netbsd
package liner
import (
"os"
"syscall"
)
func handleCtrlZ() {
p, err := os.FindProcess(os.Getpid())
if err == nil {
p.Signal(syscall.SIGTSTP)
}
}

3
vendor/github.com/peterh/liner/signal_windows.go generated vendored Normal file

@ -0,0 +1,3 @@
package liner
func handleCtrlZ() {}

@ -20,6 +20,7 @@ import (
"math/big" "math/big"
"reflect" "reflect"
"sort" "sort"
"strconv"
"strings" "strings"
"golang.org/x/tools/internal/typeparams" "golang.org/x/tools/internal/typeparams"
@ -158,7 +159,7 @@ func (w *exportWriter) writeIndex(index map[types.Object]uint64) {
} }
for obj := range index { for obj := range index {
name := w.p.indexName(obj) name := w.p.exportName(obj)
pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], pkgObj{obj, name}) pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], pkgObj{obj, name})
} }
@ -190,10 +191,9 @@ func (w *exportWriter) writeIndex(index map[types.Object]uint64) {
} }
} }
// indexName returns the 'indexed' name of an object. It differs from // exportName returns the 'exported' name of an object. It differs from
// obj.Name() only for type parameter names, where the name is qualified by // obj.Name() only for type parameters (see tparamExportName for details).
// owner. func (p *iexporter) exportName(obj types.Object) (res string) {
func (p *iexporter) indexName(obj types.Object) (res string) {
if name := p.tparamNames[obj]; name != "" { if name := p.tparamNames[obj]; name != "" {
return name return name
} }
@ -219,7 +219,7 @@ type iexporter struct {
data0 intWriter data0 intWriter
declIndex map[types.Object]uint64 declIndex map[types.Object]uint64
tparamNames map[types.Object]string // typeparam->qualified name tparamNames map[types.Object]string // typeparam->exported name
typIndex map[types.Type]uint64 typIndex map[types.Type]uint64
indent int // for tracing support indent int // for tracing support
@ -310,14 +310,15 @@ func (p *iexporter) doDecl(obj types.Object) {
w.tag('G') w.tag('G')
} }
w.pos(obj.Pos()) w.pos(obj.Pos())
// The tparam list of the function type is the // The tparam list of the function type is the declaration of the type
// declaration of the type params. So, write out the type // params. So, write out the type params right now. Then those type params
// params right now. Then those type params will be // will be referenced via their type offset (via typOff) in all other
// referenced via their type offset (via typOff) in all // places in the signature and function where they are used.
// other places in the signature and function that they //
// are used. // While importing the type parameters, tparamList computes and records
// their export name, so that it can be later used when writing the index.
if tparams := typeparams.ForSignature(sig); tparams.Len() > 0 { if tparams := typeparams.ForSignature(sig); tparams.Len() > 0 {
w.tparamList(obj, tparams, obj.Pkg()) w.tparamList(obj.Name(), tparams, obj.Pkg())
} }
w.signature(sig) w.signature(sig)
@ -365,7 +366,9 @@ func (p *iexporter) doDecl(obj types.Object) {
w.pos(obj.Pos()) w.pos(obj.Pos())
if typeparams.ForNamed(named).Len() > 0 { if typeparams.ForNamed(named).Len() > 0 {
w.tparamList(obj, typeparams.ForNamed(named), obj.Pkg()) // While importing the type parameters, tparamList computes and records
// their export name, so that it can be later used when writing the index.
w.tparamList(obj.Name(), typeparams.ForNamed(named), obj.Pkg())
} }
underlying := obj.Type().Underlying() underlying := obj.Type().Underlying()
@ -385,11 +388,13 @@ func (p *iexporter) doDecl(obj types.Object) {
// Receiver type parameters are type arguments of the receiver type, so // Receiver type parameters are type arguments of the receiver type, so
// their name must be qualified before exporting recv. // their name must be qualified before exporting recv.
rparams := typeparams.RecvTypeParams(sig) if rparams := typeparams.RecvTypeParams(sig); rparams.Len() > 0 {
for i := 0; i < rparams.Len(); i++ { prefix := obj.Name() + "." + m.Name()
rparam := rparams.At(i) for i := 0; i < rparams.Len(); i++ {
name := obj.Name() + "." + m.Name() + "." + rparam.Obj().Name() rparam := rparams.At(i)
w.p.tparamNames[rparam.Obj()] = name name := tparamExportName(prefix, rparam)
w.p.tparamNames[rparam.Obj()] = name
}
} }
w.param(sig.Recv()) w.param(sig.Recv())
w.signature(sig) w.signature(sig)
@ -490,7 +495,7 @@ func (w *exportWriter) pkg(pkg *types.Package) {
} }
func (w *exportWriter) qualifiedIdent(obj types.Object) { func (w *exportWriter) qualifiedIdent(obj types.Object) {
name := w.p.indexName(obj) name := w.p.exportName(obj)
// Ensure any referenced declarations are written out too. // Ensure any referenced declarations are written out too.
w.p.pushDecl(obj) w.p.pushDecl(obj)
@ -672,18 +677,49 @@ func (w *exportWriter) typeList(ts *typeparams.TypeList, pkg *types.Package) {
} }
} }
func (w *exportWriter) tparamList(owner types.Object, list *typeparams.TypeParamList, pkg *types.Package) { func (w *exportWriter) tparamList(prefix string, list *typeparams.TypeParamList, pkg *types.Package) {
ll := uint64(list.Len()) ll := uint64(list.Len())
w.uint64(ll) w.uint64(ll)
for i := 0; i < list.Len(); i++ { for i := 0; i < list.Len(); i++ {
tparam := list.At(i) tparam := list.At(i)
// Qualify the type parameter name before exporting its type. // Set the type parameter exportName before exporting its type.
name := owner.Name() + "." + tparam.Obj().Name() exportName := tparamExportName(prefix, tparam)
w.p.tparamNames[tparam.Obj()] = name w.p.tparamNames[tparam.Obj()] = exportName
w.typ(list.At(i), pkg) w.typ(list.At(i), pkg)
} }
} }
const blankMarker = "$"
// tparamExportName returns the 'exported' name of a type parameter, which
// differs from its actual object name: it is prefixed with a qualifier, and
// blank type parameter names are disambiguated by their index in the type
// parameter list.
func tparamExportName(prefix string, tparam *typeparams.TypeParam) string {
assert(prefix != "")
name := tparam.Obj().Name()
if name == "_" {
name = blankMarker + strconv.Itoa(tparam.Index())
}
return prefix + "." + name
}
// tparamName returns the real name of a type parameter, after stripping its
// qualifying prefix and reverting blank-name encoding. See tparamExportName
// for details.
func tparamName(exportName string) string {
// Remove the "path" from the type param name that makes it unique.
ix := strings.LastIndex(exportName, ".")
if ix < 0 {
errorf("malformed type parameter export name %s: missing prefix", exportName)
}
name := exportName[ix+1:]
if strings.HasPrefix(name, blankMarker) {
return "_"
}
return name
}
func (w *exportWriter) paramList(tup *types.Tuple) { func (w *exportWriter) paramList(tup *types.Tuple) {
n := tup.Len() n := tup.Len()
w.uint64(uint64(n)) w.uint64(uint64(n))

@ -45,20 +45,11 @@ func (r *intReader) uint64() uint64 {
} }
// Keep this in sync with constants in iexport.go. // Keep this in sync with constants in iexport.go.
//
// Temporarily, the x/tools importer accepts generic code at both version 1 and
// 2. However, version 2 contains some breaking changes on top of version 1:
// - the 'implicit' bit is added to exported constraints
// - a 'kind' byte is added to constant values (not yet done)
//
// Once we've completed the bump to version 2 in the standard library, we'll
// remove support for generics here at version 1.
const ( const (
iexportVersionGo1_11 = 0 iexportVersionGo1_11 = 0
iexportVersionPosCol = 1 iexportVersionPosCol = 1
iexportVersionGo1_18 = 2 iexportVersionGo1_18 = 2
// TODO: before release, change this back to 2. iexportVersionGenerics = 2
iexportVersionGenerics = iexportVersionPosCol
) )
type ident struct { type ident struct {
@ -447,12 +438,7 @@ func (r *importReader) obj(name string) {
if r.p.version < iexportVersionGenerics { if r.p.version < iexportVersionGenerics {
errorf("unexpected type param type") errorf("unexpected type param type")
} }
// Remove the "path" from the type param name that makes it unique name0 := tparamName(name)
ix := strings.LastIndex(name, ".")
if ix < 0 {
errorf("missing path for type param")
}
name0 := name[ix+1:]
tn := types.NewTypeName(pos, r.currPkg, name0, nil) tn := types.NewTypeName(pos, r.currPkg, name0, nil)
t := typeparams.NewTypeParam(tn, nil) t := typeparams.NewTypeParam(tn, nil)

@ -328,6 +328,9 @@ type Package struct {
// The NeedSyntax LoadMode bit populates this field for packages matching the patterns. // The NeedSyntax LoadMode bit populates this field for packages matching the patterns.
// If NeedDeps and NeedImports are also set, this field will also be populated // If NeedDeps and NeedImports are also set, this field will also be populated
// for dependencies. // for dependencies.
//
// Syntax is kept in the same order as CompiledGoFiles, with the caveat that nils are
// removed. If parsing returned nil, Syntax may be shorter than CompiledGoFiles.
Syntax []*ast.File Syntax []*ast.File
// TypesInfo provides type information about the package's syntax trees. // TypesInfo provides type information about the package's syntax trees.

@ -2,12 +2,25 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package typeparams provides functions to work indirectly with type parameter // Package typeparams contains common utilities for writing tools that interact
// data stored in go/ast and go/types objects, while these API are guarded by a // with generic Go code, as introduced with Go 1.18.
// build constraint.
// //
// This package exists to make it easier for tools to work with generic code, // Many of the types and functions in this package are proxies for the new APIs
// while also compiling against older Go versions. // introduced in the standard library with Go 1.18. For example, the
// typeparams.Union type is an alias for go/types.Union, and the ForTypeSpec
// function returns the value of the go/ast.TypeSpec.TypeParams field. At Go
// versions older than 1.18 these helpers are implemented as stubs, allowing
// users of this package to write code that handles generic constructs inline,
// even if the Go version being used to compile does not support generics.
//
// Additionally, this package contains common utilities for working with the
// new generic constructs, to supplement the standard library APIs. Notably,
// the StructuralTerms API computes a minimal representation of the structural
// restrictions on a type parameter. In the future, this API may be available
// from go/types.
//
// See the example/README.md for a more detailed guide on how to update tools
// to support generics.
package typeparams package typeparams
import ( import (
@ -16,13 +29,47 @@ import (
"go/types" "go/types"
) )
// A IndexExprData holds data from both ast.IndexExpr and the new // UnpackIndexExpr extracts data from AST nodes that represent index
// ast.MultiIndexExpr, which was introduced in Go 1.18. // expressions.
type IndexExprData struct { //
X ast.Expr // expression // For an ast.IndexExpr, the resulting indices slice will contain exactly one
Lbrack token.Pos // position of "[" // index expression. For an ast.IndexListExpr (go1.18+), it may have a variable
Indices []ast.Expr // index expressions // number of index expressions.
Rbrack token.Pos // position of "]" //
// For nodes that don't represent index expressions, the first return value of
// UnpackIndexExpr will be nil.
func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) {
switch e := n.(type) {
case *ast.IndexExpr:
return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack
case *IndexListExpr:
return e.X, e.Lbrack, e.Indices, e.Rbrack
}
return nil, token.NoPos, nil, token.NoPos
}
// PackIndexExpr returns an *ast.IndexExpr or *ast.IndexListExpr, depending on
// the cardinality of indices. Calling PackIndexExpr with len(indices) == 0
// will panic.
func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr {
switch len(indices) {
case 0:
panic("empty indices")
case 1:
return &ast.IndexExpr{
X: x,
Lbrack: lbrack,
Index: indices[0],
Rbrack: rbrack,
}
default:
return &IndexListExpr{
X: x,
Lbrack: lbrack,
Indices: indices,
Rbrack: rbrack,
}
}
} }
// IsTypeParam reports whether t is a type parameter. // IsTypeParam reports whether t is a type parameter.

@ -17,38 +17,6 @@ func unsupported() {
panic("type parameters are unsupported at this go version") panic("type parameters are unsupported at this go version")
} }
// GetIndexExprData extracts data from *ast.IndexExpr nodes.
// For other nodes, GetIndexExprData returns nil.
func GetIndexExprData(n ast.Node) *IndexExprData {
if e, _ := n.(*ast.IndexExpr); e != nil {
return &IndexExprData{
X: e.X,
Lbrack: e.Lbrack,
Indices: []ast.Expr{e.Index},
Rbrack: e.Rbrack,
}
}
return nil
}
// PackIndexExpr returns an *ast.IndexExpr with the given index.
// Calling PackIndexExpr with len(indices) != 1 will panic.
func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr {
switch len(indices) {
case 0:
panic("empty indices")
case 1:
return &ast.IndexExpr{
X: x,
Lbrack: lbrack,
Index: indices[0],
Rbrack: rbrack,
}
default:
panic("cannot pack multiple indices at this go version")
}
}
// IndexListExpr is a placeholder type, as type parameters are not supported at // IndexListExpr is a placeholder type, as type parameters are not supported at
// this Go version. Its methods panic on use. // this Go version. Its methods panic on use.
type IndexListExpr struct { type IndexListExpr struct {

@ -9,59 +9,9 @@ package typeparams
import ( import (
"go/ast" "go/ast"
"go/token"
"go/types" "go/types"
) )
// GetIndexExprData extracts data from AST nodes that represent index
// expressions.
//
// For an ast.IndexExpr, the resulting IndexExprData will have exactly one
// index expression. For an ast.IndexListExpr (go1.18+), it may have a
// variable number of index expressions.
//
// For nodes that don't represent index expressions, GetIndexExprData returns
// nil.
// TODO(rfindley): remove this function in favor of using the alias below.
func GetIndexExprData(n ast.Node) *IndexExprData {
switch e := n.(type) {
case *ast.IndexExpr:
return &IndexExprData{
X: e.X,
Lbrack: e.Lbrack,
Indices: []ast.Expr{e.Index},
Rbrack: e.Rbrack,
}
case *ast.IndexListExpr:
return (*IndexExprData)(e)
}
return nil
}
// PackIndexExpr returns an *ast.IndexExpr or *ast.IndexListExpr, depending on
// the cardinality of indices. Calling PackIndexExpr with len(indices) == 0
// will panic.
func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr {
switch len(indices) {
case 0:
panic("empty indices")
case 1:
return &ast.IndexExpr{
X: x,
Lbrack: lbrack,
Index: indices[0],
Rbrack: rbrack,
}
default:
return &ast.IndexListExpr{
X: x,
Lbrack: lbrack,
Indices: indices,
Rbrack: rbrack,
}
}
}
// IndexListExpr is an alias for ast.IndexListExpr. // IndexListExpr is an alias for ast.IndexListExpr.
type IndexListExpr = ast.IndexListExpr type IndexListExpr = ast.IndexListExpr

4
vendor/modules.txt vendored

@ -36,7 +36,7 @@ github.com/mattn/go-colorable
github.com/mattn/go-isatty github.com/mattn/go-isatty
# github.com/mattn/go-runewidth v0.0.3 # github.com/mattn/go-runewidth v0.0.3
github.com/mattn/go-runewidth github.com/mattn/go-runewidth
# github.com/peterh/liner v1.2.2 # github.com/peterh/liner v1.2.2 => github.com/go-delve/liner v1.2.2-1
## explicit ## explicit
github.com/peterh/liner github.com/peterh/liner
# github.com/russross/blackfriday/v2 v2.0.1 # github.com/russross/blackfriday/v2 v2.0.1
@ -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 # golang.org/x/tools v0.1.9
## 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