mirror of
https://github.com/golang/go
synced 2024-11-11 19:51:37 -07:00
[dev.regabi] cmd/compile: first start towards using Ident
This CL adds Ident, which will eventually replace *Name and *PkgName within the AST for representing uses of declared names. (Originally, I intended to call it "IdentExpr", but neither go/ast nor cmd/compile/internal/syntax include the "Expr" suffix for their respective types.) To start, this CL converts two uses of *Name to *Ident: the tag identifier in a TypeSwitchGuard (which doesn't actually declare a variable by itself), and the not-yet-known placeholder ONONAME returned by oldname to stand-in for identifiers that might be declared later in the package. The TypeSwitchGuard's Name's Used flag was previously used for detecting whether none of the per-clause variables were used. To avoid bloating all Idents for this rare use, a "Used" bool is added to TypeSwitchGuard instead. Eventually it could maybe be packed into miniNode.bits, but for now this is good enough. Passes buildall w/ toolstash -cmp. Change-Id: I393284d86757cbbebd26e1320c7354e2bdcb30b0 Reviewed-on: https://go-review.googlesource.com/c/go/+/276113 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
eae8fd519b
commit
63bc23b545
@ -215,7 +215,7 @@ func oldname(s *types.Sym) ir.Node {
|
||||
// Maybe a top-level declaration will come along later to
|
||||
// define s. resolve will check s.Def again once all input
|
||||
// source has been processed.
|
||||
return ir.NewDeclNameAt(base.Pos, s)
|
||||
return ir.NewIdent(base.Pos, s)
|
||||
}
|
||||
|
||||
if Curfn != nil && n.Op() == ir.ONAME && n.Name().Curfn != nil && n.Name().Curfn != Curfn {
|
||||
|
@ -833,13 +833,13 @@ func (r *importReader) node() ir.Node {
|
||||
return ir.TypeNode(r.typ())
|
||||
|
||||
case ir.OTYPESW:
|
||||
n := ir.NodAt(r.pos(), ir.OTYPESW, nil, nil)
|
||||
pos := r.pos()
|
||||
var tag *ir.Ident
|
||||
if s := r.ident(); s != nil {
|
||||
n.SetLeft(ir.NewDeclNameAt(n.Pos(), s))
|
||||
tag = ir.NewIdent(pos, s)
|
||||
}
|
||||
right, _ := r.exprsOrNil()
|
||||
n.SetRight(right)
|
||||
return n
|
||||
expr, _ := r.exprsOrNil()
|
||||
return ir.NewTypeSwitchGuard(pos, tag, expr)
|
||||
|
||||
// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
|
||||
// unreachable - should have been resolved by typechecking
|
||||
|
@ -751,14 +751,14 @@ func (p *noder) expr(expr syntax.Expr) ir.Node {
|
||||
p.typeExpr(expr.Elem), p.chanDir(expr.Dir))
|
||||
|
||||
case *syntax.TypeSwitchGuard:
|
||||
n := p.nod(expr, ir.OTYPESW, nil, p.expr(expr.X))
|
||||
var tag *ir.Ident
|
||||
if expr.Lhs != nil {
|
||||
n.SetLeft(p.declName(expr.Lhs))
|
||||
if ir.IsBlank(n.Left()) {
|
||||
base.Errorf("invalid variable name %v in type switch", n.Left())
|
||||
tag = ir.NewIdent(p.pos(expr.Lhs), p.name(expr.Lhs))
|
||||
if ir.IsBlank(tag) {
|
||||
base.Errorf("invalid variable name %v in type switch", tag)
|
||||
}
|
||||
}
|
||||
return n
|
||||
return ir.NewTypeSwitchGuard(p.pos(expr), tag, p.expr(expr.X))
|
||||
}
|
||||
panic("unhandled Expr")
|
||||
}
|
||||
|
@ -90,12 +90,16 @@ func resolve(n ir.Node) (res ir.Node) {
|
||||
defer tracePrint("resolve", n)(&res)
|
||||
}
|
||||
|
||||
if n.Sym().Pkg != types.LocalPkg {
|
||||
// Stub ir.Name left for us by iimport.
|
||||
if n, ok := n.(*ir.Name); ok {
|
||||
if n.Sym().Pkg == types.LocalPkg {
|
||||
base.Fatalf("unexpected Name: %+v", n)
|
||||
}
|
||||
if inimport {
|
||||
base.Fatalf("recursive inimport")
|
||||
}
|
||||
inimport = true
|
||||
expandDecl(n.(*ir.Name))
|
||||
expandDecl(n)
|
||||
inimport = false
|
||||
return n
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ func walk(fn *ir.Func) {
|
||||
// Propagate the used flag for typeswitch variables up to the NONAME in its definition.
|
||||
for _, ln := range fn.Dcl {
|
||||
if ln.Op() == ir.ONAME && (ln.Class() == ir.PAUTO || ln.Class() == ir.PAUTOHEAP) && ln.Defn != nil && ln.Defn.Op() == ir.OTYPESW && ln.Used() {
|
||||
ln.Defn.Left().Name().SetUsed(true)
|
||||
ln.Defn.(*ir.TypeSwitchGuard).Used = true
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,12 +52,12 @@ func walk(fn *ir.Func) {
|
||||
if ln.Op() != ir.ONAME || (ln.Class() != ir.PAUTO && ln.Class() != ir.PAUTOHEAP) || ln.Sym().Name[0] == '&' || ln.Used() {
|
||||
continue
|
||||
}
|
||||
if defn := ln.Defn; defn != nil && defn.Op() == ir.OTYPESW {
|
||||
if defn.Left().Name().Used() {
|
||||
if defn, ok := ln.Defn.(*ir.TypeSwitchGuard); ok {
|
||||
if defn.Used {
|
||||
continue
|
||||
}
|
||||
base.ErrorfAt(defn.Left().Pos(), "%v declared but not used", ln.Sym())
|
||||
defn.Left().Name().SetUsed(true) // suppress repeats
|
||||
base.ErrorfAt(defn.Tag.Pos(), "%v declared but not used", ln.Sym())
|
||||
defn.Used = true // suppress repeats
|
||||
} else {
|
||||
base.ErrorfAt(ln.Pos(), "%v declared but not used", ln.Sym())
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ func main() {
|
||||
nodesType := lookup("Nodes")
|
||||
ptrFieldType := types.NewPointer(lookup("Field"))
|
||||
slicePtrFieldType := types.NewSlice(ptrFieldType)
|
||||
ptrNameType := types.NewPointer(lookup("Name"))
|
||||
ptrIdentType := types.NewPointer(lookup("Ident"))
|
||||
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprintln(&buf, "// Code generated by mknode.go. DO NOT EDIT.")
|
||||
@ -84,7 +84,7 @@ func main() {
|
||||
fmt.Fprintf(&buf, "func (n *%s) doChildren(do func(Node) error) error { var err error\n", name)
|
||||
forNodeFields(typName, typ, func(name string, is func(types.Type) bool) {
|
||||
switch {
|
||||
case is(ptrNameType):
|
||||
case is(ptrIdentType):
|
||||
fmt.Fprintf(&buf, "if n.%s != nil { err = maybeDo(n.%s, err, do) }\n", name, name)
|
||||
case is(nodeType), is(ntypeType):
|
||||
fmt.Fprintf(&buf, "err = maybeDo(n.%s, err, do)\n", name)
|
||||
@ -101,8 +101,8 @@ func main() {
|
||||
fmt.Fprintf(&buf, "func (n *%s) editChildren(edit func(Node) Node) {\n", name)
|
||||
forNodeFields(typName, typ, func(name string, is func(types.Type) bool) {
|
||||
switch {
|
||||
case is(ptrNameType):
|
||||
fmt.Fprintf(&buf, "if n.%s != nil { n.%s = edit(n.%s).(*Name) }\n", name, name, name)
|
||||
case is(ptrIdentType):
|
||||
fmt.Fprintf(&buf, "if n.%s != nil { n.%s = edit(n.%s).(*Ident) }\n", name, name, name)
|
||||
case is(nodeType):
|
||||
fmt.Fprintf(&buf, "n.%s = maybeEdit(n.%s, edit)\n", name, name)
|
||||
case is(ntypeType):
|
||||
|
@ -13,6 +13,25 @@ import (
|
||||
"go/constant"
|
||||
)
|
||||
|
||||
// An Ident is an identifier, possibly qualified.
|
||||
type Ident struct {
|
||||
miniExpr
|
||||
sym *types.Sym
|
||||
Used bool
|
||||
}
|
||||
|
||||
func NewIdent(pos src.XPos, sym *types.Sym) *Ident {
|
||||
n := new(Ident)
|
||||
n.op = ONONAME
|
||||
n.pos = pos
|
||||
n.sym = sym
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Ident) Sym() *types.Sym { return n.sym }
|
||||
|
||||
func (*Ident) CanBeNtype() {}
|
||||
|
||||
// Name holds Node fields used only by named nodes (ONAME, OTYPE, some OLITERAL).
|
||||
type Name struct {
|
||||
miniExpr
|
||||
|
@ -794,8 +794,6 @@ func NodAt(pos src.XPos, op Op, nleft, nright Node) Node {
|
||||
return NewSliceHeaderExpr(pos, nil, nleft, nil, nil)
|
||||
case OSWITCH:
|
||||
return NewSwitchStmt(pos, nleft, nil)
|
||||
case OTYPESW:
|
||||
return NewTypeSwitchGuard(pos, nleft, nright)
|
||||
case OINLCALL:
|
||||
return NewInlinedCallExpr(pos, nil, nil)
|
||||
}
|
||||
|
@ -450,6 +450,22 @@ func (n *GoDeferStmt) editChildren(edit func(Node) Node) {
|
||||
n.Call = maybeEdit(n.Call, edit)
|
||||
}
|
||||
|
||||
func (n *Ident) String() string { return fmt.Sprint(n) }
|
||||
func (n *Ident) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
|
||||
func (n *Ident) copy() Node {
|
||||
c := *n
|
||||
c.init = c.init.Copy()
|
||||
return &c
|
||||
}
|
||||
func (n *Ident) doChildren(do func(Node) error) error {
|
||||
var err error
|
||||
err = maybeDoList(n.init, err, do)
|
||||
return err
|
||||
}
|
||||
func (n *Ident) editChildren(edit func(Node) Node) {
|
||||
editList(n.init, edit)
|
||||
}
|
||||
|
||||
func (n *IfStmt) String() string { return fmt.Sprint(n) }
|
||||
func (n *IfStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
|
||||
func (n *IfStmt) copy() Node {
|
||||
@ -1004,15 +1020,15 @@ func (n *TypeSwitchGuard) copy() Node {
|
||||
}
|
||||
func (n *TypeSwitchGuard) doChildren(do func(Node) error) error {
|
||||
var err error
|
||||
if n.Name_ != nil {
|
||||
err = maybeDo(n.Name_, err, do)
|
||||
if n.Tag != nil {
|
||||
err = maybeDo(n.Tag, err, do)
|
||||
}
|
||||
err = maybeDo(n.X, err, do)
|
||||
return err
|
||||
}
|
||||
func (n *TypeSwitchGuard) editChildren(edit func(Node) Node) {
|
||||
if n.Name_ != nil {
|
||||
n.Name_ = edit(n.Name_).(*Name)
|
||||
if n.Tag != nil {
|
||||
n.Tag = edit(n.Tag).(*Ident)
|
||||
}
|
||||
n.X = maybeEdit(n.X, edit)
|
||||
}
|
||||
|
@ -512,32 +512,30 @@ func (n *SwitchStmt) SetHasBreak(x bool) { n.HasBreak_ = x }
|
||||
// A TypeSwitchGuard is the [Name :=] X.(type) in a type switch.
|
||||
type TypeSwitchGuard struct {
|
||||
miniNode
|
||||
Name_ *Name
|
||||
X Node
|
||||
Tag *Ident
|
||||
X Node
|
||||
Used bool
|
||||
}
|
||||
|
||||
func NewTypeSwitchGuard(pos src.XPos, name, x Node) *TypeSwitchGuard {
|
||||
n := &TypeSwitchGuard{X: x}
|
||||
if name != nil {
|
||||
n.Name_ = name.(*Name)
|
||||
}
|
||||
func NewTypeSwitchGuard(pos src.XPos, tag *Ident, x Node) *TypeSwitchGuard {
|
||||
n := &TypeSwitchGuard{Tag: tag, X: x}
|
||||
n.pos = pos
|
||||
n.op = OTYPESW
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *TypeSwitchGuard) Left() Node {
|
||||
if n.Name_ == nil {
|
||||
if n.Tag == nil {
|
||||
return nil
|
||||
}
|
||||
return n.Name_
|
||||
return n.Tag
|
||||
}
|
||||
func (n *TypeSwitchGuard) SetLeft(x Node) {
|
||||
if x == nil {
|
||||
n.Name_ = nil
|
||||
n.Tag = nil
|
||||
return
|
||||
}
|
||||
n.Name_ = x.(*Name)
|
||||
n.Tag = x.(*Ident)
|
||||
}
|
||||
func (n *TypeSwitchGuard) Right() Node { return n.X }
|
||||
func (n *TypeSwitchGuard) SetRight(x Node) { n.X = x }
|
||||
|
Loading…
Reference in New Issue
Block a user