[dev.typeparams] cmd/compile: implement generic type switches

Add a new dynamicType node, which is used as a case entry when
the type being switched to is generic.

Change-Id: Ice77c6f224b8fdd3ff574fdf4a8ea5f6c7ddbe75
Reviewed-on: https://go-review.googlesource.com/c/go/+/339429
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
This commit is contained in:
Keith Randall 2021-08-03 08:10:17 -07:00
parent 57668b84ff
commit ca3c6985cd
21 changed files with 342 additions and 18 deletions

View file

@ -360,10 +360,10 @@ func walkSwitchType(sw *ir.SwitchStmt) {
}
if singleType != nil && singleType.IsInterface() {
s.Add(ncase.Pos(), n1.Type(), caseVar, jmp)
s.Add(ncase.Pos(), n1, caseVar, jmp)
caseVarInitialized = true
} else {
s.Add(ncase.Pos(), n1.Type(), nil, jmp)
s.Add(ncase.Pos(), n1, nil, jmp)
}
}
@ -377,6 +377,17 @@ func walkSwitchType(sw *ir.SwitchStmt) {
}
val = ifaceData(ncase.Pos(), s.facename, singleType)
}
if len(ncase.List) == 1 && ncase.List[0].Op() == ir.ODYNAMICTYPE {
dt := ncase.List[0].(*ir.DynamicType)
x := ir.NewDynamicTypeAssertExpr(ncase.Pos(), ir.ODYNAMICDOTTYPE, val, dt.X)
if dt.ITab != nil {
// TODO: make ITab a separate field in DynamicTypeAssertExpr?
x.T = dt.ITab
}
x.SetType(caseVar.Type())
x.SetTypecheck(1)
val = x
}
l := []ir.Node{
ir.NewDecl(ncase.Pos(), ir.ODCL, caseVar),
ir.NewAssignStmt(ncase.Pos(), caseVar, val),
@ -446,7 +457,8 @@ type typeClause struct {
body ir.Nodes
}
func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar *ir.Name, jmp ir.Node) {
func (s *typeSwitch) Add(pos src.XPos, n1 ir.Node, caseVar *ir.Name, jmp ir.Node) {
typ := n1.Type()
var body ir.Nodes
if caseVar != nil {
l := []ir.Node{
@ -462,9 +474,25 @@ func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar *ir.Name, jmp ir
// cv, ok = iface.(type)
as := ir.NewAssignListStmt(pos, ir.OAS2, nil, nil)
as.Lhs = []ir.Node{caseVar, s.okname} // cv, ok =
dot := ir.NewTypeAssertExpr(pos, s.facename, nil)
dot.SetType(typ) // iface.(type)
as.Rhs = []ir.Node{dot}
switch n1.Op() {
case ir.OTYPE:
// Static type assertion (non-generic)
dot := ir.NewTypeAssertExpr(pos, s.facename, nil)
dot.SetType(typ) // iface.(type)
as.Rhs = []ir.Node{dot}
case ir.ODYNAMICTYPE:
// Dynamic type assertion (generic)
dt := n1.(*ir.DynamicType)
dot := ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, s.facename, dt.X)
if dt.ITab != nil {
dot.T = dt.ITab
}
dot.SetType(typ)
dot.SetTypecheck(1)
as.Rhs = []ir.Node{dot}
default:
base.Fatalf("unhandled type case %s", n1.Op())
}
appendWalkStmt(&body, as)
// if ok { goto label }
@ -473,9 +501,10 @@ func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar *ir.Name, jmp ir
nif.Body = []ir.Node{jmp}
body.Append(nif)
if !typ.IsInterface() {
if n1.Op() == ir.OTYPE && !typ.IsInterface() {
// Defer static, noninterface cases so they can be binary searched by hash.
s.clauses = append(s.clauses, typeClause{
hash: types.TypeHash(typ),
hash: types.TypeHash(n1.Type()),
body: body,
})
return