aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/noder/irgen.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/noder/irgen.go')
-rw-r--r--src/cmd/compile/internal/noder/irgen.go112
1 files changed, 96 insertions, 16 deletions
diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go
index 3e0d3285ab..7bc8a6bcc3 100644
--- a/src/cmd/compile/internal/noder/irgen.go
+++ b/src/cmd/compile/internal/noder/irgen.go
@@ -18,9 +18,9 @@ import (
"cmd/internal/src"
)
-// check2 type checks a Go package using types2, and then generates IR
-// using the results.
-func check2(noders []*noder) {
+// checkFiles configures and runs the types2 checker on the given
+// parsed source files and then returns the result.
+func checkFiles(noders []*noder) (posMap, *types2.Package, *types2.Info) {
if base.SyntaxErrors() != 0 {
base.ErrorExit()
}
@@ -34,20 +34,22 @@ func check2(noders []*noder) {
}
// typechecking
+ importer := gcimports{
+ packages: make(map[string]*types2.Package),
+ }
conf := types2.Config{
GoVersion: base.Flag.Lang,
IgnoreLabels: true, // parser already checked via syntax.CheckBranches mode
CompilerErrorMessages: true, // use error strings matching existing compiler errors
+ AllowTypeLists: true, // remove this line once all tests use type set syntax
Error: func(err error) {
terr := err.(types2.Error)
base.ErrorfAt(m.makeXPos(terr.Pos), "%s", terr.Msg)
},
- Importer: &gcimports{
- packages: make(map[string]*types2.Package),
- },
- Sizes: &gcSizes{},
+ Importer: &importer,
+ Sizes: &gcSizes{},
}
- info := types2.Info{
+ info := &types2.Info{
Types: make(map[syntax.Expr]types2.TypeAndValue),
Defs: make(map[*syntax.Name]types2.Object),
Uses: make(map[*syntax.Name]types2.Object),
@@ -57,12 +59,24 @@ func check2(noders []*noder) {
Inferred: make(map[syntax.Expr]types2.Inferred),
// expand as needed
}
- pkg, err := conf.Check(base.Ctxt.Pkgpath, files, &info)
- files = nil
+
+ pkg := types2.NewPackage(base.Ctxt.Pkgpath, "")
+ importer.check = types2.NewChecker(&conf, pkg, info)
+ err := importer.check.Files(files)
+
base.ExitIfErrors()
if err != nil {
base.FatalfAt(src.NoXPos, "conf.Check error: %v", err)
}
+
+ return m, pkg, info
+}
+
+// check2 type checks a Go package using types2, and then generates IR
+// using the results.
+func check2(noders []*noder) {
+ m, pkg, info := checkFiles(noders)
+
if base.Flag.G < 2 {
os.Exit(0)
}
@@ -70,7 +84,7 @@ func check2(noders []*noder) {
g := irgen{
target: typecheck.Target,
self: pkg,
- info: &info,
+ info: info,
posMap: m,
objs: make(map[types2.Object]*ir.Name),
typs: make(map[types2.Type]*types.Type),
@@ -82,6 +96,41 @@ func check2(noders []*noder) {
}
}
+// gfInfo is information gathered on a generic function.
+type gfInfo struct {
+ tparams []*types.Type
+ derivedTypes []*types.Type
+ // Nodes in generic function that requires a subdictionary. Includes
+ // method and function calls (OCALL), function values (OFUNCINST), method
+ // values/expressions (OXDOT).
+ subDictCalls []ir.Node
+ // Nodes in generic functions that are a conversion from a typeparam/derived
+ // type to a specific interface.
+ itabConvs []ir.Node
+ // For type switches on nonempty interfaces, a map from OTYPE entries of
+ // HasTParam type, to the interface type we're switching from.
+ // TODO: what if the type we're switching from is a shape type?
+ type2switchType map[ir.Node]*types.Type
+}
+
+// instInfo is information gathered on an gcshape (or fully concrete)
+// instantiation of a function.
+type instInfo struct {
+ fun *ir.Func // The instantiated function (with body)
+ dictParam *ir.Name // The node inside fun that refers to the dictionary param
+
+ gf *ir.Name // The associated generic function
+ gfInfo *gfInfo
+
+ startSubDict int // Start of dict entries for subdictionaries
+ startItabConv int // Start of dict entries for itab conversions
+ dictLen int // Total number of entries in dictionary
+
+ // Map from nodes in instantiated fun (OCALL, OCALLMETHOD, OFUNCINST, and
+ // OMETHEXPR) to the associated dictionary entry for a sub-dictionary
+ dictEntryMap map[ir.Node]int
+}
+
type irgen struct {
target *ir.Package
self *types2.Package
@@ -94,10 +143,38 @@ type irgen struct {
// Fully-instantiated generic types whose methods should be instantiated
instTypeList []*types.Type
+
+ dnum int // for generating unique dictionary variables
+
+ // Map from generic function to information about its type params, derived
+ // types, and subdictionaries.
+ gfInfoMap map[*types.Sym]*gfInfo
+
+ // Map from a name of function that been instantiated to information about
+ // its instantiated function, associated generic function/method, and the
+ // mapping from IR nodes to dictionary entries.
+ instInfoMap map[*types.Sym]*instInfo
+
+ // dictionary syms which we need to finish, by writing out any itabconv
+ // entries.
+ dictSymsToFinalize []*delayInfo
+
+ // True when we are compiling a top-level generic function or method. Use to
+ // avoid adding closures of generic functions/methods to the target.Decls
+ // list.
+ topFuncIsGeneric bool
+}
+
+type delayInfo struct {
+ gf *ir.Name
+ targs []*types.Type
+ sym *types.Sym
+ off int
}
func (g *irgen) generate(noders []*noder) {
types.LocalPkg.Name = g.self.Name()
+ types.LocalPkg.Height = g.self.Height()
typecheck.TypecheckAllowed = true
// Prevent size calculations until we set the underlying type
@@ -132,7 +209,6 @@ Outer:
}
}
}
- 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
@@ -167,6 +243,10 @@ Outer:
}
}
+ // Check for unusual case where noder2 encounters a type error that types2
+ // doesn't check for (e.g. notinheap incompatibility).
+ base.ExitIfErrors()
+
typecheck.DeclareUniverse()
for _, p := range noders {
@@ -175,7 +255,7 @@ Outer:
// 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 {
+ syntax.Crawl(p.file, func(n syntax.Node) bool {
g.validate(n)
return false
})
@@ -184,9 +264,9 @@ Outer:
// Create any needed stencils of generic functions
g.stencil()
- // For now, remove all generic functions from g.target.Decl, since they
- // have been used for stenciling, but don't compile. TODO: We will
- // eventually export any exportable generic functions.
+ // Remove all generic functions from g.target.Decl, since they have been
+ // used for stenciling, but don't compile. Generic functions will already
+ // have been marked for export as appropriate.
j := 0
for i, decl := range g.target.Decls {
if decl.Op() != ir.ODCLFUNC || !decl.Type().HasTParam() {