Merge pull request #12210 from Microsoft/typePredicateCheck
Fix type predicate check circularity
This commit is contained in:
commit
db813d5171
|
@ -8981,6 +8981,28 @@ namespace ts {
|
|||
return isLengthPushOrUnshift || isElementAssignment;
|
||||
}
|
||||
|
||||
function maybeTypePredicateCall(node: CallExpression) {
|
||||
const links = getNodeLinks(node);
|
||||
if (links.maybeTypePredicate === undefined) {
|
||||
links.maybeTypePredicate = getMaybeTypePredicate(node);
|
||||
}
|
||||
return links.maybeTypePredicate;
|
||||
}
|
||||
|
||||
function getMaybeTypePredicate(node: CallExpression) {
|
||||
if (node.expression.kind !== SyntaxKind.SuperKeyword) {
|
||||
const funcType = checkNonNullExpression(node.expression);
|
||||
if (funcType !== silentNeverType) {
|
||||
const apparentType = getApparentType(funcType);
|
||||
if (apparentType !== unknownType) {
|
||||
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
|
||||
return !!forEach(callSignatures, sig => sig.typePredicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, flowContainer: Node) {
|
||||
let key: string;
|
||||
if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
|
||||
|
@ -9495,7 +9517,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type {
|
||||
if (!hasMatchingArgument(callExpression, reference)) {
|
||||
if (!hasMatchingArgument(callExpression, reference) || !maybeTypePredicateCall(callExpression)) {
|
||||
return type;
|
||||
}
|
||||
const signature = getResolvedSignature(callExpression);
|
||||
|
|
|
@ -2668,6 +2668,7 @@ namespace ts {
|
|||
resolvedSignature?: Signature; // Cached signature of signature node or call expression
|
||||
resolvedSymbol?: Symbol; // Cached name resolution result
|
||||
resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result
|
||||
maybeTypePredicate?: boolean; // Cached check whether call expression might reference a type predicate
|
||||
enumMemberValue?: number; // Constant value of enum member
|
||||
isVisible?: boolean; // Is this node visible
|
||||
hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context
|
||||
|
|
38
tests/baselines/reference/typePredicateInLoop.js
Normal file
38
tests/baselines/reference/typePredicateInLoop.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
//// [typePredicateInLoop.ts]
|
||||
// Repro from #12101
|
||||
|
||||
interface Type {
|
||||
type: number;
|
||||
}
|
||||
|
||||
interface TypeExt extends Type {
|
||||
arr: Type[];
|
||||
}
|
||||
|
||||
const guard = (arg: Type): arg is TypeExt => arg.type === 1;
|
||||
const otherFunc = (arg1: Type, arg2: TypeExt): void => {};
|
||||
|
||||
export function y(arg: Type): void {
|
||||
if (guard(arg)) {
|
||||
for (const ITEM of arg.arr) {
|
||||
if (otherFunc(ITEM, arg)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//// [typePredicateInLoop.js]
|
||||
// Repro from #12101
|
||||
"use strict";
|
||||
var guard = function (arg) { return arg.type === 1; };
|
||||
var otherFunc = function (arg1, arg2) { };
|
||||
function y(arg) {
|
||||
if (guard(arg)) {
|
||||
for (var _i = 0, _a = arg.arr; _i < _a.length; _i++) {
|
||||
var ITEM = _a[_i];
|
||||
if (otherFunc(ITEM, arg)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.y = y;
|
59
tests/baselines/reference/typePredicateInLoop.symbols
Normal file
59
tests/baselines/reference/typePredicateInLoop.symbols
Normal file
|
@ -0,0 +1,59 @@
|
|||
=== tests/cases/compiler/typePredicateInLoop.ts ===
|
||||
// Repro from #12101
|
||||
|
||||
interface Type {
|
||||
>Type : Symbol(Type, Decl(typePredicateInLoop.ts, 0, 0))
|
||||
|
||||
type: number;
|
||||
>type : Symbol(Type.type, Decl(typePredicateInLoop.ts, 2, 16))
|
||||
}
|
||||
|
||||
interface TypeExt extends Type {
|
||||
>TypeExt : Symbol(TypeExt, Decl(typePredicateInLoop.ts, 4, 1))
|
||||
>Type : Symbol(Type, Decl(typePredicateInLoop.ts, 0, 0))
|
||||
|
||||
arr: Type[];
|
||||
>arr : Symbol(TypeExt.arr, Decl(typePredicateInLoop.ts, 6, 32))
|
||||
>Type : Symbol(Type, Decl(typePredicateInLoop.ts, 0, 0))
|
||||
}
|
||||
|
||||
const guard = (arg: Type): arg is TypeExt => arg.type === 1;
|
||||
>guard : Symbol(guard, Decl(typePredicateInLoop.ts, 10, 5))
|
||||
>arg : Symbol(arg, Decl(typePredicateInLoop.ts, 10, 15))
|
||||
>Type : Symbol(Type, Decl(typePredicateInLoop.ts, 0, 0))
|
||||
>arg : Symbol(arg, Decl(typePredicateInLoop.ts, 10, 15))
|
||||
>TypeExt : Symbol(TypeExt, Decl(typePredicateInLoop.ts, 4, 1))
|
||||
>arg.type : Symbol(Type.type, Decl(typePredicateInLoop.ts, 2, 16))
|
||||
>arg : Symbol(arg, Decl(typePredicateInLoop.ts, 10, 15))
|
||||
>type : Symbol(Type.type, Decl(typePredicateInLoop.ts, 2, 16))
|
||||
|
||||
const otherFunc = (arg1: Type, arg2: TypeExt): void => {};
|
||||
>otherFunc : Symbol(otherFunc, Decl(typePredicateInLoop.ts, 11, 5))
|
||||
>arg1 : Symbol(arg1, Decl(typePredicateInLoop.ts, 11, 19))
|
||||
>Type : Symbol(Type, Decl(typePredicateInLoop.ts, 0, 0))
|
||||
>arg2 : Symbol(arg2, Decl(typePredicateInLoop.ts, 11, 30))
|
||||
>TypeExt : Symbol(TypeExt, Decl(typePredicateInLoop.ts, 4, 1))
|
||||
|
||||
export function y(arg: Type): void {
|
||||
>y : Symbol(y, Decl(typePredicateInLoop.ts, 11, 58))
|
||||
>arg : Symbol(arg, Decl(typePredicateInLoop.ts, 13, 18))
|
||||
>Type : Symbol(Type, Decl(typePredicateInLoop.ts, 0, 0))
|
||||
|
||||
if (guard(arg)) {
|
||||
>guard : Symbol(guard, Decl(typePredicateInLoop.ts, 10, 5))
|
||||
>arg : Symbol(arg, Decl(typePredicateInLoop.ts, 13, 18))
|
||||
|
||||
for (const ITEM of arg.arr) {
|
||||
>ITEM : Symbol(ITEM, Decl(typePredicateInLoop.ts, 15, 14))
|
||||
>arg.arr : Symbol(TypeExt.arr, Decl(typePredicateInLoop.ts, 6, 32))
|
||||
>arg : Symbol(arg, Decl(typePredicateInLoop.ts, 13, 18))
|
||||
>arr : Symbol(TypeExt.arr, Decl(typePredicateInLoop.ts, 6, 32))
|
||||
|
||||
if (otherFunc(ITEM, arg)) {
|
||||
>otherFunc : Symbol(otherFunc, Decl(typePredicateInLoop.ts, 11, 5))
|
||||
>ITEM : Symbol(ITEM, Decl(typePredicateInLoop.ts, 15, 14))
|
||||
>arg : Symbol(arg, Decl(typePredicateInLoop.ts, 13, 18))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
65
tests/baselines/reference/typePredicateInLoop.types
Normal file
65
tests/baselines/reference/typePredicateInLoop.types
Normal file
|
@ -0,0 +1,65 @@
|
|||
=== tests/cases/compiler/typePredicateInLoop.ts ===
|
||||
// Repro from #12101
|
||||
|
||||
interface Type {
|
||||
>Type : Type
|
||||
|
||||
type: number;
|
||||
>type : number
|
||||
}
|
||||
|
||||
interface TypeExt extends Type {
|
||||
>TypeExt : TypeExt
|
||||
>Type : Type
|
||||
|
||||
arr: Type[];
|
||||
>arr : Type[]
|
||||
>Type : Type
|
||||
}
|
||||
|
||||
const guard = (arg: Type): arg is TypeExt => arg.type === 1;
|
||||
>guard : (arg: Type) => arg is TypeExt
|
||||
>(arg: Type): arg is TypeExt => arg.type === 1 : (arg: Type) => arg is TypeExt
|
||||
>arg : Type
|
||||
>Type : Type
|
||||
>arg : any
|
||||
>TypeExt : TypeExt
|
||||
>arg.type === 1 : boolean
|
||||
>arg.type : number
|
||||
>arg : Type
|
||||
>type : number
|
||||
>1 : 1
|
||||
|
||||
const otherFunc = (arg1: Type, arg2: TypeExt): void => {};
|
||||
>otherFunc : (arg1: Type, arg2: TypeExt) => void
|
||||
>(arg1: Type, arg2: TypeExt): void => {} : (arg1: Type, arg2: TypeExt) => void
|
||||
>arg1 : Type
|
||||
>Type : Type
|
||||
>arg2 : TypeExt
|
||||
>TypeExt : TypeExt
|
||||
|
||||
export function y(arg: Type): void {
|
||||
>y : (arg: Type) => void
|
||||
>arg : Type
|
||||
>Type : Type
|
||||
|
||||
if (guard(arg)) {
|
||||
>guard(arg) : boolean
|
||||
>guard : (arg: Type) => arg is TypeExt
|
||||
>arg : Type
|
||||
|
||||
for (const ITEM of arg.arr) {
|
||||
>ITEM : Type
|
||||
>arg.arr : Type[]
|
||||
>arg : TypeExt
|
||||
>arr : Type[]
|
||||
|
||||
if (otherFunc(ITEM, arg)) {
|
||||
>otherFunc(ITEM, arg) : void
|
||||
>otherFunc : (arg1: Type, arg2: TypeExt) => void
|
||||
>ITEM : Type
|
||||
>arg : TypeExt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
tests/cases/compiler/typePredicateInLoop.ts
Normal file
21
tests/cases/compiler/typePredicateInLoop.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Repro from #12101
|
||||
|
||||
interface Type {
|
||||
type: number;
|
||||
}
|
||||
|
||||
interface TypeExt extends Type {
|
||||
arr: Type[];
|
||||
}
|
||||
|
||||
const guard = (arg: Type): arg is TypeExt => arg.type === 1;
|
||||
const otherFunc = (arg1: Type, arg2: TypeExt): void => {};
|
||||
|
||||
export function y(arg: Type): void {
|
||||
if (guard(arg)) {
|
||||
for (const ITEM of arg.arr) {
|
||||
if (otherFunc(ITEM, arg)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue