Skip to content

Commit 8153397

Browse files
author
Andy
authored
Lazily compute signature type predicates (#17600)
* Lazily compute signature type predicates * Use an instance of IdentifierTypePredicate to represent an unresolved type predicate * Simplify `getMaybeTypePredicate` * Invert representation of `resolvedTypePredicate` * Remove `__unresolvedTypePredicate` type and remember to use `noTypePredicate` instead of `undefined` when in all `createSignature` calls * Fix style of getTypePredicateOfSignature * Use in createGetSymbolWalker * Fix bugs for unions of type predicates * Code review * Make noTypePredicate purely an implementation detail of getTypePredictateOfSignature * Add test * Add test for #19642 * Add test with reversed order
1 parent e42ecea commit 8153397

29 files changed

+1080
-480
lines changed

src/compiler/checker.ts

Lines changed: 151 additions & 59 deletions
Large diffs are not rendered by default.

src/compiler/symbolWalker.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
namespace ts {
33
export function createGetSymbolWalker(
44
getRestTypeOfSignature: (sig: Signature) => Type,
5+
getTypePredicateOfSignature: (sig: Signature) => TypePredicate | undefined,
56
getReturnTypeOfSignature: (sig: Signature) => Type,
67
getBaseTypes: (type: Type) => Type[],
78
resolveStructuredTypeMembers: (type: ObjectType) => ResolvedType,
@@ -117,8 +118,9 @@ namespace ts {
117118
}
118119

119120
function visitSignature(signature: Signature): void {
120-
if (signature.typePredicate) {
121-
visitType(signature.typePredicate.type);
121+
const typePredicate = getTypePredicateOfSignature(signature);
122+
if (typePredicate) {
123+
visitType(typePredicate.type);
122124
}
123125
forEach(signature.typeParameters, visitType);
124126

src/compiler/types.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2791,7 +2791,17 @@ namespace ts {
27912791
/* @internal */ createPromiseType(type: Type): Type;
27922792

27932793
/* @internal */ createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo): Type;
2794-
/* @internal */ createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], thisParameter: Symbol | undefined, parameters: Symbol[], resolvedReturnType: Type, typePredicate: TypePredicate, minArgumentCount: number, hasRestParameter: boolean, hasLiteralTypes: boolean): Signature;
2794+
/* @internal */ createSignature(
2795+
declaration: SignatureDeclaration,
2796+
typeParameters: TypeParameter[],
2797+
thisParameter: Symbol | undefined,
2798+
parameters: Symbol[],
2799+
resolvedReturnType: Type,
2800+
typePredicate: TypePredicate | undefined,
2801+
minArgumentCount: number,
2802+
hasRestParameter: boolean,
2803+
hasLiteralTypes: boolean,
2804+
): Signature;
27952805
/* @internal */ createSymbol(flags: SymbolFlags, name: __String): TransientSymbol;
27962806
/* @internal */ createIndexInfo(type: Type, isReadonly: boolean, declaration?: SignatureDeclaration): IndexInfo;
27972807
/* @internal */ isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult;
@@ -3638,7 +3648,13 @@ namespace ts {
36383648
/* @internal */
36393649
thisParameter?: Symbol; // symbol of this-type parameter
36403650
/* @internal */
3641-
resolvedReturnType: Type; // Resolved return type
3651+
// See comment in `instantiateSignature` for why these are set lazily.
3652+
resolvedReturnType: Type | undefined; // Lazily set by `getReturnTypeOfSignature`.
3653+
/* @internal */
3654+
// Lazily set by `getTypePredicateOfSignature`.
3655+
// `undefined` indicates a type predicate that has not yet been computed.
3656+
// Uses a special `noTypePredicate` sentinel value to indicate that there is no type predicate. This looks like a TypePredicate at runtime to avoid polymorphism.
3657+
resolvedTypePredicate: TypePredicate | undefined;
36423658
/* @internal */
36433659
minArgumentCount: number; // Number of non-optional parameters
36443660
/* @internal */
@@ -3658,8 +3674,6 @@ namespace ts {
36583674
/* @internal */
36593675
isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison
36603676
/* @internal */
3661-
typePredicate?: TypePredicate;
3662-
/* @internal */
36633677
instantiations?: Map<Signature>; // Generic signature instantiation cache
36643678
}
36653679

src/services/services.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ namespace ts {
488488
parameters: Symbol[];
489489
thisParameter: Symbol;
490490
resolvedReturnType: Type;
491+
resolvedTypePredicate: TypePredicate | undefined;
491492
minTypeArgumentCount: number;
492493
minArgumentCount: number;
493494
hasRestParameter: boolean;

tests/baselines/reference/fixSignatureCaching.errors.txt

Lines changed: 70 additions & 67 deletions
Large diffs are not rendered by default.

tests/baselines/reference/fixSignatureCaching.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,9 @@ define(function () {
297297

298298
isArray = ('isArray' in Array) ?
299299
Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; };
300+
isArray = 'isArray' in Array
301+
? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }
302+
: Array.isArray;
300303

301304
function equalIC(a, b) {
302305
return a != null && b != null && a.toLowerCase() === b.toLowerCase();
@@ -967,7 +970,7 @@ define(function () {
967970

968971
// should not be replaced by a completely new object - just overwrite existing methods
969972
MobileDetect._impl = impl;
970-
973+
971974
MobileDetect.version = '1.3.3 2016-07-31';
972975

973976
return MobileDetect;
@@ -1276,6 +1279,9 @@ define(function () {
12761279
impl.FALLBACK_MOBILE = 'UnknownMobile';
12771280
isArray = ('isArray' in Array) ?
12781281
Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; };
1282+
isArray = 'isArray' in Array
1283+
? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }
1284+
: Array.isArray;
12791285
function equalIC(a, b) {
12801286
return a != null && b != null && a.toLowerCase() === b.toLowerCase();
12811287
}

0 commit comments

Comments
 (0)