TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Truthy value not recognized by CFA as a constant condition in loops

Open Andarist opened this issue 3 years ago • 3 comments

Bug Report

🔎 Search Terms

while loop, infinite, cfa, control flow analysis

🕗 Version & Regression Information

This is also the 'Nightly' version in the playground: nightly TS playground

  • This is the behavior in every version I tried

⏯ Playground Link

Playground link with relevant code

💻 Code

type DigraphNode = {
  data: {
    key: string;
  };
  parent?: DigraphNode;
};

export function getStringPath(node: DigraphNode): string[] { // Function lacks ending return statement and return type does not include 'undefined'.(2366)
  let currentNode: DigraphNode = node;
  const path = [];

  while (currentNode) {
    // do not include root's key
    if (!currentNode.parent) {
      return path.reverse();
    }
    path.push(currentNode.data.key);
    currentNode = currentNode.parent;
  }
}

🙁 Actual behavior

I get an error:

Function lacks ending return statement and return type does not include 'undefined'.(2366)

🙂 Expected behavior

I shouldn't get an error because currentNode is always truthy, this should work in the same way as while (true) (TS playground).

Andarist avatar Oct 17 '22 10:10 Andarist

Interesting case. Right now this check is almost entirely syntactic; it does consider exhaustive switches but otherwise doesn't use CFA types at all.

This is probably a Won't Fix unless the fix is extremely cheap, since the logic of "this is the same as a while (true)" strongly implies that the program should just be written that way.

RyanCavanaugh avatar Oct 17 '22 18:10 RyanCavanaugh

Wouldn’t it just be the same check as the one that produces “this condition will always be true because…” diagnostics for if statements?

fatcerberus avatar Oct 17 '22 19:10 fatcerberus

This is probably a Won't Fix unless the fix is extremely cheap, since the logic of "this is the same as a while (true)" strongly implies that the program should just be written that way.

I agree that this is how it should be written and I've rewritten it this way before opening this issue. However, I think that the compiler shouldn't rely on this - that's why I've created an issue. A diagnostic like the one mentioned by @fatcerberus would also be nice but not necessary.

Wouldn’t it just be the same check as the one that produces “this condition will always be true because…” diagnostics for if statements?

Interestingly, this particular situation doesn't produce such a diagnostic even with the if statement and it suffers from the same issue related to the return type:

type DigraphNode = {
  data: {
    key: string;
  };
  parent?: DigraphNode;
};

export function getStringPath(node: DigraphNode): string[] { // Function lacks ending return statement and return type does not include 'undefined'.(2366)

  let currentNode: DigraphNode = node;
  const path = [];

  if (currentNode) {
    path.push(currentNode.data.key);
    return path.reverse();
  }
}

Andarist avatar Oct 17 '22 19:10 Andarist