]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: simplify writer.collectDecls
authorMatthew Dempsky <mdempsky@google.com>
Wed, 23 Jun 2021 21:04:11 +0000 (14:04 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 24 Jun 2021 06:58:33 +0000 (06:58 +0000)
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>
src/cmd/compile/internal/noder/writer.go

index bc89e1a262ae34816bd25c5b5111e74ce3dfee50..889a96ef9ce764c294ea7e601259ed0414e64b39 100644 (file)
@@ -1386,89 +1386,111 @@ type typeDeclGen struct {
        gen int
 }
 
-func (pw *pkgWriter) collectDecls(noders []*noder) {
-       var typegen int
+type fileImports struct {
+       importedEmbed, importedUnsafe bool
+}
 
-       for _, p := range noders {
-               var importedEmbed, importedUnsafe bool
+type declCollector struct {
+       pw         *pkgWriter
+       typegen    *int
+       file       *fileImports
+       withinFunc bool
+}
 
-               syntax.Crawl(p.file, func(n syntax.Node) bool {
-                       switch n := n.(type) {
-                       case *syntax.File:
-                               pw.checkPragmas(n.Pragma, ir.GoBuildPragma, false)
+func (c *declCollector) Visit(n syntax.Node) syntax.Visitor {
+       pw := c.pw
 
-                       case *syntax.ImportDecl:
-                               pw.checkPragmas(n.Pragma, 0, false)
+       switch n := n.(type) {
+       case *syntax.File:
+               pw.checkPragmas(n.Pragma, ir.GoBuildPragma, false)
 
-                               switch pkgNameOf(pw.info, n).Imported().Path() {
-                               case "embed":
-                                       importedEmbed = true
-                               case "unsafe":
-                                       importedUnsafe = true
-                               }
+       case *syntax.ImportDecl:
+               pw.checkPragmas(n.Pragma, 0, false)
 
-                       case *syntax.ConstDecl:
-                               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.FuncDecl:
-                               pw.checkPragmas(n.Pragma, funcPragmas, false)
+       case *syntax.ConstDecl:
+               pw.checkPragmas(n.Pragma, 0, false)
 
-                               obj := pw.info.Defs[n.Name].(*types2.Func)
-                               pw.funDecls[obj] = n
+       case *syntax.FuncDecl:
+               pw.checkPragmas(n.Pragma, funcPragmas, false)
 
-                       case *syntax.TypeDecl:
-                               obj := pw.info.Defs[n.Name].(*types2.TypeName)
-                               d := typeDeclGen{TypeDecl: n}
+               obj := pw.info.Defs[n.Name].(*types2.Func)
+               pw.funDecls[obj] = n
 
-                               if n.Alias {
-                                       pw.checkPragmas(n.Pragma, 0, false)
-                               } else {
-                                       pw.checkPragmas(n.Pragma, typePragmas, false)
+       case *syntax.TypeDecl:
+               obj := pw.info.Defs[n.Name].(*types2.TypeName)
+               d := typeDeclGen{TypeDecl: n}
 
-                                       // Assign a unique ID to function-scoped defined types.
-                                       if !isGlobal(obj) {
-                                               typegen++
-                                               d.gen = typegen
-                                       }
-                               }
+               if n.Alias {
+                       pw.checkPragmas(n.Pragma, 0, false)
+               } else {
+                       pw.checkPragmas(n.Pragma, typePragmas, false)
 
-                               pw.typDecls[obj] = d
+                       // Assign a unique ID to function-scoped defined types.
+                       if !isGlobal(obj) {
+                               *c.typegen++
+                               d.gen = *c.typegen
+                       }
+               }
 
-                       case *syntax.VarDecl:
-                               pw.checkPragmas(n.Pragma, 0, true)
+               pw.typDecls[obj] = d
 
-                               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)
-                                       }
-                               }
+       case *syntax.VarDecl:
+               pw.checkPragmas(n.Pragma, 0, true)
 
-                               // 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)
-                                       }
-                               }
+               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)
                        }
-                       return false
+               }
+
+               // 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) {
+       var typegen int
+       for _, p := range noders {
+               var file fileImports
+
+               syntax.Walk(p.file, &declCollector{
+                       pw:      pw,
+                       typegen: &typegen,
+                       file:    &file,
                })
 
                pw.cgoPragmas = append(pw.cgoPragmas, p.pragcgobuf...)
 
                for _, l := range p.linknames {
-                       if !importedUnsafe {
+                       if !file.importedUnsafe {
                                pw.errorf(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
                                continue
                        }