mirror of
https://github.com/golang/go.git
synced 2025-11-08 04:31:01 +00:00
177 lines
5.1 KiB
Go
177 lines
5.1 KiB
Go
|
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||
|
|
// Use of this source code is governed by a BSD-style
|
||
|
|
// license that can be found in the LICENSE file.
|
||
|
|
|
||
|
|
package noder
|
||
|
|
|
||
|
|
import (
|
||
|
|
"os"
|
||
|
|
|
||
|
|
"cmd/compile/internal/base"
|
||
|
|
"cmd/compile/internal/dwarfgen"
|
||
|
|
"cmd/compile/internal/ir"
|
||
|
|
"cmd/compile/internal/syntax"
|
||
|
|
"cmd/compile/internal/typecheck"
|
||
|
|
"cmd/compile/internal/types"
|
||
|
|
"cmd/compile/internal/types2"
|
||
|
|
"cmd/internal/src"
|
||
|
|
)
|
||
|
|
|
||
|
|
// check2 type checks a Go package using types2, and then generates IR
|
||
|
|
// using the results.
|
||
|
|
func check2(noders []*noder) {
|
||
|
|
if base.SyntaxErrors() != 0 {
|
||
|
|
base.ErrorExit()
|
||
|
|
}
|
||
|
|
|
||
|
|
// setup and syntax error reporting
|
||
|
|
var m posMap
|
||
|
|
files := make([]*syntax.File, len(noders))
|
||
|
|
for i, p := range noders {
|
||
|
|
m.join(&p.posMap)
|
||
|
|
files[i] = p.file
|
||
|
|
}
|
||
|
|
|
||
|
|
// 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
|
||
|
|
}
|
||
|
|
base.ErrorfAt(m.makeXPos(terr.Pos), "%s", terr.Msg)
|
||
|
|
},
|
||
|
|
Importer: &gcimports{
|
||
|
|
packages: make(map[string]*types2.Package),
|
||
|
|
},
|
||
|
|
Sizes: &gcSizes{},
|
||
|
|
}
|
||
|
|
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),
|
||
|
|
Implicits: make(map[syntax.Node]types2.Object),
|
||
|
|
Scopes: make(map[syntax.Node]*types2.Scope),
|
||
|
|
// expand as needed
|
||
|
|
}
|
||
|
|
pkg, err := conf.Check(base.Ctxt.Pkgpath, files, &info)
|
||
|
|
files = nil
|
||
|
|
if err != nil {
|
||
|
|
base.FatalfAt(src.NoXPos, "conf.Check error: %v", err)
|
||
|
|
}
|
||
|
|
base.ExitIfErrors()
|
||
|
|
if base.Flag.G < 2 {
|
||
|
|
os.Exit(0)
|
||
|
|
}
|
||
|
|
|
||
|
|
g := irgen{
|
||
|
|
target: typecheck.Target,
|
||
|
|
self: pkg,
|
||
|
|
info: &info,
|
||
|
|
posMap: m,
|
||
|
|
objs: make(map[types2.Object]*ir.Name),
|
||
|
|
}
|
||
|
|
g.generate(noders)
|
||
|
|
|
||
|
|
if base.Flag.G < 3 {
|
||
|
|
os.Exit(0)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
type irgen struct {
|
||
|
|
target *ir.Package
|
||
|
|
self *types2.Package
|
||
|
|
info *types2.Info
|
||
|
|
|
||
|
|
posMap
|
||
|
|
objs map[types2.Object]*ir.Name
|
||
|
|
marker dwarfgen.ScopeMarker
|
||
|
|
}
|
||
|
|
|
||
|
|
func (g *irgen) generate(noders []*noder) {
|
||
|
|
types.LocalPkg.Name = g.self.Name()
|
||
|
|
typecheck.TypecheckAllowed = true
|
||
|
|
|
||
|
|
// At this point, types2 has already handled name resolution and
|
||
|
|
// type checking. We just need to map from its object and type
|
||
|
|
// representations to those currently used by the rest of the
|
||
|
|
// compiler. This happens mostly in 3 passes.
|
||
|
|
|
||
|
|
// 1. Process all import declarations. We use the compiler's own
|
||
|
|
// importer for this, rather than types2's gcimporter-derived one,
|
||
|
|
// to handle extensions and inline function bodies correctly.
|
||
|
|
//
|
||
|
|
// Also, we need to do this in a separate pass, because mappings are
|
||
|
|
// instantiated on demand. If we interleaved processing import
|
||
|
|
// declarations with other declarations, it's likely we'd end up
|
||
|
|
// wanting to map an object/type from another source file, but not
|
||
|
|
// yet have the import data it relies on.
|
||
|
|
declLists := make([][]syntax.Decl, len(noders))
|
||
|
|
Outer:
|
||
|
|
for i, p := range noders {
|
||
|
|
g.pragmaFlags(p.file.Pragma, ir.GoBuildPragma)
|
||
|
|
for j, decl := range p.file.DeclList {
|
||
|
|
switch decl := decl.(type) {
|
||
|
|
case *syntax.ImportDecl:
|
||
|
|
g.importDecl(p, decl)
|
||
|
|
default:
|
||
|
|
declLists[i] = p.file.DeclList[j:]
|
||
|
|
continue Outer // no more ImportDecls
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
types.LocalPkg.Height = myheight
|
||
|
|
|
||
|
|
// 2. Process all package-block type declarations. As with imports,
|
||
|
|
// we need to make sure all types are properly instantiated before
|
||
|
|
// trying to map any expressions that utilize them. In particular,
|
||
|
|
// we need to make sure type pragmas are already known (see comment
|
||
|
|
// in irgen.typeDecl).
|
||
|
|
//
|
||
|
|
// We could perhaps instead defer processing of package-block
|
||
|
|
// variable initializers and function bodies, like noder does, but
|
||
|
|
// special-casing just package-block type declarations minimizes the
|
||
|
|
// differences between processing package-block and function-scoped
|
||
|
|
// declarations.
|
||
|
|
for _, declList := range declLists {
|
||
|
|
for _, decl := range declList {
|
||
|
|
switch decl := decl.(type) {
|
||
|
|
case *syntax.TypeDecl:
|
||
|
|
g.typeDecl((*ir.Nodes)(&g.target.Decls), decl)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 3. Process all remaining declarations.
|
||
|
|
for _, declList := range declLists {
|
||
|
|
g.target.Decls = append(g.target.Decls, g.decls(declList)...)
|
||
|
|
}
|
||
|
|
typecheck.DeclareUniverse()
|
||
|
|
|
||
|
|
for _, p := range noders {
|
||
|
|
// Process linkname and cgo pragmas.
|
||
|
|
p.processPragmas()
|
||
|
|
|
||
|
|
// Double check for any type-checking inconsistencies. This can be
|
||
|
|
// removed once we're confident in IR generation results.
|
||
|
|
syntax.Walk(p.file, func(n syntax.Node) bool {
|
||
|
|
g.validate(n)
|
||
|
|
return false
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (g *irgen) unhandled(what string, p poser) {
|
||
|
|
base.FatalfAt(g.pos(p), "unhandled %s: %T", what, p)
|
||
|
|
panic("unreachable")
|
||
|
|
}
|