Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2023-08-31 22:43:48 +08:00
commit 92d9218cf1
28 changed files with 239 additions and 72 deletions

View file

@ -7754,10 +7754,23 @@ bool
BytecodeEmitter::emitLeftAssociative(ListNode* node)
{
// Left-associative operator chain.
if (!emitTree(node->head()))
return false;
JSOp op = node->getOp();
ParseNode* nextExpr = node->head()->pn_next;
ParseNode* headExpr = node->head();
if (op == JSOP_IN && headExpr->isKind(PNK_NAME) && headExpr->as<NameNode>().isPrivateName()) {
// {Goanna} The only way a "naked" private name can show up as the leftmost side of an in-chain
// is from an ergonomic brand check (`this.#x in ...` would be a PNK_DOT child node).
// Instead of going through the emitTree machinery, we pretend that this identifier
// reference is actually a string, which allows us to use the JSOP_IN interpreter routines.
// This erroneously doesn't call updateLineNumberNotes, but this is not a big issue:
// the begin pos is correct as we're on the start of the current tree, the end is on the
// same line anyway.
if (!emitAtomOp(headExpr->as<NameNode>().atom(), JSOP_STRING))
return false;
} else {
if (!emitTree(headExpr))
return false;
}
ParseNode* nextExpr = headExpr->pn_next;
do {
if (!emitTree(nextExpr))
return false;

View file

@ -965,6 +965,10 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
return node->isKind(PNK_NAME);
}
bool isPrivateName(Node node) {
return node->isKind(PNK_NAME) && node->as<NameNode>().isPrivateName();
}
bool isArgumentsAnyParentheses(Node node, ExclusiveContext* cx) {
return node->isKind(PNK_NAME) && node->as<NameNode>().atom() == cx->names().arguments;
}

View file

@ -953,6 +953,10 @@ class NameNode : public ParseNode
JSAtom* atom() const {
return pn_u.name.atom;
}
bool isPrivateName() const {
return atom()->asPropertyName()->latin1OrTwoByteChar(0) == '#';
}
ParseNode* initializer() const {
return pn_u.name.initOrStmt;

View file

@ -8951,6 +8951,15 @@ Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling
if (!tokenStream.getToken(&tok))
return null();
// Ensure that if we have a private name lhs we are legally constructing a
// `#x in obj` expression:
if (handler.isPrivateName(pn)) {
if (tok != TOK_IN) {
error(JSMSG_ILLEGAL_PRIVATE_NAME);
return null();
}
}
ParseNodeKind pnk;
if (tok == TOK_IN ? inHandling == InAllowed : TokenKindIsBinaryOp(tok)) {
// We're definitely not in a destructuring context, so report any
@ -8987,7 +8996,20 @@ Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling
// If we have not detected a mixing error at this point, record that
// we have an unparenthesized expression, in case we have one later.
unparenthesizedExpression = EnforcedParentheses::CoalesceExpr;
break;
break;
case TOK_IN:
// if the LHS is a private name, and the operator is In,
// ensure we're construcing an ergonomic brand check of
// '#x in y', rather than having a higher precedence operator
// like + cause a different reduction, such as
// 1 + #x in y.
if (handler.isPrivateName(pn)) {
if (depth > 0 && Precedence(kindStack[depth - 1]) >= Precedence(PNK_IN)) {
error(JSMSG_ILLEGAL_PRIVATE_NAME);
return null();
}
}
break;
default:
// Do nothing in other cases.
break;

View file

@ -104,6 +104,9 @@ class SyntaxParseHandler
// Node representing the "async" name, which may actually be a
// contextual keyword.
NodePotentialAsyncKeyword,
// Node representing a private name. Handled mostly like NodeUnparenthesizedName.
NodePrivateName,
// Valuable for recognizing potential destructuring patterns.
NodeUnparenthesizedArray,
@ -212,6 +215,8 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
return NodePotentialAsyncKeyword;
if (name == cx->names().eval)
return NodeUnparenthesizedEvalName;
if (name->length() >= 1 && name->latin1OrTwoByteChar(0) == '#')
return NodePrivateName;
return NodeUnparenthesizedName;
}
@ -614,7 +619,8 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
return node == NodeUnparenthesizedArgumentsName ||
node == NodeUnparenthesizedEvalName ||
node == NodeUnparenthesizedName ||
node == NodePotentialAsyncKeyword;
node == NodePotentialAsyncKeyword ||
node == NodePrivateName;
}
bool isNameAnyParentheses(Node node) {
@ -625,6 +631,10 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
node == NodeParenthesizedName;
}
bool isPrivateName(Node node) {
return node == NodePrivateName;
}
bool isArgumentsAnyParentheses(Node node, ExclusiveContext* cx) {
return node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName;
}

View file

@ -364,6 +364,7 @@ MSG_DEF(JSMSG_BAD_NEW_OPTIONAL, 0, JSEXN_SYNTAXERR, "new keyword cannot b
MSG_DEF(JSMSG_BAD_OPTIONAL_TEMPLATE, 0, JSEXN_SYNTAXERR, "tagged template cannot be used with optional chain")
MSG_DEF(JSMSG_ESCAPED_KEYWORD, 0, JSEXN_SYNTAXERR, "keywords must be written literally, without embedded escapes")
MSG_DEF(JSMSG_FIELDS_NOT_SUPPORTED, 0, JSEXN_SYNTAXERR, "fields are not currently supported")
MSG_DEF(JSMSG_ILLEGAL_PRIVATE_NAME, 0, JSEXN_SYNTAXERR, "private names aren't valid in this context")
// asm.js
MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL, 1, JSEXN_TYPEERR, "asm.js type error: {0}")