Reland "Set .name of anonymous functions on the RHS of logical assignment."

This is a reland of c342ba8247730d96960f1da85d6b77b4e3cad9cc

Original change's description:
> Set .name of anonymous functions on the RHS of logical assignment.
> 
> https://github.com/tc39/proposal-logical-assignment/pull/24 reached
> consensus in June TC39.
> 
> Drive-by refactoring of testing for logical assignment ops using
> IsInRange.
> 
> Bug: v8:10579
> Change-Id: I5a203ba552a905cd28f75c5d223998431a1966ce
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2225809
> Reviewed-by: Marja Hölttä <marja@chromium.org>
> Commit-Queue: Shu-yu Guo <syg@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#68101}

Bug: v8:10579
Change-Id: I321cf0e29515a146844abc05250e9b50ad651caf
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2227255
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68161}
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
index 903ce2b..88c7384 100644
--- a/src/parsing/parser-base.h
+++ b/src/parsing/parser-base.h
@@ -2755,8 +2755,7 @@
   Token::Value op = peek();
 
   if (!Token::IsArrowOrAssignmentOp(op)) return expression;
-  if ((op == Token::ASSIGN_NULLISH || op == Token::ASSIGN_OR ||
-       op == Token::ASSIGN_AND) &&
+  if (Token::IsLogicalAssignmentOp(op) &&
       !flags().allow_harmony_logical_assignment()) {
     return expression;
   }
@@ -2830,13 +2829,8 @@
 
   ExpressionT right = ParseAssignmentExpression();
 
-  if (op == Token::ASSIGN) {
-    // We try to estimate the set of properties set by constructors. We define a
-    // new property whenever there is an assignment to a property of 'this'. We
-    // should probably only add properties if we haven't seen them before.
-    // Otherwise we'll probably overestimate the number of properties.
-    if (impl()->IsThisProperty(expression)) function_state_->AddProperty();
-
+  // Anonymous function name inference applies to =, ||=, &&=, and ??=.
+  if (op == Token::ASSIGN || Token::IsLogicalAssignmentOp(op)) {
     impl()->CheckAssigningFunctionLiteralToProperty(expression, right);
 
     // Check if the right hand side is a call to avoid inferring a
@@ -2850,10 +2844,20 @@
 
     impl()->SetFunctionNameFromIdentifierRef(right, expression);
   } else {
+    fni_.RemoveLastFunction();
+  }
+
+  if (op == Token::ASSIGN) {
+    // We try to estimate the set of properties set by constructors. We define a
+    // new property whenever there is an assignment to a property of 'this'. We
+    // should probably only add properties if we haven't seen them before.
+    // Otherwise we'll probably overestimate the number of properties.
+    if (impl()->IsThisProperty(expression)) function_state_->AddProperty();
+  } else {
+    // Only initializers (i.e. no compound assignments) are allowed in patterns.
     expression_scope()->RecordPatternError(
         Scanner::Location(lhs_beg_pos, end_position()),
         MessageTemplate::kInvalidDestructuringTarget);
-    fni_.RemoveLastFunction();
   }
 
   return factory()->NewAssignment(op, expression, right, op_position);
diff --git a/src/parsing/token.h b/src/parsing/token.h
index ef92238..dabbff0 100644
--- a/src/parsing/token.h
+++ b/src/parsing/token.h
@@ -284,6 +284,10 @@
     return base::IsInRange(token, INIT, ASSIGN_SUB);
   }
 
+  static bool IsLogicalAssignmentOp(Value token) {
+    return base::IsInRange(token, ASSIGN_NULLISH, ASSIGN_AND);
+  }
+
   static bool IsBinaryOp(Value op) { return base::IsInRange(op, COMMA, SUB); }
 
   static bool IsCompareOp(Value op) { return base::IsInRange(op, EQ, IN); }
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index a7a846b..5fbefb6 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -1573,6 +1573,7 @@
   kAllowHarmonyPrivateMethods,
   kAllowHarmonyDynamicImport,
   kAllowHarmonyImportMeta,
+  kAllowHarmonyLogicalAssignment,
 };
 
 enum ParserSyncTestResult {
@@ -1586,6 +1587,8 @@
   i::FLAG_harmony_private_methods = flags.contains(kAllowHarmonyPrivateMethods);
   i::FLAG_harmony_dynamic_import = flags.contains(kAllowHarmonyDynamicImport);
   i::FLAG_harmony_import_meta = flags.contains(kAllowHarmonyImportMeta);
+  i::FLAG_harmony_logical_assignment =
+      flags.contains(kAllowHarmonyLogicalAssignment);
 }
 
 void SetParserFlags(i::UnoptimizedCompileFlags* compile_flags,
@@ -1597,6 +1600,8 @@
       flags.contains(kAllowHarmonyDynamicImport));
   compile_flags->set_allow_harmony_import_meta(
       flags.contains(kAllowHarmonyImportMeta));
+  compile_flags->set_allow_harmony_logical_assignment(
+      flags.contains(kAllowHarmonyLogicalAssignment));
 }
 
 void TestParserSyncWithFlags(i::Handle<i::String> source,
@@ -11741,6 +11746,36 @@
   SyntaxErrorTest(other_context_data, hashbang_data);
 }
 
+TEST(LogicalAssignmentDestructuringErrors) {
+  // clang-format off
+  const char* context_data[][2] = {
+    { "if (", ") { foo(); }" },
+    { "(", ")" },
+    { "foo(", ")" },
+    { nullptr, nullptr }
+  };
+  const char* error_data[] = {
+    "[ x ] ||= [ 2 ]",
+    "[ x ||= 2 ] = [ 2 ]",
+    "{ x } ||= { x: 2 }",
+    "{ x: x ||= 2 ] = { x: 2 }",
+    "[ x ] &&= [ 2 ]",
+    "[ x &&= 2 ] = [ 2 ]",
+    "{ x } &&= { x: 2 }",
+    "{ x: x &&= 2 ] = { x: 2 }",
+    R"JS([ x ] ??= [ 2 ])JS",
+    R"JS([ x ??= 2 ] = [ 2 ])JS",
+    R"JS({ x } ??= { x: 2 })JS",
+    R"JS({ x: x ??= 2 ] = { x: 2 })JS",
+    nullptr
+  };
+  // clang-format on
+
+  static const ParserFlag flags[] = {kAllowHarmonyLogicalAssignment};
+  RunParserSyncTest(context_data, error_data, kError, nullptr, 0, flags,
+                    arraysize(flags));
+}
+
 }  // namespace test_parsing
 }  // namespace internal
 }  // namespace v8
diff --git a/test/mjsunit/harmony/logical-assignment-function-name.js b/test/mjsunit/harmony/logical-assignment-function-name.js
new file mode 100644
index 0000000..f894664
--- /dev/null
+++ b/test/mjsunit/harmony/logical-assignment-function-name.js
@@ -0,0 +1,27 @@
+// Copyright 2020 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.
+
+// Flags: --harmony-logical-assignment
+
+{
+  let x = undefined;
+  x ??= function() {};
+
+  assertEquals(x.name, "x");
+}
+
+
+{
+  let y = false;
+  y ||= function() {};
+
+  assertEquals(y.name, "y");
+}
+
+{
+  let z = true;
+  z &&= function() {};
+
+  assertEquals(z.name, "z");
+}