diff options
Diffstat (limited to 'src/cmd/compile/internal/noder/irgen.go')
-rw-r--r-- | src/cmd/compile/internal/noder/irgen.go | 112 |
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() { |