]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: include typecheck information in export/import
authorKeith Randall <khr@golang.org>
Fri, 12 Mar 2021 20:57:39 +0000 (12:57 -0800)
committerKeith Randall <khr@golang.org>
Sat, 10 Apr 2021 14:58:18 +0000 (14:58 +0000)
Include type information on exported function bodies, so that the
importer does not have to re-typecheck the body. This involves
including type information in the encoded output, as well as
avoiding some of the opcode rewriting and other changes that the
old exporter did assuming there would be a re-typechecking pass.

This CL could be considered a cleanup, but is more important than that
because it is an enabling change for generics. Without this CL, we'd
have to upgrade the current typechecker to understand generics. With
this CL, the current typechecker can mostly go away in favor of the
types2 typechecker.

For now, inlining of functions that contain closures is turned off.
We will hopefully resolve this before freeze.

Object files are only 0.07% bigger.

Change-Id: I85c9da09f66bfdc910dc3e26abb2613a1831634d
Reviewed-on: https://go-review.googlesource.com/c/go/+/301291
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Dan Scales <danscales@google.com>
src/cmd/compile/internal/escape/escape.go
src/cmd/compile/internal/inline/inl.go
src/cmd/compile/internal/typecheck/func.go
src/cmd/compile/internal/typecheck/iexport.go
src/cmd/compile/internal/typecheck/iimport.go
test/closure3.dir/main.go
test/inline.go

index 213ef7832d362c61369a6bd7e827b476851621fd..6bebe5422f83b42a7190a61f2f43608536daff8f 100644 (file)
@@ -587,7 +587,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
 
        switch n.Op() {
        default:
-               base.Fatalf("unexpected expr: %v", n)
+               base.Fatalf("unexpected expr: %s %v", n.Op().String(), n)
 
        case ir.OLITERAL, ir.ONIL, ir.OGETG, ir.OTYPE, ir.OMETHEXPR, ir.OLINKSYMOFFSET:
                // nop
index 1941dc44bca30feb82f16b0ce4604d76e13a81b9..4470df1d2afc1ad2395c6f45615a7992ca4e67fc 100644 (file)
@@ -354,7 +354,7 @@ func (v *hairyVisitor) doNode(n ir.Node) bool {
                return true
 
        case ir.OCLOSURE:
-               if base.Debug.InlFuncsWithClosures == 0 {
+               if base.Debug.InlFuncsWithClosures == 0 || typecheck.Go117ExportTypes { // TODO: remove latter condition
                        v.reason = "not inlining functions with closures"
                        return true
                }
@@ -1013,7 +1013,9 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
        lab := ir.NewLabelStmt(base.Pos, retlabel)
        body = append(body, lab)
 
-       typecheck.Stmts(body)
+       if !typecheck.Go117ExportTypes {
+               typecheck.Stmts(body)
+       }
 
        if base.Flag.GenDwarfInl > 0 {
                for _, v := range inlfvars {
index bc31284a85737267f85117a46a58ad640795aad4..eaae2a81fac9812fd497c8e07d4a3be270015d3b 100644 (file)
@@ -144,15 +144,18 @@ func ImportedBody(fn *ir.Func) {
                fmt.Printf("typecheck import [%v] %L { %v }\n", fn.Sym(), fn, ir.Nodes(fn.Inl.Body))
        }
 
-       savefn := ir.CurFunc
-       ir.CurFunc = fn
-       if inTypeCheckInl {
-               base.Fatalf("inTypeCheckInl should not be set recursively")
+       if !go117ExportTypes {
+               // If we didn't export & import types, typecheck the code here.
+               savefn := ir.CurFunc
+               ir.CurFunc = fn
+               if inTypeCheckInl {
+                       base.Fatalf("inTypeCheckInl should not be set recursively")
+               }
+               inTypeCheckInl = true
+               Stmts(fn.Inl.Body)
+               inTypeCheckInl = false
+               ir.CurFunc = savefn
        }
-       inTypeCheckInl = true
-       Stmts(fn.Inl.Body)
-       inTypeCheckInl = false
-       ir.CurFunc = savefn
 
        base.Pos = lno
 }
index 43cc4e4a25ae0dcc183f68ddf8791bd304e4a8b8..8f8931e4957e394e1b980df069825552b15b89b1 100644 (file)
@@ -633,6 +633,79 @@ func (w *exportWriter) selector(s *types.Sym) {
        w.string(s.Name)
 }
 
+func (w *exportWriter) typ(t *types.Type) {
+       w.data.uint64(w.p.typOff(t))
+}
+
+// The "exotic" functions in this section encode a wider range of
+// items than the standard encoding functions above. These include
+// types that do not appear in declarations, only in code, such as
+// method types. These methods need to be separate from the standard
+// encoding functions because we don't want to modify the encoding
+// generated by the standard functions (because that exported
+// information is read by tools besides the compiler).
+
+// exoticType exports a type to the writer.
+func (w *exportWriter) exoticType(t *types.Type) {
+       switch {
+       case t == nil:
+               // Calls-as-statements have no type.
+               w.data.uint64(exoticTypeNil)
+       case t.IsStruct() && t.StructType().Funarg != types.FunargNone:
+               // These are weird structs for representing tuples of types returned
+               // by multi-return functions.
+               // They don't fit the standard struct type mold. For instance,
+               // they don't have any package info.
+               w.data.uint64(exoticTypeTuple)
+               w.uint64(uint64(t.StructType().Funarg))
+               w.uint64(uint64(t.NumFields()))
+               for _, f := range t.FieldSlice() {
+                       w.pos(f.Pos)
+                       s := f.Sym
+                       if s == nil {
+                               w.uint64(0)
+                       } else if s.Pkg == nil {
+                               w.uint64(exoticTypeSymNoPkg)
+                               w.string(s.Name)
+                       } else {
+                               w.uint64(exoticTypeSymWithPkg)
+                               w.pkg(s.Pkg)
+                               w.string(s.Name)
+                       }
+                       w.typ(f.Type)
+                       if f.Embedded != 0 || f.Note != "" {
+                               panic("extra info in funarg struct field")
+                       }
+               }
+       case t.Kind() == types.TFUNC && t.Recv() != nil:
+               w.data.uint64(exoticTypeRecv)
+               // interface method types have a fake receiver type.
+               isFakeRecv := t.Recv().Type == types.FakeRecvType()
+               w.bool(isFakeRecv)
+               if !isFakeRecv {
+                       w.exoticParam(t.Recv())
+               }
+               w.exoticSignature(t)
+
+       default:
+               // A regular type.
+               w.data.uint64(exoticTypeRegular)
+               w.typ(t)
+       }
+}
+
+const (
+       exoticTypeNil = iota
+       exoticTypeTuple
+       exoticTypeRecv
+       exoticTypeRegular
+)
+const (
+       exoticTypeSymNil = iota
+       exoticTypeSymNoPkg
+       exoticTypeSymWithPkg
+)
+
 // Export a selector, but one whose package may not match
 // the package being compiled. This is a separate function
 // because the standard selector() serialization format is fixed
@@ -653,8 +726,42 @@ func (w *exportWriter) exoticSelector(s *types.Sym) {
        }
 }
 
-func (w *exportWriter) typ(t *types.Type) {
-       w.data.uint64(w.p.typOff(t))
+func (w *exportWriter) exoticSignature(t *types.Type) {
+       hasPkg := t.Pkg() != nil
+       w.bool(hasPkg)
+       if hasPkg {
+               w.pkg(t.Pkg())
+       }
+       w.exoticParamList(t.Params().FieldSlice())
+       w.exoticParamList(t.Results().FieldSlice())
+}
+
+func (w *exportWriter) exoticParamList(fs []*types.Field) {
+       w.uint64(uint64(len(fs)))
+       for _, f := range fs {
+               w.exoticParam(f)
+       }
+
+}
+func (w *exportWriter) exoticParam(f *types.Field) {
+       w.pos(f.Pos)
+       w.exoticSym(f.Sym)
+       w.uint64(uint64(f.Offset))
+       w.exoticType(f.Type)
+       w.bool(f.IsDDD())
+}
+func (w *exportWriter) exoticSym(s *types.Sym) {
+       if s == nil {
+               w.string("")
+               return
+       }
+       if s.Name == "" {
+               base.Fatalf("empty symbol name")
+       }
+       w.string(s.Name)
+       if !types.IsExported(s.Name) {
+               w.pkg(s.Pkg)
+       }
 }
 
 func (p *iexporter) newWriter() *exportWriter {
@@ -1133,6 +1240,7 @@ func (w *exportWriter) writeNames(dcl []*ir.Name) {
 }
 
 func (w *exportWriter) funcBody(fn *ir.Func) {
+       //fmt.Printf("Exporting %s\n", fn.Nname.Sym().Name)
        w.writeNames(fn.Inl.Dcl)
 
        w.stmtList(fn.Inl.Body)
@@ -1208,7 +1316,11 @@ func (w *exportWriter) stmt(n ir.Node) {
 
        case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
                n := n.(*ir.AssignListStmt)
-               w.op(ir.OAS2)
+               if go117ExportTypes {
+                       w.op(n.Op())
+               } else {
+                       w.op(ir.OAS2)
+               }
                w.pos(n.Pos())
                w.exprList(n.Lhs)
                w.exprList(n.Rhs)
@@ -1220,7 +1332,7 @@ func (w *exportWriter) stmt(n ir.Node) {
                w.exprList(n.Results)
 
        // case ORETJMP:
-       //      unreachable - generated by compiler for trampolin routines
+       //      unreachable - generated by compiler for trampoline routines
 
        case ir.OGO, ir.ODEFER:
                n := n.(*ir.GoDeferStmt)
@@ -1357,10 +1469,15 @@ func (w *exportWriter) expr(n ir.Node) {
                if (n.Class == ir.PEXTERN || n.Class == ir.PFUNC) && !ir.IsBlank(n) {
                        w.op(ir.ONONAME)
                        w.qualifiedIdent(n)
+                       if go117ExportTypes {
+                               w.typ(n.Type())
+                       }
                        break
                }
 
                // Function scope name.
+               // We don't need a type here, as the type will be provided at the
+               // declaration of n.
                w.op(ir.ONAME)
                w.localName(n)
 
@@ -1418,9 +1535,16 @@ func (w *exportWriter) expr(n ir.Node) {
 
        case ir.OPTRLIT:
                n := n.(*ir.AddrExpr)
-               w.op(ir.OADDR)
+               if go117ExportTypes {
+                       w.op(ir.OPTRLIT)
+               } else {
+                       w.op(ir.OADDR)
+               }
                w.pos(n.Pos())
                w.expr(n.X)
+               if go117ExportTypes {
+                       w.typ(n.Type())
+               }
 
        case ir.OSTRUCTLIT:
                n := n.(*ir.CompLitExpr)
@@ -1431,11 +1555,17 @@ func (w *exportWriter) expr(n ir.Node) {
 
        case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
                n := n.(*ir.CompLitExpr)
-               w.op(ir.OCOMPLIT)
+               if go117ExportTypes {
+                       w.op(n.Op())
+               } else {
+                       w.op(ir.OCOMPLIT)
+               }
                w.pos(n.Pos())
                w.typ(n.Type())
                w.exprList(n.List)
-
+               if go117ExportTypes && n.Op() == ir.OSLICELIT {
+                       w.uint64(uint64(n.Len))
+               }
        case ir.OKEY:
                n := n.(*ir.KeyExpr)
                w.op(ir.OKEY)
@@ -1448,39 +1578,89 @@ func (w *exportWriter) expr(n ir.Node) {
 
        case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
                n := n.(*ir.SelectorExpr)
-               w.op(ir.OXDOT)
+               if go117ExportTypes {
+                       if n.Op() == ir.OXDOT {
+                               base.Fatalf("shouldn't encounter XDOT  in new exporter")
+                       }
+                       w.op(n.Op())
+               } else {
+                       w.op(ir.OXDOT)
+               }
                w.pos(n.Pos())
                w.expr(n.X)
                w.exoticSelector(n.Sel)
+               if go117ExportTypes {
+                       w.exoticType(n.Type())
+                       if n.Op() == ir.ODOT || n.Op() == ir.ODOTPTR || n.Op() == ir.ODOTINTER || n.Op() == ir.OMETHEXPR {
+                               w.exoticParam(n.Selection)
+                               if n.Op() == ir.OMETHEXPR {
+                                       name := ir.MethodExprName(n)
+                                       w.bool(name != nil)
+                                       if name != nil {
+                                               w.exoticType(name.Type())
+                                       }
+                               }
+                       }
+                       // n.Selection is not required for ODOTMETH and OCALLPART. It will
+                       // be reconstructed during import.
+               }
 
        case ir.ODOTTYPE, ir.ODOTTYPE2:
                n := n.(*ir.TypeAssertExpr)
-               w.op(ir.ODOTTYPE)
+               if go117ExportTypes {
+                       w.op(n.Op())
+               } else {
+                       w.op(ir.ODOTTYPE)
+               }
                w.pos(n.Pos())
                w.expr(n.X)
                w.typ(n.Type())
 
        case ir.OINDEX, ir.OINDEXMAP:
                n := n.(*ir.IndexExpr)
-               w.op(ir.OINDEX)
+               if go117ExportTypes {
+                       w.op(n.Op())
+               } else {
+                       w.op(ir.OINDEX)
+               }
                w.pos(n.Pos())
                w.expr(n.X)
                w.expr(n.Index)
+               if go117ExportTypes {
+                       w.typ(n.Type())
+                       if n.Op() == ir.OINDEXMAP {
+                               w.bool(n.Assigned)
+                       }
+               }
 
        case ir.OSLICE, ir.OSLICESTR, ir.OSLICEARR:
                n := n.(*ir.SliceExpr)
-               w.op(ir.OSLICE)
+               if go117ExportTypes {
+                       w.op(n.Op())
+               } else {
+                       w.op(ir.OSLICE)
+               }
                w.pos(n.Pos())
                w.expr(n.X)
                w.exprsOrNil(n.Low, n.High)
+               if go117ExportTypes {
+                       w.typ(n.Type())
+               }
 
        case ir.OSLICE3, ir.OSLICE3ARR:
                n := n.(*ir.SliceExpr)
-               w.op(ir.OSLICE3)
+               if go117ExportTypes {
+                       w.op(n.Op())
+               } else {
+                       w.op(ir.OSLICE3)
+               }
                w.pos(n.Pos())
                w.expr(n.X)
                w.exprsOrNil(n.Low, n.High)
                w.expr(n.Max)
+               if go117ExportTypes {
+                       w.typ(n.Type())
+               }
 
        case ir.OCOPY, ir.OCOMPLEX:
                // treated like other builtin calls (see e.g., OREAL)
@@ -1489,11 +1669,19 @@ func (w *exportWriter) expr(n ir.Node) {
                w.pos(n.Pos())
                w.expr(n.X)
                w.expr(n.Y)
-               w.op(ir.OEND)
+               if go117ExportTypes {
+                       w.typ(n.Type())
+               } else {
+                       w.op(ir.OEND)
+               }
 
        case ir.OCONV, ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR:
                n := n.(*ir.ConvExpr)
-               w.op(ir.OCONV)
+               if go117ExportTypes {
+                       w.op(n.Op())
+               } else {
+                       w.op(ir.OCONV)
+               }
                w.pos(n.Pos())
                w.typ(n.Type())
                w.expr(n.X)
@@ -1503,7 +1691,13 @@ func (w *exportWriter) expr(n ir.Node) {
                w.op(n.Op())
                w.pos(n.Pos())
                w.expr(n.X)
-               w.op(ir.OEND)
+               if go117ExportTypes {
+                       if n.Op() != ir.OPANIC {
+                               w.typ(n.Type())
+                       }
+               } else {
+                       w.op(ir.OEND)
+               }
 
        case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
                n := n.(*ir.CallExpr)
@@ -1516,15 +1710,28 @@ func (w *exportWriter) expr(n ir.Node) {
                } else if n.IsDDD {
                        base.Fatalf("exporter: unexpected '...' with %v call", n.Op())
                }
+               if go117ExportTypes {
+                       if n.Op() != ir.ODELETE && n.Op() != ir.OPRINT && n.Op() != ir.OPRINTN {
+                               w.typ(n.Type())
+                       }
+               }
 
        case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG:
                n := n.(*ir.CallExpr)
-               w.op(ir.OCALL)
+               if go117ExportTypes {
+                       w.op(n.Op())
+               } else {
+                       w.op(ir.OCALL)
+               }
                w.pos(n.Pos())
                w.stmtList(n.Init())
                w.expr(n.X)
                w.exprList(n.Args)
                w.bool(n.IsDDD)
+               if go117ExportTypes {
+                       w.exoticType(n.Type())
+                       w.uint64(uint64(n.Use))
+               }
 
        case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
                n := n.(*ir.MakeExpr)
@@ -1540,6 +1747,12 @@ func (w *exportWriter) expr(n ir.Node) {
                        w.expr(n.Cap)
                        w.op(ir.OEND)
                case n.Len != nil && (n.Op() == ir.OMAKESLICE || !n.Len.Type().IsUntyped()):
+                       // Note: the extra conditional exists because make(T) for
+                       // T a map or chan type, gets an untyped zero added as
+                       // an argument. Don't serialize that argument here.
+                       w.expr(n.Len)
+                       w.op(ir.OEND)
+               case n.Len != nil && go117ExportTypes:
                        w.expr(n.Len)
                        w.op(ir.OEND)
                }
@@ -1550,18 +1763,27 @@ func (w *exportWriter) expr(n ir.Node) {
                w.op(n.Op())
                w.pos(n.Pos())
                w.expr(n.X)
+               if go117ExportTypes {
+                       w.typ(n.Type())
+               }
 
        case ir.OADDR:
                n := n.(*ir.AddrExpr)
                w.op(n.Op())
                w.pos(n.Pos())
                w.expr(n.X)
+               if go117ExportTypes {
+                       w.typ(n.Type())
+               }
 
        case ir.ODEREF:
                n := n.(*ir.StarExpr)
                w.op(n.Op())
                w.pos(n.Pos())
                w.expr(n.X)
+               if go117ExportTypes {
+                       w.typ(n.Type())
+               }
 
        case ir.OSEND:
                n := n.(*ir.SendStmt)
@@ -1578,6 +1800,9 @@ func (w *exportWriter) expr(n ir.Node) {
                w.pos(n.Pos())
                w.expr(n.X)
                w.expr(n.Y)
+               if go117ExportTypes {
+                       w.typ(n.Type())
+               }
 
        case ir.OANDAND, ir.OOROR:
                n := n.(*ir.LogicalExpr)
@@ -1585,12 +1810,18 @@ func (w *exportWriter) expr(n ir.Node) {
                w.pos(n.Pos())
                w.expr(n.X)
                w.expr(n.Y)
+               if go117ExportTypes {
+                       w.typ(n.Type())
+               }
 
        case ir.OADDSTR:
                n := n.(*ir.AddStringExpr)
                w.op(ir.OADDSTR)
                w.pos(n.Pos())
                w.exprList(n.List)
+               if go117ExportTypes {
+                       w.typ(n.Type())
+               }
 
        case ir.ODCLCONST:
                // if exporting, DCLCONST should just be removed as its usage
@@ -1633,6 +1864,9 @@ func (w *exportWriter) fieldList(list ir.Nodes) {
                w.pos(n.Pos())
                w.selector(n.Field)
                w.expr(n.Value)
+               if go117ExportTypes {
+                       w.uint64(uint64(n.Offset))
+               }
        }
 }
 
@@ -1693,3 +1927,13 @@ func (w *intWriter) uint64(x uint64) {
        n := binary.PutUvarint(buf[:], x)
        w.Write(buf[:n])
 }
+
+// If go117ExportTypes is true, then we write type information when
+// exporting function bodies, so those function bodies don't need to
+// be re-typechecked on import.
+// This flag adds some other info to the serialized stream as well
+// which was previously recomputed during typechecking, like
+// specializing opcodes (e.g. OXDOT to ODOTPTR) and ancillary
+// information (e.g. length field for OSLICELIT).
+const go117ExportTypes = true
+const Go117ExportTypes = go117ExportTypes
index 35a1a0083af813b94803fb85cbf9b11ff768fffb..0d5d892ef5f96c0b4bd9ae781f0788e1d80fe0ed 100644 (file)
@@ -466,21 +466,6 @@ func (r *importReader) ident(selector bool) *types.Sym {
 func (r *importReader) localIdent() *types.Sym { return r.ident(false) }
 func (r *importReader) selector() *types.Sym   { return r.ident(true) }
 
-func (r *importReader) exoticSelector() *types.Sym {
-       name := r.string()
-       if name == "" {
-               return nil
-       }
-       pkg := r.currPkg
-       if types.IsExported(name) {
-               pkg = types.LocalPkg
-       }
-       if r.uint64() != 0 {
-               pkg = r.pkg()
-       }
-       return pkg.Lookup(name)
-}
-
 func (r *importReader) qualifiedIdent() *ir.Ident {
        name := r.string()
        pkg := r.pkg()
@@ -516,6 +501,114 @@ func (r *importReader) typ() *types.Type {
        return r.p.typAt(r.uint64())
 }
 
+func (r *importReader) exoticType() *types.Type {
+       switch r.uint64() {
+       case exoticTypeNil:
+               return nil
+       case exoticTypeTuple:
+               funarg := types.Funarg(r.uint64())
+               n := r.uint64()
+               fs := make([]*types.Field, n)
+               for i := range fs {
+                       pos := r.pos()
+                       var sym *types.Sym
+                       switch r.uint64() {
+                       case exoticTypeSymNil:
+                               sym = nil
+                       case exoticTypeSymNoPkg:
+                               sym = types.NoPkg.Lookup(r.string())
+                       case exoticTypeSymWithPkg:
+                               pkg := r.pkg()
+                               sym = pkg.Lookup(r.string())
+                       default:
+                               base.Fatalf("unknown symbol kind")
+                       }
+                       typ := r.typ()
+                       f := types.NewField(pos, sym, typ)
+                       fs[i] = f
+               }
+               t := types.NewStruct(types.NoPkg, fs)
+               t.StructType().Funarg = funarg
+               return t
+       case exoticTypeRecv:
+               var rcvr *types.Field
+               if r.bool() { // isFakeRecv
+                       rcvr = fakeRecvField()
+               } else {
+                       rcvr = r.exoticParam()
+               }
+               return r.exoticSignature(rcvr)
+       case exoticTypeRegular:
+               return r.typ()
+       default:
+               base.Fatalf("bad kind of call type")
+               return nil
+       }
+}
+
+func (r *importReader) exoticSelector() *types.Sym {
+       name := r.string()
+       if name == "" {
+               return nil
+       }
+       pkg := r.currPkg
+       if types.IsExported(name) {
+               pkg = types.LocalPkg
+       }
+       if r.uint64() != 0 {
+               pkg = r.pkg()
+       }
+       return pkg.Lookup(name)
+}
+
+func (r *importReader) exoticSignature(recv *types.Field) *types.Type {
+       var pkg *types.Pkg
+       if r.bool() { // hasPkg
+               pkg = r.pkg()
+       }
+       params := r.exoticParamList()
+       results := r.exoticParamList()
+       return types.NewSignature(pkg, recv, nil, params, results)
+}
+
+func (r *importReader) exoticParamList() []*types.Field {
+       n := r.uint64()
+       fs := make([]*types.Field, n)
+       for i := range fs {
+               fs[i] = r.exoticParam()
+       }
+       return fs
+}
+
+func (r *importReader) exoticParam() *types.Field {
+       pos := r.pos()
+       sym := r.exoticSym()
+       off := r.uint64()
+       typ := r.exoticType()
+       ddd := r.bool()
+       f := types.NewField(pos, sym, typ)
+       f.Offset = int64(off)
+       if sym != nil {
+               f.Nname = ir.NewNameAt(pos, sym)
+       }
+       f.SetIsDDD(ddd)
+       return f
+}
+
+func (r *importReader) exoticSym() *types.Sym {
+       name := r.string()
+       if name == "" {
+               return nil
+       }
+       var pkg *types.Pkg
+       if types.IsExported(name) {
+               pkg = types.LocalPkg
+       } else {
+               pkg = r.pkg()
+       }
+       return pkg.Lookup(name)
+}
+
 func (p *iimporter) typAt(off uint64) *types.Type {
        t, ok := p.typCache[off]
        if !ok {
@@ -815,6 +908,11 @@ func (r *importReader) funcBody(fn *ir.Func) {
                // functions).
                body = []ir.Node{}
        }
+       if go117ExportTypes {
+               ir.VisitList(body, func(n ir.Node) {
+                       n.SetTypecheck(1)
+               })
+       }
        fn.Inl.Body = body
 
        r.curfn = outerfn
@@ -942,7 +1040,8 @@ func (r *importReader) expr() ir.Node {
 
 // TODO(gri) split into expr and stmt
 func (r *importReader) node() ir.Node {
-       switch op := r.op(); op {
+       op := r.op()
+       switch op {
        // expressions
        // case OPAREN:
        //      unreachable - unpacked by exporter
@@ -964,7 +1063,16 @@ func (r *importReader) node() ir.Node {
                return n
 
        case ir.ONONAME:
-               return r.qualifiedIdent()
+               n := r.qualifiedIdent()
+               if go117ExportTypes {
+                       n2 := Resolve(n)
+                       typ := r.typ()
+                       if n2.Type() == nil {
+                               n2.SetType(typ)
+                       }
+                       return n2
+               }
+               return n
 
        case ir.ONAME:
                return r.localName()
@@ -1028,64 +1136,145 @@ func (r *importReader) node() ir.Node {
 
                return clo
 
-       // case OPTRLIT:
-       //      unreachable - mapped to case OADDR below by exporter
-
        case ir.OSTRUCTLIT:
+               if go117ExportTypes {
+                       pos := r.pos()
+                       typ := r.typ()
+                       list := r.fieldList()
+                       n := ir.NewCompLitExpr(pos, ir.OSTRUCTLIT, nil, list)
+                       n.SetType(typ)
+                       return n
+               }
                return ir.NewCompLitExpr(r.pos(), ir.OCOMPLIT, ir.TypeNode(r.typ()), r.fieldList())
 
-       // case OARRAYLIT, OSLICELIT, OMAPLIT:
-       //      unreachable - mapped to case OCOMPLIT below by exporter
-
        case ir.OCOMPLIT:
                return ir.NewCompLitExpr(r.pos(), ir.OCOMPLIT, ir.TypeNode(r.typ()), r.exprList())
 
+       case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
+               if !go117ExportTypes {
+                       // unreachable - mapped to OCOMPLIT by exporter
+                       goto error
+               }
+               pos := r.pos()
+               typ := r.typ()
+               list := r.exprList()
+               n := ir.NewCompLitExpr(pos, op, ir.TypeNode(typ), list)
+               n.SetType(typ)
+               if op == ir.OSLICELIT {
+                       n.Len = int64(r.uint64())
+               }
+               return n
+
        case ir.OKEY:
                return ir.NewKeyExpr(r.pos(), r.expr(), r.expr())
 
        // case OSTRUCTKEY:
        //      unreachable - handled in case OSTRUCTLIT by elemList
 
-       // case OCALLPART:
-       //      unreachable - mapped to case OXDOT below by exporter
-
-       // case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
-       //      unreachable - mapped to case OXDOT below by exporter
-
        case ir.OXDOT:
                // see parser.new_dotname
+               if go117ExportTypes {
+                       base.Fatalf("shouldn't encounter XDOT in new importer")
+               }
                return ir.NewSelectorExpr(r.pos(), ir.OXDOT, r.expr(), r.exoticSelector())
 
-       // case ODOTTYPE, ODOTTYPE2:
-       //      unreachable - mapped to case ODOTTYPE below by exporter
+       case ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
+               if !go117ExportTypes {
+                       // unreachable - mapped to case OXDOT by exporter
+                       goto error
+               }
+               pos := r.pos()
+               expr := r.expr()
+               sel := r.exoticSelector()
+               n := ir.NewSelectorExpr(pos, ir.OXDOT, expr, sel)
+               n.SetOp(op)
+               n.SetType(r.exoticType())
+               switch op {
+               case ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.OMETHEXPR:
+                       n.Selection = r.exoticParam()
+                       if op == ir.OMETHEXPR {
+                               if r.bool() { // has name
+                                       ir.MethodExprName(n).SetType(r.exoticType())
+                               }
+                       }
+               case ir.ODOTMETH, ir.OCALLPART:
+                       // These require a Lookup to link to the correct declaration.
+                       rcvrType := expr.Type()
+                       typ := n.Type()
+                       n.Selection = Lookdot(n, rcvrType, 1)
+                       if op == ir.OCALLPART {
+                               // Lookdot clobbers the opcode and type, undo that.
+                               n.SetOp(op)
+                               n.SetType(typ)
+                       }
+               }
+               return n
 
-       case ir.ODOTTYPE:
+       case ir.ODOTTYPE, ir.ODOTTYPE2:
                n := ir.NewTypeAssertExpr(r.pos(), r.expr(), nil)
                n.SetType(r.typ())
+               if go117ExportTypes {
+                       n.SetOp(op)
+               }
                return n
 
-       // case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
-       //      unreachable - mapped to cases below by exporter
-
-       case ir.OINDEX:
-               return ir.NewIndexExpr(r.pos(), r.expr(), r.expr())
+       case ir.OINDEX, ir.OINDEXMAP:
+               n := ir.NewIndexExpr(r.pos(), r.expr(), r.expr())
+               if go117ExportTypes {
+                       n.SetOp(op)
+                       n.SetType(r.typ())
+                       if op == ir.OINDEXMAP {
+                               n.Assigned = r.bool()
+                       }
+               }
+               return n
 
-       case ir.OSLICE, ir.OSLICE3:
+       case ir.OSLICE, ir.OSLICESTR, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
                pos, x := r.pos(), r.expr()
                low, high := r.exprsOrNil()
                var max ir.Node
                if op.IsSlice3() {
                        max = r.expr()
                }
-               return ir.NewSliceExpr(pos, op, x, low, high, max)
-
-       // case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR:
-       //      unreachable - mapped to OCONV case below by exporter
+               n := ir.NewSliceExpr(pos, op, x, low, high, max)
+               if go117ExportTypes {
+                       n.SetType(r.typ())
+               }
+               return n
 
-       case ir.OCONV:
-               return ir.NewConvExpr(r.pos(), ir.OCONV, r.typ(), r.expr())
+       case ir.OCONV, ir.OCONVIFACE, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR:
+               if !go117ExportTypes && op != ir.OCONV {
+                       //      unreachable - mapped to OCONV case by exporter
+                       goto error
+               }
+               return ir.NewConvExpr(r.pos(), op, r.typ(), r.expr())
 
        case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
+               if go117ExportTypes {
+                       switch op {
+                       case ir.OCOPY, ir.OCOMPLEX:
+                               n := ir.NewBinaryExpr(r.pos(), op, r.expr(), r.expr())
+                               n.SetType(r.typ())
+                               return n
+                       case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
+                               n := ir.NewUnaryExpr(r.pos(), op, r.expr())
+                               if op != ir.OPANIC {
+                                       n.SetType(r.typ())
+                               }
+                               return n
+                       case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
+                               n := ir.NewCallExpr(r.pos(), op, nil, r.exprList())
+                               if op == ir.OAPPEND {
+                                       n.IsDDD = r.bool()
+                               }
+                               if op == ir.OAPPEND || op == ir.ORECOVER {
+                                       n.SetType(r.typ())
+                               }
+                               return n
+                       }
+                       // ir.OMAKE
+                       goto error
+               }
                n := builtinCall(r.pos(), op)
                n.Args = r.exprList()
                if op == ir.OAPPEND {
@@ -1093,18 +1282,37 @@ func (r *importReader) node() ir.Node {
                }
                return n
 
-       // case OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
-       //      unreachable - mapped to OCALL case below by exporter
-
-       case ir.OCALL:
+       case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG:
                pos := r.pos()
                init := r.stmtList()
                n := ir.NewCallExpr(pos, ir.OCALL, r.expr(), r.exprList())
+               if go117ExportTypes {
+                       n.SetOp(op)
+               }
                *n.PtrInit() = init
                n.IsDDD = r.bool()
+               if go117ExportTypes {
+                       n.SetType(r.exoticType())
+                       n.Use = ir.CallUse(r.uint64())
+               }
                return n
 
        case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
+               if go117ExportTypes {
+                       pos := r.pos()
+                       typ := r.typ()
+                       list := r.exprList()
+                       var len_, cap_ ir.Node
+                       if len(list) > 0 {
+                               len_ = list[0]
+                       }
+                       if len(list) > 1 {
+                               cap_ = list[1]
+                       }
+                       n := ir.NewMakeExpr(pos, op, len_, cap_)
+                       n.SetType(typ)
+                       return n
+               }
                n := builtinCall(r.pos(), ir.OMAKE)
                n.Args.Append(ir.TypeNode(r.typ()))
                n.Args.Append(r.exprList()...)
@@ -1112,21 +1320,42 @@ func (r *importReader) node() ir.Node {
 
        // unary expressions
        case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV:
-               return ir.NewUnaryExpr(r.pos(), op, r.expr())
+               n := ir.NewUnaryExpr(r.pos(), op, r.expr())
+               if go117ExportTypes {
+                       n.SetType(r.typ())
+               }
+               return n
 
-       case ir.OADDR:
-               return NodAddrAt(r.pos(), r.expr())
+       case ir.OADDR, ir.OPTRLIT:
+               n := NodAddrAt(r.pos(), r.expr())
+               if go117ExportTypes {
+                       n.SetOp(op)
+                       n.SetType(r.typ())
+               }
+               return n
 
        case ir.ODEREF:
-               return ir.NewStarExpr(r.pos(), r.expr())
+               n := ir.NewStarExpr(r.pos(), r.expr())
+               if go117ExportTypes {
+                       n.SetType(r.typ())
+               }
+               return n
 
        // binary expressions
        case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT,
                ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR:
-               return ir.NewBinaryExpr(r.pos(), op, r.expr(), r.expr())
+               n := ir.NewBinaryExpr(r.pos(), op, r.expr(), r.expr())
+               if go117ExportTypes {
+                       n.SetType(r.typ())
+               }
+               return n
 
        case ir.OANDAND, ir.OOROR:
-               return ir.NewLogicalExpr(r.pos(), op, r.expr(), r.expr())
+               n := ir.NewLogicalExpr(r.pos(), op, r.expr(), r.expr())
+               if go117ExportTypes {
+                       n.SetType(r.typ())
+               }
+               return n
 
        case ir.OSEND:
                return ir.NewSendStmt(r.pos(), r.expr(), r.expr())
@@ -1134,6 +1363,11 @@ func (r *importReader) node() ir.Node {
        case ir.OADDSTR:
                pos := r.pos()
                list := r.exprList()
+               if go117ExportTypes {
+                       n := ir.NewAddStringExpr(pos, list)
+                       n.SetType(r.typ())
+                       return n
+               }
                x := list[0]
                for _, y := range list[1:] {
                        x = ir.NewBinaryExpr(pos, ir.OADD, x, y)
@@ -1149,8 +1383,8 @@ func (r *importReader) node() ir.Node {
                stmts.Append(ir.NewAssignStmt(n.Pos(), n, nil))
                return ir.NewBlockStmt(n.Pos(), stmts)
 
-       // case OAS, OASWB:
-       //      unreachable - mapped to OAS case below by exporter
+       // case OASWB:
+       //      unreachable - never exported
 
        case ir.OAS:
                return ir.NewAssignStmt(r.pos(), r.expr(), r.expr())
@@ -1165,11 +1399,12 @@ func (r *importReader) node() ir.Node {
                }
                return n
 
-       // case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
-       //      unreachable - mapped to OAS2 case below by exporter
-
-       case ir.OAS2:
-               return ir.NewAssignListStmt(r.pos(), ir.OAS2, r.exprList(), r.exprList())
+       case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
+               if !go117ExportTypes && op != ir.OAS2 {
+                       // unreachable - mapped to case OAS2 by exporter
+                       goto error
+               }
+               return ir.NewAssignListStmt(r.pos(), op, r.exprList(), r.exprList())
 
        case ir.ORETURN:
                return ir.NewReturnStmt(r.pos(), r.exprList())
@@ -1241,6 +1476,10 @@ func (r *importReader) node() ir.Node {
                        "\t==> please file an issue and assign to gri@", op, int(op))
                panic("unreachable") // satisfy compiler
        }
+error:
+       base.Fatalf("cannot import %v (%d) node\n"+
+               "\t==> please file an issue and assign to khr@", op, int(op))
+       panic("unreachable") // satisfy compiler
 }
 
 func (r *importReader) op() ir.Op {
@@ -1253,7 +1492,11 @@ func (r *importReader) op() ir.Op {
 func (r *importReader) fieldList() []ir.Node {
        list := make([]ir.Node, r.uint64())
        for i := range list {
-               list[i] = ir.NewStructKeyExpr(r.pos(), r.selector(), r.expr())
+               x := ir.NewStructKeyExpr(r.pos(), r.selector(), r.expr())
+               if go117ExportTypes {
+                       x.Offset = int64(r.uint64())
+               }
+               list[i] = x
        }
        return list
 }
@@ -1270,5 +1513,9 @@ func (r *importReader) exprsOrNil() (a, b ir.Node) {
 }
 
 func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr {
+       if go117ExportTypes {
+               // These should all be encoded as direct ops, not OCALL.
+               base.Fatalf("builtinCall should not be invoked when types are included in inport/export")
+       }
        return ir.NewCallExpr(pos, ir.OCALL, ir.NewIdent(base.Pos, types.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
 }
index 2fc33753ed7f8c0c8ea96c78292a82a0c61da0f7..e8e1e99860f5c1ae28b273ad448b74eca6bde713 100644 (file)
@@ -93,11 +93,11 @@ func main() {
                y := func(x int) int { // ERROR "can inline main.func11" "func literal does not escape"
                        return x + 2
                }
-               y, sink = func() (func(int) int, int) { // ERROR "can inline main.func12"
-                       return func(x int) int { // ERROR "can inline main.func12"
+               y, sink = func() (func(int) int, int) { // ERROR "func literal does not escape"
+                       return func(x int) int { // ERROR "can inline main.func12" "func literal escapes"
                                return x + 1
                        }, 42
-               }() // ERROR "func literal does not escape" "inlining call to main.func12"
+               }()
                if y(40) != 41 {
                        ppanic("y(40) != 41")
                }
@@ -105,14 +105,14 @@ func main() {
 
        {
                func() { // ERROR "func literal does not escape"
-                       y := func(x int) int { // ERROR "func literal does not escape" "can inline main.func13.1"
+                       y := func(x int) int { // ERROR "can inline main.func13.1" "func literal does not escape"
                                return x + 2
                        }
-                       y, sink = func() (func(int) int, int) { // ERROR "can inline main.func13.2"
-                               return func(x int) int { // ERROR "can inline main.func13.2"
+                       y, sink = func() (func(int) int, int) { // ERROR "func literal does not escape"
+                               return func(x int) int { // ERROR "can inline main.func13.2" "func literal escapes"
                                        return x + 1
                                }, 42
-                       }() // ERROR "inlining call to main.func13.2" "func literal does not escape"
+                       }()
                        if y(40) != 41 {
                                ppanic("y(40) != 41")
                        }
@@ -187,29 +187,29 @@ func main() {
 
        {
                x := 42
-               if z := func(y int) int { // ERROR "can inline main.func22"
-                       return func() int { // ERROR "can inline main.func22.1" "can inline main.func30"
+               if z := func(y int) int { // ERROR "func literal does not escape"
+                       return func() int { // ERROR "can inline main.func22.1"
                                return x + y
                        }() // ERROR "inlining call to main.func22.1"
-               }(1); z != 43 { // ERROR "inlining call to main.func22" "inlining call to main.func30"
+               }(1); z != 43 {
                        ppanic("z != 43")
                }
-               if z := func(y int) int { // ERROR "func literal does not escape" "can inline main.func23"
-                       return func() int { // ERROR "can inline main.func23.1" "can inline main.func31"
+               if z := func(y int) int { // ERROR "func literal does not escape"
+                       return func() int { // ERROR "can inline main.func23.1"
                                return x + y
                        }() // ERROR "inlining call to main.func23.1"
-               }; z(1) != 43 { // ERROR "inlining call to main.func23" "inlining call to main.func31"
+               }; z(1) != 43 {
                        ppanic("z(1) != 43")
                }
        }
 
        {
                a := 1
-               func() { // ERROR "can inline main.func24"
-                       func() { // ERROR "can inline main.func24" "can inline main.func32"
+               func() { // ERROR "func literal does not escape"
+                       func() { // ERROR "can inline main.func24"
                                a = 2
                        }() // ERROR "inlining call to main.func24"
-               }() // ERROR "inlining call to main.func24" "inlining call to main.func32"
+               }()
                if a != 2 {
                        ppanic("a != 2")
                }
@@ -250,12 +250,12 @@ func main() {
                a := 2
                if r := func(x int) int { // ERROR "func literal does not escape"
                        b := 3
-                       return func(y int) int { // ERROR "can inline main.func27.1"
+                       return func(y int) int { // ERROR "func literal does not escape"
                                c := 5
-                               return func(z int) int { // ERROR "can inline main.func27.1.1" "can inline main.func27.2"
+                               return func(z int) int { // ERROR "can inline main.func27.1.1"
                                        return a*x + b*y + c*z
                                }(10) // ERROR "inlining call to main.func27.1.1"
-                       }(100) // ERROR "inlining call to main.func27.1" "inlining call to main.func27.2"
+                       }(100)
                }(1000); r != 2350 {
                        ppanic("r != 2350")
                }
@@ -265,15 +265,15 @@ func main() {
                a := 2
                if r := func(x int) int { // ERROR "func literal does not escape"
                        b := 3
-                       return func(y int) int { // ERROR "can inline main.func28.1"
+                       return func(y int) int { // ERROR "func literal does not escape"
                                c := 5
-                               func(z int) { // ERROR "can inline main.func28.1.1" "can inline main.func28.2"
+                               func(z int) { // ERROR "can inline main.func28.1.1"
                                        a = a * x
                                        b = b * y
                                        c = c * z
                                }(10) // ERROR "inlining call to main.func28.1.1"
                                return a + c
-                       }(100) + b // ERROR "inlining call to main.func28.1" "inlining call to main.func28.2"
+                       }(100) + b
                }(1000); r != 2350 {
                        ppanic("r != 2350")
                }
index bc23768d0161a87bd4f4ab398edda3c71362179b..b0911056caaadf5eb49b2526d4495c5321a1973c 100644 (file)
@@ -58,7 +58,7 @@ func _() int { // ERROR "can inline _"
 var somethingWrong error
 
 // local closures can be inlined
-func l(x, y int) (int, int, error) { // ERROR "can inline l"
+func l(x, y int) (int, int, error) {
        e := func(err error) (int, int, error) { // ERROR "can inline l.func1" "func literal does not escape" "leaking param: err to result"
                return 0, 0, err
        }
@@ -90,19 +90,19 @@ func n() int {
 // make sure assignment inside closure is detected
 func o() int {
        foo := func() int { return 1 } // ERROR "can inline o.func1" "func literal does not escape"
-       func(x int) {                  // ERROR "can inline o.func2"
+       func(x int) {                  // ERROR "func literal does not escape"
                if x > 10 {
-                       foo = func() int { return 2 } // ERROR "can inline o.func2"
+                       foo = func() int { return 2 } // ERROR "can inline o.func2" "func literal escapes"
                }
-       }(11) // ERROR "func literal does not escape" "inlining call to o.func2"
+       }(11)
        return foo()
 }
 
-func p() int { // ERROR "can inline p"
+func p() int {
        return func() int { return 42 }() // ERROR "can inline p.func1" "inlining call to p.func1"
 }
 
-func q(x int) int { // ERROR "can inline q"
+func q(x int) int {
        foo := func() int { return x * 2 } // ERROR "can inline q.func1" "func literal does not escape"
        return foo()                       // ERROR "inlining call to q.func1"
 }
@@ -111,15 +111,15 @@ func r(z int) int {
        foo := func(x int) int { // ERROR "can inline r.func1" "func literal does not escape"
                return x + z
        }
-       bar := func(x int) int { // ERROR "func literal does not escape" "can inline r.func2"
-               return x + func(y int) int { // ERROR "can inline r.func2.1" "can inline r.func3"
+       bar := func(x int) int { // ERROR "func literal does not escape"
+               return x + func(y int) int { // ERROR "can inline r.func2.1"
                        return 2*y + x*z
                }(x) // ERROR "inlining call to r.func2.1"
        }
-       return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "inlining call to r.func3"
+       return foo(42) + bar(42) // ERROR "inlining call to r.func1"
 }
 
-func s0(x int) int { // ERROR "can inline s0"
+func s0(x int) int {
        foo := func() { // ERROR "can inline s0.func1" "func literal does not escape"
                x = x + 1
        }
@@ -127,7 +127,7 @@ func s0(x int) int { // ERROR "can inline s0"
        return x
 }
 
-func s1(x int) int { // ERROR "can inline s1"
+func s1(x int) int {
        foo := func() int { // ERROR "can inline s1.func1" "func literal does not escape"
                return x
        }