mirror of
https://github.com/golang/go
synced 2024-09-29 07:24:32 -06:00
go/types: generate builtins.go from types2 source
Minor changes to types2.builtin.go to simplify automatic translation. Added new conversion functions to generate_test.go to handle the translation of builtins.go. While at it, added additional helper functions to generate_test.go and simplified some of the existing conversion functions. This CL reduces the amount of code that needs to be maintained manually by about 1000 LOC. Change-Id: I1bd5c8eda0c0194a0b47e69882d2b987d91eef50 Reviewed-on: https://go-review.googlesource.com/c/go/+/562835 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Robert Findley <rfindley@google.com> Reviewed-by: Robert Griesemer <gri@google.com> Auto-Submit: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
808c8fb815
commit
81609c454b
@ -23,8 +23,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||
// append is the only built-in that permits the use of ... for the last argument
|
||||
bin := predeclaredFuncs[id]
|
||||
if hasDots(call) && id != _Append {
|
||||
//check.errorf(call.Ellipsis, invalidOp + "invalid use of ... with built-in %s", bin.name)
|
||||
check.errorf(call,
|
||||
check.errorf(dddErrPos(call),
|
||||
InvalidDotDotDot,
|
||||
invalidOp+"invalid use of ... with built-in %s", bin.name)
|
||||
check.use(argList...)
|
||||
@ -76,7 +75,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||
msg = "too many"
|
||||
}
|
||||
if msg != "" {
|
||||
check.errorf(call, WrongArgCount, invalidOp+"%s arguments for %v (expected %d, found %d)", msg, call, bin.nargs, nargs)
|
||||
check.errorf(argErrPos(call), WrongArgCount, invalidOp+"%s arguments for %v (expected %d, found %d)", msg, call, bin.nargs, nargs)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -24,5 +24,16 @@ func cmpPos(p, q syntax.Pos) int { return p.Cmp(q) }
|
||||
// hasDots reports whether the last argument in the call is followed by ...
|
||||
func hasDots(call *syntax.CallExpr) bool { return call.HasDots }
|
||||
|
||||
// dddErrPos returns the node (poser) for reporting an invalid ... use in a call.
|
||||
func dddErrPos(call *syntax.CallExpr) *syntax.CallExpr {
|
||||
// TODO(gri) should use "..." instead of call position
|
||||
return call
|
||||
}
|
||||
|
||||
// argErrPos returns the node (poser) for reportign an invalid argument count.
|
||||
func argErrPos(call *syntax.CallExpr) *syntax.CallExpr {
|
||||
return call
|
||||
}
|
||||
|
||||
// ExprString returns a string representation of x.
|
||||
func ExprString(x syntax.Node) string { return syntax.String(x) }
|
||||
|
@ -1,3 +1,5 @@
|
||||
// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
|
||||
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
@ -23,7 +25,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
// append is the only built-in that permits the use of ... for the last argument
|
||||
bin := predeclaredFuncs[id]
|
||||
if hasDots(call) && id != _Append {
|
||||
check.errorf(atPos(call.Ellipsis),
|
||||
check.errorf(dddErrPos(call),
|
||||
InvalidDotDotDot,
|
||||
invalidOp+"invalid use of ... with built-in %s", bin.name)
|
||||
check.use(argList...)
|
||||
@ -75,7 +77,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
msg = "too many"
|
||||
}
|
||||
if msg != "" {
|
||||
check.errorf(inNode(call, call.Rparen), WrongArgCount, invalidOp+"%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs)
|
||||
check.errorf(argErrPos(call), WrongArgCount, invalidOp+"%s arguments for %v (expected %d, found %d)", msg, call, bin.nargs, nargs)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -99,81 +99,108 @@ var filemap = map[string]action{
|
||||
"array.go": nil,
|
||||
"api_predicates.go": nil,
|
||||
"basic.go": nil,
|
||||
"chan.go": nil,
|
||||
"const.go": func(f *ast.File) { fixTokenPos(f) },
|
||||
"context.go": nil,
|
||||
"context_test.go": nil,
|
||||
"errsupport.go": nil,
|
||||
"gccgosizes.go": nil,
|
||||
"gcsizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") },
|
||||
"hilbert_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"`, `"go/types"`) },
|
||||
"infer.go": func(f *ast.File) {
|
||||
fixTokenPos(f)
|
||||
fixInferSig(f)
|
||||
"builtins.go": func(f *ast.File) {
|
||||
renameImportPath(f, `"cmd/compile/internal/syntax"`, `"go/ast"`)
|
||||
renameIdents(f, "syntax->ast")
|
||||
renameSelectors(f, "ArgList->Args")
|
||||
fixSelValue(f)
|
||||
fixAtPosCall(f)
|
||||
},
|
||||
"chan.go": nil,
|
||||
"const.go": func(f *ast.File) { fixTokenPos(f) },
|
||||
"context.go": nil,
|
||||
"context_test.go": nil,
|
||||
"errsupport.go": nil,
|
||||
"gccgosizes.go": nil,
|
||||
"gcsizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") },
|
||||
"hilbert_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"`, `"go/types"`) },
|
||||
"infer.go": func(f *ast.File) { fixTokenPos(f); fixInferSig(f) },
|
||||
// "initorder.go": fixErrErrorfCall, // disabled for now due to unresolved error_ use implications for gopls
|
||||
"instantiate.go": func(f *ast.File) { fixTokenPos(f); fixCheckErrorfCall(f) },
|
||||
"instantiate_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"`, `"go/types"`) },
|
||||
"lookup.go": func(f *ast.File) { fixTokenPos(f) },
|
||||
"main_test.go": nil,
|
||||
"map.go": nil,
|
||||
"named.go": func(f *ast.File) { fixTokenPos(f); fixTraceSel(f) },
|
||||
"named.go": func(f *ast.File) { fixTokenPos(f); renameSelectors(f, "Trace->_Trace") },
|
||||
"object.go": func(f *ast.File) { fixTokenPos(f); renameIdents(f, "NewTypeNameLazy->_NewTypeNameLazy") },
|
||||
"object_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"`, `"go/types"`) },
|
||||
"objset.go": nil,
|
||||
"package.go": nil,
|
||||
"pointer.go": nil,
|
||||
"predicates.go": nil,
|
||||
"scope.go": func(f *ast.File) {
|
||||
fixTokenPos(f)
|
||||
renameIdents(f, "Squash->squash", "InsertLazy->_InsertLazy")
|
||||
},
|
||||
"selection.go": nil,
|
||||
"sizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") },
|
||||
"slice.go": nil,
|
||||
"subst.go": func(f *ast.File) { fixTokenPos(f); fixTraceSel(f) },
|
||||
"termlist.go": nil,
|
||||
"termlist_test.go": nil,
|
||||
"tuple.go": nil,
|
||||
"typelists.go": nil,
|
||||
"typeparam.go": nil,
|
||||
"typeterm_test.go": nil,
|
||||
"typeterm.go": nil,
|
||||
"under.go": nil,
|
||||
"unify.go": fixSprintf,
|
||||
"universe.go": fixGlobalTypVarDecl,
|
||||
"util_test.go": fixTokenPos,
|
||||
"validtype.go": nil,
|
||||
"scope.go": func(f *ast.File) { fixTokenPos(f); renameIdents(f, "Squash->squash", "InsertLazy->_InsertLazy") },
|
||||
"selection.go": nil,
|
||||
"sizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") },
|
||||
"slice.go": nil,
|
||||
"subst.go": func(f *ast.File) { fixTokenPos(f); renameSelectors(f, "Trace->_Trace") },
|
||||
"termlist.go": nil,
|
||||
"termlist_test.go": nil,
|
||||
"tuple.go": nil,
|
||||
"typelists.go": nil,
|
||||
"typeparam.go": nil,
|
||||
"typeterm_test.go": nil,
|
||||
"typeterm.go": nil,
|
||||
"under.go": nil,
|
||||
"unify.go": fixSprintf,
|
||||
"universe.go": fixGlobalTypVarDecl,
|
||||
"util_test.go": fixTokenPos,
|
||||
"validtype.go": nil,
|
||||
}
|
||||
|
||||
// TODO(gri) We should be able to make these rewriters more configurable/composable.
|
||||
// For now this is a good starting point.
|
||||
|
||||
// renameIdent renames identifiers: each renames entry is of the form from->to.
|
||||
// Note: This doesn't change the use of the identifiers in comments.
|
||||
func renameIdents(f *ast.File, renames ...string) {
|
||||
var list [][]string
|
||||
// A renameMap maps old names to new names.
|
||||
type renameMap map[string]string
|
||||
|
||||
// makeRenameMap returns a renameMap populates from renames entries of the form "from->to".
|
||||
func makeRenameMap(renames ...string) renameMap {
|
||||
m := make(renameMap)
|
||||
for _, r := range renames {
|
||||
s := strings.Split(r, "->")
|
||||
if len(s) != 2 {
|
||||
panic("invalid rename entry: " + r)
|
||||
}
|
||||
list = append(list, s)
|
||||
m[s[0]] = s[1]
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// rename renames the given name if a corresponding rename exists in m.
|
||||
func (m renameMap) rename(name *string) {
|
||||
if new, ok := m[*name]; ok {
|
||||
*name = new
|
||||
}
|
||||
}
|
||||
|
||||
// renameIdents renames identifiers: each renames entry is of the form "from->to".
|
||||
// Note: This doesn't change the use of the identifiers in comments.
|
||||
func renameIdents(f *ast.File, renames ...string) {
|
||||
m := makeRenameMap(renames...)
|
||||
ast.Inspect(f, func(n ast.Node) bool {
|
||||
switch n := n.(type) {
|
||||
case *ast.Ident:
|
||||
for _, r := range list {
|
||||
if n.Name == r[0] {
|
||||
n.Name = r[1]
|
||||
}
|
||||
}
|
||||
m.rename(&n.Name)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// renameSelectors is like renameIdents but only looks at selectors.
|
||||
func renameSelectors(f *ast.File, renames ...string) {
|
||||
m := makeRenameMap(renames...)
|
||||
ast.Inspect(f, func(n ast.Node) bool {
|
||||
switch n := n.(type) {
|
||||
case *ast.SelectorExpr:
|
||||
m.rename(&n.Sel.Name)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// renameImportPath renames an import path.
|
||||
func renameImportPath(f *ast.File, from, to string) {
|
||||
ast.Inspect(f, func(n ast.Node) bool {
|
||||
@ -201,7 +228,7 @@ func fixTokenPos(f *ast.File) {
|
||||
}
|
||||
case *ast.SelectorExpr:
|
||||
// rewrite syntax.Pos to token.Pos
|
||||
if x, _ := n.X.(*ast.Ident); x != nil && x.Name == "syntax" && n.Sel.Name == "Pos" {
|
||||
if x := asIdent(n.X, "syntax"); x != nil && n.Sel.Name == "Pos" {
|
||||
x.Name = "token"
|
||||
return false
|
||||
}
|
||||
@ -216,6 +243,22 @@ func fixTokenPos(f *ast.File) {
|
||||
})
|
||||
}
|
||||
|
||||
// fixSelValue updates the selector Sel.Value to Sel.Name.
|
||||
func fixSelValue(f *ast.File) {
|
||||
ast.Inspect(f, func(n ast.Node) bool {
|
||||
switch n := n.(type) {
|
||||
case *ast.SelectorExpr:
|
||||
if n.Sel.Name == "Value" {
|
||||
if selx, _ := n.X.(*ast.SelectorExpr); selx != nil && selx.Sel.Name == "Sel" {
|
||||
n.Sel.Name = "Name"
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// fixInferSig updates the Checker.infer signature to use a positioner instead of a token.Position
|
||||
// as first argument, renames the argument from "pos" to "posn", and updates a few internal uses of
|
||||
// "pos" to "posn" and "posn.Pos()" respectively.
|
||||
@ -237,7 +280,7 @@ func fixInferSig(f *ast.File) {
|
||||
switch selx.Sel.Name {
|
||||
case "renameTParams":
|
||||
// rewrite check.renameTParams(pos, ... ) to check.renameTParams(posn.Pos(), ... )
|
||||
if ident, _ := n.Args[0].(*ast.Ident); ident != nil && ident.Name == "pos" {
|
||||
if isIdent(n.Args[0], "pos") {
|
||||
pos := n.Args[0].Pos()
|
||||
fun := &ast.SelectorExpr{X: newIdent(pos, "posn"), Sel: newIdent(pos, "Pos")}
|
||||
arg := &ast.CallExpr{Fun: fun, Lparen: pos, Args: nil, Ellipsis: token.NoPos, Rparen: pos}
|
||||
@ -246,7 +289,7 @@ func fixInferSig(f *ast.File) {
|
||||
}
|
||||
case "errorf":
|
||||
// rewrite check.errorf(pos, ...) to check.errorf(posn, ...)
|
||||
if ident, _ := n.Args[0].(*ast.Ident); ident != nil && ident.Name == "pos" {
|
||||
if isIdent(n.Args[0], "pos") {
|
||||
pos := n.Args[0].Pos()
|
||||
arg := newIdent(pos, "posn")
|
||||
n.Args[0] = arg
|
||||
@ -254,7 +297,7 @@ func fixInferSig(f *ast.File) {
|
||||
}
|
||||
case "allowVersion":
|
||||
// rewrite check.allowVersion(..., pos, ...) to check.allowVersion(..., posn, ...)
|
||||
if ident, _ := n.Args[1].(*ast.Ident); ident != nil && ident.Name == "pos" {
|
||||
if isIdent(n.Args[1], "pos") {
|
||||
pos := n.Args[1].Pos()
|
||||
arg := newIdent(pos, "posn")
|
||||
n.Args[1] = arg
|
||||
@ -267,21 +310,44 @@ func fixInferSig(f *ast.File) {
|
||||
})
|
||||
}
|
||||
|
||||
// fixAtPosCall updates calls of the form atPos(x) to x.Pos() in argument lists of (check).dump calls.
|
||||
// TODO(gri) can we avoid this and just use atPos consistently in go/types and types2?
|
||||
func fixAtPosCall(f *ast.File) {
|
||||
ast.Inspect(f, func(n ast.Node) bool {
|
||||
switch n := n.(type) {
|
||||
case *ast.CallExpr:
|
||||
if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil && selx.Sel.Name == "dump" {
|
||||
for i, arg := range n.Args {
|
||||
if call, _ := arg.(*ast.CallExpr); call != nil {
|
||||
// rewrite xxx.dump(..., atPos(x), ...) to xxx.dump(..., x.Pos(), ...)
|
||||
if isIdent(call.Fun, "atPos") {
|
||||
pos := call.Args[0].Pos()
|
||||
fun := &ast.SelectorExpr{X: call.Args[0], Sel: newIdent(pos, "Pos")}
|
||||
n.Args[i] = &ast.CallExpr{Fun: fun, Lparen: pos, Rparen: pos}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// fixErrErrorfCall updates calls of the form err.errorf(obj, ...) to err.errorf(obj.Pos(), ...).
|
||||
func fixErrErrorfCall(f *ast.File) {
|
||||
ast.Inspect(f, func(n ast.Node) bool {
|
||||
switch n := n.(type) {
|
||||
case *ast.CallExpr:
|
||||
if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil {
|
||||
if ident, _ := selx.X.(*ast.Ident); ident != nil && ident.Name == "err" {
|
||||
if isIdent(selx.X, "err") {
|
||||
switch selx.Sel.Name {
|
||||
case "errorf":
|
||||
// rewrite err.errorf(obj, ... ) to err.errorf(obj.Pos(), ... )
|
||||
if ident, _ := n.Args[0].(*ast.Ident); ident != nil && ident.Name == "obj" {
|
||||
pos := n.Args[0].Pos()
|
||||
fun := &ast.SelectorExpr{X: ident, Sel: newIdent(pos, "Pos")}
|
||||
arg := &ast.CallExpr{Fun: fun, Lparen: pos, Args: nil, Ellipsis: token.NoPos, Rparen: pos}
|
||||
n.Args[0] = arg
|
||||
n.Args[0] = &ast.CallExpr{Fun: fun, Lparen: pos, Rparen: pos}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -298,15 +364,14 @@ func fixCheckErrorfCall(f *ast.File) {
|
||||
switch n := n.(type) {
|
||||
case *ast.CallExpr:
|
||||
if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil {
|
||||
if ident, _ := selx.X.(*ast.Ident); ident != nil && ident.Name == "check" {
|
||||
if isIdent(selx.X, "check") {
|
||||
switch selx.Sel.Name {
|
||||
case "errorf":
|
||||
// rewrite check.errorf(pos, ... ) to check.errorf(atPos(pos), ... )
|
||||
if ident, _ := n.Args[0].(*ast.Ident); ident != nil && ident.Name == "pos" {
|
||||
if ident := asIdent(n.Args[0], "pos"); ident != nil {
|
||||
pos := n.Args[0].Pos()
|
||||
fun := newIdent(pos, "atPos")
|
||||
arg := &ast.CallExpr{Fun: fun, Lparen: pos, Args: []ast.Expr{ident}, Ellipsis: token.NoPos, Rparen: pos}
|
||||
n.Args[0] = arg
|
||||
n.Args[0] = &ast.CallExpr{Fun: fun, Lparen: pos, Args: []ast.Expr{ident}, Rparen: pos}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -317,21 +382,6 @@ func fixCheckErrorfCall(f *ast.File) {
|
||||
})
|
||||
}
|
||||
|
||||
// fixTraceSel renames uses of x.Trace to x.trace, where x for any x with a Trace field.
|
||||
func fixTraceSel(f *ast.File) {
|
||||
ast.Inspect(f, func(n ast.Node) bool {
|
||||
switch n := n.(type) {
|
||||
case *ast.SelectorExpr:
|
||||
// rewrite x.Trace to x._Trace (for Config.Trace)
|
||||
if n.Sel.Name == "Trace" {
|
||||
n.Sel.Name = "_Trace"
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// fixGlobalTypVarDecl changes the global Typ variable from an array to a slice
|
||||
// (in types2 we use an array for efficiency, in go/types it's a slice and we
|
||||
// cannot change that).
|
||||
@ -354,7 +404,7 @@ func fixSprintf(f *ast.File) {
|
||||
ast.Inspect(f, func(n ast.Node) bool {
|
||||
switch n := n.(type) {
|
||||
case *ast.CallExpr:
|
||||
if fun, _ := n.Fun.(*ast.Ident); fun != nil && fun.Name == "sprintf" && len(n.Args) >= 4 /* ... args */ {
|
||||
if isIdent(n.Fun, "sprintf") && len(n.Args) >= 4 /* ... args */ {
|
||||
n.Args = insert(n.Args, 1, newIdent(n.Args[1].Pos(), "nil"))
|
||||
return false
|
||||
}
|
||||
@ -363,6 +413,19 @@ func fixSprintf(f *ast.File) {
|
||||
})
|
||||
}
|
||||
|
||||
// asIdent returns x as *ast.Ident if it is an identifier with the given name.
|
||||
func asIdent(x ast.Node, name string) *ast.Ident {
|
||||
if ident, _ := x.(*ast.Ident); ident != nil && ident.Name == name {
|
||||
return ident
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// isIdent reports whether x is an identifier with the given name.
|
||||
func isIdent(x ast.Node, name string) bool {
|
||||
return asIdent(x, name) != nil
|
||||
}
|
||||
|
||||
// newIdent returns a new identifier with the given position and name.
|
||||
func newIdent(pos token.Pos, name string) *ast.Ident {
|
||||
id := ast.NewIdent(name)
|
||||
|
@ -26,3 +26,13 @@ func cmpPos(p, q token.Pos) int { return int(p - q) }
|
||||
|
||||
// hasDots reports whether the last argument in the call is followed by ...
|
||||
func hasDots(call *ast.CallExpr) bool { return call.Ellipsis.IsValid() }
|
||||
|
||||
// dddErrPos returns the positioner for reporting an invalid ... use in a call.
|
||||
func dddErrPos(call *ast.CallExpr) positioner {
|
||||
return atPos(call.Ellipsis)
|
||||
}
|
||||
|
||||
// argErrPos returns positioner for reportign an invalid argument count.
|
||||
func argErrPos(call *ast.CallExpr) positioner {
|
||||
return inNode(call, call.Rparen)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user