Ignore:
Timestamp:
Nov 18, 2015, 5:26:36 PM (10 years ago)
Author:
[email protected]
Message:

There is a bug when default parameter values are mixed with destructuring parameter values
https://bugs.webkit.org/show_bug.cgi?id=151369

Reviewed by Geoffrey Garen and Mark Lam.

Relanding this after a rollout.

This patch changes our parser to no longer declare destructuring
parameters as "var"s. This is a weird bug that just happened
to work in a world without default parameter values. In a world with
default parameter values this is just completely wrong. It would
incorrectly transform this program:
function foo(a = function() { b = 40; }, {b}) { a(); return b; }; foo(undefined, {b: 42}); // Should return 40
into
function foo(a = function() { b = 40; }, {b}) { var b; a(); return b; }; foo(undefined, {b:42}); // Returns 42, not 40.
Which is wrong because we end up with two distinct bindings of "b" when
there should only be one.

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseVariableDeclarationList):
(JSC::Parser<LexerType>::createBindingPattern):
(JSC::Parser<LexerType>::parseDestructuringPattern):

  • parser/Parser.h:

(JSC::Scope::declareParameter):
(JSC::Scope::getUsedVariables):
(JSC::Parser::strictMode):
(JSC::Parser::isValidStrictMode):
(JSC::Parser::declareParameter):
(JSC::Parser::breakIsValid):
(JSC::Scope::declareBoundParameter): Deleted.
(JSC::Parser::declareBoundParameter): Deleted.

  • tests/stress/es6-default-parameters.js:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r192597 r192603  
    668668
    669669template <typename LexerType>
    670 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier& name, int depth, JSToken token, AssignmentContext bindingContext, const Identifier** duplicateIdentifier)
     670template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier& name, JSToken token, AssignmentContext bindingContext, const Identifier** duplicateIdentifier)
    671671{
    672672    ASSERT(!name.isNull());
     
    686686        }
    687687    } else if (kind == DestructureToParameters) {
    688         if (depth) {
    689             auto bindingResult = declareBoundParameter(&name);
    690             if (bindingResult == Scope::StrictBindingFailed && strictMode()) {
    691                 semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
    692                 if (m_lastFunctionName && name == *m_lastFunctionName)
    693                     semanticFail("Cannot destructure to '", name.impl(), "' as it shadows the name of a strict mode function");
    694                 semanticFailureDueToKeyword("bound parameter name");
    695                 if (hasDeclaredParameter(name))
    696                     semanticFail("Cannot destructure to '", name.impl(), "' as it has already been declared");
    697                 semanticFail("Cannot bind to a parameter named '", name.impl(), "' in strict mode");
    698             }
    699             if (bindingResult == Scope::BindingFailed) {
    700                 semanticFailureDueToKeyword("bound parameter name");
    701                 if (hasDeclaredParameter(name))
    702                     semanticFail("Cannot destructure to '", name.impl(), "' as it has already been declared");
    703                 semanticFail("Cannot destructure to a parameter named '", name.impl(), "'");
    704             }
    705         } else {
    706             DeclarationResultMask declarationResult = declareParameter(&name);
    707             if ((declarationResult & DeclarationResult::InvalidStrictMode) && strictMode()) {
    708                 semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
    709                 if (m_lastFunctionName && name == *m_lastFunctionName)
    710                     semanticFail("Cannot declare a parameter named '", name.impl(), "' as it shadows the name of a strict mode function");
    711                 semanticFailureDueToKeyword("parameter name");
    712                 if (hasDeclaredParameter(name))
    713                     semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode as it has already been declared");
    714                 semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode");
    715             }
    716             if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) {
    717                 // It's not always an error to define a duplicate parameter.
    718                 // It's only an error when there are default parameter values or destructuring parameters.
    719                 // We note this value now so we can check it later.
    720                 if (duplicateIdentifier)
    721                     *duplicateIdentifier = &name;
    722             }
     688        DeclarationResultMask declarationResult = declareParameter(&name);
     689        if ((declarationResult & DeclarationResult::InvalidStrictMode) && strictMode()) {
     690            semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
     691            if (m_lastFunctionName && name == *m_lastFunctionName)
     692                semanticFail("Cannot declare a parameter named '", name.impl(), "' as it shadows the name of a strict mode function");
     693            semanticFailureDueToKeyword("parameter name");
     694            if (hasDeclaredParameter(name))
     695                semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode as it has already been declared");
     696            semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode");
     697        }
     698        if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) {
     699            // It's not always an error to define a duplicate parameter.
     700            // It's only an error when there are default parameter values or destructuring parameters.
     701            // We note this value now so we can check it later.
     702            if (duplicateIdentifier)
     703                *duplicateIdentifier = &name;
    723704        }
    724705    }
     
    848829                    innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
    849830                else
    850                     innerPattern = createBindingPattern(context, kind, exportType, *propertyName, depth + 1, identifierToken, bindingContext, duplicateIdentifier);
     831                    innerPattern = createBindingPattern(context, kind, exportType, *propertyName, identifierToken, bindingContext, duplicateIdentifier);
    851832            } else {
    852833                JSTokenType tokenType = m_token.m_type;
     
    904885        }
    905886        failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
    906         pattern = createBindingPattern(context, kind, exportType, *m_token.m_data.ident, depth, m_token, bindingContext, duplicateIdentifier);
     887        pattern = createBindingPattern(context, kind, exportType, *m_token.m_data.ident, m_token, bindingContext, duplicateIdentifier);
    907888        next();
    908889        break;
Note: See TracChangeset for help on using the changeset viewer.