1
0
mirror of https://github.com/golang/go synced 2024-11-22 14:44:50 -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:
Russ Cox 2020-12-10 18:46:29 -05:00
parent aa55d4e54b
commit 5fe64298a4
4 changed files with 123 additions and 79 deletions

View File

@ -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())

View File

@ -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)
}

View File

@ -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.

View File

@ -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
}