]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: provide scaffolding to get types2 types during noding
authorRobert Griesemer <gri@golang.org>
Thu, 3 Dec 2020 00:58:46 +0000 (16:58 -0800)
committerRobert Griesemer <gri@golang.org>
Thu, 3 Dec 2020 01:56:40 +0000 (01:56 +0000)
Initial setup of types2.Info structure to provide access to types
computed by generic typechecker.

Use -G flag to control compiler phases with new typechecker:

-G    (or -G=1)  parsing and typechecking ony
-G -G (or -G=2)  parsing, typechecking, and noding
-G=3             continue after noding (currently will run old
                 typechecker again, leading to duplicate errors

Change-Id: I87dd54f7c3773228f288f7a134ac809d9481ca95
Reviewed-on: https://go-review.googlesource.com/c/go/+/274444
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>

src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/noder.go

index 6b7123dc7162bc7e2e646e8b5f06d0a9fb020e4c..69a457da4d38185a3b8c0787a6a27a4836ba7147 100644 (file)
@@ -229,10 +229,10 @@ func Main(archInit func(*Arch)) {
        loadsys()
 
        timings.Start("fe", "parse")
-       lines := parseFiles(flag.Args(), base.Flag.G != 0)
+       lines := parseFiles(flag.Args())
        timings.Stop()
        timings.AddEvent(int64(lines), "lines")
-       if base.Flag.G != 0 {
+       if base.Flag.G != 0 && base.Flag.G < 3 {
                // can only parse generic code for now
                base.ExitIfErrors()
                return
index 5115932b1e407de44dc02ceb89c82781135e1395..4eaeedb63b951adf5fd0aeb071c0aa7ab1c258e1 100644 (file)
@@ -32,7 +32,7 @@ import (
 // Each declaration in every *syntax.File is converted to a syntax tree
 // and its root represented by *Node is appended to xtop.
 // Returns the total count of parsed lines.
-func parseFiles(filenames []string, allowGenerics bool) (lines uint) {
+func parseFiles(filenames []string) (lines uint) {
        noders := make([]*noder, 0, len(filenames))
        // Limit the number of simultaneously open files.
        sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10)
@@ -48,7 +48,7 @@ func parseFiles(filenames []string, allowGenerics bool) (lines uint) {
                        sem <- struct{}{}
                        defer func() { <-sem }()
                        defer close(p.err)
-                       base := syntax.NewFileBase(filename)
+                       fbase := syntax.NewFileBase(filename)
 
                        f, err := os.Open(filename)
                        if err != nil {
@@ -58,14 +58,16 @@ func parseFiles(filenames []string, allowGenerics bool) (lines uint) {
                        defer f.Close()
 
                        mode := syntax.CheckBranches
-                       if allowGenerics {
+                       if base.Flag.G != 0 {
                                mode |= syntax.AllowGenerics
                        }
-                       p.file, _ = syntax.Parse(base, f, p.error, p.pragma, mode) // errors are tracked via p.error
+                       p.file, _ = syntax.Parse(fbase, f, p.error, p.pragma, mode) // errors are tracked via p.error
                }(filename)
        }
 
-       if allowGenerics {
+       // generic noding phase (using new typechecker)
+       if base.Flag.G != 0 {
+               // setup and syntax error reporting
                nodersmap := make(map[string]*noder)
                var files []*syntax.File
                for _, p := range noders {
@@ -77,11 +79,12 @@ func parseFiles(filenames []string, allowGenerics bool) (lines uint) {
                        files = append(files, p.file)
                        lines += p.file.EOF.Line()
 
-                       if base.SyntaxErrors() != 0 {
-                               base.ErrorExit()
-                       }
+               }
+               if base.SyntaxErrors() != 0 {
+                       base.ErrorExit()
                }
 
+               // typechecking
                conf := types2.Config{
                        InferFromConstraints:  true,
                        IgnoreBranches:        true, // parser already checked via syntax.CheckBranches mode
@@ -110,10 +113,37 @@ func parseFiles(filenames []string, allowGenerics bool) (lines uint) {
                                },
                        },
                }
-               conf.Check(base.Ctxt.Pkgpath, files, nil)
+               info := types2.Info{
+                       Types: make(map[syntax.Expr]types2.TypeAndValue),
+                       Defs:  make(map[*syntax.Name]types2.Object),
+                       Uses:  make(map[*syntax.Name]types2.Object),
+                       // expand as needed
+               }
+               conf.Check(base.Ctxt.Pkgpath, files, &info)
+               base.ExitIfErrors()
+               if base.Flag.G < 2 {
+                       return
+               }
+
+               // noding
+               for _, p := range noders {
+                       // errors have already been reported
+
+                       p.typeInfo = &info
+                       p.node()
+                       lines += p.file.EOF.Line()
+                       p.file = nil // release memory
+                       base.ExitIfErrors()
+
+                       // Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
+                       testdclstack()
+               }
+
+               ir.LocalPkg.Height = myheight
                return
        }
 
+       // traditional (non-generic) noding phase
        for _, p := range noders {
                for e := range p.err {
                        p.errorAt(e.Pos, "%s", e.Msg)
@@ -122,10 +152,10 @@ func parseFiles(filenames []string, allowGenerics bool) (lines uint) {
                p.node()
                lines += p.file.EOF.Line()
                p.file = nil // release memory
-
                if base.SyntaxErrors() != 0 {
                        base.ErrorExit()
                }
+
                // Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
                testdclstack()
        }
@@ -220,9 +250,35 @@ type noder struct {
        // current function at the moment each open scope was opened.
        scopeVars []int
 
+       // typeInfo provides access to the type information computed by the new
+       // typechecker. It is only present if -G is set, and all noders point to
+       // the same types.Info. For now this is a local field, if need be we can
+       // make it global.
+       typeInfo *types2.Info
+
        lastCloseScopePos syntax.Pos
 }
 
+// For now we provide these basic accessors to get to type and object
+// information of expression nodes during noding. Eventually we will
+// attach this information directly to the syntax tree which should
+// simplify access and make it more efficient as well.
+
+// typ returns the type and value information for the given expression.
+func (p *noder) typ(x syntax.Expr) types2.TypeAndValue {
+       return p.typeInfo.Types[x]
+}
+
+// def returns the object for the given name in its declaration.
+func (p *noder) def(x *syntax.Name) types2.Object {
+       return p.typeInfo.Defs[x]
+}
+
+// use returns the object for the given name outside its declaration.
+func (p *noder) use(x *syntax.Name) types2.Object {
+       return p.typeInfo.Uses[x]
+}
+
 func (p *noder) funcBody(fn ir.Node, block *syntax.BlockStmt) {
        oldScope := p.scope
        p.scope = 0