Skip to content

Regression: failure when comparing two values of the same enum type #10665

Closed
@DirtyHairy

Description

@DirtyHairy

TypeScript Version: 2.0.2

Code

Unfortunately, I have not been able to construct a reduced testcase, so I prepared a branch in the failing project to demonstrate the issue. Please checkout

https://github.com/DirtyHairy/6502.ts

and switch to the branch ts-broken. Doing npm install and grunt initial will demonstrate the issue. After that, the failing compile can be retriggered via grunt ts.

Expected behavior:

Project builds.

Actual behavior:

Using tsc v2.0.2
src/machine/stella/Board.ts(139,16): error TS2365: Operator '!==' cannot be applied to types 'ExecutionState.boot' and 'ExecutionState.fetch'

The code used to compile fine before 2.0.2 . The failing code fragment is this function:

    boot(): Board {
        let cycles = 0,
            cpuCycles = 0;

        this.reset();

        if (this._cpu.executionState !== CpuInterface.ExecutionState.boot)
            throw new Error("Already booted!");

        while (this._cpu.executionState !== CpuInterface.ExecutionState.fetch) {
            this._cycle();

            cycles++;
            if (this._subClock === 0) {
                cpuCycles++;
            }
        }

        this.cpuClock.dispatch(cpuCycles);
        this.clock.dispatch(cycles);
        return this;
    }

The corresponding types are declared in this snippet:

interface CpuInterface {

    // [...]

    executionState: CpuInterface.ExecutionState;

    // [...]

}

module CpuInterface {
    export const enum ExecutionState {
        boot, fetch, execute
    }

    // [...] 

}

I think the problem was introduced when enum values were split into different types, and I suspect that two issues are at work here:

  1. The assertion leads the compiler to infer the type of this._cpu.executionState to be CpuInterface.ExecutionState.boot. However, calling this.cycle() will mutate the execution state.
  2. The compiler deems the two sides of !== to be of different type and rejects the comparision.

After introducing a manual cast

while (this._cpu.executionState as CpuInterface.ExecutionState !== CpuInterface.ExecutionState.fetch) {

the code compiles fine

However, as I said, I have not been able to construct a reduced test case, so some other aspect of my code seems to contribute to the compiler's confusion 😏

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptDesign LimitationConstraints of the existing architecture prevent this from being fixed

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions