Skip to content

Commit fabf5d8

Browse files
committed
findAncestor:single callback returns boolean|"quit"
Previously there was a 'found' callback and a 'quit' callback.
1 parent 3739216 commit fabf5d8

File tree

2 files changed

+41
-35
lines changed

2 files changed

+41
-35
lines changed

src/compiler/checker.ts

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,9 @@ namespace ts {
803803

804804
function isUsedInFunctionOrInstanceProperty(usage: Node, declaration: Node, container?: Node): boolean {
805805
return !!findAncestor(usage, current => {
806+
if (current === container) {
807+
return "quit";
808+
}
806809
if (isFunctionLike(current)) {
807810
return true;
808811
}
@@ -824,7 +827,7 @@ namespace ts {
824827
}
825828
}
826829
}
827-
}, n => n === container);
830+
});
828831
}
829832
}
830833

@@ -1246,7 +1249,7 @@ namespace ts {
12461249
* Return false if 'stopAt' node is reached or isFunctionLike(current) === true.
12471250
*/
12481251
function isSameScopeDescendentOf(initial: Node, parent: Node, stopAt: Node): boolean {
1249-
return parent && !!findAncestor(initial, n => n === parent, n => n === stopAt || isFunctionLike(n));
1252+
return parent && !!findAncestor(initial, n => n === stopAt || isFunctionLike(n) ? "quit" : n === parent);
12501253
}
12511254

12521255
function getAnyImportSyntax(node: Node): AnyImportSyntax {
@@ -7890,6 +7893,9 @@ namespace ts {
78907893
// the type parameters introduced by enclosing declarations. We just pick the first
78917894
// declaration since multiple declarations will all have the same parent anyway.
78927895
return !!findAncestor(symbol.declarations[0], node => {
7896+
if (node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.SourceFile) {
7897+
return "quit";
7898+
}
78937899
switch (node.kind) {
78947900
case SyntaxKind.FunctionType:
78957901
case SyntaxKind.ConstructorType:
@@ -7937,8 +7943,7 @@ namespace ts {
79377943
}
79387944
break;
79397945
}
7940-
},
7941-
node => node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.SourceFile);
7946+
});
79427947
}
79437948

79447949
function isTopLevelTypeAlias(symbol: Symbol) {
@@ -10384,8 +10389,7 @@ namespace ts {
1038410389
// The expression is restricted to a single identifier or a sequence of identifiers separated by periods
1038510390
return !!findAncestor(
1038610391
node,
10387-
n => n.kind === SyntaxKind.TypeQuery,
10388-
n => n.kind !== SyntaxKind.TypeQuery && n.kind !== SyntaxKind.Identifier && n.kind !== SyntaxKind.QualifiedName);
10392+
n => n.kind === SyntaxKind.TypeQuery ? true : n.kind === SyntaxKind.Identifier || n.kind === SyntaxKind.QualifiedName ? false : "quit");
1038910393
}
1039010394

1039110395
// Return the flow cache key for a "dotted name" (i.e. a sequence of identifiers
@@ -11629,7 +11633,7 @@ namespace ts {
1162911633
}
1163011634

1163111635
function hasParentWithAssignmentsMarked(node: Node) {
11632-
return !!findAncestor(node.parent, node => isFunctionLike(node) && getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked);
11636+
return !!findAncestor(node.parent, node => isFunctionLike(node) && !!(getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked));
1163311637
}
1163411638

1163511639
function markParameterAssignments(node: Node) {
@@ -11801,7 +11805,7 @@ namespace ts {
1180111805
}
1180211806

1180311807
function isInsideFunction(node: Node, threshold: Node): boolean {
11804-
return !!findAncestor(node, isFunctionLike, n => n === threshold);
11808+
return !!findAncestor(node, n => n === threshold ? "quit" : isFunctionLike(n));
1180511809
}
1180611810

1180711811
function checkNestedBlockScopedBinding(node: Identifier, symbol: Symbol): void {
@@ -11875,7 +11879,7 @@ namespace ts {
1187511879

1187611880
// at this point we know that node is the target of assignment
1187711881
// now check that modification happens inside the statement part of the ForStatement
11878-
return !!findAncestor(current, n => n === container.statement, n => n === container);
11882+
return !!findAncestor(current, n => n === container ? "quit" : n === container.statement);
1187911883
}
1188011884

1188111885
function captureLexicalThis(node: Node, container: Node): void {
@@ -12057,7 +12061,7 @@ namespace ts {
1205712061
}
1205812062

1205912063
function isInConstructorArgumentInitializer(node: Node, constructorDecl: Node): boolean {
12060-
return !!findAncestor(node, n => n.kind === SyntaxKind.Parameter, n => n === constructorDecl);
12064+
return !!findAncestor(node, n => n === constructorDecl ? "quit" : n.kind === SyntaxKind.Parameter);
1206112065
}
1206212066

1206312067
function checkSuperExpression(node: Node): Type {
@@ -12083,7 +12087,7 @@ namespace ts {
1208312087
// class B {
1208412088
// [super.foo()]() {}
1208512089
// }
12086-
const current = findAncestor(node, n => n.kind === SyntaxKind.ComputedPropertyName, n => n === container);
12090+
const current = findAncestor(node, n => n === container ? "quit" : n.kind === SyntaxKind.ComputedPropertyName);
1208712091
if (current && current.kind === SyntaxKind.ComputedPropertyName) {
1208812092
error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name);
1208912093
}
@@ -12687,7 +12691,7 @@ namespace ts {
1268712691
}
1268812692

1268912693
function getContextualMapper(node: Node) {
12690-
node = findAncestor(node, n => n.contextualMapper);
12694+
node = findAncestor(node, n => !!n.contextualMapper);
1269112695
return node ? node.contextualMapper : identityMapper;
1269212696
}
1269312697

@@ -19138,14 +19142,17 @@ namespace ts {
1913819142
// - parameter is wrapped in function-like entity
1913919143
if (findAncestor(
1914019144
n,
19141-
current =>
19142-
isFunctionLike(current.parent) ||
19143-
// computed property names/initializers in instance property declaration of class like entities
19144-
// are executed in constructor and thus deferred
19145-
(current.parent.kind === SyntaxKind.PropertyDeclaration &&
19146-
!(hasModifier(current.parent, ModifierFlags.Static)) &&
19147-
isClassLike(current.parent.parent)),
19148-
n => n === node.initializer)) {
19145+
current => {
19146+
if (current === node.initializer) {
19147+
return "quit";
19148+
}
19149+
return isFunctionLike(current.parent) ||
19150+
// computed property names/initializers in instance property declaration of class like entities
19151+
// are executed in constructor and thus deferred
19152+
(current.parent.kind === SyntaxKind.PropertyDeclaration &&
19153+
!(hasModifier(current.parent, ModifierFlags.Static)) &&
19154+
isClassLike(current.parent.parent));
19155+
})) {
1914919156
return;
1915019157
}
1915119158
// fall through to report error
@@ -19946,13 +19953,15 @@ namespace ts {
1994619953
if (!checkGrammarStatementInAmbientContext(node)) {
1994719954
findAncestor(node.parent,
1994819955
current => {
19956+
if (isFunctionLike(current)) {
19957+
return "quit";
19958+
}
1994919959
if (current.kind === SyntaxKind.LabeledStatement && (<LabeledStatement>current).label.text === node.label.text) {
1995019960
const sourceFile = getSourceFileOfNode(node);
1995119961
grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0, getTextOfNodeFromSourceText(sourceFile.text, node.label));
1995219962
return true;
1995319963
}
19954-
},
19955-
isFunctionLike);
19964+
});
1995619965
}
1995719966

1995819967
// ensure that label is unique

src/compiler/core.ts

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -224,29 +224,26 @@ namespace ts {
224224
}
225225
return undefined;
226226
}
227-
228227
/**
229228
* Iterates through the parent chain of a node and performs the callback on each parent until the callback
230229
* returns a truthy value, then returns that value.
231-
* If no such value is found, it applies the callback until the parent pointer is undefined or 'done' returns true
230+
* If no such value is found, it applies the callback until the parent pointer is undefined or the callback returns "quit"
232231
* At that point findAncestor returns undefined.
233232
*/
234-
export function findAncestor<T>(node: Node, callback: (element: Node) => T | undefined, done?: (element: Node) => boolean): Node {
235-
if (node) {
236-
while (node) {
237-
if (done && done(node)) {
238-
break;
239-
}
240-
if (callback(node)) {
241-
return node;
242-
}
243-
node = node.parent;
233+
export function findAncestor(node: Node, callback: (element: Node) => boolean | "quit"): Node {
234+
while (node) {
235+
const result = callback(node);
236+
if (result === "quit") {
237+
return undefined;
244238
}
239+
else if (result) {
240+
return node;
241+
}
242+
node = node.parent;
245243
}
246244
return undefined;
247245
}
248246

249-
250247
export function zipWith<T, U>(arrayA: T[], arrayB: U[], callback: (a: T, b: U, index: number) => void): void {
251248
Debug.assert(arrayA.length === arrayB.length);
252249
for (let i = 0; i < arrayA.length; i++) {

0 commit comments

Comments
 (0)