All container nodes are kept on a linked list in declaration order. This list is used by the getLocalNameOfContainer function in the type checker to validate that the local name used for a container is unique.
(node *ast.Node, containerFlags ContainerFlags)
| 1475 | // the getLocalNameOfContainer function in the type checker to validate that the local name |
| 1476 | // used for a container is unique. |
| 1477 | func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) { |
| 1478 | // Before we recurse into a node's children, we first save the existing parent, container |
| 1479 | // and block-container. Then after we pop out of processing the children, we restore |
| 1480 | // these saved values. |
| 1481 | saveContainer := b.container |
| 1482 | saveThisContainer := b.thisContainer |
| 1483 | savedBlockScopeContainer := b.blockScopeContainer |
| 1484 | // Depending on what kind of node this is, we may have to adjust the current container |
| 1485 | // and block-container. If the current node is a container, then it is automatically |
| 1486 | // considered the current block-container as well. Also, for containers that we know |
| 1487 | // may contain locals, we eagerly initialize the .locals field. We do this because |
| 1488 | // it's highly likely that the .locals will be needed to place some child in (for example, |
| 1489 | // a parameter, or variable declaration). |
| 1490 | // |
| 1491 | // However, we do not proactively create the .locals for block-containers because it's |
| 1492 | // totally normal and common for block-containers to never actually have a block-scoped |
| 1493 | // variable in them. We don't want to end up allocating an object for every 'block' we |
| 1494 | // run into when most of them won't be necessary. |
| 1495 | // |
| 1496 | // Finally, if this is a block-container, then we clear out any existing .locals object |
| 1497 | // it may contain within it. This happens in incremental scenarios. Because we can be |
| 1498 | // reusing a node from a previous compilation, that node may have had 'locals' created |
| 1499 | // for it. We must clear this so we don't accidentally move any stale data forward from |
| 1500 | // a previous compilation. |
| 1501 | if containerFlags&ContainerFlagsIsContainer != 0 { |
| 1502 | b.container = node |
| 1503 | b.blockScopeContainer = node |
| 1504 | if containerFlags&ContainerFlagsHasLocals != 0 { |
| 1505 | // localsContainer := node |
| 1506 | // localsContainer.LocalsContainerData().locals = make(SymbolTable) |
| 1507 | b.addToContainerChain(node) |
| 1508 | } |
| 1509 | } else if containerFlags&ContainerFlagsIsBlockScopedContainer != 0 { |
| 1510 | b.blockScopeContainer = node |
| 1511 | b.addToContainerChain(node) |
| 1512 | } |
| 1513 | if containerFlags&ContainerFlagsIsThisContainer != 0 { |
| 1514 | b.thisContainer = node |
| 1515 | } |
| 1516 | if containerFlags&ContainerFlagsIsControlFlowContainer != 0 { |
| 1517 | saveCurrentFlow := b.currentFlow |
| 1518 | saveBreakTarget := b.currentBreakTarget |
| 1519 | saveContinueTarget := b.currentContinueTarget |
| 1520 | saveReturnTarget := b.currentReturnTarget |
| 1521 | saveExceptionTarget := b.currentExceptionTarget |
| 1522 | saveActiveLabelList := b.activeLabelList |
| 1523 | saveHasExplicitReturn := b.hasExplicitReturn |
| 1524 | saveSeenThisKeyword := b.seenThisKeyword |
| 1525 | isImmediatelyInvoked := (containerFlags&ContainerFlagsIsFunctionExpression != 0 && |
| 1526 | !ast.HasSyntacticModifier(node, ast.ModifierFlagsAsync) && |
| 1527 | !isGeneratorFunctionExpression(node) && |
| 1528 | ast.GetImmediatelyInvokedFunctionExpression(node) != nil) || node.Kind == ast.KindClassStaticBlockDeclaration |
| 1529 | // A non-async, non-generator IIFE is considered part of the containing control flow. Return statements behave |
| 1530 | // similarly to break statements that exit to a label just past the statement body. |
| 1531 | if !isImmediatelyInvoked { |
| 1532 | flowStart := b.newFlowNode(ast.FlowFlagsStart) |
| 1533 | b.currentFlow = flowStart |
| 1534 | if containerFlags&(ContainerFlagsIsFunctionExpression|ContainerFlagsIsObjectLiteralOrClassExpressionMethodOrAccessor) != 0 { |
no test coverage detected