pkg/compiler: fix infinite recursion in template instantiation

Currently we replace a template argument and then recurse
into the new type AST to see if there is more to replace.
If the description is buggy and the template argument
contains itself, then we will recurse infintiely trying
to replace it more and more.
Use post-order traversal when replacing template argument to fix this.
diff --git a/pkg/ast/walk.go b/pkg/ast/walk.go
index fe91125..1ec3a8f 100644
--- a/pkg/ast/walk.go
+++ b/pkg/ast/walk.go
@@ -4,7 +4,7 @@
 package ast
 
 // Walk calls callback cb for every top-level node in description.
-// Note: it's not recursive. Use Recursive helper for recursive walk.
+// Note: it's not recursive. Use Recursive/PostRecursive helpers for recursive walk.
 func (desc *Description) Walk(cb func(Node)) {
 	for _, n := range desc.Nodes {
 		cb(n)
@@ -20,6 +20,15 @@
 	return rec
 }
 
+func PostRecursive(cb func(Node)) func(Node) {
+	var rec func(Node)
+	rec = func(n Node) {
+		n.Walk(rec)
+		cb(n)
+	}
+	return rec
+}
+
 func (n *NewLine) Walk(cb func(Node)) {}
 func (n *Comment) Walk(cb func(Node)) {}
 func (n *Ident) Walk(cb func(Node))   {}
diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go
index eb57228..adf6f4e 100644
--- a/pkg/compiler/check.go
+++ b/pkg/compiler/check.go
@@ -942,7 +942,7 @@
 	}
 	argUsed := make(map[string]bool)
 	err0 := comp.errors
-	templ.Walk(ast.Recursive(func(n ast.Node) {
+	templ.Walk(ast.PostRecursive(func(n ast.Node) {
 		templArg, ok := n.(*ast.Type)
 		if !ok {
 			return
diff --git a/pkg/compiler/compiler_test.go b/pkg/compiler/compiler_test.go
index 8f10ac5..4ea5b27 100644
--- a/pkg/compiler/compiler_test.go
+++ b/pkg/compiler/compiler_test.go
@@ -201,6 +201,11 @@
 type D[e]l`,
 		"E",
 		"#",
+		`
+type p b[L]
+type b[L] {
+	e b[L[L]]
+}`,
 	} {
 		Fuzz([]byte(data)[:len(data):len(data)])
 	}