Skip to content

Commit

Permalink
cmd/compile: clean up the switch statements in (*genInst).node()
Browse files Browse the repository at this point in the history
There were two main outer switch statements in node() that can just be
combined. Also, for simplicity, changed an IsCmp() conditional into just
another case in the switch statement.

Also, the inner OCALL switch statement had a bunch of fairly duplicate
cases. Combined the cases that all had no special semantics, into a
single default case calling transformCall().

In the OCALL case in dictPass(), got rid of a check for OFUNCINST (which
will always have been removed by this point). Also, eliminated an assert
that could cause unneded failures. transformCall() should always be
called if the node op is still OCALL, so no need to assert on the ops of
call.X.

Added an extra test in issue47078.go, to explicitly check for case where
the X argument of a call is a DOTTYPE.

Change-Id: Ifb3f812ce12820a4ce08afe2887f00f7fc00cd2f
Reviewed-on: https://go-review.googlesource.com/c/go/+/358596
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
  • Loading branch information
danscales committed Oct 26, 2021
1 parent 1dc77a3 commit b54bdd2
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 86 deletions.
161 changes: 75 additions & 86 deletions src/cmd/compile/internal/noder/stencil.go
Expand Up @@ -928,8 +928,9 @@ func getDictionaryType(info *instInfo, dictParam *ir.Name, pos src.XPos, i int)
}

// node is like DeepCopy(), but substitutes ONAME nodes based on subst.ts.vars, and
// also descends into closures. It substitutes type arguments for type parameters
// in all the new nodes.
// also descends into closures. It substitutes type arguments for type parameters in
// all the new nodes and does the transformations that were delayed on the generic
// function.
func (subst *subster) node(n ir.Node) ir.Node {
// Use closure to capture all state needed by the ir.EditChildren argument.
var edit func(ir.Node) ir.Node
Expand Down Expand Up @@ -973,15 +974,15 @@ func (subst *subster) node(n ir.Node) ir.Node {
if _, isExpr := m.(ir.Expr); isExpr {
t := x.Type()
if t == nil {
// t can be nil only if this is a call that has no
// return values, so allow that and otherwise give
// an error.
// Check for known cases where t can be nil (call
// that has no return values, and key expressions)
// and otherwise cause a fatal error.
_, isCallExpr := m.(*ir.CallExpr)
_, isStructKeyExpr := m.(*ir.StructKeyExpr)
_, isKeyExpr := m.(*ir.KeyExpr)
if !isCallExpr && !isStructKeyExpr && !isKeyExpr && x.Op() != ir.OPANIC &&
x.Op() != ir.OCLOSE {
base.Fatalf(fmt.Sprintf("Nil type for %v", x))
base.FatalfAt(m.Pos(), "Nil type for %v", x)
}
} else if x.Op() != ir.OCLOSURE {
m.SetType(subst.ts.Typ(x.Type()))
Expand All @@ -991,56 +992,55 @@ func (subst *subster) node(n ir.Node) ir.Node {
ir.EditChildren(m, edit)

m.SetTypecheck(1)
if x.Op().IsCmp() {

// Do the transformations that we delayed on the generic function
// node, now that we have substituted in the type args.
switch x.Op() {
case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
transformCompare(m.(*ir.BinaryExpr))
} else {
switch x.Op() {
case ir.OSLICE, ir.OSLICE3:
transformSlice(m.(*ir.SliceExpr))

case ir.OADD:
m = transformAdd(m.(*ir.BinaryExpr))

case ir.OINDEX:
transformIndex(m.(*ir.IndexExpr))

case ir.OAS2:
as2 := m.(*ir.AssignListStmt)
transformAssign(as2, as2.Lhs, as2.Rhs)

case ir.OAS:
as := m.(*ir.AssignStmt)
if as.Y != nil {
// transformAssign doesn't handle the case
// of zeroing assignment of a dcl (rhs[0] is nil).
lhs, rhs := []ir.Node{as.X}, []ir.Node{as.Y}
transformAssign(as, lhs, rhs)
as.X, as.Y = lhs[0], rhs[0]
}

case ir.OASOP:
as := m.(*ir.AssignOpStmt)
transformCheckAssign(as, as.X)
case ir.OSLICE, ir.OSLICE3:
transformSlice(m.(*ir.SliceExpr))

case ir.ORETURN:
transformReturn(m.(*ir.ReturnStmt))
case ir.OADD:
m = transformAdd(m.(*ir.BinaryExpr))

case ir.OSEND:
transformSend(m.(*ir.SendStmt))
case ir.OINDEX:
transformIndex(m.(*ir.IndexExpr))

case ir.OSELECT:
transformSelect(m.(*ir.SelectStmt))
case ir.OAS2:
as2 := m.(*ir.AssignListStmt)
transformAssign(as2, as2.Lhs, as2.Rhs)

case ir.OCOMPLIT:
transformCompLit(m.(*ir.CompLitExpr))
case ir.OAS:
as := m.(*ir.AssignStmt)
if as.Y != nil {
// transformAssign doesn't handle the case
// of zeroing assignment of a dcl (rhs[0] is nil).
lhs, rhs := []ir.Node{as.X}, []ir.Node{as.Y}
transformAssign(as, lhs, rhs)
as.X, as.Y = lhs[0], rhs[0]
}

case ir.OADDR:
transformAddr(m.(*ir.AddrExpr))
case ir.OASOP:
as := m.(*ir.AssignOpStmt)
transformCheckAssign(as, as.X)

}
}
case ir.ORETURN:
transformReturn(m.(*ir.ReturnStmt))

case ir.OSEND:
transformSend(m.(*ir.SendStmt))

case ir.OSELECT:
transformSelect(m.(*ir.SelectStmt))

case ir.OCOMPLIT:
transformCompLit(m.(*ir.CompLitExpr))

case ir.OADDR:
transformAddr(m.(*ir.AddrExpr))

switch x.Op() {
case ir.OLITERAL:
t := m.Type()
if t != x.Type() {
Expand All @@ -1058,16 +1058,13 @@ func (subst *subster) node(n ir.Node) ir.Node {
}

case ir.OXDOT:
// A method value/call via a type param will have been
// left as an OXDOT. When we see this during stenciling,
// finish the transformation, now that we have the
// instantiated receiver type. We need to do this now,
// since the access/selection to the method for the real
// type is very different from the selection for the type
// param. m will be transformed to an OMETHVALUE node. It
// will be transformed to an ODOTMETH or ODOTINTER node if
// we find in the OCALL case below that the method value
// is actually called.
// Finish the transformation of an OXDOT, unless this was a
// bound call (a direct call on a type param). A bound call
// will be transformed during the dictPass. Otherwise, m
// will be transformed to an OMETHVALUE node. It will be
// transformed to an ODOTMETH or ODOTINTER node if we find in
// the OCALL case below that the method value is actually
// called.
mse := m.(*ir.SelectorExpr)
if src := mse.X.Type(); !src.IsShape() {
transformDot(mse, false)
Expand All @@ -1080,7 +1077,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
// Transform the conversion, now that we know the
// type argument.
m = transformConvCall(call)
// CONVIFACE transformation was already done in node2
// CONVIFACE transformation was already done in noder2
assert(m.Op() != ir.OCONVIFACE)

case ir.OMETHVALUE, ir.OMETHEXPR:
Expand Down Expand Up @@ -1116,34 +1113,29 @@ func (subst *subster) node(n ir.Node) ir.Node {
transformCall(call)
}

case ir.OCLOSURE:
transformCall(call)

case ir.ODEREF, ir.OINDEX, ir.OINDEXMAP, ir.ORECV:
// Transform a call that was delayed because of the
// use of typeparam inside an expression that required
// a pointer dereference, array indexing, map indexing,
// or channel receive to compute function value.
transformCall(call)

case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
transformCall(call)

case ir.OCONVNOP:
transformCall(call)

case ir.OFUNCINST:
// A call with an OFUNCINST will get transformed
// in stencil() once we have created & attached the
// instantiation to be called.
// We must transform the arguments of the call now, though,
// so that any needed CONVIFACE nodes are exposed,
// so the dictionary format is correct
// so the dictionary format is correct.
transformEarlyCall(call)

case ir.OXDOT, ir.ODOTTYPE, ir.ODOTTYPE2:
case ir.OXDOT:
// This is the case of a bound call on a typeparam,
// which will be handled in the dictPass.

case ir.ODOTTYPE, ir.ODOTTYPE2:
// These are DOTTYPEs that could get transformed into
// ODYNAMIC DOTTYPEs by the dict pass.

default:
base.FatalfAt(call.Pos(), fmt.Sprintf("Unexpected op with CALL during stenciling: %v", call.X.Op()))
// Transform a call for all other values of
// call.X.Op() that don't require any special
// handling.
transformCall(call)

}

case ir.OCLOSURE:
Expand Down Expand Up @@ -1268,16 +1260,13 @@ func (g *genInst) dictPass(info *instInfo) {
}
case ir.OCALL:
op := m.(*ir.CallExpr).X.Op()
if op != ir.OFUNCINST {
assert(op == ir.OMETHVALUE || op == ir.OCLOSURE || op == ir.ODYNAMICDOTTYPE || op == ir.ODYNAMICDOTTYPE2)
if op == ir.OMETHVALUE {
// Redo the transformation of OXDOT, now that we
// know the method value is being called.
m.(*ir.CallExpr).X.(*ir.SelectorExpr).SetOp(ir.OXDOT)
transformDot(m.(*ir.CallExpr).X.(*ir.SelectorExpr), true)
}
transformCall(m.(*ir.CallExpr))
if op == ir.OMETHVALUE {
// Redo the transformation of OXDOT, now that we
// know the method value is being called.
m.(*ir.CallExpr).X.(*ir.SelectorExpr).SetOp(ir.OXDOT)
transformDot(m.(*ir.CallExpr).X.(*ir.SelectorExpr), true)
}
transformCall(m.(*ir.CallExpr))

case ir.OCONVIFACE:
if m.Type().IsEmptyInterface() && m.(*ir.ConvExpr).X.Type().IsEmptyInterface() {
Expand Down
10 changes: 10 additions & 0 deletions test/typeparam/issue47878.go
Expand Up @@ -31,6 +31,13 @@ func (s Src4[T]) Next() {
_ = (<-s)()
}

type Src5[T any] func() Src5[T]

func (s Src5[T]) Next() {
var x interface{} = s
_ = (x.(Src5[T]))()
}

func main() {
var src1 Src1[int]
src1.Next()
Expand All @@ -43,4 +50,7 @@ func main() {

var src4 Src4[int]
src4.Next()

var src5 Src5[int]
src5.Next()
}

0 comments on commit b54bdd2

Please sign in to comment.