mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Fix inner classes in class heritage environment (#2686)
This patch is the proper fix for #2667, since #2269 did not fix the problem entirely. JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
This commit is contained in:
parent
cfdb5eddb3
commit
86e60ddf8d
@ -99,11 +99,12 @@ typedef enum
|
||||
ECMA_PARSE_NO_OPTS = 0, /**< no options passed */
|
||||
ECMA_PARSE_STRICT_MODE = (1u << 0), /**< enable strict mode */
|
||||
ECMA_PARSE_DIRECT_EVAL = (1u << 1), /**< eval is called directly (ECMA-262 v5, 15.1.2.1.1) */
|
||||
/* These three status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
|
||||
/* These four status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
|
||||
ECMA_PARSE_CLASS_CONSTRUCTOR = (1u << 2), /**< a class constructor is being parsed (this value must be kept in
|
||||
* in sync with PARSER_CLASS_CONSTRUCTOR) */
|
||||
ECMA_PARSE_HAS_SUPER = (1u << 3), /**< the current context has super reference */
|
||||
ECMA_PARSE_HAS_STATIC_SUPER = (1u << 4), /**< the current context is a static class method */
|
||||
ECMA_PARSE_HAS_IMPL_SUPER = (1u << 4), /**< the current context has implicit parent class */
|
||||
ECMA_PARSE_HAS_STATIC_SUPER = (1u << 5), /**< the current context is a static class method */
|
||||
} ecma_parse_opts_t;
|
||||
|
||||
/**
|
||||
|
||||
@ -1053,7 +1053,7 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
|
||||
/* Catch the special case when a the class extends value in null
|
||||
and the class has no explicit constructor to raise TypeError.*/
|
||||
JERRY_ASSERT (!ecma_op_function_has_construct_flag (arguments_list_p));
|
||||
JERRY_ASSERT (ecma_get_object_prototype (func_obj_p) == NULL);
|
||||
JERRY_ASSERT (ecma_get_object_prototype (func_obj_p) == ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE));
|
||||
|
||||
ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Super constructor null is not a constructor."));
|
||||
break;
|
||||
|
||||
@ -364,7 +364,8 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */
|
||||
parser_emit_cbc (context_p, CBC_CREATE_OBJECT);
|
||||
|
||||
bool super_called = false;
|
||||
uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | (context_p->status_flags & PARSER_CLASS_HAS_SUPER);
|
||||
uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE;
|
||||
status_flags |= context_p->status_flags & (PARSER_CLASS_HAS_SUPER | PARSER_CLASS_IMPLICIT_SUPER);
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -472,12 +473,13 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */
|
||||
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
|
||||
}
|
||||
|
||||
uint16_t result_index = context_p->literal_count;
|
||||
lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
|
||||
literal_p->type = LEXER_UNUSED_LITERAL;
|
||||
literal_p->status_flags = 0;
|
||||
literal_p->u.bytecode_p = parser_parse_function (context_p, constructor_status_flags);
|
||||
literal_p->type = LEXER_FUNCTION_LITERAL;
|
||||
parser_emit_cbc_literal (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_SET_CLASS_LITERAL), context_p->literal_count);
|
||||
parser_emit_cbc_literal (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_SET_CLASS_LITERAL), result_index);
|
||||
context_p->literal_count++;
|
||||
continue;
|
||||
}
|
||||
@ -555,8 +557,6 @@ parser_parse_class (parser_context_t *context_p, /**< context */
|
||||
{
|
||||
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_CLASS);
|
||||
|
||||
context_p->status_flags &= (uint32_t) ~PARSER_CLASS_HAS_SUPER;
|
||||
|
||||
uint16_t class_ident_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS;
|
||||
|
||||
if (is_statement)
|
||||
@ -582,7 +582,10 @@ parser_parse_class (parser_context_t *context_p, /**< context */
|
||||
}
|
||||
}
|
||||
|
||||
if (context_p->token.type == LEXER_KEYW_EXTENDS)
|
||||
bool create_class_env = (context_p->token.type == LEXER_KEYW_EXTENDS
|
||||
|| (context_p->status_flags & PARSER_CLASS_HAS_SUPER));
|
||||
|
||||
if (create_class_env)
|
||||
{
|
||||
parser_parse_super_class_context_start (context_p);
|
||||
}
|
||||
@ -615,10 +618,10 @@ parser_parse_class (parser_context_t *context_p, /**< context */
|
||||
parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, class_ident_index);
|
||||
}
|
||||
|
||||
if (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
|
||||
if (create_class_env)
|
||||
{
|
||||
parser_parse_super_class_context_end (context_p, is_statement);
|
||||
context_p->status_flags &= (uint32_t) ~PARSER_CLASS_HAS_SUPER;
|
||||
context_p->status_flags &= (uint32_t) ~(PARSER_CLASS_HAS_SUPER | PARSER_CLASS_IMPLICIT_SUPER);
|
||||
}
|
||||
|
||||
parser_flush_cbc (context_p);
|
||||
@ -1366,7 +1369,14 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
|
||||
#ifndef CONFIG_DISABLE_ES2015_CLASS
|
||||
if (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags))
|
||||
{
|
||||
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
|
||||
if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER)
|
||||
{
|
||||
parser_emit_cbc (context_p, CBC_PUSH_THIS);
|
||||
}
|
||||
else
|
||||
{
|
||||
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1415,6 +1425,12 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
|
||||
break;
|
||||
}
|
||||
|
||||
if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER)
|
||||
{
|
||||
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_STATIC_SUPER);
|
||||
break;
|
||||
}
|
||||
|
||||
bool is_static = (context_p->status_flags & PARSER_CLASS_STATIC_FUNCTION) != 0;
|
||||
parser_emit_cbc_ext (context_p, is_static ? CBC_EXT_PUSH_STATIC_SUPER : CBC_EXT_PUSH_SUPER);
|
||||
break;
|
||||
@ -1422,6 +1438,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
|
||||
|
||||
if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)
|
||||
&& (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
|
||||
&& !(context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER)
|
||||
&& (context_p->status_flags & (PARSER_IS_ARROW_FUNCTION | PARSER_CLASS_CONSTRUCTOR)))
|
||||
{
|
||||
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_SUPER);
|
||||
|
||||
@ -67,12 +67,13 @@ typedef enum
|
||||
PARSER_ARROW_PARSE_ARGS = (1u << 19), /**< parse the argument list of an arrow function */
|
||||
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
|
||||
#ifndef CONFIG_DISABLE_ES2015_CLASS
|
||||
/* These three status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
|
||||
/* These four status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
|
||||
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed (this value must be kept in
|
||||
* in sync with ECMA_PARSE_CLASS_CONSTRUCTOR) */
|
||||
PARSER_CLASS_HAS_SUPER = (1u << 21), /**< class has super reference */
|
||||
PARSER_CLASS_STATIC_FUNCTION = (1u << 22), /**< this function is a static class method */
|
||||
PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 23), /**< super property call or assignment */
|
||||
PARSER_CLASS_IMPLICIT_SUPER = (1u << 22), /**< class has implicit parent class */
|
||||
PARSER_CLASS_STATIC_FUNCTION = (1u << 23), /**< this function is a static class method */
|
||||
PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 24), /**< super property call or assignment */
|
||||
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
|
||||
} parser_general_flags_t;
|
||||
|
||||
|
||||
@ -606,16 +606,25 @@ parser_parse_with_statement_end (parser_context_t *context_p) /**< context */
|
||||
void
|
||||
parser_parse_super_class_context_start (parser_context_t *context_p) /**< context */
|
||||
{
|
||||
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_EXTENDS);
|
||||
|
||||
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_EXTENDS
|
||||
|| (context_p->status_flags & PARSER_CLASS_HAS_SUPER));
|
||||
parser_with_statement_t with_statement;
|
||||
|
||||
lexer_next_token (context_p);
|
||||
if (context_p->token.type == LEXER_KEYW_EXTENDS)
|
||||
{
|
||||
lexer_next_token (context_p);
|
||||
|
||||
/* NOTE: Currently there is no proper way to check whether the currently parsed expression
|
||||
is a valid lefthand-side expression or not, so we do not throw syntax error and parse
|
||||
the class extending value as an expression. */
|
||||
parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_NO_COMMA);
|
||||
/* NOTE: Currently there is no proper way to check whether the currently parsed expression
|
||||
is a valid lefthand-side expression or not, so we do not throw syntax error and parse
|
||||
the class extending value as an expression. */
|
||||
parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_NO_COMMA);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (context_p->status_flags & PARSER_CLASS_HAS_SUPER);
|
||||
parser_emit_cbc (context_p, CBC_PUSH_NULL);
|
||||
context_p->status_flags |= PARSER_CLASS_IMPLICIT_SUPER;
|
||||
}
|
||||
|
||||
#ifndef JERRY_NDEBUG
|
||||
PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION);
|
||||
@ -2022,7 +2031,14 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
|
||||
#ifndef CONFIG_DISABLE_ES2015_CLASS
|
||||
if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags)))
|
||||
{
|
||||
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
|
||||
if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER)
|
||||
{
|
||||
parser_emit_cbc (context_p, CBC_PUSH_THIS);
|
||||
}
|
||||
else
|
||||
{
|
||||
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
|
||||
}
|
||||
parser_emit_cbc (context_p, CBC_RETURN);
|
||||
}
|
||||
else
|
||||
@ -2164,7 +2180,14 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
|
||||
#ifndef CONFIG_DISABLE_ES2015_CLASS
|
||||
if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags)))
|
||||
{
|
||||
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
|
||||
if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER)
|
||||
{
|
||||
parser_emit_cbc (context_p, CBC_PUSH_THIS);
|
||||
}
|
||||
else
|
||||
{
|
||||
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
|
||||
}
|
||||
parser_emit_cbc (context_p, CBC_RETURN);
|
||||
parser_flush_cbc (context_p);
|
||||
}
|
||||
|
||||
@ -1336,7 +1336,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
||||
|
||||
if (ecma_is_value_null (super_value))
|
||||
{
|
||||
super_class_p = ecma_create_object (NULL, 0, ECMA_OBJECT_TYPE_GENERAL);
|
||||
super_class_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE),
|
||||
0,
|
||||
ECMA_OBJECT_TYPE_GENERAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1541,7 +1543,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
||||
else
|
||||
{
|
||||
ecma_object_t *super_class_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p);
|
||||
*stack_top_p++ = ecma_fast_copy_value (ecma_make_object_value (super_class_p));
|
||||
ecma_ref_object (super_class_p);
|
||||
*stack_top_p++ = ecma_make_object_value (super_class_p);
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
59
tests/jerry/es2015/class-inheritance-inner-class.js
Normal file
59
tests/jerry/es2015/class-inheritance-inner-class.js
Normal file
@ -0,0 +1,59 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
var console = { assert : assert };
|
||||
|
||||
class C1 {
|
||||
f () {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
class C2 extends C1 {
|
||||
f () {
|
||||
assert (super.f () === 5);
|
||||
|
||||
class G {
|
||||
g () {
|
||||
assert (super.f === undefined);
|
||||
assert (super.toString () === "[object Object]");
|
||||
var a = super.valueOf ();
|
||||
try {
|
||||
a ();
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
}
|
||||
|
||||
constructor () {
|
||||
// Test to overwrite the current lit-object
|
||||
console.assert (Object.getPrototypeOf (this) === G.prototype);
|
||||
|
||||
try {
|
||||
eval ("super ()");
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof SyntaxError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var g = new G ();
|
||||
g.g ();
|
||||
}
|
||||
}
|
||||
|
||||
(new C2).f ();
|
||||
Loading…
x
Reference in New Issue
Block a user