diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c
index c6e3b1bf1..1bc46dffc 100644
--- a/jerry-core/vm/opcodes.c
+++ b/jerry-core/vm/opcodes.c
@@ -324,29 +324,47 @@ vm_op_delete_var (ecma_value_t name_literal, /**< name literal */
/**
* 'for-in' opcode handler
*
+ * Note: from ES2015 (ES6) the for-in can trigger error when
+ * the property names are not available (ex.: via Proxy ownKeys).
+ * In these cases an error must be returned.
+ *
+ * This error is returned as the `result_obj_p` and the
+ * function's return value is NULL.
+ *
* See also:
* ECMA-262 v5, 12.6.4
*
- * @return chain list of property names
+ * @return - chain list of property names
+ * - In case of error: NULL is returned and the `result_obj_p`
+ * must be checked.
*/
ecma_collection_t *
-opfunc_for_in (ecma_value_t left_value, /**< left value */
+opfunc_for_in (ecma_value_t iterable_value, /**< ideally an iterable value */
ecma_value_t *result_obj_p) /**< expression object */
{
/* 3. */
- if (ecma_is_value_undefined (left_value)
- || ecma_is_value_null (left_value))
+ if (ecma_is_value_undefined (iterable_value)
+ || ecma_is_value_null (iterable_value))
{
return NULL;
}
/* 4. */
- ecma_value_t obj_expr_value = ecma_op_to_object (left_value);
+ ecma_value_t obj_expr_value = ecma_op_to_object (iterable_value);
/* ecma_op_to_object will only raise error on null/undefined values but those are handled above. */
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (obj_expr_value));
ecma_object_t *obj_p = ecma_get_object_from_value (obj_expr_value);
ecma_collection_t *prop_names_p = ecma_op_object_enumerate (obj_p);
+#if ENABLED (JERRY_ESNEXT)
+ if (JERRY_UNLIKELY (prop_names_p == NULL))
+ {
+ ecma_deref_object (obj_p);
+ *result_obj_p = ECMA_VALUE_ERROR;
+ return NULL;
+ }
+#endif /* ENABLED (JERRY_ESNEXT) */
+
if (prop_names_p->item_count != 0)
{
*result_obj_p = ecma_make_object_value (obj_p);
diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c
index f6d81b248..9744bece9 100644
--- a/jerry-core/vm/vm.c
+++ b/jerry-core/vm/vm.c
@@ -3737,6 +3737,14 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
if (prop_names_p == NULL)
{
+#if ENABLED (JERRY_ESNEXT)
+ if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (expr_obj_value)))
+ {
+ result = expr_obj_value;
+ goto error;
+ }
+#endif /* ENABLED (JERRY_ESNEXT) */
+
/* The collection is already released */
byte_code_p = byte_code_start_p + branch_offset;
continue;
diff --git a/tests/jerry/es.next/proxy-for-in.js b/tests/jerry/es.next/proxy-for-in.js
new file mode 100644
index 000000000..7927c8605
--- /dev/null
+++ b/tests/jerry/es.next/proxy-for-in.js
@@ -0,0 +1,78 @@
+// Copyright JS Foundation and other contributors, http://js.foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var handlerBoolean = {
+ ownKeys: function() { return true; },
+}
+var boolProxy = new Proxy({}, handlerBoolean);
+
+try {
+ for (var a in boolProxy) {
+ // This should never be called.
+ assert (false);
+ }
+
+ assert (false);
+} catch (ex) {
+ assert (ex instanceof TypeError);
+}
+
+
+var handlerSymbol = {
+ ownKeys: function() { return Symbol("alma"); },
+}
+var symbolProxy = new Proxy({}, handlerSymbol);
+
+try {
+ for (var a in symbolProxy) {
+ // This should never be called.
+ assert (false);
+ }
+
+ assert (false);
+} catch (ex) {
+ assert (ex instanceof TypeError);
+}
+
+
+var handlerNumber = {
+ ownKeys: function() { return 1; },
+}
+var numberProxy = new Proxy({}, handlerNumber);
+
+try {
+ for (var a in numberProxy) {
+ // This should never be called.
+ assert (false);
+ }
+
+ assert (false);
+} catch (ex) {
+ assert (ex instanceof TypeError);
+}
+
+
+var handlerObject = {
+ ownKeys: function() { return {}; },
+}
+var objectProxy = new Proxy({}, handlerObject);
+
+for (var a in objectProxy) {
+ // This should never be called.
+ assert (false);
+}
diff --git a/tests/test262-es6-excludelist.xml b/tests/test262-es6-excludelist.xml
index 8fdcc9345..d01545488 100644
--- a/tests/test262-es6-excludelist.xml
+++ b/tests/test262-es6-excludelist.xml
@@ -56,7 +56,6 @@
For-in supports proxy
For-in supports proxy
For-in supports proxy
- For-in supports proxy
For-in supports proxy