TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Spurious "referenced directly or indirectly in its own initializer" when combined with narrowing, asserts function, and loop

Open jakebailey opened this issue 2 years ago • 3 comments

Bug Report

🔎 Search Terms

referenced directly or indirectly asserts

🕗 Version & Regression Information

  • This is the behavior in every version I tried

⏯ Playground Link

Playground Link

💻 Code

declare const myRequire: ((p: string) => {} | undefined) | undefined;

declare function assertIsDefined<T>(value: T): asserts value is NonNullable<T>

function fn1() {
    if (!myRequire) {
        return;
    }

    for (const p of ["a", "b"]) {
        // Error?
        const result = myRequire("something");
        assertIsDefined(result);
    }
}

🙁 Actual behavior

result is claimed to be referenced directly or indirectly in its initializer.

Modifying the code in various ways makes the error go away.

🙂 Expected behavior

No error; there's no relationship between the initializer and the result.

jakebailey avatar Apr 21 '23 19:04 jakebailey

Here's what happens:

  • checkVariableLikeDeclaration call for result variable.
  • getTypeOfSymbol for result variable.
  • Type is inferred from initializer, so checkExpression for myRequire("something").
  • getFlowTypeOfReference for myRequire.
  • getTypeAtFlowLoopLabel for back edge of loop.
  • getEffectsSignature for assertIsDefined(result) call.
  • inferTypeArguments for that call.
  • checkExpression for result argument.
  • getTypeOfSymbol for result variable.
  • Circularity!

We probably could be a bit smarter about realizing that none of the arguments in the assertIsDefined(result) call match the reference (myRequire) for which we are currently doing CFA.

ahejlsberg avatar Apr 21 '23 20:04 ahejlsberg

I'm noticing an odd "referenced directly or indirectly in its own initializer" error in my code. Wondering if you can help confirm whether this is the same issue or a separate one?

Playground link

TomerAberbach avatar Aug 10 '24 02:08 TomerAberbach

Not sure if this is the same case but my problem looks also very similar: Playground link

In case somebody wonders about the strange "initial buffer" location: The code originates from some audio generation where I get chunks of audio and dynamically size the buffer initially. I get the estimated audio sample count as part of the initial chunk.

Danielku15 avatar Jun 14 '25 18:06 Danielku15