mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 12:51:30 -05:00
Merge pull request #28742 from Microsoft/fixIncrementalParsingBailout
Fix incremental parsing bailout logic
This commit is contained in:
@@ -1717,6 +1717,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function currentNode(parsingContext: ParsingContext): Node | undefined {
|
||||
// If we don't have a cursor or the parsing context isn't reusable, there's nothing to reuse.
|
||||
//
|
||||
// If there is an outstanding parse error that we've encountered, but not attached to
|
||||
// some node, then we cannot get a node from the old source tree. This is because we
|
||||
// want to mark the next node we encounter as being unusable.
|
||||
@@ -1724,30 +1726,17 @@ namespace ts {
|
||||
// Note: This may be too conservative. Perhaps we could reuse the node and set the bit
|
||||
// on it (or its leftmost child) as having the error. For now though, being conservative
|
||||
// is nice and likely won't ever affect perf.
|
||||
if (parseErrorBeforeNextFinishedNode) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!syntaxCursor) {
|
||||
// if we don't have a cursor, we could never return a node from the old tree.
|
||||
if (!syntaxCursor || !isReusableParsingContext(parsingContext) || parseErrorBeforeNextFinishedNode) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const node = syntaxCursor.currentNode(scanner.getStartPos());
|
||||
|
||||
// Can't reuse a missing node.
|
||||
if (nodeIsMissing(node)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Can't reuse a node that intersected the change range.
|
||||
if (node.intersectsChange) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Can't reuse a node that contains a parse error. This is necessary so that we
|
||||
// produce the same set of errors again.
|
||||
if (containsParseError(node)) {
|
||||
if (nodeIsMissing(node) || node.intersectsChange || containsParseError(node)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -1788,6 +1777,23 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
function isReusableParsingContext(parsingContext: ParsingContext): boolean {
|
||||
switch (parsingContext) {
|
||||
case ParsingContext.ClassMembers:
|
||||
case ParsingContext.SwitchClauses:
|
||||
case ParsingContext.SourceElements:
|
||||
case ParsingContext.BlockStatements:
|
||||
case ParsingContext.SwitchClauseStatements:
|
||||
case ParsingContext.EnumMembers:
|
||||
case ParsingContext.TypeMembers:
|
||||
case ParsingContext.VariableDeclarations:
|
||||
case ParsingContext.JSDocParameters:
|
||||
case ParsingContext.Parameters:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function canReuseNode(node: Node, parsingContext: ParsingContext): boolean {
|
||||
switch (parsingContext) {
|
||||
case ParsingContext.ClassMembers:
|
||||
@@ -1814,25 +1820,23 @@ namespace ts {
|
||||
case ParsingContext.Parameters:
|
||||
return isReusableParameter(node);
|
||||
|
||||
case ParsingContext.RestProperties:
|
||||
return false;
|
||||
|
||||
// Any other lists we do not care about reusing nodes in. But feel free to add if
|
||||
// you can do so safely. Danger areas involve nodes that may involve speculative
|
||||
// parsing. If speculative parsing is involved with the node, then the range the
|
||||
// parser reached while looking ahead might be in the edited range (see the example
|
||||
// in canReuseVariableDeclaratorNode for a good case of this).
|
||||
case ParsingContext.HeritageClauses:
|
||||
|
||||
// case ParsingContext.HeritageClauses:
|
||||
// This would probably be safe to reuse. There is no speculative parsing with
|
||||
// heritage clauses.
|
||||
|
||||
case ParsingContext.TypeParameters:
|
||||
// case ParsingContext.TypeParameters:
|
||||
// This would probably be safe to reuse. There is no speculative parsing with
|
||||
// type parameters. Note that that's because type *parameters* only occur in
|
||||
// unambiguous *type* contexts. While type *arguments* occur in very ambiguous
|
||||
// *expression* contexts.
|
||||
|
||||
case ParsingContext.TupleElementTypes:
|
||||
// case ParsingContext.TupleElementTypes:
|
||||
// This would probably be safe to reuse. There is no speculative parsing with
|
||||
// tuple types.
|
||||
|
||||
@@ -1841,28 +1845,28 @@ namespace ts {
|
||||
// produced from speculative parsing a < as a type argument list), we only have
|
||||
// the types because speculative parsing succeeded. Thus, the lookahead never
|
||||
// went past the end of the list and rewound.
|
||||
case ParsingContext.TypeArguments:
|
||||
// case ParsingContext.TypeArguments:
|
||||
|
||||
// Note: these are almost certainly not safe to ever reuse. Expressions commonly
|
||||
// need a large amount of lookahead, and we should not reuse them as they may
|
||||
// have actually intersected the edit.
|
||||
case ParsingContext.ArgumentExpressions:
|
||||
// case ParsingContext.ArgumentExpressions:
|
||||
|
||||
// This is not safe to reuse for the same reason as the 'AssignmentExpression'
|
||||
// cases. i.e. a property assignment may end with an expression, and thus might
|
||||
// have lookahead far beyond it's old node.
|
||||
case ParsingContext.ObjectLiteralMembers:
|
||||
// case ParsingContext.ObjectLiteralMembers:
|
||||
|
||||
// This is probably not safe to reuse. There can be speculative parsing with
|
||||
// type names in a heritage clause. There can be generic names in the type
|
||||
// name list, and there can be left hand side expressions (which can have type
|
||||
// arguments.)
|
||||
case ParsingContext.HeritageClauseElement:
|
||||
// case ParsingContext.HeritageClauseElement:
|
||||
|
||||
// Perhaps safe to reuse, but it's unlikely we'd see more than a dozen attributes
|
||||
// on any given element. Same for children.
|
||||
case ParsingContext.JsxAttributes:
|
||||
case ParsingContext.JsxChildren:
|
||||
// case ParsingContext.JsxAttributes:
|
||||
// case ParsingContext.JsxChildren:
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user