]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/compile/internal/gc/noder.go
[dev.typeparams] all: merge dev.regabi (ec741b0) into dev.typeparams
[gostls13.git] / src / cmd / compile / internal / gc / noder.go
index 97a9ac4396194ac51348f32378c95f9538a73f83..8beef0d18b0f22f25aa3c500485c8e244ed67fdd 100644 (file)
@@ -8,6 +8,7 @@ import (
        "fmt"
        "go/constant"
        "go/token"
+       "io"
        "os"
        "path/filepath"
        "runtime"
@@ -17,9 +18,11 @@ import (
        "unicode/utf8"
 
        "cmd/compile/internal/base"
+       "cmd/compile/internal/importer"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
        "cmd/compile/internal/types"
+       "cmd/compile/internal/types2"
        "cmd/internal/objabi"
        "cmd/internal/src"
 )
@@ -28,7 +31,7 @@ import (
 // Each declaration in every *syntax.File is converted to a syntax tree
 // and its root represented by *Node is appended to Target.Decls.
 // Returns the total count of parsed lines.
-func parseFiles(filenames []string) 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)
@@ -45,7 +48,7 @@ func parseFiles(filenames []string) 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 {
@@ -54,23 +57,106 @@ func parseFiles(filenames []string) uint {
                        }
                        defer f.Close()
 
-                       p.file, _ = syntax.Parse(base, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error
+                       mode := syntax.CheckBranches
+                       if base.Flag.G != 0 {
+                               mode |= syntax.AllowGenerics
+                       }
+                       p.file, _ = syntax.Parse(fbase, f, p.error, p.pragma, mode) // errors are tracked via p.error
                }(filename)
        }
 
-       var lines uint
+       // 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 {
+                       for e := range p.err {
+                               p.errorAt(e.Pos, "%s", e.Msg)
+                       }
+
+                       nodersmap[p.file.Pos().RelFilename()] = p
+                       files = append(files, p.file)
+                       lines += p.file.EOF.Line()
+
+               }
+               if base.SyntaxErrors() != 0 {
+                       base.ErrorExit()
+               }
+
+               // typechecking
+               conf := types2.Config{
+                       InferFromConstraints:  true,
+                       IgnoreBranches:        true, // parser already checked via syntax.CheckBranches mode
+                       CompilerErrorMessages: true, // use error strings matching existing compiler errors
+                       Error: func(err error) {
+                               terr := err.(types2.Error)
+                               if len(terr.Msg) > 0 && terr.Msg[0] == '\t' {
+                                       // types2 reports error clarifications via separate
+                                       // error messages which are indented with a tab.
+                                       // Ignore them to satisfy tools and tests that expect
+                                       // only one error in such cases.
+                                       // TODO(gri) Need to adjust error reporting in types2.
+                                       return
+                               }
+                               p := nodersmap[terr.Pos.RelFilename()]
+                               base.ErrorfAt(p.makeXPos(terr.Pos), "%s", terr.Msg)
+                       },
+                       Importer: &gcimports{
+                               packages: make(map[string]*types2.Package),
+                               lookup: func(path string) (io.ReadCloser, error) {
+                                       file, ok := findpkg(path)
+                                       if !ok {
+                                               return nil, fmt.Errorf("can't find import: %q", path)
+                                       }
+                                       return os.Open(file)
+                               },
+                       },
+               }
+               info := types2.Info{
+                       Types:      make(map[syntax.Expr]types2.TypeAndValue),
+                       Defs:       make(map[*syntax.Name]types2.Object),
+                       Uses:       make(map[*syntax.Name]types2.Object),
+                       Selections: make(map[*syntax.SelectorExpr]*types2.Selection),
+                       // 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()
+               }
+
+               types.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)
                }
 
                p.node()
-               lines += p.file.Lines
+               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()
        }
@@ -80,8 +166,24 @@ func parseFiles(filenames []string) uint {
        }
 
        types.LocalPkg.Height = myheight
+       return
+}
 
-       return lines
+// Temporary import helper to get type2-based type-checking going.
+type gcimports struct {
+       packages map[string]*types2.Package
+       lookup   func(path string) (io.ReadCloser, error)
+}
+
+func (m *gcimports) Import(path string) (*types2.Package, error) {
+       return m.ImportFrom(path, "" /* no vendoring */, 0)
+}
+
+func (m *gcimports) ImportFrom(path, srcDir string, mode types2.ImportMode) (*types2.Package, error) {
+       if mode != 0 {
+               panic("mode must be 0")
+       }
+       return importer.Import(m.packages, path, srcDir, m.lookup)
 }
 
 // makeSrcPosBase translates from a *syntax.PosBase to a *src.PosBase.
@@ -154,9 +256,40 @@ type noder struct {
        trackScopes bool
        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]
+}
+
+// sel returns the selection information for the given selector expression.
+func (p *noder) sel(x *syntax.SelectorExpr) *types2.Selection {
+       return p.typeInfo.Selections[x]
+}
+
 func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) {
        oldScope := p.scope
        p.scope = 0
@@ -318,7 +451,7 @@ func (p *noder) decls(decls []syntax.Decl) (l []ir.Node) {
 }
 
 func (p *noder) importDecl(imp *syntax.ImportDecl) {
-       if imp.Path.Bad {
+       if imp.Path == nil || imp.Path.Bad {
                return // avoid follow-on errors if there was a syntax error
        }