diff options
author | FranklinDM <mrmineshafter17@gmail.com> | 2022-05-20 18:21:28 +0800 |
---|---|---|
committer | FranklinDM <mrmineshafter17@gmail.com> | 2022-05-21 01:02:24 +0800 |
commit | 8618fcbe89b66f15b2434879cd161b3bef35c76e (patch) | |
tree | 722a5997ae2b066c35a34839b32afe18908d5307 | |
parent | 20ee1ece0167bd2b110367fe699948dfa3648803 (diff) | |
download | uxp-8618fcbe89b66f15b2434879cd161b3bef35c76e.tar.gz |
Issue #1894 - Part 6: Check for nullish values when folding coalesce nodes
This uses a different approach by modifying the `Boolish` function directly to act differently if we're checking for nullish values.
Partially based on:
Bug 1566141 - Implement the Nullish Coalescing operator (??) proposal
Bug 1599163 - Nullish coalescing operator returns undefined for void expressions
-rw-r--r-- | js/src/frontend/FoldConstants.cpp | 43 |
1 files changed, 26 insertions, 17 deletions
diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index ff34c51df9..c3354e44a4 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -483,15 +483,19 @@ IsEffectless(ParseNode* node) enum Truthiness { Truthy, Falsy, Unknown }; static Truthiness -Boolish(ParseNode* pn) +Boolish(ParseNode* pn, bool isNullish = false) { switch (pn->getKind()) { - case PNK_NUMBER: - return (pn->pn_dval != 0 && !IsNaN(pn->pn_dval)) ? Truthy : Falsy; + case PNK_NUMBER: { + bool isNonZeroNumber = (pn->pn_dval != 0 && !IsNaN(pn->pn_dval)); + return (isNullish || isNonZeroNumber) ? Truthy : Falsy; + } case PNK_STRING: - case PNK_TEMPLATE_STRING: - return (pn->pn_atom->length() > 0) ? Truthy : Falsy; + case PNK_TEMPLATE_STRING: { + bool isNonZeroLengthString = (pn->pn_atom->length() > 0); + return (isNullish || isNonZeroLengthString) ? Truthy : Falsy; + } case PNK_TRUE: case PNK_FUNCTION: @@ -499,6 +503,8 @@ Boolish(ParseNode* pn) return Truthy; case PNK_FALSE: + return isNullish ? Truthy : Falsy; + case PNK_NULL: case PNK_RAW_UNDEFINED: return Falsy; @@ -758,19 +764,19 @@ FoldLogical(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& { ParseNode* node = *nodePtr; - MOZ_ASSERT(node->isKind(PNK_AND) || - node->isKind(PNK_OR) || - node->isKind(PNK_COALESCE)); + bool isCoalesceNode = node->isKind(PNK_COALESCE); + bool isOrNode = node->isKind(PNK_OR); + bool isAndNode = node->isKind(PNK_AND); + + MOZ_ASSERT(isCoalesceNode || isOrNode || isAndNode); MOZ_ASSERT(node->isArity(PN_LIST)); - bool isOrNode = (node->isKind(PNK_OR) || - node->isKind(PNK_COALESCE)); ParseNode** elem = &node->pn_head; do { if (!Fold(cx, elem, parser, inGenexpLambda)) return false; - Truthiness t = Boolish(*elem); + Truthiness t = Boolish(*elem, isCoalesceNode); // If we don't know the constant-folded node's truthiness, we can't // reduce this node with its surroundings. Continue folding any @@ -780,11 +786,16 @@ FoldLogical(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& continue; } + bool terminateEarly = (isOrNode && t == Truthy) || + (isAndNode && t == Falsy) || + (isCoalesceNode && t == Truthy); + // If the constant-folded node's truthiness will terminate the - // condition -- `a || true || expr` or |b && false && expr| -- then - // trailing nodes will never be evaluated. Truncate the list after - // the known-truthiness node, as it's the overall result. - if ((t == Truthy) == isOrNode) { + // condition -- `a || true || expr` or `b && false && expr` or + // `false ?? c ?? expr` -- then trailing nodes will never be + // evaluated. Truncate the list after the known-truthiness node, + // as it's the overall result. + if (terminateEarly) { ParseNode* afterNext; for (ParseNode* next = (*elem)->pn_next; next; next = afterNext) { afterNext = next->pn_next; @@ -799,8 +810,6 @@ FoldLogical(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& break; } - MOZ_ASSERT((t == Truthy) == !isOrNode); - // We've encountered a vacuous node that'll never short- circuit // evaluation. if ((*elem)->pn_next) { |