Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / js / src / frontend / ParseContext.cpp
blobececac705b8e9a2d9c9af83d7ef904f88e94b544
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "frontend/ParseContext-inl.h"
9 #include "frontend/CompilationStencil.h" // ScopeContext
10 #include "frontend/Parser.h" // ParserBase
11 #include "js/friend/ErrorMessages.h" // JSMSG_*
13 using mozilla::Maybe;
14 using mozilla::Nothing;
15 using mozilla::Some;
17 namespace js {
18 namespace frontend {
20 using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
21 using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
23 const char* DeclarationKindString(DeclarationKind kind) {
24 switch (kind) {
25 case DeclarationKind::PositionalFormalParameter:
26 case DeclarationKind::FormalParameter:
27 return "formal parameter";
28 case DeclarationKind::CoverArrowParameter:
29 return "cover arrow parameter";
30 case DeclarationKind::Var:
31 return "var";
32 case DeclarationKind::Let:
33 return "let";
34 case DeclarationKind::Const:
35 return "const";
36 case DeclarationKind::Class:
37 return "class";
38 case DeclarationKind::Import:
39 return "import";
40 case DeclarationKind::BodyLevelFunction:
41 case DeclarationKind::ModuleBodyLevelFunction:
42 case DeclarationKind::LexicalFunction:
43 case DeclarationKind::SloppyLexicalFunction:
44 return "function";
45 case DeclarationKind::VarForAnnexBLexicalFunction:
46 return "annex b var";
47 case DeclarationKind::SimpleCatchParameter:
48 case DeclarationKind::CatchParameter:
49 return "catch parameter";
50 case DeclarationKind::PrivateName:
51 return "private name";
52 case DeclarationKind::Synthetic:
53 return "synthetic";
54 case DeclarationKind::PrivateMethod:
55 return "private method";
58 MOZ_CRASH("Bad DeclarationKind");
61 bool DeclarationKindIsVar(DeclarationKind kind) {
62 return kind == DeclarationKind::Var ||
63 kind == DeclarationKind::BodyLevelFunction ||
64 kind == DeclarationKind::VarForAnnexBLexicalFunction;
67 bool DeclarationKindIsParameter(DeclarationKind kind) {
68 return kind == DeclarationKind::PositionalFormalParameter ||
69 kind == DeclarationKind::FormalParameter;
72 bool UsedNameTracker::noteUse(FrontendContext* fc, TaggedParserAtomIndex name,
73 NameVisibility visibility, uint32_t scriptId,
74 uint32_t scopeId,
75 mozilla::Maybe<TokenPos> tokenPosition) {
76 if (UsedNameMap::AddPtr p = map_.lookupForAdd(name)) {
77 p->value().maybeUpdatePos(tokenPosition);
79 if (!p->value().noteUsedInScope(scriptId, scopeId)) {
80 return false;
82 } else {
83 // We need a token position precisely where we have private visibility.
84 MOZ_ASSERT(tokenPosition.isSome() ==
85 (visibility == NameVisibility::Private));
87 if (visibility == NameVisibility::Private) {
88 // We have seen at least one private name
89 hasPrivateNames_ = true;
92 UsedNameInfo info(fc, visibility, tokenPosition);
94 if (!info.noteUsedInScope(scriptId, scopeId)) {
95 return false;
97 if (!map_.add(p, name, std::move(info))) {
98 return false;
102 return true;
105 bool UsedNameTracker::getUnboundPrivateNames(
106 Vector<UnboundPrivateName, 8>& unboundPrivateNames) {
107 // We never saw any private names, so can just return early
108 if (!hasPrivateNames_) {
109 return true;
112 for (auto iter = map_.iter(); !iter.done(); iter.next()) {
113 // Don't care about public;
114 if (iter.get().value().isPublic()) {
115 continue;
118 // empty list means all bound
119 if (iter.get().value().empty()) {
120 continue;
123 if (!unboundPrivateNames.emplaceBack(iter.get().key(),
124 *iter.get().value().pos())) {
125 return false;
129 // Return a sorted list in ascendng order of position.
130 auto comparePosition = [](const auto& a, const auto& b) {
131 return a.position < b.position;
133 std::sort(unboundPrivateNames.begin(), unboundPrivateNames.end(),
134 comparePosition);
136 return true;
139 bool UsedNameTracker::hasUnboundPrivateNames(
140 FrontendContext* fc, mozilla::Maybe<UnboundPrivateName>& maybeUnboundName) {
141 // We never saw any private names, so can just return early
142 if (!hasPrivateNames_) {
143 return true;
146 Vector<UnboundPrivateName, 8> unboundPrivateNames(fc);
147 if (!getUnboundPrivateNames(unboundPrivateNames)) {
148 return false;
151 if (unboundPrivateNames.empty()) {
152 return true;
155 // GetUnboundPrivateNames returns the list sorted.
156 maybeUnboundName.emplace(unboundPrivateNames[0]);
157 return true;
160 void UsedNameTracker::UsedNameInfo::resetToScope(uint32_t scriptId,
161 uint32_t scopeId) {
162 while (!uses_.empty()) {
163 Use& innermost = uses_.back();
164 if (innermost.scopeId < scopeId) {
165 break;
167 MOZ_ASSERT(innermost.scriptId >= scriptId);
168 uses_.popBack();
172 void UsedNameTracker::rewind(RewindToken token) {
173 scriptCounter_ = token.scriptId;
174 scopeCounter_ = token.scopeId;
176 for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
177 r.front().value().resetToScope(token.scriptId, token.scopeId);
181 #if defined(DEBUG) || defined(JS_JITSPEW)
182 void UsedNameTracker::dump(ParserAtomsTable& table) {
183 js::Fprinter out(stderr);
185 out.printf("Used names:\n");
187 for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
188 const auto& item = r.front();
190 const auto& name = item.key();
191 const auto& nameInfo = item.value();
193 out.put(" ");
194 table.dumpCharsNoQuote(out, name);
195 out.put("\n");
197 if (nameInfo.visibility_ == NameVisibility::Private) {
198 out.put(" visibility: private\n");
201 if (nameInfo.firstUsePos_) {
202 const auto& pos = *nameInfo.firstUsePos_;
203 out.printf(" first use pos: %u\n", pos.begin);
206 out.printf(" %zu user(s)", nameInfo.uses_.length());
207 bool first = true;
208 for (const auto& use : nameInfo.uses_) {
209 if (first) {
210 first = false;
211 out.put(" (");
212 } else {
213 out.put(", ");
215 out.printf("%u/%u", use.scriptId, use.scopeId);
217 if (!first) {
218 out.put(")");
220 out.put("\n");
223 #endif
225 void ParseContext::Scope::dump(ParseContext* pc, ParserBase* parser) {
226 fprintf(stdout, "ParseScope %p", this);
228 fprintf(stdout, "\n decls:\n");
229 for (DeclaredNameMap::Range r = declared_->all(); !r.empty(); r.popFront()) {
230 auto index = r.front().key();
231 UniqueChars bytes = parser->parserAtoms().toPrintableString(index);
232 if (!bytes) {
233 ReportOutOfMemory(pc->sc()->fc_);
234 return;
236 DeclaredNameInfo& info = r.front().value().wrapped;
237 fprintf(stdout, " %s %s%s\n", DeclarationKindString(info.kind()),
238 bytes.get(), info.closedOver() ? " (closed over)" : "");
241 fprintf(stdout, "\n");
244 bool ParseContext::Scope::addPossibleAnnexBFunctionBox(ParseContext* pc,
245 FunctionBox* funbox) {
246 if (!possibleAnnexBFunctionBoxes_) {
247 if (!possibleAnnexBFunctionBoxes_.acquire(pc->sc()->fc_)) {
248 return false;
252 return maybeReportOOM(pc, possibleAnnexBFunctionBoxes_->append(funbox));
255 bool ParseContext::Scope::propagateAndMarkAnnexBFunctionBoxes(
256 ParseContext* pc, ParserBase* parser) {
257 // Strict mode doesn't have wack Annex B function semantics.
258 if (pc->sc()->strict() || !possibleAnnexBFunctionBoxes_ ||
259 possibleAnnexBFunctionBoxes_->empty()) {
260 return true;
263 if (this == &pc->varScope()) {
264 // Base case: actually declare the Annex B vars and mark applicable
265 // function boxes as Annex B.
266 Maybe<DeclarationKind> redeclaredKind;
267 uint32_t unused;
268 for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
269 bool annexBApplies;
270 if (!pc->computeAnnexBAppliesToLexicalFunctionInInnermostScope(
271 funbox, parser, &annexBApplies)) {
272 return false;
274 if (annexBApplies) {
275 if (!pc->tryDeclareVar(funbox->explicitName(), parser,
276 DeclarationKind::VarForAnnexBLexicalFunction,
277 DeclaredNameInfo::npos, &redeclaredKind,
278 &unused)) {
279 return false;
282 MOZ_ASSERT(!redeclaredKind);
283 funbox->isAnnexB = true;
286 } else {
287 // Inner scope case: propagate still applicable function boxes to the
288 // enclosing scope.
289 for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
290 bool annexBApplies;
291 if (!pc->computeAnnexBAppliesToLexicalFunctionInInnermostScope(
292 funbox, parser, &annexBApplies)) {
293 return false;
295 if (annexBApplies) {
296 if (!enclosing()->addPossibleAnnexBFunctionBox(pc, funbox)) {
297 return false;
303 return true;
306 static bool DeclarationKindIsCatchParameter(DeclarationKind kind) {
307 return kind == DeclarationKind::SimpleCatchParameter ||
308 kind == DeclarationKind::CatchParameter;
311 bool ParseContext::Scope::addCatchParameters(ParseContext* pc,
312 Scope& catchParamScope) {
313 if (pc->useAsmOrInsideUseAsm()) {
314 return true;
317 for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty();
318 r.popFront()) {
319 DeclarationKind kind = r.front().value()->kind();
320 uint32_t pos = r.front().value()->pos();
321 MOZ_ASSERT(DeclarationKindIsCatchParameter(kind));
322 auto name = r.front().key();
323 AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name);
324 MOZ_ASSERT(!p);
325 if (!addDeclaredName(pc, p, name, kind, pos)) {
326 return false;
330 return true;
333 void ParseContext::Scope::removeCatchParameters(ParseContext* pc,
334 Scope& catchParamScope) {
335 if (pc->useAsmOrInsideUseAsm()) {
336 return;
339 for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty();
340 r.popFront()) {
341 auto name = r.front().key();
342 DeclaredNamePtr p = declared_->lookup(name);
343 MOZ_ASSERT(p);
345 // This check is needed because the catch body could have declared
346 // vars, which would have been added to catchParamScope.
347 if (DeclarationKindIsCatchParameter(r.front().value()->kind())) {
348 declared_->remove(p);
353 ParseContext::ParseContext(FrontendContext* fc, ParseContext*& parent,
354 SharedContext* sc, ErrorReporter& errorReporter,
355 CompilationState& compilationState,
356 Directives* newDirectives, bool isFull)
357 : Nestable<ParseContext>(&parent),
358 sc_(sc),
359 errorReporter_(errorReporter),
360 innermostStatement_(nullptr),
361 innermostScope_(nullptr),
362 varScope_(nullptr),
363 positionalFormalParameterNames_(fc->nameCollectionPool()),
364 closedOverBindingsForLazy_(fc->nameCollectionPool()),
365 innerFunctionIndexesForLazy(sc->fc_),
366 newDirectives(newDirectives),
367 lastYieldOffset(NoYieldOffset),
368 lastAwaitOffset(NoAwaitOffset),
369 scriptId_(compilationState.usedNames.nextScriptId()),
370 superScopeNeedsHomeObject_(false) {
371 if (isFunctionBox()) {
372 if (functionBox()->isNamedLambda()) {
373 namedLambdaScope_.emplace(fc, parent, compilationState.usedNames);
375 functionScope_.emplace(fc, parent, compilationState.usedNames);
379 bool ParseContext::init() {
380 if (scriptId_ == UINT32_MAX) {
381 errorReporter_.errorNoOffset(JSMSG_NEED_DIET, "script");
382 return false;
385 FrontendContext* fc = sc()->fc_;
387 if (isFunctionBox()) {
388 // Named lambdas always need a binding for their own name. If this
389 // binding is closed over when we finish parsing the function iNn
390 // finishFunctionScopes, the function box needs to be marked as
391 // needing a dynamic DeclEnv object.
392 if (functionBox()->isNamedLambda()) {
393 if (!namedLambdaScope_->init(this)) {
394 return false;
396 AddDeclaredNamePtr p = namedLambdaScope_->lookupDeclaredNameForAdd(
397 functionBox()->explicitName());
398 MOZ_ASSERT(!p);
399 if (!namedLambdaScope_->addDeclaredName(
400 this, p, functionBox()->explicitName(), DeclarationKind::Const,
401 DeclaredNameInfo::npos)) {
402 return false;
406 if (!functionScope_->init(this)) {
407 return false;
410 if (!positionalFormalParameterNames_.acquire(fc)) {
411 return false;
415 if (!closedOverBindingsForLazy_.acquire(fc)) {
416 return false;
419 return true;
422 bool ParseContext::computeAnnexBAppliesToLexicalFunctionInInnermostScope(
423 FunctionBox* funbox, ParserBase* parser, bool* annexBApplies) {
424 MOZ_ASSERT(!sc()->strict());
426 TaggedParserAtomIndex name = funbox->explicitName();
427 Maybe<DeclarationKind> redeclaredKind;
428 if (!isVarRedeclaredInInnermostScope(
429 name, parser, DeclarationKind::VarForAnnexBLexicalFunction,
430 &redeclaredKind)) {
431 return false;
434 if (!redeclaredKind && isFunctionBox()) {
435 Scope& funScope = functionScope();
436 if (&funScope != &varScope()) {
437 // Annex B.3.3.1 disallows redeclaring parameter names. In the
438 // presence of parameter expressions, parameter names are on the
439 // function scope, which encloses the var scope. This means the
440 // isVarRedeclaredInInnermostScope call above would not catch this
441 // case, so test it manually.
442 if (DeclaredNamePtr p = funScope.lookupDeclaredName(name)) {
443 DeclarationKind declaredKind = p->value()->kind();
444 if (DeclarationKindIsParameter(declaredKind)) {
445 redeclaredKind = Some(declaredKind);
446 } else {
447 MOZ_ASSERT(FunctionScope::isSpecialName(name));
453 // If an early error would have occurred already, this function should not
454 // exhibit Annex B.3.3 semantics.
455 *annexBApplies = !redeclaredKind;
456 return true;
459 bool ParseContext::isVarRedeclaredInInnermostScope(
460 TaggedParserAtomIndex name, ParserBase* parser, DeclarationKind kind,
461 mozilla::Maybe<DeclarationKind>* out) {
462 uint32_t unused;
463 return tryDeclareVarHelper<DryRunInnermostScopeOnly>(
464 name, parser, kind, DeclaredNameInfo::npos, out, &unused);
467 bool ParseContext::isVarRedeclaredInEval(TaggedParserAtomIndex name,
468 ParserBase* parser,
469 DeclarationKind kind,
470 Maybe<DeclarationKind>* out) {
471 auto maybeKind = parser->getCompilationState()
472 .scopeContext.lookupLexicalBindingInEnclosingScope(name);
473 if (!maybeKind) {
474 *out = Nothing();
475 return true;
478 switch (*maybeKind) {
479 case ScopeContext::EnclosingLexicalBindingKind::Let:
480 *out = Some(DeclarationKind::Let);
481 break;
482 case ScopeContext::EnclosingLexicalBindingKind::Const:
483 *out = Some(DeclarationKind::Const);
484 break;
485 case ScopeContext::EnclosingLexicalBindingKind::CatchParameter:
486 *out = Some(DeclarationKind::CatchParameter);
487 break;
488 case ScopeContext::EnclosingLexicalBindingKind::Synthetic:
489 *out = Some(DeclarationKind::Synthetic);
490 break;
491 case ScopeContext::EnclosingLexicalBindingKind::PrivateMethod:
492 *out = Some(DeclarationKind::PrivateMethod);
493 break;
495 return true;
498 bool ParseContext::tryDeclareVar(TaggedParserAtomIndex name, ParserBase* parser,
499 DeclarationKind kind, uint32_t beginPos,
500 Maybe<DeclarationKind>* redeclaredKind,
501 uint32_t* prevPos) {
502 return tryDeclareVarHelper<NotDryRun>(name, parser, kind, beginPos,
503 redeclaredKind, prevPos);
506 template <ParseContext::DryRunOption dryRunOption>
507 bool ParseContext::tryDeclareVarHelper(TaggedParserAtomIndex name,
508 ParserBase* parser, DeclarationKind kind,
509 uint32_t beginPos,
510 Maybe<DeclarationKind>* redeclaredKind,
511 uint32_t* prevPos) {
512 MOZ_ASSERT(DeclarationKindIsVar(kind));
514 // It is an early error if a 'var' declaration appears inside a
515 // scope contour that has a lexical declaration of the same name. For
516 // example, the following are early errors:
518 // { let x; var x; }
519 // { { var x; } let x; }
521 // And the following are not:
523 // { var x; var x; }
524 // { { let x; } var x; }
526 for (ParseContext::Scope* scope = innermostScope();
527 scope != varScope().enclosing(); scope = scope->enclosing()) {
528 if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
529 DeclarationKind declaredKind = p->value()->kind();
530 if (DeclarationKindIsVar(declaredKind)) {
531 if (dryRunOption == NotDryRun) {
532 RedeclareVar(p, kind);
534 } else if (!DeclarationKindIsParameter(declaredKind)) {
535 // Annex B.3.5 allows redeclaring simple (non-destructured)
536 // catch parameters with var declarations.
537 bool annexB35Allowance =
538 declaredKind == DeclarationKind::SimpleCatchParameter;
540 // Annex B.3.3 allows redeclaring functions in the same block.
541 bool annexB33Allowance =
542 declaredKind == DeclarationKind::SloppyLexicalFunction &&
543 kind == DeclarationKind::VarForAnnexBLexicalFunction &&
544 scope == innermostScope();
546 if (!annexB35Allowance && !annexB33Allowance) {
547 *redeclaredKind = Some(declaredKind);
548 *prevPos = p->value()->pos();
549 return true;
551 } else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) {
552 MOZ_ASSERT(DeclarationKindIsParameter(declaredKind));
554 // Annex B.3.3.1 disallows redeclaring parameter names.
555 // We don't need to set *prevPos here since this case is not
556 // an error.
557 *redeclaredKind = Some(declaredKind);
558 return true;
560 } else if (dryRunOption == NotDryRun) {
561 if (!scope->addDeclaredName(this, p, name, kind, beginPos)) {
562 return false;
566 // DryRunOption is used for propagating Annex B functions: we don't
567 // want to declare the synthesized Annex B vars until we exit the var
568 // scope and know that no early errors would have occurred. In order
569 // to avoid quadratic search, we only check for var redeclarations in
570 // the innermost scope when doing a dry run.
571 if (dryRunOption == DryRunInnermostScopeOnly) {
572 break;
576 if (!sc()->strict() && sc()->isEvalContext() &&
577 (dryRunOption == NotDryRun || innermostScope() == &varScope())) {
578 if (!isVarRedeclaredInEval(name, parser, kind, redeclaredKind)) {
579 return false;
581 // We don't have position information at runtime.
582 *prevPos = DeclaredNameInfo::npos;
585 return true;
588 bool ParseContext::hasUsedName(const UsedNameTracker& usedNames,
589 TaggedParserAtomIndex name) {
590 if (auto p = usedNames.lookup(name)) {
591 return p->value().isUsedInScript(scriptId());
593 return false;
596 bool ParseContext::hasUsedFunctionSpecialName(const UsedNameTracker& usedNames,
597 TaggedParserAtomIndex name) {
598 MOZ_ASSERT(name == TaggedParserAtomIndex::WellKnown::arguments() ||
599 name == TaggedParserAtomIndex::WellKnown::dot_this_() ||
600 name == TaggedParserAtomIndex::WellKnown::dot_newTarget_());
601 return hasUsedName(usedNames, name) ||
602 functionBox()->bindingsAccessedDynamically();
605 bool ParseContext::declareFunctionThis(const UsedNameTracker& usedNames,
606 bool canSkipLazyClosedOverBindings) {
607 // The asm.js validator does all its own symbol-table management so, as an
608 // optimization, avoid doing any work here.
609 if (useAsmOrInsideUseAsm()) {
610 return true;
613 // Derived class constructors emit JSOp::CheckReturn, which requires
614 // '.this' to be bound. Class field initializers implicitly read `.this`.
615 // Therefore we unconditionally declare `.this` in all class constructors.
616 FunctionBox* funbox = functionBox();
617 auto dotThis = TaggedParserAtomIndex::WellKnown::dot_this_();
619 bool declareThis;
620 if (canSkipLazyClosedOverBindings) {
621 declareThis = funbox->functionHasThisBinding();
622 } else {
623 declareThis = hasUsedFunctionSpecialName(usedNames, dotThis) ||
624 funbox->isClassConstructor();
627 if (declareThis) {
628 ParseContext::Scope& funScope = functionScope();
629 AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis);
630 MOZ_ASSERT(!p);
631 if (!funScope.addDeclaredName(this, p, dotThis, DeclarationKind::Var,
632 DeclaredNameInfo::npos)) {
633 return false;
635 funbox->setFunctionHasThisBinding();
638 return true;
641 bool ParseContext::declareFunctionArgumentsObject(
642 const UsedNameTracker& usedNames, bool canSkipLazyClosedOverBindings) {
643 FunctionBox* funbox = functionBox();
644 ParseContext::Scope& funScope = functionScope();
645 ParseContext::Scope& _varScope = varScope();
647 bool usesArguments = false;
648 bool hasExtraBodyVarScope = &funScope != &_varScope;
650 // Time to implement the odd semantics of 'arguments'.
651 auto argumentsName = TaggedParserAtomIndex::WellKnown::arguments();
653 bool tryDeclareArguments;
654 if (canSkipLazyClosedOverBindings) {
655 tryDeclareArguments = funbox->shouldDeclareArguments();
656 } else {
657 tryDeclareArguments = hasUsedFunctionSpecialName(usedNames, argumentsName);
660 // ES 9.2.12 steps 19 and 20 say formal parameters, lexical bindings,
661 // and body-level functions named 'arguments' shadow the arguments
662 // object.
664 // So even if there wasn't a free use of 'arguments' but there is a var
665 // binding of 'arguments', we still might need the arguments object.
667 // If we have an extra var scope due to parameter expressions and the body
668 // declared 'var arguments', we still need to declare 'arguments' in the
669 // function scope.
670 DeclaredNamePtr p = _varScope.lookupDeclaredName(argumentsName);
671 if (p && p->value()->kind() == DeclarationKind::Var) {
672 if (hasExtraBodyVarScope) {
673 tryDeclareArguments = true;
674 } else {
675 usesArguments = true;
679 if (tryDeclareArguments) {
680 AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(argumentsName);
681 if (!p) {
682 if (!funScope.addDeclaredName(this, p, argumentsName,
683 DeclarationKind::Var,
684 DeclaredNameInfo::npos)) {
685 return false;
687 funbox->setShouldDeclareArguments();
688 usesArguments = true;
689 } else if (hasExtraBodyVarScope) {
690 // Formal parameters shadow the arguments object.
691 return true;
695 if (usesArguments) {
696 funbox->setNeedsArgsObj();
699 return true;
702 bool ParseContext::declareNewTarget(const UsedNameTracker& usedNames,
703 bool canSkipLazyClosedOverBindings) {
704 // The asm.js validator does all its own symbol-table management so, as an
705 // optimization, avoid doing any work here.
706 if (useAsmOrInsideUseAsm()) {
707 return true;
710 FunctionBox* funbox = functionBox();
711 auto dotNewTarget = TaggedParserAtomIndex::WellKnown::dot_newTarget_();
713 bool declareNewTarget;
714 if (canSkipLazyClosedOverBindings) {
715 declareNewTarget = funbox->functionHasNewTargetBinding();
716 } else {
717 declareNewTarget = hasUsedFunctionSpecialName(usedNames, dotNewTarget);
720 if (declareNewTarget) {
721 ParseContext::Scope& funScope = functionScope();
722 AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotNewTarget);
723 MOZ_ASSERT(!p);
724 if (!funScope.addDeclaredName(this, p, dotNewTarget, DeclarationKind::Var,
725 DeclaredNameInfo::npos)) {
726 return false;
728 funbox->setFunctionHasNewTargetBinding();
731 return true;
734 bool ParseContext::declareDotGeneratorName() {
735 // The special '.generator' binding must be on the function scope, and must
736 // be marked closed-over, as generators expect to find it on the CallObject.
737 ParseContext::Scope& funScope = functionScope();
738 auto dotGenerator = TaggedParserAtomIndex::WellKnown::dot_generator_();
739 AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotGenerator);
740 if (!p) {
741 if (!funScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
742 DeclaredNameInfo::npos, ClosedOver::Yes)) {
743 return false;
746 return true;
749 bool ParseContext::declareTopLevelDotGeneratorName() {
750 // Provide a .generator binding on the module scope for compatibility with
751 // generator code, which expect to find it on the CallObject for normal
752 // generators.
753 MOZ_ASSERT(
754 sc()->isModuleContext(),
755 "Tried to declare top level dot generator in a non-module context.");
756 ParseContext::Scope& modScope = varScope();
757 auto dotGenerator = TaggedParserAtomIndex::WellKnown::dot_generator_();
758 AddDeclaredNamePtr p = modScope.lookupDeclaredNameForAdd(dotGenerator);
759 return p ||
760 modScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
761 DeclaredNameInfo::npos, ClosedOver::Yes);
764 } // namespace frontend
766 } // namespace js