new classes: assert that constructors are not callable and rewrite 'return;'
R=arv@chromium.org BUG=v8:3834 LOG=N Review URL: https://codereview.chromium.org/885643004 Cr-Commit-Position: refs/heads/master@{#26483}
This commit is contained in:
parent
a44511d413
commit
158a87659f
@ -261,7 +261,8 @@ class AstValue : public ZoneObject {
|
||||
F(use_asm, "use asm") \
|
||||
F(use_strong, "use strong") \
|
||||
F(use_strict, "use strict") \
|
||||
F(value, "value")
|
||||
F(value, "value") \
|
||||
F(is_construct_call, "_IsConstructCall")
|
||||
|
||||
#define OTHER_CONSTANTS(F) \
|
||||
F(true_value) \
|
||||
|
@ -2618,7 +2618,7 @@ class FunctionLiteral FINAL : public Expression {
|
||||
class HasDuplicateParameters : public BitField<ParameterFlag, 3, 1> {};
|
||||
class IsFunction : public BitField<IsFunctionFlag, 4, 1> {};
|
||||
class IsParenthesized : public BitField<IsParenthesizedFlag, 5, 1> {};
|
||||
class FunctionKindBits : public BitField<FunctionKind, 6, 6> {};
|
||||
class FunctionKindBits : public BitField<FunctionKind, 6, 7> {};
|
||||
};
|
||||
|
||||
|
||||
|
@ -591,7 +591,7 @@ class FastNewClosureStub : public HydrogenCodeStub {
|
||||
private:
|
||||
STATIC_ASSERT(LANGUAGE_END == 3);
|
||||
class LanguageModeBits : public BitField<LanguageMode, 0, 2> {};
|
||||
class FunctionKindBits : public BitField<FunctionKind, 2, 6> {};
|
||||
class FunctionKindBits : public BitField<FunctionKind, 2, 7> {};
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(FastNewClosure);
|
||||
DEFINE_HYDROGEN_CODE_STUB(FastNewClosure, HydrogenCodeStub);
|
||||
|
@ -213,6 +213,7 @@ bool Linkage::NeedsFrameState(Runtime::FunctionId function) {
|
||||
case Runtime::kStringMatch:
|
||||
case Runtime::kStringReplaceGlobalRegExpWithString:
|
||||
case Runtime::kThrowConstAssignError:
|
||||
case Runtime::kThrowConstructorNonCallableError:
|
||||
case Runtime::kThrowNonMethodError:
|
||||
case Runtime::kThrowNotDateError:
|
||||
case Runtime::kThrowReferenceError:
|
||||
|
@ -820,7 +820,8 @@ enum FunctionKind {
|
||||
kConciseGeneratorMethod = kGeneratorFunction | kConciseMethod,
|
||||
kAccessorFunction = 1 << 3,
|
||||
kDefaultConstructor = 1 << 4,
|
||||
kSubclassConstructor = 1 << 5
|
||||
kSubclassConstructor = 1 << 5,
|
||||
kBaseConstructor = 1 << 6,
|
||||
};
|
||||
|
||||
|
||||
@ -832,6 +833,7 @@ inline bool IsValidFunctionKind(FunctionKind kind) {
|
||||
kind == FunctionKind::kConciseGeneratorMethod ||
|
||||
kind == FunctionKind::kAccessorFunction ||
|
||||
kind == FunctionKind::kDefaultConstructor ||
|
||||
kind == FunctionKind::kBaseConstructor ||
|
||||
kind == FunctionKind::kSubclassConstructor;
|
||||
}
|
||||
|
||||
@ -866,10 +868,24 @@ inline bool IsDefaultConstructor(FunctionKind kind) {
|
||||
}
|
||||
|
||||
|
||||
inline bool IsBaseConstructor(FunctionKind kind) {
|
||||
DCHECK(IsValidFunctionKind(kind));
|
||||
return kind & FunctionKind::kBaseConstructor;
|
||||
}
|
||||
|
||||
|
||||
inline bool IsSubclassConstructor(FunctionKind kind) {
|
||||
DCHECK(IsValidFunctionKind(kind));
|
||||
return kind & FunctionKind::kSubclassConstructor;
|
||||
}
|
||||
|
||||
|
||||
inline bool IsConstructor(FunctionKind kind) {
|
||||
DCHECK(IsValidFunctionKind(kind));
|
||||
return kind &
|
||||
(FunctionKind::kBaseConstructor | FunctionKind::kSubclassConstructor |
|
||||
FunctionKind::kDefaultConstructor);
|
||||
}
|
||||
} } // namespace v8::internal
|
||||
|
||||
namespace i = v8::internal;
|
||||
|
@ -181,7 +181,8 @@ var kMessages = {
|
||||
sloppy_lexical: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode"],
|
||||
super_constructor_call: ["A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported."],
|
||||
duplicate_proto: ["Duplicate __proto__ fields are not allowed in object literals"],
|
||||
param_after_rest: ["Rest parameter must be last formal parameter"]
|
||||
param_after_rest: ["Rest parameter must be last formal parameter"],
|
||||
constructor_noncallable: ["Class constructors cannot be invoked without 'new'"]
|
||||
};
|
||||
|
||||
|
||||
|
@ -7195,6 +7195,7 @@ class SharedFunctionInfo: public HeapObject {
|
||||
kIsConciseMethod,
|
||||
kIsAccessorFunction,
|
||||
kIsDefaultConstructor,
|
||||
kIsBaseConstructor,
|
||||
kIsSubclassConstructor,
|
||||
kIsAsmFunction,
|
||||
kDeserialized,
|
||||
@ -7203,7 +7204,7 @@ class SharedFunctionInfo: public HeapObject {
|
||||
// Add hints for other modes when they're added.
|
||||
STATIC_ASSERT(LANGUAGE_END == 3);
|
||||
|
||||
class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 6> {};
|
||||
class FunctionKindBits : public BitField<FunctionKind, kIsArrow, 7> {};
|
||||
|
||||
class DeoptCountBits : public BitField<int, 0, 4> {};
|
||||
class OptReenableTriesBits : public BitField<int, 4, 18> {};
|
||||
|
@ -298,7 +298,7 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
|
||||
{
|
||||
AstNodeFactory function_factory(ast_value_factory());
|
||||
FunctionState function_state(&function_state_, &scope_, function_scope,
|
||||
&function_factory);
|
||||
kDefaultConstructor, &function_factory);
|
||||
|
||||
body = new (zone()) ZoneList<Statement*>(1, zone());
|
||||
if (call_super) {
|
||||
@ -946,7 +946,7 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope,
|
||||
// Enters 'scope'.
|
||||
AstNodeFactory function_factory(ast_value_factory());
|
||||
FunctionState function_state(&function_state_, &scope_, *scope,
|
||||
&function_factory);
|
||||
kNormalFunction, &function_factory);
|
||||
|
||||
scope_->SetLanguageMode(info->language_mode());
|
||||
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
|
||||
@ -1066,7 +1066,7 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
|
||||
original_scope_ = scope;
|
||||
AstNodeFactory function_factory(ast_value_factory());
|
||||
FunctionState function_state(&function_state_, &scope_, scope,
|
||||
&function_factory);
|
||||
shared_info->kind(), &function_factory);
|
||||
DCHECK(is_sloppy(scope->language_mode()) ||
|
||||
is_strict(info()->language_mode()));
|
||||
DCHECK(info()->language_mode() == shared_info->language_mode());
|
||||
@ -2650,11 +2650,17 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
|
||||
tok == Token::SEMICOLON ||
|
||||
tok == Token::RBRACE ||
|
||||
tok == Token::EOS) {
|
||||
return_value = GetLiteralUndefined(position());
|
||||
if (FLAG_experimental_classes &&
|
||||
IsSubclassConstructor(function_state_->kind())) {
|
||||
return_value = ThisExpression(scope_, factory(), loc.beg_pos);
|
||||
} else {
|
||||
return_value = GetLiteralUndefined(position());
|
||||
}
|
||||
} else {
|
||||
return_value = ParseExpression(true, CHECK_OK);
|
||||
}
|
||||
ExpectSemicolon(CHECK_OK);
|
||||
|
||||
if (is_generator()) {
|
||||
Expression* generator = factory()->NewVariableProxy(
|
||||
function_state_->generator_object_variable());
|
||||
@ -3671,7 +3677,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
// Parse function body.
|
||||
{
|
||||
AstNodeFactory function_factory(ast_value_factory());
|
||||
FunctionState function_state(&function_state_, &scope_, scope,
|
||||
FunctionState function_state(&function_state_, &scope_, scope, kind,
|
||||
&function_factory);
|
||||
scope_->SetScopeName(function_name);
|
||||
|
||||
@ -3825,7 +3831,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
&expected_property_count, CHECK_OK);
|
||||
} else {
|
||||
body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op,
|
||||
is_generator, CHECK_OK);
|
||||
kind, CHECK_OK);
|
||||
materialized_literal_count = function_state.materialized_literal_count();
|
||||
expected_property_count = function_state.expected_property_count();
|
||||
handler_count = function_state.handler_count();
|
||||
@ -3935,7 +3941,7 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name,
|
||||
|
||||
ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
|
||||
const AstRawString* function_name, int pos, Variable* fvar,
|
||||
Token::Value fvar_init_op, bool is_generator, bool* ok) {
|
||||
Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
|
||||
// Everything inside an eagerly parsed function will be parsed eagerly
|
||||
// (see comment above).
|
||||
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
|
||||
@ -3952,8 +3958,29 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
|
||||
RelocInfo::kNoPosition), zone());
|
||||
}
|
||||
|
||||
|
||||
// For concise constructors, check that they are constructed,
|
||||
// not called.
|
||||
if (FLAG_experimental_classes && i::IsConstructor(kind)) {
|
||||
ZoneList<Expression*>* arguments =
|
||||
new (zone()) ZoneList<Expression*>(0, zone());
|
||||
CallRuntime* construct_check = factory()->NewCallRuntime(
|
||||
ast_value_factory()->is_construct_call_string(),
|
||||
Runtime::FunctionForId(Runtime::kInlineIsConstructCall), arguments,
|
||||
pos);
|
||||
CallRuntime* non_callable_error = factory()->NewCallRuntime(
|
||||
ast_value_factory()->empty_string(),
|
||||
Runtime::FunctionForId(Runtime::kThrowConstructorNonCallableError),
|
||||
arguments, pos);
|
||||
IfStatement* if_statement = factory()->NewIfStatement(
|
||||
factory()->NewUnaryOperation(Token::NOT, construct_check, pos),
|
||||
factory()->NewReturnStatement(non_callable_error, pos),
|
||||
factory()->NewEmptyStatement(pos), pos);
|
||||
body->Add(if_statement, zone());
|
||||
}
|
||||
|
||||
// For generators, allocate and yield an iterator on function entry.
|
||||
if (is_generator) {
|
||||
if (IsGeneratorFunction(kind)) {
|
||||
ZoneList<Expression*>* arguments =
|
||||
new(zone()) ZoneList<Expression*>(0, zone());
|
||||
CallRuntime* allocation = factory()->NewCallRuntime(
|
||||
@ -3974,7 +4001,7 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
|
||||
|
||||
ParseStatementList(body, Token::RBRACE, false, NULL, CHECK_OK);
|
||||
|
||||
if (is_generator) {
|
||||
if (IsGeneratorFunction(kind)) {
|
||||
VariableProxy* get_proxy = factory()->NewVariableProxy(
|
||||
function_state_->generator_object_variable());
|
||||
Expression* undefined =
|
||||
@ -3985,6 +4012,14 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
|
||||
yield, RelocInfo::kNoPosition), zone());
|
||||
}
|
||||
|
||||
if (FLAG_experimental_classes && IsSubclassConstructor(kind)) {
|
||||
body->Add(
|
||||
factory()->NewReturnStatement(
|
||||
this->ThisExpression(scope_, factory(), RelocInfo::kNoPosition),
|
||||
RelocInfo::kNoPosition),
|
||||
zone());
|
||||
}
|
||||
|
||||
Expect(Token::RBRACE, CHECK_OK);
|
||||
scope_->set_end_position(scanner()->location().end_pos);
|
||||
|
||||
@ -4025,7 +4060,7 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
|
||||
reusable_preparser_->set_allow_strong_mode(allow_strong_mode());
|
||||
}
|
||||
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
|
||||
language_mode(), is_generator(), logger);
|
||||
language_mode(), function_state_->kind(), logger);
|
||||
if (pre_parse_timer_ != NULL) {
|
||||
pre_parse_timer_->Stop();
|
||||
}
|
||||
|
10
src/parser.h
10
src/parser.h
@ -583,7 +583,7 @@ class ParserTraits {
|
||||
int* expected_property_count, bool* ok);
|
||||
V8_INLINE ZoneList<Statement*>* ParseEagerFunctionBody(
|
||||
const AstRawString* name, int pos, Variable* fvar,
|
||||
Token::Value fvar_init_op, bool is_generator, bool* ok);
|
||||
Token::Value fvar_init_op, FunctionKind kind, bool* ok);
|
||||
|
||||
ClassLiteral* ParseClassLiteral(const AstRawString* name,
|
||||
Scanner::Location class_name_location,
|
||||
@ -871,7 +871,7 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
// Consumes the ending }.
|
||||
ZoneList<Statement*>* ParseEagerFunctionBody(
|
||||
const AstRawString* function_name, int pos, Variable* fvar,
|
||||
Token::Value fvar_init_op, bool is_generator, bool* ok);
|
||||
Token::Value fvar_init_op, FunctionKind kind, bool* ok);
|
||||
|
||||
void ThrowPendingError();
|
||||
|
||||
@ -936,9 +936,9 @@ void ParserTraits::SkipLazyFunctionBody(const AstRawString* function_name,
|
||||
|
||||
ZoneList<Statement*>* ParserTraits::ParseEagerFunctionBody(
|
||||
const AstRawString* name, int pos, Variable* fvar,
|
||||
Token::Value fvar_init_op, bool is_generator, bool* ok) {
|
||||
return parser_->ParseEagerFunctionBody(name, pos, fvar, fvar_init_op,
|
||||
is_generator, ok);
|
||||
Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
|
||||
return parser_->ParseEagerFunctionBody(name, pos, fvar, fvar_init_op, kind,
|
||||
ok);
|
||||
}
|
||||
|
||||
void ParserTraits::CheckConflictingVarDeclarations(v8::internal::Scope* scope,
|
||||
|
@ -104,18 +104,18 @@ PreParserExpression PreParserTraits::ParseFunctionLiteral(
|
||||
|
||||
|
||||
PreParser::PreParseResult PreParser::PreParseLazyFunction(
|
||||
LanguageMode language_mode, bool is_generator, ParserRecorder* log) {
|
||||
LanguageMode language_mode, FunctionKind kind, ParserRecorder* log) {
|
||||
log_ = log;
|
||||
// Lazy functions always have trivial outer scopes (no with/catch scopes).
|
||||
PreParserScope top_scope(scope_, SCRIPT_SCOPE);
|
||||
PreParserFactory top_factory(NULL);
|
||||
FunctionState top_state(&function_state_, &scope_, &top_scope, &top_factory);
|
||||
FunctionState top_state(&function_state_, &scope_, &top_scope,
|
||||
kNormalFunction, &top_factory);
|
||||
scope_->SetLanguageMode(language_mode);
|
||||
PreParserScope function_scope(scope_, FUNCTION_SCOPE);
|
||||
PreParserFactory function_factory(NULL);
|
||||
FunctionState function_state(&function_state_, &scope_, &function_scope,
|
||||
FunctionState function_state(&function_state_, &scope_, &function_scope, kind,
|
||||
&function_factory);
|
||||
function_state.set_is_generator(is_generator);
|
||||
DCHECK_EQ(Token::LBRACE, scanner()->current_token());
|
||||
bool ok = true;
|
||||
int start_position = peek_position();
|
||||
@ -869,9 +869,8 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
||||
ScopeType outer_scope_type = scope_->type();
|
||||
PreParserScope function_scope(scope_, FUNCTION_SCOPE);
|
||||
PreParserFactory factory(NULL);
|
||||
FunctionState function_state(&function_state_, &scope_, &function_scope,
|
||||
FunctionState function_state(&function_state_, &scope_, &function_scope, kind,
|
||||
&factory);
|
||||
function_state.set_is_generator(IsGeneratorFunction(kind));
|
||||
// FormalParameterList ::
|
||||
// '(' (Identifier)*[','] ')'
|
||||
Expect(Token::LPAREN, CHECK_OK);
|
||||
|
@ -200,7 +200,7 @@ class ParserBase : public Traits {
|
||||
public:
|
||||
FunctionState(FunctionState** function_state_stack,
|
||||
typename Traits::Type::Scope** scope_stack,
|
||||
typename Traits::Type::Scope* scope,
|
||||
typename Traits::Type::Scope* scope, FunctionKind kind,
|
||||
typename Traits::Type::Factory* factory);
|
||||
~FunctionState();
|
||||
|
||||
@ -217,15 +217,15 @@ class ParserBase : public Traits {
|
||||
void AddProperty() { expected_property_count_++; }
|
||||
int expected_property_count() { return expected_property_count_; }
|
||||
|
||||
void set_is_generator(bool is_generator) { is_generator_ = is_generator; }
|
||||
bool is_generator() const { return is_generator_; }
|
||||
bool is_generator() const { return IsGeneratorFunction(kind_); }
|
||||
|
||||
FunctionKind kind() const { return kind_; }
|
||||
|
||||
void set_generator_object_variable(
|
||||
typename Traits::Type::GeneratorVariable* variable) {
|
||||
DCHECK(variable != NULL);
|
||||
DCHECK(!is_generator());
|
||||
DCHECK(is_generator());
|
||||
generator_object_variable_ = variable;
|
||||
is_generator_ = true;
|
||||
}
|
||||
typename Traits::Type::GeneratorVariable* generator_object_variable()
|
||||
const {
|
||||
@ -246,13 +246,13 @@ class ParserBase : public Traits {
|
||||
// Properties count estimation.
|
||||
int expected_property_count_;
|
||||
|
||||
// Whether the function is a generator.
|
||||
bool is_generator_;
|
||||
FunctionKind kind_;
|
||||
// For generators, this variable may hold the generator object. It variable
|
||||
// is used by yield expressions and return statements. It is not necessary
|
||||
// for generator functions to have this variable set.
|
||||
Variable* generator_object_variable_;
|
||||
|
||||
|
||||
FunctionState** function_state_stack_;
|
||||
FunctionState* outer_function_state_;
|
||||
typename Traits::Type::Scope** scope_stack_;
|
||||
@ -1451,9 +1451,9 @@ class PreParserTraits {
|
||||
}
|
||||
|
||||
V8_INLINE PreParserStatementList
|
||||
ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
|
||||
Variable* fvar, Token::Value fvar_init_op,
|
||||
bool is_generator, bool* ok);
|
||||
ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
|
||||
Variable* fvar, Token::Value fvar_init_op,
|
||||
FunctionKind kind, bool* ok);
|
||||
|
||||
// Utility functions
|
||||
int DeclareArrowParametersFromExpression(PreParserExpression expression,
|
||||
@ -1545,7 +1545,8 @@ class PreParser : public ParserBase<PreParserTraits> {
|
||||
PreParseResult PreParseProgram(int* materialized_literals = 0) {
|
||||
PreParserScope scope(scope_, SCRIPT_SCOPE);
|
||||
PreParserFactory factory(NULL);
|
||||
FunctionState top_scope(&function_state_, &scope_, &scope, &factory);
|
||||
FunctionState top_scope(&function_state_, &scope_, &scope, kNormalFunction,
|
||||
&factory);
|
||||
bool ok = true;
|
||||
int start_position = scanner()->peek_location().beg_pos;
|
||||
ParseSourceElements(Token::EOS, &ok);
|
||||
@ -1571,7 +1572,7 @@ class PreParser : public ParserBase<PreParserTraits> {
|
||||
// At return, unless an error occurred, the scanner is positioned before the
|
||||
// the final '}'.
|
||||
PreParseResult PreParseLazyFunction(LanguageMode language_mode,
|
||||
bool is_generator, ParserRecorder* log);
|
||||
FunctionKind kind, ParserRecorder* log);
|
||||
|
||||
private:
|
||||
friend class PreParserTraits;
|
||||
@ -1635,9 +1636,9 @@ class PreParser : public ParserBase<PreParserTraits> {
|
||||
int* materialized_literal_count,
|
||||
int* expected_property_count, bool* ok);
|
||||
V8_INLINE PreParserStatementList
|
||||
ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
|
||||
Variable* fvar, Token::Value fvar_init_op,
|
||||
bool is_generator, bool* ok);
|
||||
ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
|
||||
Variable* fvar, Token::Value fvar_init_op,
|
||||
FunctionKind kind, bool* ok);
|
||||
|
||||
Expression ParseFunctionLiteral(
|
||||
Identifier name, Scanner::Location function_name_location,
|
||||
@ -1663,7 +1664,7 @@ void PreParserTraits::MaterializeTemplateCallsiteLiterals() {
|
||||
|
||||
PreParserStatementList PreParser::ParseEagerFunctionBody(
|
||||
PreParserIdentifier function_name, int pos, Variable* fvar,
|
||||
Token::Value fvar_init_op, bool is_generator, bool* ok) {
|
||||
Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
|
||||
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
|
||||
|
||||
ParseSourceElements(Token::RBRACE, ok);
|
||||
@ -1676,9 +1677,9 @@ PreParserStatementList PreParser::ParseEagerFunctionBody(
|
||||
|
||||
PreParserStatementList PreParserTraits::ParseEagerFunctionBody(
|
||||
PreParserIdentifier function_name, int pos, Variable* fvar,
|
||||
Token::Value fvar_init_op, bool is_generator, bool* ok) {
|
||||
Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
|
||||
return pre_parser_->ParseEagerFunctionBody(function_name, pos, fvar,
|
||||
fvar_init_op, is_generator, ok);
|
||||
fvar_init_op, kind, ok);
|
||||
}
|
||||
|
||||
|
||||
@ -1686,12 +1687,12 @@ template <class Traits>
|
||||
ParserBase<Traits>::FunctionState::FunctionState(
|
||||
FunctionState** function_state_stack,
|
||||
typename Traits::Type::Scope** scope_stack,
|
||||
typename Traits::Type::Scope* scope,
|
||||
typename Traits::Type::Scope* scope, FunctionKind kind,
|
||||
typename Traits::Type::Factory* factory)
|
||||
: next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
|
||||
next_handler_index_(0),
|
||||
expected_property_count_(0),
|
||||
is_generator_(false),
|
||||
kind_(kind),
|
||||
generator_object_variable_(NULL),
|
||||
function_state_stack_(function_state_stack),
|
||||
outer_function_state_(*function_state_stack),
|
||||
@ -2157,7 +2158,7 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralCheckerBase* checker,
|
||||
if (in_class && !is_static && this->IsConstructor(name)) {
|
||||
*has_seen_constructor = true;
|
||||
kind = has_extends ? FunctionKind::kSubclassConstructor
|
||||
: FunctionKind::kNormalFunction;
|
||||
: FunctionKind::kBaseConstructor;
|
||||
}
|
||||
|
||||
value = this->ParseFunctionLiteral(
|
||||
@ -2838,7 +2839,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos,
|
||||
typename Traits::Type::Factory function_factory(this->ast_value_factory());
|
||||
FunctionState function_state(&function_state_, &scope_,
|
||||
Traits::Type::ptr_to_scope(scope),
|
||||
&function_factory);
|
||||
kArrowFunction, &function_factory);
|
||||
Scanner::Location dupe_error_loc = Scanner::Location::invalid();
|
||||
num_parameters = Traits::DeclareArrowParametersFromExpression(
|
||||
params_ast, scope_, &dupe_error_loc, ok);
|
||||
@ -2871,8 +2872,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos,
|
||||
} else {
|
||||
body = this->ParseEagerFunctionBody(
|
||||
this->EmptyIdentifier(), RelocInfo::kNoPosition, NULL,
|
||||
Token::INIT_VAR, false, // Not a generator.
|
||||
CHECK_OK);
|
||||
Token::INIT_VAR, kArrowFunction, CHECK_OK);
|
||||
materialized_literal_count =
|
||||
function_state.materialized_literal_count();
|
||||
expected_property_count = function_state.expected_property_count();
|
||||
|
@ -38,6 +38,15 @@ RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ThrowConstructorNonCallableError) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate,
|
||||
NewTypeError("constructor_noncallable", HandleVector<Object>(NULL, 0)));
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ToMethod) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 2);
|
||||
|
@ -186,18 +186,19 @@ namespace internal {
|
||||
/* Classes support */ \
|
||||
F(ToMethod, 2, 1) \
|
||||
F(HomeObjectSymbol, 0, 1) \
|
||||
F(DefaultConstructorSuperCall, 0, 1) \
|
||||
F(DefineClass, 6, 1) \
|
||||
F(DefineClassMethod, 3, 1) \
|
||||
F(ClassGetSourceCode, 1, 1) \
|
||||
F(ThrowNonMethodError, 0, 1) \
|
||||
F(ThrowUnsupportedSuperError, 0, 1) \
|
||||
F(LoadFromSuper, 3, 1) \
|
||||
F(LoadKeyedFromSuper, 3, 1) \
|
||||
F(ThrowConstructorNonCallableError, 0, 1) \
|
||||
F(ThrowNonMethodError, 0, 1) \
|
||||
F(ThrowUnsupportedSuperError, 0, 1) \
|
||||
F(StoreToSuper_Strict, 4, 1) \
|
||||
F(StoreToSuper_Sloppy, 4, 1) \
|
||||
F(StoreKeyedToSuper_Strict, 4, 1) \
|
||||
F(StoreKeyedToSuper_Sloppy, 4, 1) \
|
||||
F(DefaultConstructorSuperCall, 0, 1)
|
||||
F(StoreKeyedToSuper_Sloppy, 4, 1)
|
||||
|
||||
|
||||
#define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
|
||||
|
@ -34,15 +34,18 @@ class Subclass extends Base {
|
||||
let b = new Base(1, 2);
|
||||
assertSame(3, b.prp);
|
||||
|
||||
|
||||
let s = new Subclass(2, -1);
|
||||
assertSame(1, s.prp);
|
||||
assertSame(undefined, s.prp1);
|
||||
assertFalse(s.hasOwnProperty("prp1"));
|
||||
|
||||
class Subclass2 extends Base {
|
||||
constructor() {
|
||||
constructor(x) {
|
||||
super(1,2);
|
||||
|
||||
if (x < 0) return;
|
||||
|
||||
let called = false;
|
||||
function tmp() { called = true; return 3; }
|
||||
var exn = null;
|
||||
@ -54,4 +57,11 @@ class Subclass2 extends Base {
|
||||
}
|
||||
}
|
||||
|
||||
new Subclass2();
|
||||
var s2 = new Subclass2(1);
|
||||
assertSame(3, s2.prp);
|
||||
|
||||
var s3 = new Subclass2(-1);
|
||||
assertSame(3, s3.prp);
|
||||
|
||||
assertThrows(function() { Subclass.call(new Object(), 1, 2); }, TypeError);
|
||||
assertThrows(function() { Base.call(new Object(), 1, 2); }, TypeError);
|
||||
|
Loading…
Reference in New Issue
Block a user