Improve tests/comments, to prepare for calling functions before definition

Bug: skia:12137
Change-Id: I609dd2578bf39a30e036ea85281886f8c4554579
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/431038
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni
index acd3e30..cd107b5 100644
--- a/gn/sksl_tests.gni
+++ b/gn/sksl_tests.gni
@@ -529,6 +529,7 @@
   "/sksl/runtime_errors/IllegalArrayOps.rts",
   "/sksl/runtime_errors/IllegalIndexing.rts",
   "/sksl/runtime_errors/IllegalOperators.rts",
+  "/sksl/runtime_errors/IllegalRecursion.rts",
   "/sksl/runtime_errors/IllegalShaderUse.rts",
   "/sksl/runtime_errors/IllegalStatements.rts",
   "/sksl/runtime_errors/InvalidBlendMain.rtb",
diff --git a/resources/sksl/runtime_errors/IllegalRecursion.rts b/resources/sksl/runtime_errors/IllegalRecursion.rts
new file mode 100644
index 0000000..ba14cf8
--- /dev/null
+++ b/resources/sksl/runtime_errors/IllegalRecursion.rts
@@ -0,0 +1,14 @@
+// Expect 3 errors
+
+// TODO(skia:12137) Today, we detect these as errors because we do not allow calls to undefined
+// functions. That produces three errors (one for each function calling an undefined function).
+// After we support calling declared (but not defined) functions, we should instead emit one
+// error per cycle.
+
+// Simple recursion is not allowed, even with branching:
+int fibonacci(int n) { return n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2); }
+
+// We also detect more complex cycles in the call-graph of functions:
+bool is_even(int n);
+bool is_odd (int n) { return n == 0 ? false : is_even(n - 1); }
+bool is_even(int n) { return n == 0 ? true  : is_odd (n - 1); }
diff --git a/tests/SkSLInterpreterTest.cpp b/tests/SkSLInterpreterTest.cpp
index 3e60b2c..2a17909 100644
--- a/tests/SkSLInterpreterTest.cpp
+++ b/tests/SkSLInterpreterTest.cpp
@@ -637,14 +637,6 @@
     expect_failure(r, "void main(inout float x) { do { x++; } while (x < 1); }");
 }
 
-DEF_TEST(SkSLInterpreterRestrictFunctionCalls, r) {
-    // Ensure that simple recursion is not allowed
-    expect_failure(r, "float main() { return main() + 1; }");
-
-    // Ensure that calls to undefined functions are not allowed (to prevent mutual recursion)
-    expect_failure(r, "float foo(); float bar() { return foo(); } float foo() { return bar(); }");
-}
-
 DEF_TEST(SkSLInterpreterReturnThenCall, r) {
     // Test that early returns disable execution in subsequently called functions
     const char* src = R"(
diff --git a/tests/SkSLTest.cpp b/tests/SkSLTest.cpp
index 74f58ff..5c32142 100644
--- a/tests/SkSLTest.cpp
+++ b/tests/SkSLTest.cpp
@@ -294,6 +294,8 @@
 /*
 // Incompatible with Runtime Effects because calling a function before its definition is disallowed.
 // (This was done to prevent recursion, as required by ES2.)
+// TODO(skia:12137) Enable this test once we specifically detect recursion, rather than just
+// calling functions before definition.
 SKSL_TEST(SkSLFunctionPrototype,               "shared/FunctionPrototype.sksl")
 */
 
diff --git a/tests/sksl/runtime_errors/IllegalRecursion.skvm b/tests/sksl/runtime_errors/IllegalRecursion.skvm
new file mode 100644
index 0000000..69dae42
--- /dev/null
+++ b/tests/sksl/runtime_errors/IllegalRecursion.skvm
@@ -0,0 +1,6 @@
+### Compilation failed:
+
+error: 9: call to undefined function 'fibonacci'
+error: 13: call to undefined function 'is_even'
+error: 14: call to undefined function 'is_odd'
+3 errors