Skip to content

Commit

Permalink
Fix recursive functions
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Feb 27, 2019
1 parent 58756e9 commit 4b893c3
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 0 deletions.
@@ -0,0 +1,9 @@
expect(() => {
function f(i) {
if (i) f(i - 1);
x;
}

let x;
f(3);
}).not.toThrow();
@@ -0,0 +1,7 @@
function f(i) {
if (i) f(i - 1);
x;
}

let x;
f(3);
@@ -0,0 +1,7 @@
function f(i) {
if (i) f(i - 1);
x;
}

var x;
f(3);
@@ -0,0 +1,9 @@
expect(() => {
function f(i) {
if (i) f(i - 1);
x;
}

f(3);
let x;
}).toThrow(ReferenceError);
@@ -0,0 +1,7 @@
function f(i) {
if (i) f(i - 1);
x;
}

f(3);
let x;
@@ -0,0 +1,7 @@
function f(i) {
if (i) f(i - 1);
babelHelpers.tdz("x");
}

f(3);
var x;
@@ -0,0 +1,12 @@
expect(() => {
function f(i) {
return () => {
x;
f(i - 1);
};
}

const g = f(1);
let x;
g();
}).not.toThrow();
@@ -0,0 +1,10 @@
function f(i) {
return () => {
x;
f(i - 1);
};
}

const g = f(1);
let x;
g();
@@ -0,0 +1,12 @@
var x = babelHelpers.temporalUndefined;

function f(i) {
return () => {
babelHelpers.temporalRef(x, "x");
f(i - 1);
};
}

var g = f(1);
x = void 0;
g();
12 changes: 12 additions & 0 deletions packages/babel-traverse/src/path/introspection.js
Expand Up @@ -361,6 +361,12 @@ export function _guessExecutionStatusRelativeTo(
return keyPosition.target > keyPosition.this ? "before" : "after";
}

// Used to avoid infinite recursion in cases like
// function f() { if (false) f(); }
// f();
// It also works with indirect recursion.
const executionOrderCheckedNodes = new WeakSet();

export function _guessExecutionStatusRelativeToDifferentFunctions(
target: NodePath,
): RelativeExecutionStatus {
Expand Down Expand Up @@ -392,8 +398,14 @@ export function _guessExecutionStatusRelativeToDifferentFunctions(
return "unknown";
}

// Prevent infinte loops in recursive functions
if (executionOrderCheckedNodes.has(path.node)) continue;
executionOrderCheckedNodes.add(path.node);

const status = this._guessExecutionStatusRelativeTo(path);

executionOrderCheckedNodes.delete(path.node);

if (allStatus && allStatus !== status) {
return "unknown";
} else {
Expand Down

0 comments on commit 4b893c3

Please sign in to comment.