Changeset 192586 in webkit
- Timestamp:
- Nov 18, 2015, 2:01:19 PM (10 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r192561 r192586 1 2015-11-18 Saam barati <[email protected]> 2 3 There is a bug when default parameter values are mixed with destructuring parameter values 4 https://bugs.webkit.org/show_bug.cgi?id=151369 5 6 Reviewed by Geoffrey Garen and Mark Lam. 7 8 This patch changes our parser to no longer declare destructuring 9 parameters as "var"s. This is a weird bug that just happened 10 to work in a world without default parameter values. In a world with 11 default parameter values this is just completely wrong. It would 12 incorrectly transform this program: 13 ```function foo(a = function() { b = 40; }, {b}) { a(); return b; }; foo(undefined, {b: 42}); // Should return 40``` 14 into 15 ```function foo(a = function() { b = 40; }, {b}) { var b; a(); return b; }; foo(undefined, {b:42}); // Returns 42, not 40.``` 16 Which is wrong because we end up with two distinct bindings of "b" when 17 there should only be one. 18 19 * parser/Parser.cpp: 20 (JSC::Parser<LexerType>::parseVariableDeclarationList): 21 (JSC::Parser<LexerType>::createBindingPattern): 22 (JSC::Parser<LexerType>::parseDestructuringPattern): 23 * parser/Parser.h: 24 (JSC::Scope::declareParameter): 25 (JSC::Scope::getUsedVariables): 26 (JSC::Parser::strictMode): 27 (JSC::Parser::isValidStrictMode): 28 (JSC::Parser::declareParameter): 29 (JSC::Parser::breakIsValid): 30 (JSC::Scope::declareBoundParameter): Deleted. 31 (JSC::Parser::declareBoundParameter): Deleted. 32 * tests/stress/es6-default-parameters.js: 33 1 34 2015-11-17 Benjamin Poulain <[email protected]> 2 35 -
trunk/Source/JavaScriptCore/parser/Parser.cpp
r192436 r192586 668 668 669 669 template <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)670 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier& name, JSToken token, AssignmentContext bindingContext, const Identifier** duplicateIdentifier) 671 671 { 672 672 ASSERT(!name.isNull()); … … 686 686 } 687 687 } 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; 723 704 } 724 705 } … … 880 861 innerPattern = parseBindingOrAssignmentElement(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1); 881 862 else 882 innerPattern = createBindingPattern(context, kind, exportType, *propertyName, depth + 1,identifierToken, bindingContext, duplicateIdentifier);863 innerPattern = createBindingPattern(context, kind, exportType, *propertyName, identifierToken, bindingContext, duplicateIdentifier); 883 864 } else { 884 865 JSTokenType tokenType = m_token.m_type; … … 936 917 } 937 918 failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration"); 938 pattern = createBindingPattern(context, kind, exportType, *m_token.m_data.ident, depth,m_token, bindingContext, duplicateIdentifier);919 pattern = createBindingPattern(context, kind, exportType, *m_token.m_data.ident, m_token, bindingContext, duplicateIdentifier); 939 920 next(); 940 921 break; -
trunk/Source/JavaScriptCore/parser/Parser.h
r192436 r192586 425 425 } 426 426 427 enum BindingResult {428 BindingFailed,429 StrictBindingFailed,430 BindingSucceeded431 };432 BindingResult declareBoundParameter(const Identifier* ident)433 {434 bool isArgumentsIdent = isArguments(m_vm, ident);435 auto addResult = m_declaredVariables.add(ident->impl());436 addResult.iterator->value.setIsVar(); // Treat destructuring parameters as "var"s.437 bool isValidStrictMode = addResult.isNewEntry && !isEval(m_vm, ident) && !isArgumentsIdent;438 m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;439 440 if (isArgumentsIdent)441 m_shadowsArguments = true;442 if (!addResult.isNewEntry)443 return BindingFailed;444 return isValidStrictMode ? BindingSucceeded : StrictBindingFailed;445 }446 447 427 void getUsedVariables(IdentifierSet& usedVariables) 448 428 { … … 1055 1035 bool isValidStrictMode() { return currentScope()->isValidStrictMode(); } 1056 1036 DeclarationResultMask declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); } 1057 Scope::BindingResult declareBoundParameter(const Identifier* ident) { return currentScope()->declareBoundParameter(ident); }1058 1037 bool breakIsValid() 1059 1038 { … … 1160 1139 template <class TreeBuilder> TreeSourceElements parseArrowFunctionSingleExpressionBodySourceElements(TreeBuilder&); 1161 1140 template <class TreeBuilder> TreeExpression parseArrowFunctionExpression(TreeBuilder&); 1162 template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, ExportType, const Identifier&, int depth,JSToken, AssignmentContext, const Identifier** duplicateIdentifier);1141 template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, ExportType, const Identifier&, JSToken, AssignmentContext, const Identifier** duplicateIdentifier); 1163 1142 template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createAssignmentElement(TreeBuilder&, TreeExpression&, const JSTextPosition&, const JSTextPosition&); 1164 1143 template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseBindingOrAssignmentElement(TreeBuilder& context, DestructuringKind, ExportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth); -
trunk/Source/JavaScriptCore/tests/stress/es6-default-parameters.js
r187351 r192586 236 236 237 237 238 // Test proper variable binding. 239 ;(function() { 240 function foo(a = function() { return b; }, {b}) { 241 assert(a() === 34); 242 assert(b === 34); 243 b = 50; 244 assert(a() === 50); 245 assert(b === 50); 246 } 247 function bar(a = function(x) { b = x; }, {b}) { 248 assert(b === 34); 249 a(50); 250 assert(b === 50); 251 } 252 function baz(f1 = function(x) { b = x; }, f2 = function() { return b; }, {b}) { 253 var b; 254 assert(b === 34); 255 assert(f2() === 34); 256 f1(50); 257 assert(b === 34); 258 assert(f2() === 50); 259 } 260 noInline(foo); 261 noInline(bar); 262 noInline(baz); 263 for (let i = 0; i < 1000; i++) { 264 foo(undefined, {b: 34}); 265 bar(undefined, {b: 34}); 266 baz(undefined, undefined, {b: 34}); 267 } 268 })(); 269 238 270 239 271 // Syntax errors.
Note:
See TracChangeset
for help on using the changeset viewer.