]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: generate builtins.go from types2 source
authorRobert Griesemer <gri@golang.org>
Thu, 8 Feb 2024 22:29:26 +0000 (14:29 -0800)
committerGopher Robot <gobot@golang.org>
Wed, 21 Feb 2024 17:07:56 +0000 (17:07 +0000)
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>

src/cmd/compile/internal/types2/builtins.go
src/cmd/compile/internal/types2/util.go
src/go/types/builtins.go
src/go/types/generate_test.go
src/go/types/util.go

index 5db3ae2fa48bae23dfe7d75a2e29cef2b409c071..79ed6ad640f0ef2144d9f424807afc5986d0866f 100644 (file)
@@ -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
                }
        }
index 35ab71be2b0db543e887842ccec4899e8eb54d84..9ffef1314d953e24bca61fa122b4b2df5ff89537 100644 (file)
@@ -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) }
index b49af554695cc6c32fb90eae384c3eec100eeff2..040b24f5ccb58062ea041206b20672655bbc7180 100644 (file)
@@ -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
                }
        }
index 2208f56b7db2a1feb97639c8e78a47e307a27663..d1b98ad8e404b16b3c27659211bbb0272d17388b 100644 (file)
@@ -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)
index 910a0f16d989d9ff488e4db1ee7922cc51433b43..ea0dd7b07133a2078e714ea9a8361ffb1db8ae04 100644 (file)
@@ -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)
+}