mirror of
https://github.com/golang/go
synced 2024-09-04 23:44:16 +00: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:
parent
ee4fc0c1bc
commit
9bdbf73c98
|
@ -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 ©
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue