mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 18:04:18 -05:00
Fix 31995: make cached key more precise to avoid returning wrong cached value. (#39670)
* fix 31995 * revert useless change only for debug. * add test
This commit is contained in:
@@ -20097,7 +20097,7 @@ namespace ts {
|
||||
const symbol = getResolvedSymbol(<Identifier>node);
|
||||
return symbol !== unknownSymbol ? `${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${getTypeId(initialType)}|${isConstraintPosition(node) ? "@" : ""}${getSymbolId(symbol)}` : undefined;
|
||||
case SyntaxKind.ThisKeyword:
|
||||
return "0";
|
||||
return `0|${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${getTypeId(initialType)}`;
|
||||
case SyntaxKind.NonNullExpression:
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return getFlowCacheKey((<NonNullExpression | ParenthesizedExpression>node).expression, declaredType, initialType, flowContainer);
|
||||
@@ -20960,7 +20960,7 @@ namespace ts {
|
||||
|
||||
function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, couldBeUninitialized?: boolean) {
|
||||
let key: string | undefined;
|
||||
let keySet = false;
|
||||
let isKeySet = false;
|
||||
let flowDepth = 0;
|
||||
if (flowAnalysisDisabled) {
|
||||
return errorType;
|
||||
@@ -20983,10 +20983,10 @@ namespace ts {
|
||||
return resultType;
|
||||
|
||||
function getOrSetCacheKey() {
|
||||
if (keySet) {
|
||||
if (isKeySet) {
|
||||
return key;
|
||||
}
|
||||
keySet = true;
|
||||
isKeySet = true;
|
||||
return key = getFlowCacheKey(reference, declaredType, initialType, flowContainer);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
tests/cases/conformance/classes/members/instanceAndStaticMembers/typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts(29,13): error TS2322: Type 'string | number' is not assignable to type 'number'.
|
||||
Type 'string' is not assignable to type 'number'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/classes/members/instanceAndStaticMembers/typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts (1 errors) ====
|
||||
// #31995
|
||||
type State = {
|
||||
type: "numberVariant";
|
||||
data: number;
|
||||
} | {
|
||||
type: "stringVariant";
|
||||
data: string;
|
||||
};
|
||||
|
||||
class SomeClass {
|
||||
state!: State;
|
||||
method() {
|
||||
while (0) { }
|
||||
this.state.data;
|
||||
if (this.state.type === "stringVariant") {
|
||||
const s: string = this.state.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SomeClass2 {
|
||||
state!: State;
|
||||
method() {
|
||||
const c = false;
|
||||
while (c) { }
|
||||
if (this.state.type === "numberVariant") {
|
||||
this.state.data;
|
||||
}
|
||||
let n: number = this.state?.data; // This should be an error
|
||||
~
|
||||
!!! error TS2322: Type 'string | number' is not assignable to type 'number'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
//// [typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts]
|
||||
// #31995
|
||||
type State = {
|
||||
type: "numberVariant";
|
||||
data: number;
|
||||
} | {
|
||||
type: "stringVariant";
|
||||
data: string;
|
||||
};
|
||||
|
||||
class SomeClass {
|
||||
state!: State;
|
||||
method() {
|
||||
while (0) { }
|
||||
this.state.data;
|
||||
if (this.state.type === "stringVariant") {
|
||||
const s: string = this.state.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SomeClass2 {
|
||||
state!: State;
|
||||
method() {
|
||||
const c = false;
|
||||
while (c) { }
|
||||
if (this.state.type === "numberVariant") {
|
||||
this.state.data;
|
||||
}
|
||||
let n: number = this.state?.data; // This should be an error
|
||||
}
|
||||
}
|
||||
|
||||
//// [typeOfThisInstanceMemberNarrowedWithLoopAntecedent.js]
|
||||
var SomeClass = /** @class */ (function () {
|
||||
function SomeClass() {
|
||||
}
|
||||
SomeClass.prototype.method = function () {
|
||||
while (0) { }
|
||||
this.state.data;
|
||||
if (this.state.type === "stringVariant") {
|
||||
var s = this.state.data;
|
||||
}
|
||||
};
|
||||
return SomeClass;
|
||||
}());
|
||||
var SomeClass2 = /** @class */ (function () {
|
||||
function SomeClass2() {
|
||||
}
|
||||
SomeClass2.prototype.method = function () {
|
||||
var _a;
|
||||
var c = false;
|
||||
while (c) { }
|
||||
if (this.state.type === "numberVariant") {
|
||||
this.state.data;
|
||||
}
|
||||
var n = (_a = this.state) === null || _a === void 0 ? void 0 : _a.data; // This should be an error
|
||||
};
|
||||
return SomeClass2;
|
||||
}());
|
||||
@@ -0,0 +1,95 @@
|
||||
=== tests/cases/conformance/classes/members/instanceAndStaticMembers/typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts ===
|
||||
// #31995
|
||||
type State = {
|
||||
>State : Symbol(State, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 0, 0))
|
||||
|
||||
type: "numberVariant";
|
||||
>type : Symbol(type, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 1, 14))
|
||||
|
||||
data: number;
|
||||
>data : Symbol(data, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 2, 26))
|
||||
|
||||
} | {
|
||||
type: "stringVariant";
|
||||
>type : Symbol(type, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 4, 5))
|
||||
|
||||
data: string;
|
||||
>data : Symbol(data, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 5, 26))
|
||||
|
||||
};
|
||||
|
||||
class SomeClass {
|
||||
>SomeClass : Symbol(SomeClass, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 7, 2))
|
||||
|
||||
state!: State;
|
||||
>state : Symbol(SomeClass.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 9, 17))
|
||||
>State : Symbol(State, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 0, 0))
|
||||
|
||||
method() {
|
||||
>method : Symbol(SomeClass.method, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 10, 18))
|
||||
|
||||
while (0) { }
|
||||
this.state.data;
|
||||
>this.state.data : Symbol(data, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 2, 26), Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 5, 26))
|
||||
>this.state : Symbol(SomeClass.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 9, 17))
|
||||
>this : Symbol(SomeClass, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 7, 2))
|
||||
>state : Symbol(SomeClass.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 9, 17))
|
||||
>data : Symbol(data, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 2, 26), Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 5, 26))
|
||||
|
||||
if (this.state.type === "stringVariant") {
|
||||
>this.state.type : Symbol(type, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 1, 14), Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 4, 5))
|
||||
>this.state : Symbol(SomeClass.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 9, 17))
|
||||
>this : Symbol(SomeClass, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 7, 2))
|
||||
>state : Symbol(SomeClass.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 9, 17))
|
||||
>type : Symbol(type, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 1, 14), Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 4, 5))
|
||||
|
||||
const s: string = this.state.data;
|
||||
>s : Symbol(s, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 15, 17))
|
||||
>this.state.data : Symbol(data, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 5, 26))
|
||||
>this.state : Symbol(SomeClass.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 9, 17))
|
||||
>this : Symbol(SomeClass, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 7, 2))
|
||||
>state : Symbol(SomeClass.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 9, 17))
|
||||
>data : Symbol(data, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 5, 26))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SomeClass2 {
|
||||
>SomeClass2 : Symbol(SomeClass2, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 18, 1))
|
||||
|
||||
state!: State;
|
||||
>state : Symbol(SomeClass2.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 20, 18))
|
||||
>State : Symbol(State, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 0, 0))
|
||||
|
||||
method() {
|
||||
>method : Symbol(SomeClass2.method, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 21, 18))
|
||||
|
||||
const c = false;
|
||||
>c : Symbol(c, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 23, 13))
|
||||
|
||||
while (c) { }
|
||||
>c : Symbol(c, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 23, 13))
|
||||
|
||||
if (this.state.type === "numberVariant") {
|
||||
>this.state.type : Symbol(type, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 1, 14), Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 4, 5))
|
||||
>this.state : Symbol(SomeClass2.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 20, 18))
|
||||
>this : Symbol(SomeClass2, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 18, 1))
|
||||
>state : Symbol(SomeClass2.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 20, 18))
|
||||
>type : Symbol(type, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 1, 14), Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 4, 5))
|
||||
|
||||
this.state.data;
|
||||
>this.state.data : Symbol(data, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 2, 26))
|
||||
>this.state : Symbol(SomeClass2.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 20, 18))
|
||||
>this : Symbol(SomeClass2, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 18, 1))
|
||||
>state : Symbol(SomeClass2.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 20, 18))
|
||||
>data : Symbol(data, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 2, 26))
|
||||
}
|
||||
let n: number = this.state?.data; // This should be an error
|
||||
>n : Symbol(n, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 28, 11))
|
||||
>this.state?.data : Symbol(data, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 2, 26), Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 5, 26))
|
||||
>this.state : Symbol(SomeClass2.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 20, 18))
|
||||
>this : Symbol(SomeClass2, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 18, 1))
|
||||
>state : Symbol(SomeClass2.state, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 20, 18))
|
||||
>data : Symbol(data, Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 2, 26), Decl(typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts, 5, 26))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
=== tests/cases/conformance/classes/members/instanceAndStaticMembers/typeOfThisInstanceMemberNarrowedWithLoopAntecedent.ts ===
|
||||
// #31995
|
||||
type State = {
|
||||
>State : State
|
||||
|
||||
type: "numberVariant";
|
||||
>type : "numberVariant"
|
||||
|
||||
data: number;
|
||||
>data : number
|
||||
|
||||
} | {
|
||||
type: "stringVariant";
|
||||
>type : "stringVariant"
|
||||
|
||||
data: string;
|
||||
>data : string
|
||||
|
||||
};
|
||||
|
||||
class SomeClass {
|
||||
>SomeClass : SomeClass
|
||||
|
||||
state!: State;
|
||||
>state : State
|
||||
|
||||
method() {
|
||||
>method : () => void
|
||||
|
||||
while (0) { }
|
||||
>0 : 0
|
||||
|
||||
this.state.data;
|
||||
>this.state.data : string | number
|
||||
>this.state : State
|
||||
>this : this
|
||||
>state : State
|
||||
>data : string | number
|
||||
|
||||
if (this.state.type === "stringVariant") {
|
||||
>this.state.type === "stringVariant" : boolean
|
||||
>this.state.type : "numberVariant" | "stringVariant"
|
||||
>this.state : State
|
||||
>this : this
|
||||
>state : State
|
||||
>type : "numberVariant" | "stringVariant"
|
||||
>"stringVariant" : "stringVariant"
|
||||
|
||||
const s: string = this.state.data;
|
||||
>s : string
|
||||
>this.state.data : string
|
||||
>this.state : { type: "stringVariant"; data: string; }
|
||||
>this : this
|
||||
>state : { type: "stringVariant"; data: string; }
|
||||
>data : string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SomeClass2 {
|
||||
>SomeClass2 : SomeClass2
|
||||
|
||||
state!: State;
|
||||
>state : State
|
||||
|
||||
method() {
|
||||
>method : () => void
|
||||
|
||||
const c = false;
|
||||
>c : false
|
||||
>false : false
|
||||
|
||||
while (c) { }
|
||||
>c : false
|
||||
|
||||
if (this.state.type === "numberVariant") {
|
||||
>this.state.type === "numberVariant" : boolean
|
||||
>this.state.type : "numberVariant" | "stringVariant"
|
||||
>this.state : State
|
||||
>this : this
|
||||
>state : State
|
||||
>type : "numberVariant" | "stringVariant"
|
||||
>"numberVariant" : "numberVariant"
|
||||
|
||||
this.state.data;
|
||||
>this.state.data : number
|
||||
>this.state : { type: "numberVariant"; data: number; }
|
||||
>this : this
|
||||
>state : { type: "numberVariant"; data: number; }
|
||||
>data : number
|
||||
}
|
||||
let n: number = this.state?.data; // This should be an error
|
||||
>n : number
|
||||
>this.state?.data : string | number
|
||||
>this.state : State
|
||||
>this : this
|
||||
>state : State
|
||||
>data : string | number
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// #31995
|
||||
type State = {
|
||||
type: "numberVariant";
|
||||
data: number;
|
||||
} | {
|
||||
type: "stringVariant";
|
||||
data: string;
|
||||
};
|
||||
|
||||
class SomeClass {
|
||||
state!: State;
|
||||
method() {
|
||||
while (0) { }
|
||||
this.state.data;
|
||||
if (this.state.type === "stringVariant") {
|
||||
const s: string = this.state.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SomeClass2 {
|
||||
state!: State;
|
||||
method() {
|
||||
const c = false;
|
||||
while (c) { }
|
||||
if (this.state.type === "numberVariant") {
|
||||
this.state.data;
|
||||
}
|
||||
let n: number = this.state?.data; // This should be an error
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user