Bug 1220564 - Remove legacy generator comprehensions. (r=Waldo)
authorShu-yu Guo <shu@rfrn.org>
Wed, 06 Jan 2016 16:02:15 -0800
changeset 278889 ee34d6a0db79d1c515eff54a44bd43862bdc953f
parent 278888 0814f2d30eda6175980be9318b8ed4a7fccaf435
child 278890 d3f7a477db20d3a3491fe7118c28ffadb95f64bb
push id29860
push usercbook@mozilla.com
push dateThu, 07 Jan 2016 10:51:20 +0000
treeherdermozilla-central@e0bcd16e1d4b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1220564
milestone46.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1220564 - Remove legacy generator comprehensions. (r=Waldo)
js/src/builtin/ReflectParse.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/jsversion.h
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -2972,20 +2972,18 @@ ASTSerializer::expression(ParseNode* pn,
         UnaryOperator op = unop(pn->getKind(), pn->getOp());
         LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
 
         RootedValue expr(cx);
         return expression(pn->pn_kid, &expr) &&
                builder.unaryExpression(op, expr, &pn->pn_pos, dst);
       }
 
-#if JS_HAS_GENERATOR_EXPRS
       case PNK_GENEXP:
         return generatorExpression(pn->generatorExpr(), dst);
-#endif
 
       case PNK_NEW:
       case PNK_TAGGED_TEMPLATE:
       case PNK_CALL:
       case PNK_SUPERCALL:
       {
         ParseNode* next = pn->pn_head;
         MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -834,27 +834,25 @@ class ParseNode
                isKind(PNK_TRUE) ||
                isKind(PNK_FALSE) ||
                isKind(PNK_NULL);
     }
 
     /* Return true if this node appears in a Directive Prologue. */
     bool isDirectivePrologueMember() const { return pn_prologue; }
 
-#ifdef JS_HAS_GENERATOR_EXPRS
     ParseNode* generatorExpr() const {
         MOZ_ASSERT(isKind(PNK_GENEXP));
         ParseNode* callee = this->pn_head;
         ParseNode* body = callee->pn_body;
         MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
         MOZ_ASSERT(body->last()->isKind(PNK_LEXICALSCOPE) ||
                    body->last()->isKind(PNK_COMPREHENSIONFOR));
         return body->last();
     }
-#endif
 
     inline void markAsAssigned();
 
     /*
      * Compute a pointer to the last element in a singly-linked list. NB: list
      * must be non-empty for correct PN_LAST usage -- this is asserted!
      */
     ParseNode* last() const {
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6392,17 +6392,17 @@ Parser<ParseHandler>::yieldExpression(In
                             JSMSG_BAD_ANON_GENERATOR_RETURN);
             return null();
         }
         // Fall through.
 
       case LegacyGenerator:
       {
         // We are in a legacy generator: a function that has already seen a
-        // yield, or in a legacy generator comprehension.
+        // yield.
         MOZ_ASSERT(pc->sc->isFunctionBox());
 
         pc->lastYieldOffset = begin;
 
         // Legacy generators do not require a value.
         Node exprNode;
         TokenKind tt = TOK_EOF;
         if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
@@ -8462,48 +8462,42 @@ SyntaxParseHandler::Node
 Parser<SyntaxParseHandler>::legacyArrayComprehension(Node array)
 {
     abortIfSyntaxParser();
     return null();
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::generatorComprehensionLambda(GeneratorKind comprehensionKind,
-                                                   unsigned begin, Node innerExpr)
-{
-    MOZ_ASSERT(comprehensionKind == LegacyGenerator || comprehensionKind == StarGenerator);
-    MOZ_ASSERT(!!innerExpr == (comprehensionKind == LegacyGenerator));
-
+Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin)
+{
     Node genfn = handler.newFunctionDefinition();
     if (!genfn)
         return null();
     handler.setOp(genfn, JSOP_LAMBDA);
 
     ParseContext<ParseHandler>* outerpc = pc;
 
     // If we are off the main thread, the generator meta-objects have
     // already been created by js::StartOffThreadParseScript, so cx will not
     // be necessary.
     RootedObject proto(context);
-    if (comprehensionKind == StarGenerator) {
-        JSContext* cx = context->maybeJSContext();
-        proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, context->global());
-        if (!proto)
-            return null();
-    }
+    JSContext* cx = context->maybeJSContext();
+    proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, context->global());
+    if (!proto)
+        return null();
 
     RootedFunction fun(context, newFunction(/* atom = */ nullptr, Expression,
-                                            comprehensionKind, proto));
+                                            StarGenerator, proto));
     if (!fun)
         return null();
 
     // Create box for fun->object early to root it.
     Directives directives(/* strict = */ outerpc->sc->strict());
-    FunctionBox* genFunbox = newFunctionBox(genfn, fun, outerpc, directives, comprehensionKind);
+    FunctionBox* genFunbox = newFunctionBox(genfn, fun, outerpc, directives, StarGenerator);
     if (!genFunbox)
         return null();
 
     genFunbox->inGenexpLambda = true;
 
     ParseContext<ParseHandler> genpc(this, outerpc, genfn, genFunbox,
                                      /* newDirectives = */ nullptr);
     if (!genpc.init(*this))
@@ -8514,44 +8508,33 @@ Parser<ParseHandler>::generatorComprehen
      * come from the kid. So we propagate these flags into genfn. For code
      * simplicity we also do not detect if the flags were only set in the
      * kid and could be removed from pc->sc.
      */
     genFunbox->anyCxFlags = outerpc->sc->anyCxFlags;
     if (outerpc->sc->isFunctionBox())
         genFunbox->funCxFlags = outerpc->sc->asFunctionBox()->funCxFlags;
 
-    MOZ_ASSERT(genFunbox->generatorKind() == comprehensionKind);
     handler.setBlockId(genfn, genpc.bodyid);
 
     Node generator = newName(context->names().dotGenerator);
     if (!generator)
         return null();
     if (!pc->define(tokenStream, context->names().dotGenerator, generator, Definition::VAR))
         return null();
 
     Node body = handler.newStatementList(pc->blockid(), TokenPos(begin, pos().end));
     if (!body)
         return null();
 
-    Node comp;
-    if (comprehensionKind == StarGenerator) {
-        comp = comprehension(StarGenerator);
-        if (!comp)
-            return null();
-    } else {
-        MOZ_ASSERT(comprehensionKind == LegacyGenerator);
-        comp = legacyComprehensionTail(innerExpr, outerpc->blockid(), LegacyGenerator,
-                                       outerpc, LegacyComprehensionHeadBlockScopeDepth(outerpc));
-        if (!comp)
-            return null();
-    }
-
-    if (comprehensionKind == StarGenerator)
-        MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
+    Node comp = comprehension(StarGenerator);
+    if (!comp)
+        return null();
+
+    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
 
     handler.setBeginPosition(comp, begin);
     handler.setEndPosition(comp, pos().end);
     handler.addStatementToList(body, comp, pc);
     handler.setEndPosition(body, pos().end);
     handler.setBeginPosition(genfn, begin);
     handler.setEndPosition(genfn, pos().end);
 
@@ -8571,59 +8554,16 @@ Parser<ParseHandler>::generatorComprehen
     PropagateTransitiveParseFlags(genFunbox, outerpc->sc);
 
     if (!leaveFunction(genfn, outerpc))
         return null();
 
     return genfn;
 }
 
-#if JS_HAS_GENERATOR_EXPRS
-
-/*
- * Starting from a |for| keyword after an expression, parse the comprehension
- * tail completing this generator expression. Wrap the expression |expr| in a
- * generator function that is immediately called to evaluate to the generator
- * iterator that is the value of this legacy generator expression.
- *
- * |expr| must be the expression before the |for| keyword; we return an
- * application of a generator function that includes the |for| loops and
- * |if| guards, with |expr| as the operand of a |yield| expression as the
- * innermost loop body.
- *
- * Unlike Python, we do not evaluate the expression to the right of the first
- * |in| in the chain of |for| heads. Instead, a generator expression is merely
- * sugar for a generator function expression and its application.
- */
-template <>
-ParseNode*
-Parser<FullParseHandler>::legacyGeneratorExpr(ParseNode* expr)
-{
-    MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
-
-    // Make a new node for the desugared generator function.
-    ParseNode* genfn = generatorComprehensionLambda(LegacyGenerator, expr->pn_pos.begin, expr);
-    if (!genfn)
-        return null();
-
-    // Our result is a call expression that invokes the anonymous generator
-    // function object.
-    return handler.newList(PNK_GENEXP, genfn, JSOP_CALL);
-}
-
-template <>
-SyntaxParseHandler::Node
-Parser<SyntaxParseHandler>::legacyGeneratorExpr(Node kid)
-{
-    JS_ALWAYS_FALSE(abortIfSyntaxParser());
-    return SyntaxParseHandler::NodeFailure;
-}
-
-#endif /* JS_HAS_GENERATOR_EXPRS */
-
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
 
     uint32_t begin = pos().begin;
 
@@ -8810,17 +8750,17 @@ Parser<ParseHandler>::generatorComprehen
 
     // We have no problem parsing generator comprehensions inside lazy
     // functions, but the bytecode emitter currently can't handle them that way,
     // because when it goes to emit the code for the inner generator function,
     // it expects outer functions to have non-lazy scripts.
     if (!abortIfSyntaxParser())
         return null();
 
-    Node genfn = generatorComprehensionLambda(StarGenerator, begin, null());
+    Node genfn = generatorComprehensionLambda(begin);
     if (!genfn)
         return null();
 
     Node result = handler.newList(PNK_GENEXP, genfn, JSOP_CALL);
     if (!result)
         return null();
     handler.setBeginPosition(result, begin);
     handler.setEndPosition(result, pos().end);
@@ -8852,19 +8792,16 @@ Parser<ParseHandler>::argumentList(Yield
     bool matched;
     if (!tokenStream.matchToken(&matched, TOK_RP, TokenStream::Operand))
         return false;
     if (matched) {
         handler.setEndPosition(listNode, pos().end);
         return true;
     }
 
-    uint32_t startYieldOffset = pc->lastYieldOffset;
-    bool arg0 = true;
-
     while (true) {
         bool spread = false;
         uint32_t begin = 0;
         if (!tokenStream.matchToken(&matched, TOK_TRIPLEDOT, TokenStream::Operand))
             return false;
         if (matched) {
             spread = true;
             begin = pos().begin;
@@ -8884,44 +8821,16 @@ Parser<ParseHandler>::argumentList(Yield
             TokenKind tt;
             if (!tokenStream.peekToken(&tt))
                 return false;
             if (tt == TOK_COMMA) {
                 report(ParseError, false, argNode, JSMSG_BAD_YIELD_SYNTAX);
                 return false;
             }
         }
-#if JS_HAS_GENERATOR_EXPRS
-        if (!spread) {
-            if (!tokenStream.matchToken(&matched, TOK_FOR))
-                return false;
-            if (matched) {
-                if (pc->lastYieldOffset != startYieldOffset) {
-                    reportWithOffset(ParseError, false, pc->lastYieldOffset,
-                                     JSMSG_BAD_GENEXP_BODY, js_yield_str);
-                    return false;
-                }
-                argNode = legacyGeneratorExpr(argNode);
-                if (!argNode)
-                    return false;
-                if (!arg0) {
-                    report(ParseError, false, argNode, JSMSG_BAD_GENERATOR_SYNTAX);
-                    return false;
-                }
-                TokenKind tt;
-                if (!tokenStream.peekToken(&tt))
-                    return false;
-                if (tt == TOK_COMMA) {
-                    report(ParseError, false, argNode, JSMSG_BAD_GENERATOR_SYNTAX);
-                    return false;
-                }
-            }
-        }
-#endif
-        arg0 = false;
 
         handler.addList(listNode, argNode);
 
         bool matched;
         if (!tokenStream.matchToken(&matched, TOK_COMMA))
             return false;
         if (!matched)
             break;
@@ -9885,68 +9794,23 @@ Parser<ParseHandler>::primaryExpr(YieldH
 
       default:
         report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
                "expression", TokenKindToDesc(tt));
         return null();
     }
 }
 
-// Legacy generator comprehensions can appear anywhere an expression is
-// enclosed in parentheses, even if those parentheses are part of statement
-// syntax or a function call:
-//
-//   if (_)
-//   while (_) {}
-//   do {} while (_)
-//   switch (_) {}
-//   with (_) {}
-//   foo(_)  // must be first and only argument
-//
-// This is not the case for also-nonstandard ES6-era generator comprehensions.
-// Those must be enclosed in PrimaryExpression parentheses.
-//
-//     sum(x*x for (x in y)); // ok
-//     sum(for (x of y) x*x); // SyntaxError: needs more parens
-//
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::exprInParens(InHandling inHandling, YieldHandling yieldHandling,
                                    TripledotHandling tripledotHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LP));
-    uint32_t begin = pos().begin;
-    uint32_t startYieldOffset = pc->lastYieldOffset;
-
-    Node pn = expr(inHandling, yieldHandling, tripledotHandling, PredictInvoked);
-    if (!pn)
-        return null();
-
-#if JS_HAS_GENERATOR_EXPRS
-    bool matched;
-    if (!tokenStream.matchToken(&matched, TOK_FOR))
-        return null();
-    if (matched) {
-        if (pc->lastYieldOffset != startYieldOffset) {
-            reportWithOffset(ParseError, false, pc->lastYieldOffset,
-                             JSMSG_BAD_GENEXP_BODY, js_yield_str);
-            return null();
-        }
-        if (handler.isUnparenthesizedCommaExpression(pn)) {
-            report(ParseError, false, null(), JSMSG_BAD_GENERATOR_SYNTAX);
-            return null();
-        }
-        pn = legacyGeneratorExpr(pn);
-        if (!pn)
-            return null();
-        handler.setBeginPosition(pn, begin);
-    }
-#endif /* JS_HAS_GENERATOR_EXPRS */
-
-    return pn;
+    return expr(inHandling, yieldHandling, tripledotHandling, PredictInvoked);
 }
 
 template <typename ParseHandler>
 void
 Parser<ParseHandler>::addTelemetry(JSCompartment::DeprecatedLanguageExtension e)
 {
     JSContext* cx = context->maybeJSContext();
     if (!cx)
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -794,19 +794,17 @@ class Parser : private JS::AutoGCRooter,
 
     Node condition(InHandling inHandling, YieldHandling yieldHandling);
 
     /* comprehensions */
     Node legacyComprehensionTail(Node kid, unsigned blockid, GeneratorKind comprehensionKind,
                                  ParseContext<ParseHandler>* outerpc,
                                  unsigned innerBlockScopeDepth);
     Node legacyArrayComprehension(Node array);
-    Node generatorComprehensionLambda(GeneratorKind comprehensionKind, unsigned begin,
-                                      Node innerStmt);
-    Node legacyGeneratorExpr(Node kid);
+    Node generatorComprehensionLambda(unsigned begin);
     Node comprehensionFor(GeneratorKind comprehensionKind);
     Node comprehensionIf(GeneratorKind comprehensionKind);
     Node comprehensionTail(GeneratorKind comprehensionKind);
     Node comprehension(GeneratorKind comprehensionKind);
     Node arrayComprehension(uint32_t begin);
     Node generatorComprehension(uint32_t begin);
 
     bool argumentList(YieldHandling yieldHandling, Node listNode, bool* isSpread);
--- a/js/src/jsversion.h
+++ b/js/src/jsversion.h
@@ -17,17 +17,17 @@
 #define JS_HAS_CATCH_GUARD      1       /* has exception handling catch guard */
 #define JS_HAS_UNEVAL           1       /* has uneval() top-level function */
 #define JS_HAS_CONST            1       /* (no longer used) */
 #define JS_HAS_FUN_EXPR_STMT    1       /* (no longer used) */
 #define JS_HAS_FOR_EACH_IN      1       /* has for each (lhs in iterable) */
 #define JS_HAS_GENERATORS       1       /* (no longer used) */
 #define JS_HAS_BLOCK_SCOPE      1       /* (no longer used) */
 #define JS_HAS_DESTRUCTURING    2       /* (no longer used) */
-#define JS_HAS_GENERATOR_EXPRS  1       /* has (expr for (lhs in iterable)) */
+#define JS_HAS_GENERATOR_EXPRS  1       /* (no longer used) */
 #define JS_HAS_EXPR_CLOSURES    1       /* has function (formals) listexpr */
 
 /* (no longer used) */
 #define JS_HAS_NEW_GLOBAL_OBJECT        1
 
 /* (no longer used) */
 #define JS_HAS_DESTRUCTURING_SHORTHAND  (JS_HAS_DESTRUCTURING == 2)