mirror of
https://github.com/golang/go
synced 2024-11-22 19:54:39 -07:00
[dev.regabi] cmd/compile: cleanup for concrete types - import/export
An automated rewrite will add concrete type assertions after a test of n.Op(), when n can be safely type-asserted (meaning, n is not reassigned a different type, n is not reassigned and then used outside the scope of the type assertion, and so on). This sequence of CLs handles the code that the automated rewrite does not: adding specific types to function arguments, adjusting code not to call n.Left() etc when n may have multiple representations, and so on. This CL focuses on iimport.go and iexport.go. Passes buildall w/ toolstash -cmp. Change-Id: I63edee54991ae5d982e99efa7a2894478d511910 Reviewed-on: https://go-review.googlesource.com/c/go/+/277925 Trust: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
aa55d4e54b
commit
5fe64298a4
@ -15,8 +15,11 @@ type exporter struct {
|
||||
|
||||
// markObject visits a reachable object.
|
||||
func (p *exporter) markObject(n ir.Node) {
|
||||
if n.Op() == ir.ONAME && n.Class() == ir.PFUNC {
|
||||
inlFlood(n.(*ir.Name))
|
||||
if n.Op() == ir.ONAME {
|
||||
n := n.(*ir.Name)
|
||||
if n.Class() == ir.PFUNC {
|
||||
inlFlood(n)
|
||||
}
|
||||
}
|
||||
|
||||
p.markType(n.Type())
|
||||
|
@ -1,20 +0,0 @@
|
||||
// Copyright 2015 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 gc
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/src"
|
||||
)
|
||||
|
||||
func npos(pos src.XPos, n ir.Node) ir.Node {
|
||||
n.SetPos(pos)
|
||||
return n
|
||||
}
|
||||
|
||||
func builtinCall(op ir.Op) ir.Node {
|
||||
return ir.Nod(ir.OCALL, mkname(types.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
|
||||
}
|
@ -1069,7 +1069,7 @@ func (w *exportWriter) stmt(n ir.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
switch op := n.Op(); op {
|
||||
switch n.Op() {
|
||||
case ir.OBLOCK:
|
||||
// No OBLOCK in export data.
|
||||
// Inline content into this statement list,
|
||||
@ -1084,7 +1084,7 @@ func (w *exportWriter) stmt(n ir.Node) {
|
||||
case ir.ODCL:
|
||||
w.op(ir.ODCL)
|
||||
w.pos(n.Left().Pos())
|
||||
w.localName(n.Left())
|
||||
w.localName(n.Left().(*ir.Name))
|
||||
w.typ(n.Left().Type())
|
||||
|
||||
case ir.OAS:
|
||||
@ -1099,9 +1099,10 @@ func (w *exportWriter) stmt(n ir.Node) {
|
||||
}
|
||||
|
||||
case ir.OASOP:
|
||||
n := n.(*ir.AssignOpStmt)
|
||||
w.op(ir.OASOP)
|
||||
w.pos(n.Pos())
|
||||
w.op(n.SubOp())
|
||||
w.op(n.AsOp)
|
||||
w.expr(n.Left())
|
||||
if w.bool(!n.Implicit()) {
|
||||
w.expr(n.Right())
|
||||
@ -1122,7 +1123,7 @@ func (w *exportWriter) stmt(n ir.Node) {
|
||||
// unreachable - generated by compiler for trampolin routines
|
||||
|
||||
case ir.OGO, ir.ODEFER:
|
||||
w.op(op)
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
w.expr(n.Left())
|
||||
|
||||
@ -1148,8 +1149,15 @@ func (w *exportWriter) stmt(n ir.Node) {
|
||||
w.expr(n.Right())
|
||||
w.stmtList(n.Body())
|
||||
|
||||
case ir.OSELECT, ir.OSWITCH:
|
||||
w.op(op)
|
||||
case ir.OSELECT:
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
w.stmtList(n.Init())
|
||||
w.exprsOrNil(nil, nil) // TODO(rsc): Delete (and fix importer).
|
||||
w.caseList(n)
|
||||
|
||||
case ir.OSWITCH:
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
w.stmtList(n.Init())
|
||||
w.exprsOrNil(n.Left(), nil)
|
||||
@ -1163,7 +1171,7 @@ func (w *exportWriter) stmt(n ir.Node) {
|
||||
w.pos(n.Pos())
|
||||
|
||||
case ir.OBREAK, ir.OCONTINUE, ir.OGOTO, ir.OLABEL:
|
||||
w.op(op)
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
label := ""
|
||||
if sym := n.Sym(); sym != nil {
|
||||
@ -1176,19 +1184,34 @@ func (w *exportWriter) stmt(n ir.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *exportWriter) caseList(sw ir.Node) {
|
||||
namedTypeSwitch := sw.Op() == ir.OSWITCH && sw.Left() != nil && sw.Left().Op() == ir.OTYPESW && sw.Left().Left() != nil
|
||||
func isNamedTypeSwitch(n ir.Node) bool {
|
||||
if n.Op() != ir.OSWITCH {
|
||||
return false
|
||||
}
|
||||
sw := n.(*ir.SwitchStmt)
|
||||
if sw.Left() == nil || sw.Left().Op() != ir.OTYPESW {
|
||||
return false
|
||||
}
|
||||
guard := sw.Left().(*ir.TypeSwitchGuard)
|
||||
return guard.Left() != nil
|
||||
}
|
||||
|
||||
cases := sw.List().Slice()
|
||||
func (w *exportWriter) caseList(sw ir.Node) {
|
||||
namedTypeSwitch := isNamedTypeSwitch(sw)
|
||||
|
||||
var cases []ir.Node
|
||||
if sw.Op() == ir.OSWITCH {
|
||||
cases = sw.(*ir.SwitchStmt).List().Slice()
|
||||
} else {
|
||||
cases = sw.(*ir.SelectStmt).List().Slice()
|
||||
}
|
||||
w.uint64(uint64(len(cases)))
|
||||
for _, cas := range cases {
|
||||
if cas.Op() != ir.OCASE {
|
||||
base.Fatalf("expected OCASE, got %v", cas)
|
||||
}
|
||||
cas := cas.(*ir.CaseStmt)
|
||||
w.pos(cas.Pos())
|
||||
w.stmtList(cas.List())
|
||||
if namedTypeSwitch {
|
||||
w.localName(cas.Rlist().First())
|
||||
w.localName(cas.Rlist().First().(*ir.Name))
|
||||
}
|
||||
w.stmtList(cas.Body())
|
||||
}
|
||||
@ -1201,22 +1224,29 @@ func (w *exportWriter) exprList(list ir.Nodes) {
|
||||
w.op(ir.OEND)
|
||||
}
|
||||
|
||||
func (w *exportWriter) expr(n ir.Node) {
|
||||
// from nodefmt (fmt.go)
|
||||
//
|
||||
// nodefmt reverts nodes back to their original - we don't need to do
|
||||
// it because we are not bound to produce valid Go syntax when exporting
|
||||
//
|
||||
// if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil {
|
||||
// n = n.Orig
|
||||
// }
|
||||
|
||||
// from exprfmt (fmt.go)
|
||||
for n.Op() == ir.OPAREN || n.Implicit() && (n.Op() == ir.ODEREF || n.Op() == ir.OADDR || n.Op() == ir.ODOT || n.Op() == ir.ODOTPTR) {
|
||||
n = n.Left()
|
||||
func simplifyForExport(n ir.Node) ir.Node {
|
||||
switch n.Op() {
|
||||
case ir.OPAREN:
|
||||
return simplifyForExport(n.Left())
|
||||
case ir.ODEREF:
|
||||
if n.Implicit() {
|
||||
return simplifyForExport(n.Left())
|
||||
}
|
||||
case ir.OADDR:
|
||||
if n.Implicit() {
|
||||
return simplifyForExport(n.Left())
|
||||
}
|
||||
case ir.ODOT, ir.ODOTPTR:
|
||||
if n.Implicit() {
|
||||
return simplifyForExport(n.Left())
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
switch op := n.Op(); op {
|
||||
func (w *exportWriter) expr(n ir.Node) {
|
||||
n = simplifyForExport(n)
|
||||
switch n.Op() {
|
||||
// expressions
|
||||
// (somewhat closely following the structure of exprfmt in fmt.go)
|
||||
case ir.ONIL:
|
||||
@ -1243,6 +1273,7 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
|
||||
case ir.ONAME:
|
||||
// Package scope name.
|
||||
n := n.(*ir.Name)
|
||||
if (n.Class() == ir.PEXTERN || n.Class() == ir.PFUNC) && !ir.IsBlank(n) {
|
||||
w.op(ir.ONONAME)
|
||||
w.qualifiedIdent(n)
|
||||
@ -1291,7 +1322,7 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
w.op(ir.OSTRUCTLIT)
|
||||
w.pos(n.Pos())
|
||||
w.typ(n.Type())
|
||||
w.elemList(n.List()) // special handling of field names
|
||||
w.fieldList(n.List()) // special handling of field names
|
||||
|
||||
case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
|
||||
w.op(ir.OCOMPLIT)
|
||||
@ -1349,7 +1380,7 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
|
||||
case ir.OCOPY, ir.OCOMPLEX:
|
||||
// treated like other builtin calls (see e.g., OREAL)
|
||||
w.op(op)
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
w.expr(n.Left())
|
||||
w.expr(n.Right())
|
||||
@ -1361,20 +1392,21 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
w.expr(n.Left())
|
||||
w.typ(n.Type())
|
||||
|
||||
case 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:
|
||||
w.op(op)
|
||||
case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
if n.Left() != nil {
|
||||
w.expr(n.Left())
|
||||
w.op(ir.OEND)
|
||||
} else {
|
||||
w.exprList(n.List()) // emits terminating OEND
|
||||
}
|
||||
w.expr(n.Left())
|
||||
w.op(ir.OEND)
|
||||
|
||||
case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
w.exprList(n.List()) // emits terminating OEND
|
||||
// only append() calls may contain '...' arguments
|
||||
if op == ir.OAPPEND {
|
||||
if n.Op() == ir.OAPPEND {
|
||||
w.bool(n.IsDDD())
|
||||
} else if n.IsDDD() {
|
||||
base.Fatalf("exporter: unexpected '...' with %v call", op)
|
||||
base.Fatalf("exporter: unexpected '...' with %v call", n.Op())
|
||||
}
|
||||
|
||||
case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG:
|
||||
@ -1386,15 +1418,13 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
w.bool(n.IsDDD())
|
||||
|
||||
case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
|
||||
w.op(op) // must keep separate from OMAKE for importer
|
||||
w.op(n.Op()) // must keep separate from OMAKE for importer
|
||||
w.pos(n.Pos())
|
||||
w.typ(n.Type())
|
||||
switch {
|
||||
default:
|
||||
// empty list
|
||||
w.op(ir.OEND)
|
||||
case n.List().Len() != 0: // pre-typecheck
|
||||
w.exprList(n.List()) // emits terminating OEND
|
||||
case n.Right() != nil:
|
||||
w.expr(n.Left())
|
||||
w.expr(n.Right())
|
||||
@ -1405,15 +1435,37 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
}
|
||||
|
||||
// unary expressions
|
||||
case ir.OPLUS, ir.ONEG, ir.OADDR, ir.OBITNOT, ir.ODEREF, ir.ONOT, ir.ORECV:
|
||||
w.op(op)
|
||||
case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV:
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
w.expr(n.Left())
|
||||
|
||||
case ir.OADDR:
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
w.expr(n.Left())
|
||||
|
||||
case ir.ODEREF:
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
w.expr(n.Left())
|
||||
|
||||
case ir.OSEND:
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
w.expr(n.Left())
|
||||
w.expr(n.Right())
|
||||
|
||||
// binary expressions
|
||||
case ir.OADD, ir.OAND, ir.OANDAND, 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.OOROR, ir.ORSH, ir.OSEND, ir.OSUB, ir.OXOR:
|
||||
w.op(op)
|
||||
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:
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
w.expr(n.Left())
|
||||
w.expr(n.Right())
|
||||
|
||||
case ir.OANDAND, ir.OOROR:
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
w.expr(n.Left())
|
||||
w.expr(n.Right())
|
||||
@ -1454,15 +1506,16 @@ func (w *exportWriter) exprsOrNil(a, b ir.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *exportWriter) elemList(list ir.Nodes) {
|
||||
func (w *exportWriter) fieldList(list ir.Nodes) {
|
||||
w.uint64(uint64(list.Len()))
|
||||
for _, n := range list.Slice() {
|
||||
n := n.(*ir.StructKeyExpr)
|
||||
w.selector(n.Sym())
|
||||
w.expr(n.Left())
|
||||
}
|
||||
}
|
||||
|
||||
func (w *exportWriter) localName(n ir.Node) {
|
||||
func (w *exportWriter) localName(n *ir.Name) {
|
||||
// Escape analysis happens after inline bodies are saved, but
|
||||
// we're using the same ONAME nodes, so we might still see
|
||||
// PAUTOHEAP here.
|
||||
|
@ -753,7 +753,7 @@ func (r *importReader) stmtList() []ir.Node {
|
||||
}
|
||||
|
||||
func (r *importReader) caseList(sw ir.Node) []ir.Node {
|
||||
namedTypeSwitch := sw.Op() == ir.OSWITCH && sw.Left() != nil && sw.Left().Op() == ir.OTYPESW && sw.Left().Left() != nil
|
||||
namedTypeSwitch := isNamedTypeSwitch(sw)
|
||||
|
||||
cases := make([]ir.Node, r.uint64())
|
||||
for i := range cases {
|
||||
@ -766,7 +766,7 @@ func (r *importReader) caseList(sw ir.Node) []ir.Node {
|
||||
caseVar := ir.NewNameAt(cas.Pos(), r.ident())
|
||||
declare(caseVar, dclcontext)
|
||||
cas.PtrRlist().Set1(caseVar)
|
||||
caseVar.Defn = sw.Left()
|
||||
caseVar.Defn = sw.(*ir.SwitchStmt).Left()
|
||||
}
|
||||
cas.PtrBody().Set(r.stmtList())
|
||||
cases[i] = cas
|
||||
@ -915,14 +915,14 @@ func (r *importReader) node() ir.Node {
|
||||
return n
|
||||
|
||||
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:
|
||||
n := npos(r.pos(), builtinCall(op))
|
||||
n := builtinCall(r.pos(), op)
|
||||
n.PtrList().Set(r.exprList())
|
||||
if op == ir.OAPPEND {
|
||||
n.SetIsDDD(r.bool())
|
||||
}
|
||||
return n
|
||||
|
||||
// case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
|
||||
// case OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
|
||||
// unreachable - mapped to OCALL case below by exporter
|
||||
|
||||
case ir.OCALL:
|
||||
@ -934,7 +934,7 @@ func (r *importReader) node() ir.Node {
|
||||
return n
|
||||
|
||||
case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
|
||||
n := npos(r.pos(), builtinCall(ir.OMAKE))
|
||||
n := builtinCall(r.pos(), ir.OMAKE)
|
||||
n.PtrList().Append(ir.TypeNode(r.typ()))
|
||||
n.PtrList().Append(r.exprList()...)
|
||||
return n
|
||||
@ -1042,8 +1042,7 @@ func (r *importReader) node() ir.Node {
|
||||
case ir.OSELECT:
|
||||
n := ir.NodAt(r.pos(), ir.OSELECT, nil, nil)
|
||||
n.PtrInit().Set(r.stmtList())
|
||||
left, _ := r.exprsOrNil()
|
||||
n.SetLeft(left)
|
||||
r.exprsOrNil() // TODO(rsc): Delete (and fix exporter). These are always nil.
|
||||
n.PtrList().Set(r.caseList(n))
|
||||
return n
|
||||
|
||||
@ -1110,3 +1109,12 @@ func (r *importReader) exprsOrNil() (a, b ir.Node) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr {
|
||||
return ir.NewCallExpr(pos, ir.OCALL, mkname(types.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
|
||||
}
|
||||
|
||||
func npos(pos src.XPos, n ir.Node) ir.Node {
|
||||
n.SetPos(pos)
|
||||
return n
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user