mp_resume: Elaborate handling of .throw() for objects which lack it.

In this case, the exception is just re-thrown - the ideas is that object
doesn't handle this exception specially, so it will propagated per Python
semantics.
diff --git a/py/runtime.c b/py/runtime.c
index f827fd8..f7e08e3 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -960,9 +960,20 @@
                 return MP_VM_RETURN_NORMAL;
             }
         }
-        mp_load_method(self_in, MP_QSTR_throw, dest);
-        *ret_val = mp_call_method_n_kw(1, 0, &throw_value);
-        return MP_VM_RETURN_YIELD;
+        mp_load_method_maybe(self_in, MP_QSTR_throw, dest);
+        if (dest[0] != MP_OBJ_NULL) {
+            *ret_val = mp_call_method_n_kw(1, 0, &throw_value);
+            // If .throw() method returned, we assume it's value to yield
+            // - any exception would be thrown with nlr_jump().
+            return MP_VM_RETURN_YIELD;
+        }
+        // If there's nowhere to throw exception into, then we assume that object
+        // is just incapable to handle it, so any exception thrown into it
+        // will be propagated up. This behavior is approved by test_pep380.py
+        // test_delegation_of_close_to_non_generator(),
+        //  test_delegating_throw_to_non_generator()
+        *ret_val = throw_value;
+        return MP_VM_RETURN_EXCEPTION;
     }
 
     assert(0);