Browse Source

Propagate InterruptedError if returned by wrapped go function

Mihail Stoykov 2 years ago
parent
commit
03d8fb271c
2 changed files with 36 additions and 2 deletions
  1. 8 2
      runtime.go
  2. 28 0
      runtime_test.go

+ 8 - 2
runtime.go

@@ -1992,11 +1992,17 @@ func (r *Runtime) wrapReflectFunc(value reflect.Value) func(FunctionCall) Value
 
 		if last := out[len(out)-1]; last.Type().Name() == "error" {
 			if !last.IsNil() {
-				err := last.Interface()
+				err := last.Interface().(error)
 				if _, ok := err.(*Exception); ok {
 					panic(err)
 				}
-				panic(r.NewGoError(last.Interface().(error)))
+				var intErr *InterruptedError
+				if errors.As(err, &intErr) {
+					panic(&uncatchableException{
+						err: err,
+					})
+				}
+				panic(r.NewGoError(err))
 			}
 			out = out[:len(out)-1]
 		}

+ 28 - 0
runtime_test.go

@@ -1615,6 +1615,34 @@ func TestInterruptInWrappedFunction2Recover(t *testing.T) {
 	}
 }
 
+func TestInterruptInWrappedFunctionExpectInteruptError(t *testing.T) {
+	rt := New()
+	// this test panics as otherwise goja will recover and possibly loop
+	rt.Set("v", rt.ToValue(func() {
+		rt.Interrupt("here is the error")
+	}))
+
+	rt.Set("s", rt.ToValue(func(a Callable) (Value, error) {
+		return a(nil)
+	}))
+
+	_, err := rt.RunString(`
+        s(() =>{
+            v();
+        })
+	`)
+	if err == nil {
+		t.Fatal("expected error but got no error")
+	}
+	intErr := new(InterruptedError)
+	if !errors.As(err, &intErr) {
+		t.Fatalf("Wrong error type: %T", err)
+	}
+	if !strings.Contains(intErr.Error(), "here is the error") {
+		t.Fatalf("Wrong error message: %q", intErr.Error())
+	}
+}
+
 func TestRunLoopPreempt(t *testing.T) {
 	vm := New()
 	v, err := vm.RunString("(function() {for (;;) {}})")