From 5b00a7265fc79120c53bdc64c7737b570e4cefe7 Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Mon, 24 Jan 2022 14:05:12 -0800 Subject: [PATCH] fix typefacts of intersection --- src/compiler/checker.ts | 7 ++-- .../reference/narrowingTypeofFunction.js | 11 ++++++ .../reference/narrowingTypeofFunction.symbols | 13 +++++++ .../reference/narrowingTypeofFunction.types | 16 +++++++++ .../reference/narrowingTypeofObject.js | 27 +++++++++++++++ .../reference/narrowingTypeofObject.symbols | 30 ++++++++++++++++ .../reference/narrowingTypeofObject.types | 34 +++++++++++++++++++ .../cases/compiler/narrowingTypeofFunction.ts | 6 ++++ tests/cases/compiler/narrowingTypeofObject.ts | 15 ++++++++ 9 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/narrowingTypeofObject.js create mode 100644 tests/baselines/reference/narrowingTypeofObject.symbols create mode 100644 tests/baselines/reference/narrowingTypeofObject.types create mode 100644 tests/cases/compiler/narrowingTypeofObject.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9c5beffc61130..36727d6184d1d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -135,7 +135,7 @@ namespace ts { AllTypeofNE = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined, EmptyObjectFacts = All, // Masks - OrFactsMask = TypeofEQFunction | TypeofEQObject | TypeofNEObject, + OrFactsMask = TypeofEQFunction | TypeofNEObject, AndFactsMask = All & ~OrFactsMask, } @@ -22962,7 +22962,10 @@ namespace ts { (type === falseType || type === regularFalseType) ? TypeFacts.FalseStrictFacts : TypeFacts.TrueStrictFacts : (type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts; } - if (flags & TypeFlags.Object && !ignoreObjects) { + if (flags & TypeFlags.Object) { + if (ignoreObjects) { + return TypeFacts.AndFactsMask; // This is the identity element for computing type facts of intersection. + } return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type as ObjectType) ? strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts : isFunctionObjectType(type as ObjectType) ? diff --git a/tests/baselines/reference/narrowingTypeofFunction.js b/tests/baselines/reference/narrowingTypeofFunction.js index fb38d9249cfa5..4eda1caefd3d7 100644 --- a/tests/baselines/reference/narrowingTypeofFunction.js +++ b/tests/baselines/reference/narrowingTypeofFunction.js @@ -18,6 +18,12 @@ function f2(x: (T & F) | T & string) { else { x; } +} + +function f3(x: { _foo: number } & number) { + if (typeof x === "function") { + x; + } } //// [narrowingTypeofFunction.js] @@ -38,3 +44,8 @@ function f2(x) { x; } } +function f3(x) { + if (typeof x === "function") { + x; + } +} diff --git a/tests/baselines/reference/narrowingTypeofFunction.symbols b/tests/baselines/reference/narrowingTypeofFunction.symbols index 3bad8d9a42ff5..21ce3c4435995 100644 --- a/tests/baselines/reference/narrowingTypeofFunction.symbols +++ b/tests/baselines/reference/narrowingTypeofFunction.symbols @@ -43,3 +43,16 @@ function f2(x: (T & F) | T & string) { >x : Symbol(x, Decl(narrowingTypeofFunction.ts, 12, 15)) } } + +function f3(x: { _foo: number } & number) { +>f3 : Symbol(f3, Decl(narrowingTypeofFunction.ts, 19, 1)) +>x : Symbol(x, Decl(narrowingTypeofFunction.ts, 21, 12)) +>_foo : Symbol(_foo, Decl(narrowingTypeofFunction.ts, 21, 16)) + + if (typeof x === "function") { +>x : Symbol(x, Decl(narrowingTypeofFunction.ts, 21, 12)) + + x; +>x : Symbol(x, Decl(narrowingTypeofFunction.ts, 21, 12)) + } +} diff --git a/tests/baselines/reference/narrowingTypeofFunction.types b/tests/baselines/reference/narrowingTypeofFunction.types index 86fbf0571fee2..9342585ddd54e 100644 --- a/tests/baselines/reference/narrowingTypeofFunction.types +++ b/tests/baselines/reference/narrowingTypeofFunction.types @@ -42,3 +42,19 @@ function f2(x: (T & F) | T & string) { >x : T & string } } + +function f3(x: { _foo: number } & number) { +>f3 : (x: { _foo: number;} & number) => void +>x : { _foo: number; } & number +>_foo : number + + if (typeof x === "function") { +>typeof x === "function" : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : { _foo: number; } & number +>"function" : "function" + + x; +>x : never + } +} diff --git a/tests/baselines/reference/narrowingTypeofObject.js b/tests/baselines/reference/narrowingTypeofObject.js new file mode 100644 index 0000000000000..e6c4df22a5d99 --- /dev/null +++ b/tests/baselines/reference/narrowingTypeofObject.js @@ -0,0 +1,27 @@ +//// [narrowingTypeofObject.ts] +interface F { (): string } + +function test(x: number & { _foo: string }) { + if (typeof x === 'object') { + x; + } +} + +function f1(x: F & { foo: number }) { + if (typeof x !== "object") { + x; + } +} + +//// [narrowingTypeofObject.js] +"use strict"; +function test(x) { + if (typeof x === 'object') { + x; + } +} +function f1(x) { + if (typeof x !== "object") { + x; + } +} diff --git a/tests/baselines/reference/narrowingTypeofObject.symbols b/tests/baselines/reference/narrowingTypeofObject.symbols new file mode 100644 index 0000000000000..84682e68277e6 --- /dev/null +++ b/tests/baselines/reference/narrowingTypeofObject.symbols @@ -0,0 +1,30 @@ +=== tests/cases/compiler/narrowingTypeofObject.ts === +interface F { (): string } +>F : Symbol(F, Decl(narrowingTypeofObject.ts, 0, 0)) + +function test(x: number & { _foo: string }) { +>test : Symbol(test, Decl(narrowingTypeofObject.ts, 0, 26)) +>x : Symbol(x, Decl(narrowingTypeofObject.ts, 2, 14)) +>_foo : Symbol(_foo, Decl(narrowingTypeofObject.ts, 2, 27)) + + if (typeof x === 'object') { +>x : Symbol(x, Decl(narrowingTypeofObject.ts, 2, 14)) + + x; +>x : Symbol(x, Decl(narrowingTypeofObject.ts, 2, 14)) + } +} + +function f1(x: F & { foo: number }) { +>f1 : Symbol(f1, Decl(narrowingTypeofObject.ts, 6, 1)) +>x : Symbol(x, Decl(narrowingTypeofObject.ts, 8, 12)) +>F : Symbol(F, Decl(narrowingTypeofObject.ts, 0, 0)) +>foo : Symbol(foo, Decl(narrowingTypeofObject.ts, 8, 20)) + + if (typeof x !== "object") { +>x : Symbol(x, Decl(narrowingTypeofObject.ts, 8, 12)) + + x; +>x : Symbol(x, Decl(narrowingTypeofObject.ts, 8, 12)) + } +} diff --git a/tests/baselines/reference/narrowingTypeofObject.types b/tests/baselines/reference/narrowingTypeofObject.types new file mode 100644 index 0000000000000..16284302c3bd5 --- /dev/null +++ b/tests/baselines/reference/narrowingTypeofObject.types @@ -0,0 +1,34 @@ +=== tests/cases/compiler/narrowingTypeofObject.ts === +interface F { (): string } + +function test(x: number & { _foo: string }) { +>test : (x: number & { _foo: string;}) => void +>x : number & { _foo: string; } +>_foo : string + + if (typeof x === 'object') { +>typeof x === 'object' : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : number & { _foo: string; } +>'object' : "object" + + x; +>x : never + } +} + +function f1(x: F & { foo: number }) { +>f1 : (x: F & { foo: number;}) => void +>x : F & { foo: number; } +>foo : number + + if (typeof x !== "object") { +>typeof x !== "object" : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : F & { foo: number; } +>"object" : "object" + + x; +>x : F & { foo: number; } + } +} diff --git a/tests/cases/compiler/narrowingTypeofFunction.ts b/tests/cases/compiler/narrowingTypeofFunction.ts index baceaae052222..987dc80876b7d 100644 --- a/tests/cases/compiler/narrowingTypeofFunction.ts +++ b/tests/cases/compiler/narrowingTypeofFunction.ts @@ -19,4 +19,10 @@ function f2(x: (T & F) | T & string) { else { x; } +} + +function f3(x: { _foo: number } & number) { + if (typeof x === "function") { + x; + } } \ No newline at end of file diff --git a/tests/cases/compiler/narrowingTypeofObject.ts b/tests/cases/compiler/narrowingTypeofObject.ts new file mode 100644 index 0000000000000..21625b033dc3b --- /dev/null +++ b/tests/cases/compiler/narrowingTypeofObject.ts @@ -0,0 +1,15 @@ +// @strict: true + +interface F { (): string } + +function test(x: number & { _foo: string }) { + if (typeof x === 'object') { + x; + } +} + +function f1(x: F & { foo: number }) { + if (typeof x !== "object") { + x; + } +} \ No newline at end of file