1
0
mirror of https://github.com/golang/go synced 2024-11-23 00:30:07 -07:00

[dev.typeparams] cmd/compile: simplify writer.collectDecls

The previous code for walking the syntax AST to find declarations
needed to know whether a declaration appeared within block scope, but
syntax.Crawl (née syntax.Walk) made that somewhat awkward.

This CL simplifies it a little, taking advantage of syntax.Walk's
support for keeping per-subtree state.

Change-Id: I03c7da8c44bec40f88e983852dc6bbab7e6ac13c
Reviewed-on: https://go-review.googlesource.com/c/go/+/330549
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
Matthew Dempsky 2021-06-23 14:04:11 -07:00
parent ee4fc0c1bc
commit 9bdbf73c98

View File

@ -1386,89 +1386,111 @@ type typeDeclGen struct {
gen int gen int
} }
type fileImports struct {
importedEmbed, importedUnsafe bool
}
type declCollector struct {
pw *pkgWriter
typegen *int
file *fileImports
withinFunc bool
}
func (c *declCollector) Visit(n syntax.Node) syntax.Visitor {
pw := c.pw
switch n := n.(type) {
case *syntax.File:
pw.checkPragmas(n.Pragma, ir.GoBuildPragma, false)
case *syntax.ImportDecl:
pw.checkPragmas(n.Pragma, 0, false)
switch pkgNameOf(pw.info, n).Imported().Path() {
case "embed":
c.file.importedEmbed = true
case "unsafe":
c.file.importedUnsafe = true
}
case *syntax.ConstDecl:
pw.checkPragmas(n.Pragma, 0, false)
case *syntax.FuncDecl:
pw.checkPragmas(n.Pragma, funcPragmas, false)
obj := pw.info.Defs[n.Name].(*types2.Func)
pw.funDecls[obj] = n
case *syntax.TypeDecl:
obj := pw.info.Defs[n.Name].(*types2.TypeName)
d := typeDeclGen{TypeDecl: n}
if n.Alias {
pw.checkPragmas(n.Pragma, 0, false)
} else {
pw.checkPragmas(n.Pragma, typePragmas, false)
// Assign a unique ID to function-scoped defined types.
if !isGlobal(obj) {
*c.typegen++
d.gen = *c.typegen
}
}
pw.typDecls[obj] = d
case *syntax.VarDecl:
pw.checkPragmas(n.Pragma, 0, true)
if p, ok := n.Pragma.(*pragmas); ok && len(p.Embeds) > 0 {
if err := checkEmbed(n, c.file.importedEmbed, c.withinFunc); err != nil {
pw.errorf(p.Embeds[0].Pos, "%s", err)
}
}
// Workaround for #46208. For variable declarations that
// declare multiple variables and have an explicit type
// expression, the type expression is evaluated multiple
// times. This affects toolstash -cmp, because iexport is
// sensitive to *types.Type pointer identity.
if quirksMode() && n.Type != nil {
tv, ok := pw.info.Types[n.Type]
assert(ok)
assert(tv.IsType())
for _, name := range n.NameList {
obj := pw.info.Defs[name].(*types2.Var)
pw.dups.add(obj.Type(), tv.Type)
}
}
case *syntax.BlockStmt:
if !c.withinFunc {
copy := *c
copy.withinFunc = true
return &copy
}
}
return c
}
func (pw *pkgWriter) collectDecls(noders []*noder) { func (pw *pkgWriter) collectDecls(noders []*noder) {
var typegen int var typegen int
for _, p := range noders { for _, p := range noders {
var importedEmbed, importedUnsafe bool var file fileImports
syntax.Crawl(p.file, func(n syntax.Node) bool { syntax.Walk(p.file, &declCollector{
switch n := n.(type) { pw: pw,
case *syntax.File: typegen: &typegen,
pw.checkPragmas(n.Pragma, ir.GoBuildPragma, false) file: &file,
case *syntax.ImportDecl:
pw.checkPragmas(n.Pragma, 0, false)
switch pkgNameOf(pw.info, n).Imported().Path() {
case "embed":
importedEmbed = true
case "unsafe":
importedUnsafe = true
}
case *syntax.ConstDecl:
pw.checkPragmas(n.Pragma, 0, false)
case *syntax.FuncDecl:
pw.checkPragmas(n.Pragma, funcPragmas, false)
obj := pw.info.Defs[n.Name].(*types2.Func)
pw.funDecls[obj] = n
case *syntax.TypeDecl:
obj := pw.info.Defs[n.Name].(*types2.TypeName)
d := typeDeclGen{TypeDecl: n}
if n.Alias {
pw.checkPragmas(n.Pragma, 0, false)
} else {
pw.checkPragmas(n.Pragma, typePragmas, false)
// Assign a unique ID to function-scoped defined types.
if !isGlobal(obj) {
typegen++
d.gen = typegen
}
}
pw.typDecls[obj] = d
case *syntax.VarDecl:
pw.checkPragmas(n.Pragma, 0, true)
if p, ok := n.Pragma.(*pragmas); ok && len(p.Embeds) > 0 {
obj := pw.info.Defs[n.NameList[0]].(*types2.Var)
// TODO(mdempsky): isGlobal(obj) gives false positive errors
// for //go:embed directives on package-scope blank
// variables.
if err := checkEmbed(n, importedEmbed, !isGlobal(obj)); err != nil {
pw.errorf(p.Embeds[0].Pos, "%s", err)
}
}
// Workaround for #46208. For variable declarations that
// declare multiple variables and have an explicit type
// expression, the type expression is evaluated multiple
// times. This affects toolstash -cmp, because iexport is
// sensitive to *types.Type pointer identity.
if quirksMode() && n.Type != nil {
tv, ok := pw.info.Types[n.Type]
assert(ok)
assert(tv.IsType())
for _, name := range n.NameList {
obj := pw.info.Defs[name].(*types2.Var)
pw.dups.add(obj.Type(), tv.Type)
}
}
}
return false
}) })
pw.cgoPragmas = append(pw.cgoPragmas, p.pragcgobuf...) pw.cgoPragmas = append(pw.cgoPragmas, p.pragcgobuf...)
for _, l := range p.linknames { for _, l := range p.linknames {
if !importedUnsafe { if !file.importedUnsafe {
pw.errorf(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"") pw.errorf(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
continue continue
} }