Commit f668e9f7 authored by Joyee Cheung's avatar Joyee Cheung Committed by V8 LUCI CQ

Revert "[class] implement reparsing of class instance member initializers"

This reverts commit 91f08378.

Reason for revert: It's a fairly big change, and the clusterfuzz
found some bugs. Will reland with the fix after M98 branch point.

Original change's description:
> [class] implement reparsing of class instance member initializers
>
> Previously, since the source code for the synthetic class instance
> member initializer function was recorded as the span from the first
> initializer to the last initializer, there was no way to reparse the
> class and recompile the initializer function. It was working for
> most use cases because the code for the initializer function was
> generated eagarly and it was usually alive as long as the class was
> alive, so the initializer wouldn't normally be lazily parsed. This
> didn't work, however, when the class was snapshotted with
> v8::SnapshotCreator::FunctionCodeHandling::kClear,
> becuase then we needed to recompile the initializer when the class
> was instantiated. This patch implements the reparsing so that
> these classes can work with FunctionCodeHandling::kClear.
>
> This patch refactors ParserBase::ParseClassLiteral() so that we can
> reuse it for both parsing the class body normally and reparsing it
> to collect initializers. When reparsing the synthetic initializer
> function, we rewind the scanner to the beginning of the class, and
> parse the class body to collect the initializers. During the
> reparsing, field initializers are parsed with the full parser while
> methods of the class are pre-parsed.
>
> A few notable changes:
>
> - Extended the source range of the initializer function to cover the
>   entire class so that we can rewind the scanner to parse the class
>   body to collect initializers (previously, it starts from the first
>   field initializer and ends at the last initializer). This resulted
>   some expectation changes in the debugger tests, though the
>   initializers remain debuggable.
> - A temporary ClassScope is created during reparsing. After the class
>   is reparsed, we use the information from the ScopeInfo to update
>   the allocated indices of the variables in the ClassScope.
>
> Bug: v8:10704
> Change-Id: Ifb6431a1447d8844f2a548283d59158742fe9027
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2988830
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Toon Verwaest <verwaest@chromium.org>
> Commit-Queue: Joyee Cheung <joyee@igalia.com>
> Cr-Commit-Position: refs/heads/main@{#78299}

Bug: v8:10704
Change-Id: I039cb728ebf0ada438a8f26c7d2c2547dbe3bf2d
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3325328
Auto-Submit: Joyee Cheung <joyee@igalia.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78315}
parent e8ea622d
......@@ -521,15 +521,6 @@ template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
DeclarationScope* script_scope, AstValueFactory* ast_value_factory,
DeserializationMode deserialization_mode);
#ifdef DEBUG
bool Scope::IsReparsedMemberInitializerScope() const {
return is_declaration_scope() &&
IsClassMembersInitializerFunction(
AsDeclarationScope()->function_kind()) &&
outer_scope()->AsClassScope()->is_reparsed_class_scope();
}
#endif
DeclarationScope* Scope::AsDeclarationScope() {
DCHECK(is_declaration_scope());
return static_cast<DeclarationScope*>(this);
......@@ -673,10 +664,8 @@ bool DeclarationScope::Analyze(ParseInfo* info) {
// We are compiling one of four cases:
// 1) top-level code,
// 2) a function/eval/module on the top-level
// 4) a class member initializer function scope
// 3) 4 function/eval in a scope that was already resolved.
// 3) a function/eval in a scope that was already resolved.
DCHECK(scope->is_script_scope() || scope->outer_scope()->is_script_scope() ||
scope->IsReparsedMemberInitializerScope() ||
scope->outer_scope()->already_resolved_);
// The outer scope is never lazy.
......@@ -1904,8 +1893,6 @@ void Scope::Print(int n) {
if (scope->needs_private_name_context_chain_recalc()) {
Indent(n1, "// needs #-name context chain recalc\n");
}
Indent(n1, "// ");
PrintF("%s\n", FunctionKind2String(scope->function_kind()));
}
if (num_stack_slots_ > 0) {
Indent(n1, "// ");
......@@ -2695,55 +2682,6 @@ bool IsComplementaryAccessorPair(VariableMode a, VariableMode b) {
}
}
void ClassScope::ReplaceReparsedClassScope(Isolate* isolate,
AstValueFactory* ast_value_factory,
ClassScope* old_scope) {
DCHECK_EQ(outer_scope_, old_scope->outer_scope());
Scope* outer = outer_scope_;
outer->RemoveInnerScope(old_scope);
// The outer scope should only have this deserialized inner scope,
// otherwise we have to update the sibling scopes.
DCHECK_EQ(outer->inner_scope_, this);
DCHECK_NULL(sibling_);
DCHECK_NULL(old_scope->inner_scope_);
Handle<ScopeInfo> scope_info = old_scope->scope_info_;
DCHECK(!scope_info.is_null());
DCHECK(!scope_info->IsEmpty());
// Restore variable allocation results for context-allocated variables in
// the class scope from ScopeInfo, so that we don't need to run
// resolution and allocation on these variables again when generating
// code for the initializer function.
int context_local_count = scope_info->ContextLocalCount();
int context_header_length = scope_info->ContextHeaderLength();
DisallowGarbageCollection no_gc;
for (int i = 0; i < context_local_count; ++i) {
int slot_index = context_header_length + i;
DCHECK_LT(slot_index, scope_info->ContextLength());
String name = scope_info->ContextLocalName(i);
const AstRawString* string = ast_value_factory->GetString(
name, SharedStringAccessGuardIfNeeded(isolate));
Variable* var = nullptr;
var = string->IsPrivateName() ? LookupLocalPrivateName(string)
: LookupLocal(string);
DCHECK_NOT_NULL(var);
var->AllocateTo(VariableLocation::CONTEXT, slot_index);
}
scope_info_ = scope_info;
// Set this bit so that DelcarationScope::Analyze recognizes
// the reparsed instance member initializer scope.
#ifdef DEBUG
is_reparsed_class_scope_ = true;
#endif
}
Variable* ClassScope::DeclarePrivateName(const AstRawString* name,
VariableMode mode,
IsStaticFlag is_static_flag,
......
......@@ -424,9 +424,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
return num_heap_slots() > 0;
}
#ifdef DEBUG
bool IsReparsedMemberInitializerScope() const;
#endif
// Use Scope::ForEach for depth first traversal of scopes.
// Before:
// void Scope::VisitRecursively() {
......@@ -1477,13 +1474,6 @@ class V8_EXPORT_PRIVATE ClassScope : public Scope {
should_save_class_variable_index_ = true;
}
void ReplaceReparsedClassScope(Isolate* isolate,
AstValueFactory* ast_value_factory,
ClassScope* old_scope);
#ifdef DEBUG
bool is_reparsed_class_scope() const { return is_reparsed_class_scope_; }
#endif
private:
friend class Scope;
friend class PrivateNameScopeIterator;
......@@ -1529,9 +1519,6 @@ class V8_EXPORT_PRIVATE ClassScope : public Scope {
// This is only maintained during reparsing, restored from the
// preparsed data.
bool should_save_class_variable_index_ = false;
#ifdef DEBUG
bool is_reparsed_class_scope_ = false;
#endif
};
// Iterate over the private name scope chain. The iteration proceeds from the
......
......@@ -196,7 +196,7 @@
V(_, dot_home_object_string, ".home_object") \
V(_, dot_result_string, ".result") \
V(_, dot_repl_result_string, ".repl_result") \
V(_, dot_static_home_object_string, ".static_home_object") \
V(_, dot_static_home_object_string, "._static_home_object") \
V(_, dot_string, ".") \
V(_, dot_switch_tag_string, ".switch_tag") \
V(_, dotAll_string, "dotAll") \
......
......@@ -2813,7 +2813,6 @@ void BytecodeGenerator::BuildClassProperty(ClassLiteral::Property* property) {
// Private methods are not initialized in BuildClassProperty.
DCHECK_IMPLIES(property->is_private(),
property->kind() == ClassLiteral::Property::FIELD);
builder()->SetExpressionPosition(property->key());
bool is_literal_store = property->key()->IsPropertyName() &&
!property->is_computed_name() &&
......
......@@ -1238,10 +1238,6 @@ class ParserBase {
Scanner::Location class_name_location,
bool name_is_strict_reserved,
int class_token_pos);
ExpressionT DoParseClassLiteral(ClassScope* class_scope, IdentifierT name,
Scanner::Location class_name_location,
bool is_anonymous, int class_token_pos);
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool tagged);
ExpressionT ParseSuperExpression();
ExpressionT ParseImportExpressions();
......@@ -2526,6 +2522,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer(
if (initializer_scope == nullptr) {
initializer_scope = NewFunctionScope(function_kind);
// TODO(gsathya): Make scopes be non contiguous.
initializer_scope->set_start_position(beg_pos);
initializer_scope->SetLanguageMode(LanguageMode::kStrict);
}
......@@ -2540,13 +2538,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer(
initializer = factory()->NewUndefinedLiteral(kNoSourcePosition);
}
initializer_scope->set_end_position(end_position());
if (is_static) {
// For the instance initializer, we will save the positions
// later with the positions of the class body so that we can reparse
// it later.
// TODO(joyee): Make scopes be non contiguous.
initializer_scope->set_start_position(beg_pos);
initializer_scope->set_end_position(end_position());
class_info->static_elements_scope = initializer_scope;
class_info->has_static_elements = true;
} else {
......@@ -4688,15 +4681,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
}
ClassScope* class_scope = NewClassScope(scope(), is_anonymous);
return DoParseClassLiteral(class_scope, name, class_name_location,
is_anonymous, class_token_pos);
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::DoParseClassLiteral(
ClassScope* class_scope, IdentifierT name,
Scanner::Location class_name_location, bool is_anonymous,
int class_token_pos) {
BlockState block_state(&scope_, class_scope);
RaiseLanguageMode(LanguageMode::kStrict);
......@@ -4783,12 +4767,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::DoParseClassLiteral(
Expect(Token::RBRACE);
int end_pos = end_position();
class_scope->set_end_position(end_pos);
if (class_info.instance_members_scope != nullptr) {
// Use the positions of the class body for the instance initializer
// function so that we can reparse it later.
class_info.instance_members_scope->set_start_position(class_token_pos);
class_info.instance_members_scope->set_end_position(end_pos);
}
VariableProxy* unresolvable = class_scope->ResolvePrivateNamesPartially();
if (unresolvable != nullptr) {
......
......@@ -863,13 +863,11 @@ void Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
// function is in heritage position. Otherwise the function scope's skip bit
// will be correctly inherited from the outer scope.
ClassScope::HeritageParsingScope heritage(original_scope_->AsClassScope());
result = DoParseDeserializedFunction(
isolate, shared_info, info, start_position, end_position,
function_literal_id, info->function_name());
result = DoParseFunction(isolate, info, start_position, end_position,
function_literal_id, info->function_name());
} else {
result = DoParseDeserializedFunction(
isolate, shared_info, info, start_position, end_position,
function_literal_id, info->function_name());
result = DoParseFunction(isolate, info, start_position, end_position,
function_literal_id, info->function_name());
}
MaybeProcessSourceRanges(info, result, stack_limit_);
if (result != nullptr) {
......@@ -1032,103 +1030,6 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
return result;
}
FunctionLiteral* Parser::DoParseDeserializedFunction(
Isolate* isolate, Handle<SharedFunctionInfo> shared_info, ParseInfo* info,
int start_position, int end_position, int function_literal_id,
const AstRawString* raw_name) {
if (flags().function_kind() !=
FunctionKind::kClassMembersInitializerFunction) {
return DoParseFunction(isolate, info, start_position, end_position,
function_literal_id, raw_name);
}
// Reparse the outer class while skipping the non-fields to get a list of
// ClassLiteralProperty and create a InitializeClassMembersStatement for
// the synthetic instance initializer function.
FunctionLiteral* result = ParseClassForInstanceMemberInitialization(
isolate, original_scope_->AsClassScope(), start_position,
function_literal_id);
DCHECK_EQ(result->kind(), FunctionKind::kClassMembersInitializerFunction);
DCHECK_EQ(result->function_literal_id(), function_literal_id);
DCHECK_EQ(result->end_position(), shared_info->EndPosition());
// The private_name_lookup_skips_outer_class bit should be set by
// PostProcessParseResult() during scope analysis later.
return result;
}
FunctionLiteral* Parser::ParseClassForInstanceMemberInitialization(
Isolate* isolate, ClassScope* original_scope, int initializer_pos,
int initializer_id) {
int class_token_pos = initializer_pos;
// Insert a FunctionState with the closest outer Declaration scope
DeclarationScope* nearest_decl_scope = original_scope->GetDeclarationScope();
DCHECK_NOT_NULL(nearest_decl_scope);
FunctionState function_state(&function_state_, &scope_, nearest_decl_scope);
// We will reindex the function literals later.
ResetFunctionLiteralId();
// We preparse the class members that are not fields with initializers
// in order to collect the function literal ids.
ParsingModeScope mode(this, PARSE_LAZILY);
ExpressionParsingScope no_expression_scope(impl());
// We will reparse the entire class because we want to know if
// the class is anonymous.
// When the function is a kClassMembersInitializerFunction, we record the
// source range of the entire class as its positions in its SFI, so at this
// point the scanner should be rewound to the position of the class token.
DCHECK_EQ(peek(), Token::CLASS);
Expect(Token::CLASS);
const AstRawString* class_name = NullIdentifier();
const AstRawString* variable_name = NullIdentifier();
// It's a reparse so we don't need to check for default export or
// whether the names are reserved.
if (peek() == Token::EXTENDS || peek() == Token::LBRACE) {
GetDefaultStrings(&class_name, &variable_name);
} else {
class_name = ParseIdentifier();
variable_name = class_name;
}
bool is_anonymous = class_name == nullptr || class_name->IsEmpty();
// Create a new ClassScope for the parser to create the inner scopes,
// the variable resolution would be done in the original scope, however.
// TODO(joyee): see if we can reset the original scope to a state that
// can be reused directly and avoid creating this temporary scope.
ClassScope* reparsed_scope =
NewClassScope(original_scope->outer_scope(), is_anonymous);
#ifdef DEBUG
original_scope->SetScopeName(class_name);
#endif
Expression* expr =
DoParseClassLiteral(reparsed_scope, class_name, scanner()->location(),
is_anonymous, class_token_pos);
DCHECK(expr->IsClassLiteral());
ClassLiteral* literal = expr->AsClassLiteral();
FunctionLiteral* initializer =
literal->instance_members_initializer_function();
// Reindex so that the function literal ids match.
AstFunctionLiteralIdReindexer reindexer(
stack_limit_, initializer_id - initializer->function_literal_id());
reindexer.Reindex(expr);
no_expression_scope.ValidateExpression();
// Fix up the scope chain and the references used by the instance member
// initializer.
reparsed_scope->ReplaceReparsedClassScope(isolate, ast_value_factory(),
original_scope);
original_scope_ = reparsed_scope;
return initializer;
}
Statement* Parser::ParseModuleItem() {
// ecma262/#prod-ModuleItem
// ModuleItem :
......@@ -3221,9 +3122,7 @@ FunctionLiteral* Parser::CreateInitializerFunction(
FunctionSyntaxKind::kAccessorOrMethod,
FunctionLiteral::kShouldEagerCompile, scope->start_position(), false,
GetNextFunctionLiteralId());
#ifdef DEBUG
scope->SetScopeName(ast_value_factory()->GetOneByteString(name));
#endif
RecordFunctionLiteralSourceRange(result);
return result;
......
......@@ -237,15 +237,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
int function_literal_id,
const AstRawString* raw_name);
FunctionLiteral* DoParseDeserializedFunction(
Isolate* isolate, Handle<SharedFunctionInfo> shared_info, ParseInfo* info,
int start_position, int end_position, int function_literal_id,
const AstRawString* raw_name);
FunctionLiteral* ParseClassForInstanceMemberInitialization(
Isolate* isolate, ClassScope* scope, int initializer_pos,
int initializer_id);
// Called by ParseProgram after setting up the scanner.
FunctionLiteral* DoParseProgram(Isolate* isolate, ParseInfo* info);
......
This diff is collapsed.
......@@ -22,41 +22,41 @@ var b1, b2, b3;
// y = [B1]2;
// z = [B2]3;
// }
b1 = Debug.setBreakPoint(initializer, 1, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") > 0);
b1 = Debug.setBreakPoint(initializer, 0, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === 0);
Debug.clearBreakPoint(b1);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === -1);
b2 = Debug.setBreakPoint(initializer, 2, 0);
b2 = Debug.setBreakPoint(initializer, 1, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") > 0);
Debug.clearBreakPoint(b2);
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") === -1);
b3 = Debug.setBreakPoint(initializer, 3, 0);
b3 = Debug.setBreakPoint(initializer, 2, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B0]3") > 0);
Debug.clearBreakPoint(b3);
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B0]3") === -1);
b1 = Debug.setBreakPoint(initializer, 1, 0);
b2 = Debug.setBreakPoint(initializer, 2, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") > 0);
b1 = Debug.setBreakPoint(initializer, 0, 0);
b2 = Debug.setBreakPoint(initializer, 1, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B1]2;") > 0);
Debug.clearBreakPoint(b1);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === -1);
Debug.clearBreakPoint(b2);
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B1]2;") === -1);
b1 = Debug.setBreakPoint(initializer, 1, 0);
b3 = Debug.setBreakPoint(initializer, 3, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") > 0);
b1 = Debug.setBreakPoint(initializer, 0, 0);
b3 = Debug.setBreakPoint(initializer, 2, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") > 0);
Debug.clearBreakPoint(b1);
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === -1);
Debug.clearBreakPoint(b3);
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") === -1);
b2 = Debug.setBreakPoint(initializer, 2, 0);
b3 = Debug.setBreakPoint(initializer, 3, 0);
b2 = Debug.setBreakPoint(initializer, 1, 0);
b3 = Debug.setBreakPoint(initializer, 2, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") > 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") > 0);
Debug.clearBreakPoint(b2);
......@@ -83,11 +83,11 @@ class X {
// }
initializer = %GetInitializerFunction(X);
b1 = Debug.setBreakPoint(initializer, 1, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf('[foo()] = 1;') > 0);
b1 = Debug.setBreakPoint(initializer, 0, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf('[foo()] = 1;') === 0);
Debug.clearBreakPoint(b1);
b1 = Debug.setBreakPoint(initializer, 2, 0);
b1 = Debug.setBreakPoint(initializer, 1, 0);
assertTrue(Debug.showBreakPoints(initializer).indexOf('baz = [B0]foo()') > 0);
Debug.clearBreakPoint(b1);
......
......@@ -90,8 +90,8 @@ Running test: testScopesPaused
scopeChain : [
[0] : {
endLocation : {
columnNumber : 3
lineNumber : 15
columnNumber : 13
lineNumber : 14
scriptId : <scriptId>
}
name : run
......@@ -102,8 +102,8 @@ Running test: testScopesPaused
type : object
}
startLocation : {
columnNumber : 2
lineNumber : 11
columnNumber : 4
lineNumber : 12
scriptId : <scriptId>
}
type : local
......@@ -183,8 +183,8 @@ Running test: testScopesPaused
[0] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 2
lineNumber : 11
columnNumber : 4
lineNumber : 12
scriptId : <scriptId>
}
functionName : <instance_members_initializer>
......@@ -364,8 +364,8 @@ Running test: testScopesPaused
[0] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 2
lineNumber : 11
columnNumber : 4
lineNumber : 12
scriptId : <scriptId>
}
functionName : <instance_members_initializer>
......@@ -545,8 +545,8 @@ Running test: testScopesPaused
[0] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 2
lineNumber : 11
columnNumber : 4
lineNumber : 12
scriptId : <scriptId>
}
functionName : <instance_members_initializer>
......@@ -798,8 +798,8 @@ Running test: testScopesPaused
[1] : {
callFrameId : <callFrameId>
functionLocation : {
columnNumber : 2
lineNumber : 11
columnNumber : 4
lineNumber : 12
scriptId : <scriptId>
}
functionName : <instance_members_initializer>
......
......@@ -7,23 +7,23 @@ let x = |R|class {}
|_|x = |R|class {
x = |_|1;
y = |_|2;
}|R|
y = |_|2|R|;
}
|_|x = |R|class {
x = |C|foo();
y = |_|2;
z = |C|bar();
}|R|
z = |C|bar()|R|;
}
|_|x = class {
x = |C|foo();
y = |_|2;
z = |C|bar();
z = |C|bar()|R|;
constructor() {
this.|_|x;
|R|}
}|R|
}
|_|x = class {
x = |C|foo();
......@@ -31,8 +31,8 @@ let x = |R|class {}
constructor() {
this.|_|x;
|R|}
z = |C|bar();
}|R|
z = |C|bar()|R|;
}
|_|x = class {
x = |C|foo();
......@@ -40,14 +40,14 @@ let x = |R|class {}
constructor() {
this.|_|x;
|R|}
z = |C|bar();
}|R|
z = |C|bar()|R|;
}
|_|x = |R|class {
x = |_|1;
foo() {|R|}
y = |_|2;
}|R|
y = |_|2|R|;
}
|_|x = |R|class {
x = (function() {
......@@ -55,54 +55,54 @@ let x = |R|class {}
|R|})|C|();
y = (() => {
|C|bar();
|R|})|C|();
}|R|
|R|})|C|()|R|;
}
|_|x = |R|class {
x = |_|function() {
|C|foo();
|R|};
}|R|
|R|}|R|;
}
|_|x = |R|class {
x = |_|async function() {
|_|await |C|foo();
|R|};
}|R|
|R|}|R|;
}
|_|x = |R|class {
x = |_|() => {
|C|foo();
|R|};
y = |_|() => |C|bar()|R|;
}|R|
}
|_|x = |R|class {
x = |_|async () => {
|_|await |C|foo();
|R|};
y = |_|async () => |_|await |C|bar()|R|;
}|R|
}
|_|x = |R|class {
[|_|x] = |_|1;
[|C|foo()] = |_|2;
}|R|
[|C|foo()] = |_|2|R|;
}
|_|x = |R|class {
[|_|x] = |_|[...this];
}|R|
[|_|x] = |_|[...this]|R|;
}
|_|x = |R|class {
x;
[|C|foo()];
}|R|
[|C|foo()]|R|;
}
|_|x = |R|class {
x = |_|function*|_|() {
|_|yield 1;
|R|};
}|R|
|R|}|R|;
}
|_|x = |R|class {
static x = |_|1;
......@@ -201,6 +201,6 @@ let x = |R|class {}
static [|_|z] = |_|3;
[|_|p] = |_|4;
static [|C|foo()] = |_|5|R|;
[|C|bar()] = |_|6;
}|R|
[|C|bar()] = |_|6|R|;
}
|R|
......@@ -25,7 +25,7 @@ class X { // 000
}; // 100
`,
[{"start":0,"end":149,"count":1},
{"start":0,"end":101,"count":0}]
{"start":52,"end":70,"count":0}]
);
TestCoverage(
......@@ -37,7 +37,7 @@ class X { // 000
let x = new X(); // 150
`,
[{"start":0,"end":199,"count":1},
{"start":0,"end":101,"count":1},
{"start":52,"end":70,"count":1},
{"start":56,"end":70,"count":0}]
);
......@@ -51,7 +51,7 @@ let x = new X(); // 150
x.x(); // 200
`,
[{"start":0,"end":249,"count":1},
{"start":0,"end":101,"count":1},
{"start":52,"end":70,"count":1},
{"start":56,"end":70,"count":1}]
);
......@@ -68,7 +68,7 @@ x.x(); // 300
x.y(); // 350
`,
[{"start":0,"end":399,"count":1},
{"start":0,"end":201,"count":1},
{"start":52,"end":169,"count":1},
{"start":56,"end":70,"count":1},
{"start":102,"end":111,"count":0},
{"start":156,"end":169,"count":1}]
......@@ -88,7 +88,7 @@ x.y(); // 350
x.foo(); // 400
`,
[{"start":0,"end":449,"count":1},
{"start":0,"end":201,"count":1},
{"start":52,"end":169,"count":1},
{"start":56,"end":70,"count":1},
{"start":102,"end":111,"count":1},
{"start":156,"end":169,"count":1}]
......@@ -103,7 +103,7 @@ class X { // 000
let x = new X(); // 150
`,
[{"start":0,"end":199,"count":1},
{"start":0,"end":101,"count":1},
{"start":52,"end":74,"count":1},
{"start":57,"end":71,"count":1}]
);
......@@ -118,7 +118,7 @@ let x = new X(); // 200
`,
[{"start":0,"end":249,"count":1},
{"start":0,"end":15,"count":1},
{"start":50,"end":151,"count":1},
{"start":102,"end":128,"count":1},
{"start":111,"end":125,"count":1}]
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment