aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/typecheck/crawler.go
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2022-12-01 16:27:34 -0800
committerMatthew Dempsky <mdempsky@google.com>2023-01-26 21:52:50 +0000
commitda9761303c439041251931c32b6e86bdbe739183 (patch)
tree50a79b91fa2b6b31126ce56b23aa4ac3942d4647 /src/cmd/compile/internal/typecheck/crawler.go
parenta7de684e1b6f460aae7d4dbf2568cb21130ec520 (diff)
downloadgo-da9761303c439041251931c32b6e86bdbe739183.tar.gz
go-da9761303c439041251931c32b6e86bdbe739183.zip
cmd/compile: remove GOEXPERIMENT=nounified frontend
This CL removes most of the code specific to the nounified frontend. To simplify review, it's a strict remove-only CL. Updates #57410. Change-Id: Ic3196570aa4286618c1d5e7fd0d0e6601a18195b Reviewed-on: https://go-review.googlesource.com/c/go/+/458620 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/typecheck/crawler.go')
-rw-r--r--src/cmd/compile/internal/typecheck/crawler.go378
1 files changed, 0 insertions, 378 deletions
diff --git a/src/cmd/compile/internal/typecheck/crawler.go b/src/cmd/compile/internal/typecheck/crawler.go
deleted file mode 100644
index a4a507dfec..0000000000
--- a/src/cmd/compile/internal/typecheck/crawler.go
+++ /dev/null
@@ -1,378 +0,0 @@
-// 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 typecheck
-
-import (
- "cmd/compile/internal/base"
- "cmd/compile/internal/ir"
- "cmd/compile/internal/types"
- "cmd/internal/src"
-)
-
-// crawlExports crawls the type/object graph rooted at the given list of exported
-// objects (which are variables, functions, and types). It descends through all parts
-// of types and follows methods on defined types. Any functions that are found to be
-// potentially callable by importers directly or after inlining are marked with
-// ExportInline, so that iexport.go knows to export their inline body.
-//
-// The overall purpose of crawlExports is to AVOID exporting inlineable methods
-// that cannot actually be referenced, thereby reducing the size of the exports
-// significantly.
-//
-// For non-generic defined types reachable from global variables, we only set
-// ExportInline for exported methods. For defined types that are directly named or are
-// embedded recursively in such a type, we set ExportInline for all methods, since
-// these types can be embedded in another local type. For instantiated types that are
-// used anywhere in a inlineable function, we set ExportInline on all methods of the
-// base generic type, since all methods will be needed for creating any instantiated
-// type.
-func crawlExports(exports []*ir.Name) {
- p := crawler{
- marked: make(map[*types.Type]bool),
- embedded: make(map[*types.Type]bool),
- generic: make(map[*types.Type]bool),
- checkFullyInst: make(map[*types.Type]bool),
- }
- for _, n := range exports {
- p.markObject(n)
- }
-}
-
-type crawler struct {
- marked map[*types.Type]bool // types already seen by markType
- embedded map[*types.Type]bool // types already seen by markEmbed
- generic map[*types.Type]bool // types already seen by markGeneric
- checkFullyInst map[*types.Type]bool // types already seen by checkForFullyInst
-}
-
-// markObject visits a reachable object (function, method, global type, or global variable)
-func (p *crawler) markObject(n *ir.Name) {
- if n.Op() == ir.ONAME && n.Class == ir.PFUNC {
- p.markInlBody(n)
- }
-
- // If a declared type name is reachable, users can embed it in their
- // own types, which makes even its unexported methods reachable.
- if n.Op() == ir.OTYPE {
- p.markEmbed(n.Type())
- }
-
- p.markType(n.Type())
-}
-
-// markType recursively visits types reachable from t to identify functions whose
-// inline bodies may be needed. For instantiated generic types, it visits the base
-// generic type, which has the relevant methods.
-func (p *crawler) markType(t *types.Type) {
- if orig := t.OrigType(); orig != nil {
- // Convert to the base generic type.
- t = orig
- }
- if p.marked[t] {
- return
- }
- p.marked[t] = true
-
- // If this is a defined type, mark all of its associated
- // methods. Skip interface types because t.Methods contains
- // only their unexpanded method set (i.e., exclusive of
- // interface embeddings), and the switch statement below
- // handles their full method set.
- if t.Sym() != nil && t.Kind() != types.TINTER {
- for _, m := range t.Methods().Slice() {
- if types.IsExported(m.Sym.Name) {
- p.markObject(m.Nname.(*ir.Name))
- }
- }
- }
-
- // Recursively mark any types that can be produced given a
- // value of type t: dereferencing a pointer; indexing or
- // iterating over an array, slice, or map; receiving from a
- // channel; accessing a struct field or interface method; or
- // calling a function.
- //
- // Notably, we don't mark function parameter types, because
- // the user already needs some way to construct values of
- // those types.
- switch t.Kind() {
- case types.TPTR, types.TARRAY, types.TSLICE:
- p.markType(t.Elem())
-
- case types.TCHAN:
- if t.ChanDir().CanRecv() {
- p.markType(t.Elem())
- }
-
- case types.TMAP:
- p.markType(t.Key())
- p.markType(t.Elem())
-
- case types.TSTRUCT:
- if t.IsFuncArgStruct() {
- break
- }
- for _, f := range t.FieldSlice() {
- // Mark the type of a unexported field if it is a
- // fully-instantiated type, since we create and instantiate
- // the methods of any fully-instantiated type that we see
- // during import (see end of typecheck.substInstType).
- if types.IsExported(f.Sym.Name) || f.Embedded != 0 ||
- isPtrFullyInstantiated(f.Type) {
- p.markType(f.Type)
- }
- }
-
- case types.TFUNC:
- for _, f := range t.Results().FieldSlice() {
- p.markType(f.Type)
- }
-
- case types.TINTER:
- for _, f := range t.AllMethods().Slice() {
- if types.IsExported(f.Sym.Name) {
- p.markType(f.Type)
- }
- }
-
- case types.TTYPEPARAM:
- // No other type that needs to be followed.
- }
-}
-
-// markEmbed is similar to markType, but handles finding methods that
-// need to be re-exported because t can be embedded in user code
-// (possibly transitively).
-func (p *crawler) markEmbed(t *types.Type) {
- if t.IsPtr() {
- // Defined pointer type; not allowed to embed anyway.
- if t.Sym() != nil {
- return
- }
- t = t.Elem()
- }
-
- if orig := t.OrigType(); orig != nil {
- // Convert to the base generic type.
- t = orig
- }
-
- if p.embedded[t] {
- return
- }
- p.embedded[t] = true
-
- // If t is a defined type, then re-export all of its methods. Unlike
- // in markType, we include even unexported methods here, because we
- // still need to generate wrappers for them, even if the user can't
- // refer to them directly.
- if t.Sym() != nil && t.Kind() != types.TINTER {
- for _, m := range t.Methods().Slice() {
- p.markObject(m.Nname.(*ir.Name))
- }
- }
-
- // If t is a struct, recursively visit its embedded fields.
- if t.IsStruct() {
- for _, f := range t.FieldSlice() {
- if f.Embedded != 0 {
- p.markEmbed(f.Type)
- }
- }
- }
-}
-
-// markGeneric takes an instantiated type or a base generic type t, and marks all the
-// methods of the base generic type of t. If a base generic type is written out for
-// export, even if not explicitly marked for export, then all of its methods need to
-// be available for instantiation, since we always create all methods of a specified
-// instantiated type. Non-exported methods must generally be instantiated, since they may
-// be called by the exported methods or other generic function in the same package.
-func (p *crawler) markGeneric(t *types.Type) {
- if t.IsPtr() {
- t = t.Elem()
- }
- if orig := t.OrigType(); orig != nil {
- // Convert to the base generic type.
- t = orig
- }
- if p.generic[t] {
- return
- }
- p.generic[t] = true
-
- if t.Sym() != nil && t.Kind() != types.TINTER {
- for _, m := range t.Methods().Slice() {
- p.markObject(m.Nname.(*ir.Name))
- }
- }
-}
-
-// checkForFullyInst looks for fully-instantiated types in a type (at any nesting
-// level). If it finds a fully-instantiated type, it ensures that the necessary
-// dictionary and shape methods are exported. It updates p.checkFullyInst, so it
-// traverses each particular type only once.
-func (p *crawler) checkForFullyInst(t *types.Type) {
- if p.checkFullyInst[t] {
- return
- }
- p.checkFullyInst[t] = true
-
- if t.IsFullyInstantiated() && !t.HasShape() && !t.IsInterface() && t.Methods().Len() > 0 {
- // For any fully-instantiated type, the relevant
- // dictionaries and shape instantiations will have
- // already been created or are in the import data.
- // Make sure that they are exported, so that any
- // other package that inlines this function will have
- // them available for import, and so will not need
- // another round of method and dictionary
- // instantiation after inlining.
- baseType := t.OrigType()
- shapes := make([]*types.Type, len(t.RParams()))
- for i, t1 := range t.RParams() {
- shapes[i] = Shapify(t1, i, baseType.RParams()[i])
- }
- for j, tmethod := range t.Methods().Slice() {
- baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name)
- dictsym := MakeDictSym(baseNname.Sym(), t.RParams(), true)
- if dictsym.Def == nil {
- in := Resolve(ir.NewIdent(src.NoXPos, dictsym))
- dictsym = in.Sym()
- }
- Export(dictsym.Def.(*ir.Name))
- methsym := MakeFuncInstSym(baseNname.Sym(), shapes, false, true)
- if methsym.Def == nil {
- in := Resolve(ir.NewIdent(src.NoXPos, methsym))
- methsym = in.Sym()
- }
- methNode := methsym.Def.(*ir.Name)
- Export(methNode)
- if HaveInlineBody(methNode.Func) {
- // Export the body as well if
- // instantiation is inlineable.
- ImportedBody(methNode.Func)
- methNode.Func.SetExportInline(true)
- }
- // Make sure that any associated types are also exported. (See #52279)
- p.checkForFullyInst(tmethod.Type)
- }
- }
-
- // Descend into the type. We descend even if it is a fully-instantiated type,
- // since the instantiated type may have other instantiated types inside of
- // it (in fields, methods, etc.).
- switch t.Kind() {
- case types.TPTR, types.TARRAY, types.TSLICE:
- p.checkForFullyInst(t.Elem())
-
- case types.TCHAN:
- p.checkForFullyInst(t.Elem())
-
- case types.TMAP:
- p.checkForFullyInst(t.Key())
- p.checkForFullyInst(t.Elem())
-
- case types.TSTRUCT:
- if t.IsFuncArgStruct() {
- break
- }
- for _, f := range t.FieldSlice() {
- p.checkForFullyInst(f.Type)
- }
-
- case types.TFUNC:
- if recv := t.Recv(); recv != nil {
- p.checkForFullyInst(t.Recv().Type)
- }
- for _, f := range t.Params().FieldSlice() {
- p.checkForFullyInst(f.Type)
- }
- for _, f := range t.Results().FieldSlice() {
- p.checkForFullyInst(f.Type)
- }
-
- case types.TINTER:
- for _, f := range t.AllMethods().Slice() {
- p.checkForFullyInst(f.Type)
- }
- }
-}
-
-// markInlBody marks n's inline body for export and recursively
-// ensures all called functions are marked too.
-func (p *crawler) markInlBody(n *ir.Name) {
- if n == nil {
- return
- }
- if n.Op() != ir.ONAME || n.Class != ir.PFUNC {
- base.Fatalf("markInlBody: unexpected %v, %v, %v", n, n.Op(), n.Class)
- }
- fn := n.Func
- if fn == nil {
- base.Fatalf("markInlBody: missing Func on %v", n)
- }
- if !HaveInlineBody(fn) {
- return
- }
-
- if fn.ExportInline() {
- return
- }
- fn.SetExportInline(true)
-
- ImportedBody(fn)
-
- var doFlood func(n ir.Node)
- doFlood = func(n ir.Node) {
- t := n.Type()
- if t != nil {
- if t.HasTParam() {
- // If any generic types are used, then make sure that
- // the methods of the generic type are exported and
- // scanned for other possible exports.
- p.markGeneric(t)
- } else {
- p.checkForFullyInst(t)
- }
- }
-
- switch n.Op() {
- case ir.OMETHEXPR, ir.ODOTMETH:
- p.markInlBody(ir.MethodExprName(n))
- case ir.ONAME:
- n := n.(*ir.Name)
- switch n.Class {
- case ir.PFUNC:
- p.markInlBody(n)
- // Note: this Export() and the one below seem unneeded,
- // since any function/extern name encountered in an
- // exported function body will be exported
- // automatically via qualifiedIdent() in iexport.go.
- Export(n)
- case ir.PEXTERN:
- Export(n)
- }
- case ir.OMETHVALUE:
- // Okay, because we don't yet inline indirect
- // calls to method values.
- case ir.OCLOSURE:
- // VisitList doesn't visit closure bodies, so force a
- // recursive call to VisitList on the body of the closure.
- ir.VisitList(n.(*ir.ClosureExpr).Func.Body, doFlood)
- }
- }
-
- // Recursively identify all referenced functions for
- // reexport. We want to include even non-called functions,
- // because after inlining they might be callable.
- ir.VisitList(fn.Inl.Body, doFlood)
-}
-
-// isPtrFullyInstantiated returns true if t is a fully-instantiated type, or it is a
-// pointer to a fully-instantiated type.
-func isPtrFullyInstantiated(t *types.Type) bool {
- return t.IsPtr() && t.Elem().IsFullyInstantiated() ||
- t.IsFullyInstantiated()
-}