Commit 2f66cb22 authored by Suraj Sharma's avatar Suraj Sharma Committed by Commit Bot

[inspector] Improve uninitialized binding error message

The program:

    foo;
    let foo = 5;

…now produces:

    ReferenceError: Cannot access 'foo' before initialization

…instead of:

    ReferenceError: foo is not defined

Bug: v8:6513, v8:6951
Change-Id: I6c372626734570d5abeb1d0196b814dde02b9e3e
Reviewed-on: https://chromium-review.googlesource.com/c/1441151Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarMathias Bynens <mathias@chromium.org>
Commit-Queue: Suraj Sharma <surshar@microsoft.com>
Commit-Queue: Mathias Bynens <mathias@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59307}
parent 4e07bfb0
...@@ -2168,7 +2168,7 @@ void BytecodeGraphBuilder::BuildHoleCheckAndThrow( ...@@ -2168,7 +2168,7 @@ void BytecodeGraphBuilder::BuildHoleCheckAndThrow(
bytecode_iterator().current_offset())); bytecode_iterator().current_offset()));
Node* node; Node* node;
const Operator* op = javascript()->CallRuntime(runtime_id); const Operator* op = javascript()->CallRuntime(runtime_id);
if (runtime_id == Runtime::kThrowReferenceError) { if (runtime_id == Runtime::kThrowAccessedUninitializedVariable) {
DCHECK_NOT_NULL(name); DCHECK_NOT_NULL(name);
node = NewNode(op, name); node = NewNode(op, name);
} else { } else {
...@@ -2190,7 +2190,8 @@ void BytecodeGraphBuilder::VisitThrowReferenceErrorIfHole() { ...@@ -2190,7 +2190,8 @@ void BytecodeGraphBuilder::VisitThrowReferenceErrorIfHole() {
jsgraph()->TheHoleConstant()); jsgraph()->TheHoleConstant());
Node* name = jsgraph()->Constant( Node* name = jsgraph()->Constant(
handle(bytecode_iterator().GetConstantForIndexOperand(0), isolate())); handle(bytecode_iterator().GetConstantForIndexOperand(0), isolate()));
BuildHoleCheckAndThrow(check_for_hole, Runtime::kThrowReferenceError, name); BuildHoleCheckAndThrow(check_for_hole,
Runtime::kThrowAccessedUninitializedVariable, name);
} }
void BytecodeGraphBuilder::VisitThrowSuperNotCalledIfHole() { void BytecodeGraphBuilder::VisitThrowSuperNotCalledIfHole() {
......
...@@ -2958,7 +2958,8 @@ IGNITION_HANDLER(ThrowReferenceErrorIfHole, InterpreterAssembler) { ...@@ -2958,7 +2958,8 @@ IGNITION_HANDLER(ThrowReferenceErrorIfHole, InterpreterAssembler) {
BIND(&throw_error); BIND(&throw_error);
{ {
Node* name = LoadConstantPoolEntryAtOperandIndex(0); Node* name = LoadConstantPoolEntryAtOperandIndex(0);
CallRuntime(Runtime::kThrowReferenceError, GetContext(), name); CallRuntime(Runtime::kThrowAccessedUninitializedVariable, GetContext(),
name);
// We shouldn't ever return from a throw. // We shouldn't ever return from a throw.
Abort(AbortReason::kUnexpectedReturnFromThrow); Abort(AbortReason::kUnexpectedReturnFromThrow);
Unreachable(); Unreachable();
......
...@@ -292,6 +292,7 @@ namespace internal { ...@@ -292,6 +292,7 @@ namespace internal {
/* ReferenceError */ \ /* ReferenceError */ \
T(NotDefined, "% is not defined") \ T(NotDefined, "% is not defined") \
T(SuperAlreadyCalled, "Super constructor may only be called once") \ T(SuperAlreadyCalled, "Super constructor may only be called once") \
T(AccessedUninitializedVariable, "Cannot access '%' before initialization") \
T(UnsupportedSuper, "Unsupported reference to 'super'") \ T(UnsupportedSuper, "Unsupported reference to 'super'") \
/* RangeError */ \ /* RangeError */ \
T(BigIntDivZero, "Division by zero") \ T(BigIntDivZero, "Division by zero") \
......
...@@ -157,6 +157,15 @@ RUNTIME_FUNCTION(Runtime_ThrowReferenceError) { ...@@ -157,6 +157,15 @@ RUNTIME_FUNCTION(Runtime_ThrowReferenceError) {
isolate, NewReferenceError(MessageTemplate::kNotDefined, name)); isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
} }
RUNTIME_FUNCTION(Runtime_ThrowAccessedUninitializedVariable) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewReferenceError(MessageTemplate::kAccessedUninitializedVariable, name));
}
RUNTIME_FUNCTION(Runtime_NewTypeError) { RUNTIME_FUNCTION(Runtime_NewTypeError) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(2, args.length()); DCHECK_EQ(2, args.length());
......
...@@ -124,6 +124,7 @@ bool Runtime::NeedsExactContext(FunctionId id) { ...@@ -124,6 +124,7 @@ bool Runtime::NeedsExactContext(FunctionId id) {
case Runtime::kThrowNotConstructor: case Runtime::kThrowNotConstructor:
case Runtime::kThrowRangeError: case Runtime::kThrowRangeError:
case Runtime::kThrowReferenceError: case Runtime::kThrowReferenceError:
case Runtime::kThrowAccessedUninitializedVariable:
case Runtime::kThrowStackOverflow: case Runtime::kThrowStackOverflow:
case Runtime::kThrowStaticPrototypeError: case Runtime::kThrowStaticPrototypeError:
case Runtime::kThrowSuperAlreadyCalledError: case Runtime::kThrowSuperAlreadyCalledError:
...@@ -163,6 +164,7 @@ bool Runtime::IsNonReturning(FunctionId id) { ...@@ -163,6 +164,7 @@ bool Runtime::IsNonReturning(FunctionId id) {
case Runtime::kThrowNotConstructor: case Runtime::kThrowNotConstructor:
case Runtime::kThrowRangeError: case Runtime::kThrowRangeError:
case Runtime::kThrowReferenceError: case Runtime::kThrowReferenceError:
case Runtime::kThrowAccessedUninitializedVariable:
case Runtime::kThrowStackOverflow: case Runtime::kThrowStackOverflow:
case Runtime::kThrowSymbolAsyncIteratorInvalid: case Runtime::kThrowSymbolAsyncIteratorInvalid:
case Runtime::kThrowTypeError: case Runtime::kThrowTypeError:
......
...@@ -242,6 +242,7 @@ namespace internal { ...@@ -242,6 +242,7 @@ namespace internal {
F(ThrowPatternAssignmentNonCoercible, 0, 1) \ F(ThrowPatternAssignmentNonCoercible, 0, 1) \
F(ThrowRangeError, -1 /* >= 1 */, 1) \ F(ThrowRangeError, -1 /* >= 1 */, 1) \
F(ThrowReferenceError, 1, 1) \ F(ThrowReferenceError, 1, 1) \
F(ThrowAccessedUninitializedVariable, 1, 1) \
F(ThrowStackOverflow, 0, 1) \ F(ThrowStackOverflow, 0, 1) \
F(ThrowSymbolAsyncIteratorInvalid, 0, 1) \ F(ThrowSymbolAsyncIteratorInvalid, 0, 1) \
F(ThrowSymbolIteratorInvalid, 0, 1) \ F(ThrowSymbolIteratorInvalid, 0, 1) \
......
...@@ -2891,7 +2891,7 @@ TEST(BytecodeGraphBuilderIllegalConstDeclaration) { ...@@ -2891,7 +2891,7 @@ TEST(BytecodeGraphBuilderIllegalConstDeclaration) {
ExpectedSnippet<0, const char*> illegal_const_decl[] = { ExpectedSnippet<0, const char*> illegal_const_decl[] = {
{"const x = x = 10 + 3; return x;", {"const x = x = 10 + 3; return x;",
{"Uncaught ReferenceError: x is not defined"}}, {"Uncaught ReferenceError: Cannot access 'x' before initialization"}},
{"const x = 10; x = 20; return x;", {"const x = 10; x = 20; return x;",
{"Uncaught TypeError: Assignment to constant variable."}}, {"Uncaught TypeError: Assignment to constant variable."}},
{"const x = 10; { x = 20; } return x;", {"const x = 10; { x = 20; } return x;",
...@@ -2899,7 +2899,7 @@ TEST(BytecodeGraphBuilderIllegalConstDeclaration) { ...@@ -2899,7 +2899,7 @@ TEST(BytecodeGraphBuilderIllegalConstDeclaration) {
{"const x = 10; eval('x = 20;'); return x;", {"const x = 10; eval('x = 20;'); return x;",
{"Uncaught TypeError: Assignment to constant variable."}}, {"Uncaught TypeError: Assignment to constant variable."}},
{"let x = x + 10; return x;", {"let x = x + 10; return x;",
{"Uncaught ReferenceError: x is not defined"}}, {"Uncaught ReferenceError: Cannot access 'x' before initialization"}},
{"'use strict'; (function f1() { f1 = 123; })() ", {"'use strict'; (function f1() { f1 = 123; })() ",
{"Uncaught TypeError: Assignment to constant variable."}}, {"Uncaught TypeError: Assignment to constant variable."}},
}; };
......
...@@ -4944,7 +4944,7 @@ TEST(InterpreterIllegalConstDeclaration) { ...@@ -4944,7 +4944,7 @@ TEST(InterpreterIllegalConstDeclaration) {
std::pair<const char*, const char*> const_decl[] = { std::pair<const char*, const char*> const_decl[] = {
{"const x = x = 10 + 3; return x;", {"const x = x = 10 + 3; return x;",
"Uncaught ReferenceError: x is not defined"}, "Uncaught ReferenceError: Cannot access 'x' before initialization"},
{"const x = 10; x = 20; return x;", {"const x = 10; x = 20; return x;",
"Uncaught TypeError: Assignment to constant variable."}, "Uncaught TypeError: Assignment to constant variable."},
{"const x = 10; { x = 20; } return x;", {"const x = 10; { x = 20; } return x;",
...@@ -4952,7 +4952,7 @@ TEST(InterpreterIllegalConstDeclaration) { ...@@ -4952,7 +4952,7 @@ TEST(InterpreterIllegalConstDeclaration) {
{"const x = 10; eval('x = 20;'); return x;", {"const x = 10; eval('x = 20;'); return x;",
"Uncaught TypeError: Assignment to constant variable."}, "Uncaught TypeError: Assignment to constant variable."},
{"let x = x + 10; return x;", {"let x = x + 10; return x;",
"Uncaught ReferenceError: x is not defined"}, "Uncaught ReferenceError: Cannot access 'x' before initialization"},
{"'use strict'; (function f1() { f1 = 123; })() ", {"'use strict'; (function f1() { f1 = 123; })() ",
"Uncaught TypeError: Assignment to constant variable."}, "Uncaught TypeError: Assignment to constant variable."},
}; };
......
*%(basename)s:7: ReferenceError: a is not defined *%(basename)s:7: ReferenceError: Cannot access 'a' before initialization
((a=-a) => { })(); ((a=-a) => { })();
^ ^
ReferenceError: a is not defined ReferenceError: Cannot access 'a' before initialization
at *%(basename)s:7:6 at *%(basename)s:7:6
at *%(basename)s:7:16 at *%(basename)s:7:16
*%(basename)s:7: ReferenceError: a is not defined *%(basename)s:7: ReferenceError: Cannot access 'a' before initialization
(function(a=+a) { })(); (function(a=+a) { })();
^ ^
ReferenceError: a is not defined ReferenceError: Cannot access 'a' before initialization
at *%(basename)s:7:14 at *%(basename)s:7:14
at *%(basename)s:7:21 at *%(basename)s:7:21
...@@ -108,8 +108,8 @@ PASS 'use strict'; var VarA = class A { constructor() {} }; var VarB = class B e ...@@ -108,8 +108,8 @@ PASS 'use strict'; var VarA = class A { constructor() {} }; var VarB = class B e
Class statement binding in other circumstances Class statement binding in other circumstances
PASS var result = A; result threw exception ReferenceError: A is not defined. PASS var result = A; result threw exception ReferenceError: A is not defined.
PASS 'use strict'; var result = A; result threw exception ReferenceError: A is not defined. PASS 'use strict'; var result = A; result threw exception ReferenceError: A is not defined.
PASS var result = A; class A {}; result threw exception ReferenceError: A is not defined. PASS var result = A; class A {}; result threw exception ReferenceError: Cannot access 'A' before initialization.
PASS 'use strict'; var result = A; class A {}; result threw exception ReferenceError: A is not defined. PASS 'use strict'; var result = A; class A {}; result threw exception ReferenceError: Cannot access 'A' before initialization.
PASS class A { constructor() { A = 1; } }; new A threw exception TypeError: Assignment to constant variable.. PASS class A { constructor() { A = 1; } }; new A threw exception TypeError: Assignment to constant variable..
PASS 'use strict'; class A { constructor() { A = 1; } }; new A threw exception TypeError: Assignment to constant variable.. PASS 'use strict'; class A { constructor() { A = 1; } }; new A threw exception TypeError: Assignment to constant variable..
PASS class A { constructor() { } }; A = 1; A is 1 PASS class A { constructor() { } }; A = 1; A is 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