1
0
mirror of https://github.com/golang/go synced 2024-11-26 05:07:59 -07:00

[dev.typeparams] cmd/compile: provide scaffolding to get types2 types during noding

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>
This commit is contained in:
Robert Griesemer 2020-12-02 16:58:46 -08:00
parent 72cc2353f0
commit 6b4da14dd3
2 changed files with 68 additions and 12 deletions

View 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

View 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