Answer stability round 1: a method is keyed by its receiver, and panicsOnOtherNodeKinds names what it checks

This commit is contained in:
2026-10-09 11:56:02 +02:00
committed by Lillem4n
parent ae5a4e5a6c
commit 5945a32bc3
+16 -12
View File
@@ -64,11 +64,11 @@ func (*unhandledNode) isNode() {}
// nodeSwitchSkips is the kinds a switch is never handed: its callers step past them first. // nodeSwitchSkips is the kinds a switch is never handed: its callers step past them first.
var nodeSwitchSkips = map[string][]string{ var nodeSwitchSkips = map[string][]string{
"childNamed": {"choice", "table", "tableRow"}, "childNamed": {"choice", "table", "tableRow"},
"columnItems": {"folder", "table", "tableRow"}, "columnItems": {"folder", "table", "tableRow"},
"prove": {"folder"}, "render": {"folder"},
"render": {"folder"}, "routeSteps": {"choice", "folder", "nullItem", "template"},
"routeSteps": {"choice", "folder", "nullItem", "template"}, "valueProof.prove": {"folder"},
} }
func TestNodeSwitchesHandleEveryKind(t *testing.T) { func TestNodeSwitchesHandleEveryKind(t *testing.T) {
@@ -103,13 +103,13 @@ func TestNodeSwitchesHandleEveryKind(t *testing.T) {
"columnItems": func(n node) { columnItems(n) }, "columnItems": func(n node) { columnItems(n) },
"contained": func(n node) { contained(n) }, "contained": func(n node) { contained(n) },
"paths": func(n node) { paths(n, false) }, "paths": func(n node) { paths(n, false) },
"prove": func(n node) { (&valueProof{}).prove(n) },
"render": func(n node) { "render": func(n node) {
var frames frameStack var frames frameStack
render(engine(1).drawState, n, renderEnv{frames: &frames, row: renderedRow{tbl, 0}}) render(engine(1).drawState, n, renderEnv{frames: &frames, row: renderedRow{tbl, 0}})
}, },
"renderEdges": func(n node) { renderEdges(n) }, "renderEdges": func(n node) { renderEdges(n) },
"routeSteps": func(n node) { _, _ = routeSteps(nil, nil, tbl, tableRoute{next: n}, 0) }, "routeSteps": func(n node) { _, _ = routeSteps(nil, nil, tbl, tableRoute{next: n}, 0) },
"valueProof.prove": func(n node) { (&valueProof{}).prove(n) },
} }
found := exhaustiveNodeSwitches(t, kinds) found := exhaustiveNodeSwitches(t, kinds)
listed := make([]string, 0, len(switches)) listed := make([]string, 0, len(switches))
@@ -161,7 +161,7 @@ func nodeKinds(t *testing.T) []string {
} }
// exhaustiveNodeSwitches names each function holding a type switch that has a case for a // exhaustiveNodeSwitches names each function holding a type switch that has a case for a
// node kind and a default that panics. // node kind and a default that panics, a method as recv.name.
func exhaustiveNodeSwitches(t *testing.T, kinds []string) []string { func exhaustiveNodeSwitches(t *testing.T, kinds []string) []string {
t.Helper() t.Helper()
var names []string var names []string
@@ -172,9 +172,13 @@ func exhaustiveNodeSwitches(t *testing.T, kinds []string) []string {
if !isFunc || d.Body == nil { if !isFunc || d.Body == nil {
continue continue
} }
name := d.Name.Name
if recv := receiverType(d.Recv); recv != "" {
name = recv + "." + name
}
ast.Inspect(d.Body, func(n ast.Node) bool { ast.Inspect(d.Body, func(n ast.Node) bool {
if sw, isTypeSwitch := n.(*ast.TypeSwitchStmt); isTypeSwitch && switchesOverNode(sw, kinds) { if sw, isTypeSwitch := n.(*ast.TypeSwitchStmt); isTypeSwitch && panicsOnOtherNodeKinds(sw, kinds) {
names = append(names, d.Name.Name) names = append(names, name)
} }
return true return true
}) })
@@ -184,7 +188,7 @@ func exhaustiveNodeSwitches(t *testing.T, kinds []string) []string {
return slices.Compact(names) return slices.Compact(names)
} }
func switchesOverNode(sw *ast.TypeSwitchStmt, kinds []string) bool { func panicsOnOtherNodeKinds(sw *ast.TypeSwitchStmt, kinds []string) bool {
casesNode, panics := false, false casesNode, panics := false, false
for _, stmt := range sw.Body.List { for _, stmt := range sw.Body.List {
clause := stmt.(*ast.CaseClause) clause := stmt.(*ast.CaseClause)