diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go index 213ef7832d..6bebe5422f 100644 --- a/src/cmd/compile/internal/escape/escape.go +++ b/src/cmd/compile/internal/escape/escape.go @@ -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 diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 1941dc44bc..4470df1d2a 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -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 { diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index bc31284a85..eaae2a81fa 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -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 } diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 43cc4e4a25..8f8931e495 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -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 diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 35a1a0083a..0d5d892ef5 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -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.ODOTTYPE: - n := ir.NewTypeAssertExpr(r.pos(), r.expr(), nil) - n.SetType(r.typ()) + 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 OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR: - // unreachable - mapped to cases below by exporter + 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 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) + n := ir.NewSliceExpr(pos, op, x, low, high, max) + if go117ExportTypes { + n.SetType(r.typ()) + } + return n - // case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR: - // unreachable - mapped to OCONV case below by exporter - - 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) } diff --git a/test/closure3.dir/main.go b/test/closure3.dir/main.go index 2fc33753ed..e8e1e99860 100644 --- a/test/closure3.dir/main.go +++ b/test/closure3.dir/main.go @@ -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") } diff --git a/test/inline.go b/test/inline.go index bc23768d01..b0911056ca 100644 --- a/test/inline.go +++ b/test/inline.go @@ -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 }