Commit bc2c785c authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[parser] Better error message when destructuring against undefined/null

Previously, when destructuring against null or undefined we would
print:

  d8> var { x } = null
  (d8):1: TypeError: Cannot match against 'undefined' or 'null'.
  var { x } = null
  ^
  TypeError: Cannot match against 'undefined' or 'null'.
      at (d8):1:1


The above message uses the term "match" which isn't a common term in
JavaScript to describe destructuring. This message also doesn't
provide the name of the property that fails destructuring.

This patch changes the error message to be:

  d8> var { x } = null;
  (d8):1: TypeError: Cannot destructure property `x` of 'undefined' or 'null'.
  var { x } = null;
        ^
  TypeError: Cannot destructure property `x` of 'undefined' or 'null'.
      at (d8):1:1

This patch changes the message to say "destructure" instead of "match".

This patch adds support for printing property names that are string
literals. We iterate through every property and pick the first string
literal property name if it exists. This provides at least some
feedback to the developer.

This patch also makes the pointer point to the position of the
property name that fails destructuring.

For computed and numeric property names, we print a generic error:
  d8> var { 1: x } = null
  (d8):1: TypeError: Cannot destructure against 'undefined' or 'null'.
  var { 1: x } = null
  ^
  TypeError: Cannot destructure against 'undefined' or 'null'.
      at (d8):1:1

Bug: v8:6499
Change-Id: I35b1ac749489828686f042975294b9926e2dfc53
Reviewed-on: https://chromium-review.googlesource.com/537341Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45965}
parent 390ad8c5
......@@ -330,7 +330,9 @@ class ErrorUtils : public AllStatic {
T(NoAccess, "no access") \
T(NonCallableInInstanceOfCheck, \
"Right-hand side of 'instanceof' is not callable") \
T(NonCoercible, "Cannot match against 'undefined' or 'null'.") \
T(NonCoercible, "Cannot destructure 'undefined' or 'null'.") \
T(NonCoercibleWithProperty, \
"Cannot destructure property `%` of 'undefined' or 'null'.") \
T(NonExtensibleProto, "% is not extensible") \
T(NonObjectInInstanceOfCheck, \
"Right-hand side of 'instanceof' is not an object") \
......
......@@ -2908,10 +2908,22 @@ Parser::LazyParsingResult Parser::SkipFunction(FunctionKind kind,
return kLazyParsingComplete;
}
Statement* Parser::BuildAssertIsCoercible(Variable* var) {
Statement* Parser::BuildAssertIsCoercible(Variable* var,
ObjectLiteral* pattern) {
// if (var === null || var === undefined)
// throw /* type error kNonCoercible) */;
auto source_position = pattern->position();
const AstRawString* property = ast_value_factory()->empty_string();
MessageTemplate::Template msg = MessageTemplate::kNonCoercible;
for (ObjectLiteralProperty* literal_property : *pattern->properties()) {
Expression* key = literal_property->key();
if (key->IsPropertyName()) {
property = key->AsLiteral()->AsRawPropertyName();
msg = MessageTemplate::kNonCoercibleWithProperty;
source_position = key->position();
break;
}
}
Expression* condition = factory()->NewBinaryOperation(
Token::OR,
......@@ -2923,8 +2935,7 @@ Statement* Parser::BuildAssertIsCoercible(Variable* var) {
factory()->NewNullLiteral(kNoSourcePosition), kNoSourcePosition),
kNoSourcePosition);
Expression* throw_type_error =
NewThrowTypeError(MessageTemplate::kNonCoercible,
ast_value_factory()->empty_string(), kNoSourcePosition);
NewThrowTypeError(msg, property, source_position);
IfStatement* if_statement = factory()->NewIfStatement(
condition,
factory()->NewExpressionStatement(throw_type_error, kNoSourcePosition),
......@@ -2932,7 +2943,6 @@ Statement* Parser::BuildAssertIsCoercible(Variable* var) {
return if_statement;
}
class InitializerRewriter final
: public AstTraversalVisitor<InitializerRewriter> {
public:
......
......@@ -545,7 +545,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
BreakableStatement* LookupBreakTarget(const AstRawString* label, bool* ok);
IterationStatement* LookupContinueTarget(const AstRawString* label, bool* ok);
Statement* BuildAssertIsCoercible(Variable* var);
Statement* BuildAssertIsCoercible(Variable* var, ObjectLiteral* pattern);
// Factory methods.
FunctionLiteral* DefaultConstructor(const AstRawString* name, bool call_super,
......
......@@ -368,7 +368,8 @@ void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
rest_runtime_callargs->Add(factory()->NewVariableProxy(temp), zone());
}
block_->statements()->Add(parser_->BuildAssertIsCoercible(temp), zone());
block_->statements()->Add(parser_->BuildAssertIsCoercible(temp, pattern),
zone());
for (ObjectLiteralProperty* property : *pattern->properties()) {
PatternContext context = SetInitializerContextIfNeeded(property->value());
......
......@@ -156,7 +156,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(20),
B(LdaConstant), U8(15),
B(Star), R(21),
......@@ -488,7 +488,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(20),
B(LdaConstant), U8(15),
B(Star), R(21),
......@@ -843,7 +843,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(20),
B(LdaConstant), U8(15),
B(Star), R(21),
......@@ -1123,7 +1123,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(16),
B(LdaConstant), U8(10),
B(Star), R(17),
......
......@@ -85,7 +85,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(11),
B(LdaConstant), U8(8),
B(Star), R(12),
......@@ -225,7 +225,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(12),
B(LdaConstant), U8(8),
B(Star), R(13),
......@@ -377,7 +377,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(11),
B(LdaConstant), U8(8),
B(Star), R(12),
......@@ -520,7 +520,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(10),
B(LdaConstant), U8(10),
B(Star), R(11),
......
......@@ -89,7 +89,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(13),
B(LdaConstant), U8(7),
B(Star), R(14),
......@@ -266,7 +266,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(12),
B(LdaConstant), U8(11),
B(Star), R(13),
......@@ -419,7 +419,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(11),
B(LdaConstant), U8(9),
B(Star), R(12),
......@@ -521,15 +521,15 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(6),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(61),
B(LdaSmi), I8(62),
B(Star), R(17),
B(LdaConstant), U8(4),
B(Star), R(18),
B(CallRuntime), U16(Runtime::kNewTypeError), R(17), U8(2),
B(Throw),
/* 31 S> */ B(LdaNamedProperty), R(6), U8(5), U8(17),
/* 31 E> */ B(Throw),
/* 31 S> */ B(LdaNamedProperty), R(6), U8(4), U8(17),
B(Star), R(1),
/* 34 S> */ B(LdaNamedProperty), R(6), U8(6), U8(19),
/* 34 S> */ B(LdaNamedProperty), R(6), U8(5), U8(19),
B(Star), R(2),
/* 56 S> */ B(Ldar), R(2),
/* 58 E> */ B(Add), R(1), U8(21),
......@@ -540,7 +540,7 @@ bytecodes: [
B(Jump), U8(36),
B(Star), R(17),
B(Ldar), R(closure),
/* 56 E> */ B(CreateCatchContext), R(17), U8(7), U8(8),
/* 56 E> */ B(CreateCatchContext), R(17), U8(6), U8(7),
B(PushContext), R(17),
B(Star), R(16),
B(LdaSmi), I8(2),
......@@ -564,7 +564,7 @@ bytecodes: [
B(LdaZero),
B(TestEqualStrict), R(9), U8(23),
B(JumpIfTrue), U8(104),
B(LdaNamedProperty), R(7), U8(9), U8(24),
B(LdaNamedProperty), R(7), U8(8), U8(24),
B(Star), R(11),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
......@@ -576,9 +576,9 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(16),
B(LdaConstant), U8(4),
B(LdaConstant), U8(9),
B(Star), R(17),
B(CallRuntime), U16(Runtime::kNewTypeError), R(16), U8(2),
B(Throw),
......@@ -589,7 +589,7 @@ bytecodes: [
B(Jump), U8(20),
B(Star), R(17),
B(Ldar), R(closure),
B(CreateCatchContext), R(17), U8(7), U8(10),
B(CreateCatchContext), R(17), U8(6), U8(10),
B(Star), R(16),
B(LdaTheHole),
B(SetPendingMessage),
......@@ -620,12 +620,12 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["x"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["y"],
ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"],
FIXED_ARRAY_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"],
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
FIXED_ARRAY_TYPE,
]
handlers: [
......@@ -756,7 +756,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(17),
B(LdaConstant), U8(10),
B(Star), R(18),
......@@ -965,7 +965,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(16),
B(LdaConstant), U8(14),
B(Star), R(17),
......@@ -1129,7 +1129,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(20),
B(LdaConstant), U8(7),
B(Star), R(21),
......@@ -1390,7 +1390,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(21),
B(LdaConstant), U8(11),
B(Star), R(22),
......
......@@ -283,7 +283,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(15),
B(LdaConstant), U8(15),
B(Star), R(16),
......@@ -475,7 +475,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(12),
B(LdaConstant), U8(10),
B(Star), R(13),
......@@ -504,7 +504,7 @@ bytecodes: [
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(7), U8(1),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(12),
B(LdaConstant), U8(10),
B(Star), R(13),
......
......@@ -231,15 +231,15 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(3),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(61),
B(LdaSmi), I8(62),
B(Star), R(4),
B(LdaConstant), U8(1),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kNewTypeError), R(4), U8(2),
B(Throw),
/* 37 S> */ B(LdaNamedProperty), R(3), U8(2), U8(6),
/* 28 E> */ B(Throw),
/* 37 S> */ B(LdaNamedProperty), R(3), U8(1), U8(6),
B(Star), R(1),
/* 37 S> */ B(LdaNamedProperty), R(3), U8(3), U8(8),
/* 37 S> */ B(LdaNamedProperty), R(3), U8(2), U8(8),
B(Star), R(2),
/* 55 S> */ B(LdaZero),
/* 55 E> */ B(TestGreaterThan), R(2), U8(10),
......@@ -257,7 +257,6 @@ bytecodes: [
]
constant pool: [
FIXED_ARRAY_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["x"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["y"],
]
......
// Copyright 2017 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 { [x] : y } = undefined;
*%(basename)s:5: TypeError: Cannot destructure 'undefined' or 'null'.
var { [x] : y } = undefined;
^
TypeError: Cannot destructure 'undefined' or 'null'.
at *%(basename)s:5:19
// Copyright 2017 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 { 1: x } = undefined;
*%(basename)s:5: TypeError: Cannot destructure 'undefined' or 'null'.
var { 1: x } = undefined;
^
TypeError: Cannot destructure 'undefined' or 'null'.
at *%(basename)s:5:16
// Copyright 2017 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 { x } = undefined;
*%(basename)s:5: TypeError: Cannot destructure property `x` of 'undefined' or 'null'.
var { x } = undefined;
^
TypeError: Cannot destructure property `x` of 'undefined' or 'null'.
at *%(basename)s:5:13
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