Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,8 +614,10 @@ type Checker struct {
evaluate evaluator.Evaluator
stringLiteralTypes map[string]*Type
numberLiteralTypes map[jsnum.Number]*Type
nanType *Type
bigintLiteralTypes map[jsnum.PseudoBigInt]*Type
enumLiteralTypes map[EnumLiteralKey]*Type
enumNaNLiteralTypes map[*ast.Symbol]*Type
indexedAccessTypes map[CacheHashKey]*Type
templateLiteralTypes map[CacheHashKey]*Type
stringMappingTypes map[StringMappingKey]*Type
Expand Down Expand Up @@ -924,6 +926,7 @@ func NewChecker(program Program, tracer *Tracer) (*Checker, *sync.Mutex) {
c.numberLiteralTypes = make(map[jsnum.Number]*Type)
c.bigintLiteralTypes = make(map[jsnum.PseudoBigInt]*Type)
c.enumLiteralTypes = make(map[EnumLiteralKey]*Type)
c.enumNaNLiteralTypes = make(map[*ast.Symbol]*Type)
c.indexedAccessTypes = make(map[CacheHashKey]*Type)
c.templateLiteralTypes = make(map[CacheHashKey]*Type)
c.stringMappingTypes = make(map[StringMappingKey]*Type)
Expand Down Expand Up @@ -25152,6 +25155,14 @@ func (c *Checker) getStringLiteralType(value string) *Type {
}

func (c *Checker) getNumberLiteralType(value jsnum.Number) *Type {
// NaN cannot be used as a Go map key because NaN != NaN in IEEE 754,
// so Go map lookups for NaN always miss. Cache NaN type separately.
if value.IsNaN() {
if c.nanType == nil {
c.nanType = c.newLiteralType(TypeFlagsNumberLiteral, value, nil)
}
return c.nanType
}
t := c.numberLiteralTypes[value]
if t == nil {
t = c.newLiteralType(TypeFlagsNumberLiteral, value, nil)
Expand Down Expand Up @@ -25193,11 +25204,22 @@ func getBooleanLiteralValue(t *Type) bool {

func (c *Checker) getEnumLiteralType(value any, enumSymbol *ast.Symbol, symbol *ast.Symbol) *Type {
var flags TypeFlags
switch value.(type) {
switch v := value.(type) {
case string:
flags = TypeFlagsEnumLiteral | TypeFlagsStringLiteral
case jsnum.Number:
flags = TypeFlagsEnumLiteral | TypeFlagsNumberLiteral
// NaN cannot be used as a Go map key because NaN != NaN in IEEE 754,
// so Go map lookups for NaN always miss. Cache NaN enum types separately by enum symbol.
if v.IsNaN() {
t := c.enumNaNLiteralTypes[enumSymbol]
if t == nil {
t = c.newLiteralType(flags, value, nil)
t.symbol = symbol
c.enumNaNLiteralTypes[enumSymbol] = t
}
return t
}
default:
panic("Unhandled case in getEnumLiteralType")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ enum E {
>0 : 0

B,
>B : E.B
>B : E.A
}

20 changes: 20 additions & 0 deletions testdata/baselines/reference/compiler/enumNaNValues.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
enumNaNValues.ts(13,7): error TS2322: Type 'F' is not assignable to type 'E'.


==== enumNaNValues.ts (1 errors) ====
enum E {
A = NaN,
B = NaN,
}

const a: E.A = E.B;
const b: E.B = E.A;

enum F {
X = NaN,
}

const c: E.A = F.X; // Error expected - different enums
~
!!! error TS2322: Type 'F' is not assignable to type 'E'.

32 changes: 32 additions & 0 deletions testdata/baselines/reference/compiler/enumNaNValues.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//// [tests/cases/compiler/enumNaNValues.ts] ////

//// [enumNaNValues.ts]
enum E {
A = NaN,
B = NaN,
}

const a: E.A = E.B;
const b: E.B = E.A;

enum F {
X = NaN,
}

const c: E.A = F.X; // Error expected - different enums


//// [enumNaNValues.js]
"use strict";
var E;
(function (E) {
E[E["A"] = NaN] = "A";
E[E["B"] = NaN] = "B";
})(E || (E = {}));
const a = E.B;
const b = E.A;
var F;
(function (F) {
F[F["X"] = NaN] = "X";
})(F || (F = {}));
const c = F.X; // Error expected - different enums
47 changes: 47 additions & 0 deletions testdata/baselines/reference/compiler/enumNaNValues.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//// [tests/cases/compiler/enumNaNValues.ts] ////

=== enumNaNValues.ts ===
enum E {
>E : Symbol(E, Decl(enumNaNValues.ts, 0, 0))

A = NaN,
>A : Symbol(E.A, Decl(enumNaNValues.ts, 0, 8))
>NaN : Symbol(NaN, Decl(lib.es5.d.ts, --, --))

B = NaN,
>B : Symbol(E.B, Decl(enumNaNValues.ts, 1, 10))
>NaN : Symbol(NaN, Decl(lib.es5.d.ts, --, --))
}

const a: E.A = E.B;
>a : Symbol(a, Decl(enumNaNValues.ts, 5, 5))
>E : Symbol(E, Decl(enumNaNValues.ts, 0, 0))
>A : Symbol(E.A, Decl(enumNaNValues.ts, 0, 8))
>E.B : Symbol(E.B, Decl(enumNaNValues.ts, 1, 10))
>E : Symbol(E, Decl(enumNaNValues.ts, 0, 0))
>B : Symbol(E.B, Decl(enumNaNValues.ts, 1, 10))

const b: E.B = E.A;
>b : Symbol(b, Decl(enumNaNValues.ts, 6, 5))
>E : Symbol(E, Decl(enumNaNValues.ts, 0, 0))
>B : Symbol(E.B, Decl(enumNaNValues.ts, 1, 10))
>E.A : Symbol(E.A, Decl(enumNaNValues.ts, 0, 8))
>E : Symbol(E, Decl(enumNaNValues.ts, 0, 0))
>A : Symbol(E.A, Decl(enumNaNValues.ts, 0, 8))

enum F {
>F : Symbol(F, Decl(enumNaNValues.ts, 6, 19))

X = NaN,
>X : Symbol(F.X, Decl(enumNaNValues.ts, 8, 8))
>NaN : Symbol(NaN, Decl(lib.es5.d.ts, --, --))
}

const c: E.A = F.X; // Error expected - different enums
>c : Symbol(c, Decl(enumNaNValues.ts, 12, 5))
>E : Symbol(E, Decl(enumNaNValues.ts, 0, 0))
>A : Symbol(E.A, Decl(enumNaNValues.ts, 0, 8))
>F.X : Symbol(F.X, Decl(enumNaNValues.ts, 8, 8))
>F : Symbol(F, Decl(enumNaNValues.ts, 6, 19))
>X : Symbol(F.X, Decl(enumNaNValues.ts, 8, 8))

44 changes: 44 additions & 0 deletions testdata/baselines/reference/compiler/enumNaNValues.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//// [tests/cases/compiler/enumNaNValues.ts] ////

=== enumNaNValues.ts ===
enum E {
>E : E

A = NaN,
>A : E.A
>NaN : number

B = NaN,
>B : E.A
>NaN : number
}

const a: E.A = E.B;
>a : E
>E : any
>E.B : E
>E : typeof E
>B : E

const b: E.B = E.A;
>b : E
>E : any
>E.A : E
>E : typeof E
>A : E

enum F {
>F : F

X = NaN,
>X : F.X
>NaN : number
}

const c: E.A = F.X; // Error expected - different enums
>c : E
>E : any
>F.X : F
>F : typeof F
>X : F

Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ enum E5 {
>0.0 : 0

e = NaN,
>e : E5.e
>e : E5.d
>NaN : number

f = Infinity,
Expand Down Expand Up @@ -120,7 +120,7 @@ const enum E6 {
>0.0 : 0

e = NaN,
>e : E6.e
>e : E6.d
>NaN : number

f = Infinity,
Expand Down

This file was deleted.

15 changes: 15 additions & 0 deletions testdata/tests/cases/compiler/enumNaNValues.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @strict: true

enum E {
A = NaN,
B = NaN,
}

const a: E.A = E.B;
const b: E.B = E.A;

enum F {
X = NaN,
}

const c: E.A = F.X; // Error expected - different enums
Loading