From b3856bd32373bd6678c2579d375fd24914c9a358 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 9 Feb 2021 15:31:15 -0800 Subject: [PATCH 1/2] When structurally comparing similar types, check if we are already in the middle of a more general comparison of those same types --- src/compiler/checker.ts | 68 +++ ...denticalInterfacesWithGenericSignatures.js | 162 +++++++ ...calInterfacesWithGenericSignatures.symbols | 402 ++++++++++++++++++ ...ticalInterfacesWithGenericSignatures.types | 207 +++++++++ ...denticalInterfacesWithGenericSignatures.ts | 89 ++++ 5 files changed, 928 insertions(+) create mode 100644 tests/baselines/reference/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.js create mode 100644 tests/baselines/reference/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.symbols create mode 100644 tests/baselines/reference/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.types create mode 100644 tests/cases/compiler/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bf7d17a951f72..caf670b11cafc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17773,6 +17773,13 @@ namespace ts { return result; } + function getInstanceOfAliasOrReferenceWithMarker(input: Type, typeArguments: readonly Type[]) { + const s = input.aliasSymbol ? getTypeAliasInstantiation(input.aliasSymbol, typeArguments) : createTypeReference((input).target, typeArguments); + if (s.aliasSymbol) s.aliasTypeArgumentsContainsMarker = true; + else (s).objectFlags |= ObjectFlags.MarkerType; + return s; + } + function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { if (intersectionState & IntersectionState.PropertyCheck) { return propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, IntersectionState.None); @@ -17861,6 +17868,67 @@ namespace ts { } } + // If a more _general_ version of the source and target are being compared, consider them related with assumptions + // eg, if { x: Q } and { x: Q, y: A } are being compared and we're about to look at { x: Q' } and { x: Q', y: A } where Q' + // is some specialization or subtype of Q + // This is difficult to detect generally, so we scan for prior comparisons of the same instantiated type, and match up matching + // type arguments into sets to create a canonicalization based on those matches + if (relation !== identityRelation && ((source.aliasSymbol && !source.aliasTypeArgumentsContainsMarker && source.aliasTypeArguments) || (getObjectFlags(source) & ObjectFlags.Reference && !!getTypeArguments(source).length && !(getObjectFlags(source) & ObjectFlags.MarkerType))) && + ((target.aliasSymbol && !target.aliasTypeArgumentsContainsMarker && target.aliasTypeArguments) || (getObjectFlags(target) & ObjectFlags.Reference && !!getTypeArguments(target).length && !(getObjectFlags(target) & ObjectFlags.MarkerType)))) { + if (source.aliasSymbol || target.aliasSymbol || (source).target !== (target).target) { // ensure like symbols are just handled by standard variance analysis + const sourceTypeArguments = source.aliasTypeArguments || getTypeArguments(source); + const sourceHasMarker = some(sourceTypeArguments, a => a === markerOtherType); + const targetTypeArguments = target.aliasTypeArguments || getTypeArguments(target); + const targetHasMarker = some(targetTypeArguments, a => a === markerOtherType); + // We're using `markerOtherType` as an existential, so we can't use it again if it's already in use, + // as we'd get spurious equivalencies - we'd need to use a second existential type, and once we're doing + // that we lose a lot of the benefit of canonicalizing back to a single-existential comparison, since then + // we'd need to manufacture new type identities for every new existential we make + // The above checks don't catch all cases this can occur, as they can only detect when the containing type + // was flagged during construction as containing a marker; however if a marker enters a type through instantiation + // we need to catch that here. + // We only do this when there's a handful of possible ways to match the type parameters up, as otherwise we manufacture + // an inordinate quantity of types just to calculate their IDs! + if (!sourceHasMarker && !targetHasMarker && sourceTypeArguments.length * targetTypeArguments.length < 10) { + const originalKey = getRelationKey(source, target, intersectionState, relation); + for (let i = 0; i < sourceTypeArguments.length; i++) { + for (let j = 0; j < targetTypeArguments.length; j++) { + if ((!(sourceTypeArguments[i].flags & TypeFlags.TypeParameter) && !isTypeAny(sourceTypeArguments[i]) && sourceTypeArguments[i] === targetTypeArguments[j]) || + // Similarly, if we're comparing X to Z, X is assignable to Z trivially if X is assignable to Z + (!(sourceTypeArguments[i].flags & TypeFlags.TypeParameter) && isTypeAny(targetTypeArguments[j])) || + // Again, but for `X` vs `Z` + (isTypeAny(sourceTypeArguments[i]) && !(targetTypeArguments[j].flags & TypeFlags.TypeParameter)) || + // Likewise, if we're comparing X to Z and are already comparing X to Z, we can assume it to be true + !!(sourceTypeArguments[i].flags & TypeFlags.TypeParameter) && sourceTypeArguments[i] === targetTypeArguments[j]) { + const sourceClone = sourceTypeArguments.slice(); + sourceClone[i] = markerOtherType; + const s = getInstanceOfAliasOrReferenceWithMarker(source, sourceClone); + const targetClone = targetTypeArguments.slice(); + targetClone[j] = markerOtherType; + const t = getInstanceOfAliasOrReferenceWithMarker(target, targetClone); + // If the marker-instantiated form looks "the same" as the type we already have (eg, + // because we replace unconstrained generics with unconstrained generics), skip the check + // since we'll otherwise deliver a spurious `Maybe` result from the key _just_ set upon + // entry into `recursiveTypeRelatedTo` + const existentialKey = getRelationKey(s, t, intersectionState, relation); + if (existentialKey !== originalKey) { + // We don't actually trigger the comparison, since we'd rather not do an extra comparison + // if we haven't already started that more general comparison; instead we just look for the + // key in the maybeKeys stack + for (let i = 0; i < maybeCount; i++) { + // If source and target are already being compared, consider them related with assumptions + if (existentialKey === maybeKeys[i]) { + return Ternary.Maybe; + } + } + } + } + } + } + } + } + } + // For a generic type T and a type U that is assignable to T, [...U] is assignable to T, U is assignable to readonly [...T], // and U is assignable to [...T] when U is constrained to a mutable array or tuple type. if (isSingleElementGenericTupleType(source) && !source.target.readonly && (result = isRelatedTo(getTypeArguments(source)[0], target)) || diff --git a/tests/baselines/reference/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.js b/tests/baselines/reference/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.js new file mode 100644 index 0000000000000..b1c89ffd36ab4 --- /dev/null +++ b/tests/baselines/reference/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.js @@ -0,0 +1,162 @@ +//// [performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts] +export declare type ThenArg = T extends any ? any : T extends PromiseLike ? U : T; + +export interface InterfaceA { + filter(callback: (newValue: T, oldValue: T) => boolean): InterfaceA; + map(callback: (value: T) => D): InterfaceA; + await>(): InterfaceA; + awaitLatest>(): InterfaceA; + awaitOrdered>(): InterfaceA; + awaitOrdered2>(): InterfaceA; + awaitOrdered3>(): InterfaceA; + awaitOrdered4>(): InterfaceA; + awaitOrdered5>(): InterfaceA; + awaitOrdered6>(): InterfaceA; + awaitOrdered7>(): InterfaceA; + awaitOrdered8>(): InterfaceA; + awaitOrdered9>(): InterfaceA; +} + +export interface InterfaceB extends InterfaceA { + map(callback: (value: T) => D): InterfaceB; + await>(): InterfaceB; + awaitLatest>(): InterfaceB; + awaitOrdered>(): InterfaceB; + awaitOrdered2>(): InterfaceB; + awaitOrdered3>(): InterfaceB; + awaitOrdered4>(): InterfaceB; + awaitOrdered5>(): InterfaceB; + awaitOrdered6>(): InterfaceB; + awaitOrdered7>(): InterfaceB; + awaitOrdered8>(): InterfaceB; + awaitOrdered9>(): InterfaceB; +} + +export class A implements InterfaceB { + public filter(callback: (newValue: T, oldValue: T) => boolean): B { + return undefined as any; + } + + public map(callback: (value: T) => D): B { + return undefined as any; + } + + public await>(): B { + return undefined as any; + } + + public awaitOrdered>(): B { + return undefined as any; + } + + public awaitOrdered2>(): B { + return undefined as any; + } + + public awaitOrdered3>(): B { + return undefined as any; + } + + public awaitOrdered4>(): B { + return undefined as any; + } + + public awaitOrdered5>(): B { + return undefined as any; + } + + public awaitOrdered6>(): B { + return undefined as any; + } + + public awaitOrdered7>(): B { + return undefined as any; + } + + public awaitOrdered8>(): B { + return undefined as any; + } + + public awaitOrdered9>(): B { + return undefined as any; + } + + public awaitLatest>(): B { + return undefined as any; + } +} + +export class B extends A { } + +//// [performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.js] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +exports.B = exports.A = void 0; +var A = /** @class */ (function () { + function A() { + } + A.prototype.filter = function (callback) { + return undefined; + }; + A.prototype.map = function (callback) { + return undefined; + }; + A.prototype.await = function () { + return undefined; + }; + A.prototype.awaitOrdered = function () { + return undefined; + }; + A.prototype.awaitOrdered2 = function () { + return undefined; + }; + A.prototype.awaitOrdered3 = function () { + return undefined; + }; + A.prototype.awaitOrdered4 = function () { + return undefined; + }; + A.prototype.awaitOrdered5 = function () { + return undefined; + }; + A.prototype.awaitOrdered6 = function () { + return undefined; + }; + A.prototype.awaitOrdered7 = function () { + return undefined; + }; + A.prototype.awaitOrdered8 = function () { + return undefined; + }; + A.prototype.awaitOrdered9 = function () { + return undefined; + }; + A.prototype.awaitLatest = function () { + return undefined; + }; + return A; +}()); +exports.A = A; +var B = /** @class */ (function (_super) { + __extends(B, _super); + function B() { + return _super !== null && _super.apply(this, arguments) || this; + } + return B; +}(A)); +exports.B = B; diff --git a/tests/baselines/reference/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.symbols b/tests/baselines/reference/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.symbols new file mode 100644 index 0000000000000..2458ef733c57a --- /dev/null +++ b/tests/baselines/reference/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.symbols @@ -0,0 +1,402 @@ +=== tests/cases/compiler/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts === +export declare type ThenArg = T extends any ? any : T extends PromiseLike ? U : T; +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 28)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 28)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 28)) +>PromiseLike : Symbol(PromiseLike, Decl(lib.es5.d.ts, --, --)) +>U : Symbol(U, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 82)) +>U : Symbol(U, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 82)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 28)) + +export interface InterfaceA { +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) + + filter(callback: (newValue: T, oldValue: T) => boolean): InterfaceA; +>filter : Symbol(InterfaceA.filter, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 32)) +>callback : Symbol(callback, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 3, 11)) +>newValue : Symbol(newValue, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 3, 22)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>oldValue : Symbol(oldValue, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 3, 34)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) + + map(callback: (value: T) => D): InterfaceA; +>map : Symbol(InterfaceA.map, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 3, 75)) +>D : Symbol(D, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 4, 8)) +>callback : Symbol(callback, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 4, 11)) +>value : Symbol(value, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 4, 22)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>D : Symbol(D, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 4, 8)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>D : Symbol(D, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 4, 8)) + + await>(): InterfaceA; +>await : Symbol(InterfaceA.await, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 4, 53)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 5, 10)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 5, 10)) + + awaitLatest>(): InterfaceA; +>awaitLatest : Symbol(InterfaceA.awaitLatest, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 5, 49)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 6, 16)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 6, 16)) + + awaitOrdered>(): InterfaceA; +>awaitOrdered : Symbol(InterfaceA.awaitOrdered, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 6, 55)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 7, 17)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 7, 17)) + + awaitOrdered2>(): InterfaceA; +>awaitOrdered2 : Symbol(InterfaceA.awaitOrdered2, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 7, 56)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 8, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 8, 18)) + + awaitOrdered3>(): InterfaceA; +>awaitOrdered3 : Symbol(InterfaceA.awaitOrdered3, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 8, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 9, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 9, 18)) + + awaitOrdered4>(): InterfaceA; +>awaitOrdered4 : Symbol(InterfaceA.awaitOrdered4, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 9, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 10, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 10, 18)) + + awaitOrdered5>(): InterfaceA; +>awaitOrdered5 : Symbol(InterfaceA.awaitOrdered5, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 10, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 11, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 11, 18)) + + awaitOrdered6>(): InterfaceA; +>awaitOrdered6 : Symbol(InterfaceA.awaitOrdered6, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 11, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 12, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 12, 18)) + + awaitOrdered7>(): InterfaceA; +>awaitOrdered7 : Symbol(InterfaceA.awaitOrdered7, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 12, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 13, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 13, 18)) + + awaitOrdered8>(): InterfaceA; +>awaitOrdered8 : Symbol(InterfaceA.awaitOrdered8, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 13, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 14, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 14, 18)) + + awaitOrdered9>(): InterfaceA; +>awaitOrdered9 : Symbol(InterfaceA.awaitOrdered9, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 14, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 15, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 2, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 15, 18)) +} + +export interface InterfaceB extends InterfaceA { +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>InterfaceA : Symbol(InterfaceA, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 94)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) + + map(callback: (value: T) => D): InterfaceB; +>map : Symbol(InterfaceB.map, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 54)) +>D : Symbol(D, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 19, 8)) +>callback : Symbol(callback, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 19, 11)) +>value : Symbol(value, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 19, 22)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>D : Symbol(D, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 19, 8)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>D : Symbol(D, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 19, 8)) + + await>(): InterfaceB; +>await : Symbol(InterfaceB.await, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 19, 53)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 20, 10)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 20, 10)) + + awaitLatest>(): InterfaceB; +>awaitLatest : Symbol(InterfaceB.awaitLatest, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 20, 49)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 21, 16)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 21, 16)) + + awaitOrdered>(): InterfaceB; +>awaitOrdered : Symbol(InterfaceB.awaitOrdered, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 21, 55)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 22, 17)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 22, 17)) + + awaitOrdered2>(): InterfaceB; +>awaitOrdered2 : Symbol(InterfaceB.awaitOrdered2, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 22, 56)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 23, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 23, 18)) + + awaitOrdered3>(): InterfaceB; +>awaitOrdered3 : Symbol(InterfaceB.awaitOrdered3, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 23, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 24, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 24, 18)) + + awaitOrdered4>(): InterfaceB; +>awaitOrdered4 : Symbol(InterfaceB.awaitOrdered4, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 24, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 25, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 25, 18)) + + awaitOrdered5>(): InterfaceB; +>awaitOrdered5 : Symbol(InterfaceB.awaitOrdered5, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 25, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 26, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 26, 18)) + + awaitOrdered6>(): InterfaceB; +>awaitOrdered6 : Symbol(InterfaceB.awaitOrdered6, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 26, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 27, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 27, 18)) + + awaitOrdered7>(): InterfaceB; +>awaitOrdered7 : Symbol(InterfaceB.awaitOrdered7, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 27, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 28, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 28, 18)) + + awaitOrdered8>(): InterfaceB; +>awaitOrdered8 : Symbol(InterfaceB.awaitOrdered8, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 28, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 29, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 29, 18)) + + awaitOrdered9>(): InterfaceB; +>awaitOrdered9 : Symbol(InterfaceB.awaitOrdered9, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 29, 57)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 30, 18)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 18, 28)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 30, 18)) +} + +export class A implements InterfaceB { +>A : Symbol(A, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 31, 1)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>InterfaceB : Symbol(InterfaceB, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 16, 1)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) + + public filter(callback: (newValue: T, oldValue: T) => boolean): B { +>filter : Symbol(A.filter, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 44)) +>callback : Symbol(callback, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 34, 18)) +>newValue : Symbol(newValue, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 34, 29)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>oldValue : Symbol(oldValue, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 34, 41)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) + + return undefined as any; +>undefined : Symbol(undefined) + } + + public map(callback: (value: T) => D): B { +>map : Symbol(A.map, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 36, 5)) +>D : Symbol(D, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 38, 15)) +>callback : Symbol(callback, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 38, 18)) +>value : Symbol(value, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 38, 29)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>D : Symbol(D, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 38, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>D : Symbol(D, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 38, 15)) + + return undefined as any; +>undefined : Symbol(undefined) + } + + public await>(): B { +>await : Symbol(A.await, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 40, 5)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 42, 17)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 42, 17)) + + return undefined as any; +>undefined : Symbol(undefined) + } + + public awaitOrdered>(): B { +>awaitOrdered : Symbol(A.awaitOrdered, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 44, 5)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 46, 24)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 46, 24)) + + return undefined as any; +>undefined : Symbol(undefined) + } + + public awaitOrdered2>(): B { +>awaitOrdered2 : Symbol(A.awaitOrdered2, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 48, 5)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 50, 25)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 50, 25)) + + return undefined as any; +>undefined : Symbol(undefined) + } + + public awaitOrdered3>(): B { +>awaitOrdered3 : Symbol(A.awaitOrdered3, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 52, 5)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 54, 25)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 54, 25)) + + return undefined as any; +>undefined : Symbol(undefined) + } + + public awaitOrdered4>(): B { +>awaitOrdered4 : Symbol(A.awaitOrdered4, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 56, 5)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 58, 25)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 58, 25)) + + return undefined as any; +>undefined : Symbol(undefined) + } + + public awaitOrdered5>(): B { +>awaitOrdered5 : Symbol(A.awaitOrdered5, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 60, 5)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 62, 25)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 62, 25)) + + return undefined as any; +>undefined : Symbol(undefined) + } + + public awaitOrdered6>(): B { +>awaitOrdered6 : Symbol(A.awaitOrdered6, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 64, 5)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 66, 25)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 66, 25)) + + return undefined as any; +>undefined : Symbol(undefined) + } + + public awaitOrdered7>(): B { +>awaitOrdered7 : Symbol(A.awaitOrdered7, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 68, 5)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 70, 25)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 70, 25)) + + return undefined as any; +>undefined : Symbol(undefined) + } + + public awaitOrdered8>(): B { +>awaitOrdered8 : Symbol(A.awaitOrdered8, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 72, 5)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 74, 25)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 74, 25)) + + return undefined as any; +>undefined : Symbol(undefined) + } + + public awaitOrdered9>(): B { +>awaitOrdered9 : Symbol(A.awaitOrdered9, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 76, 5)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 78, 25)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 78, 25)) + + return undefined as any; +>undefined : Symbol(undefined) + } + + public awaitLatest>(): B { +>awaitLatest : Symbol(A.awaitLatest, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 80, 5)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 82, 23)) +>ThenArg : Symbol(ThenArg, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 0, 0)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 33, 15)) +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>R : Symbol(R, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 82, 23)) + + return undefined as any; +>undefined : Symbol(undefined) + } +} + +export class B extends A { } +>B : Symbol(B, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 85, 1)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 87, 15)) +>A : Symbol(A, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 31, 1)) +>T : Symbol(T, Decl(performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts, 87, 15)) + diff --git a/tests/baselines/reference/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.types b/tests/baselines/reference/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.types new file mode 100644 index 0000000000000..b1d5ef39069d2 --- /dev/null +++ b/tests/baselines/reference/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.types @@ -0,0 +1,207 @@ +=== tests/cases/compiler/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts === +export declare type ThenArg = T extends any ? any : T extends PromiseLike ? U : T; +>ThenArg : ThenArg + +export interface InterfaceA { + filter(callback: (newValue: T, oldValue: T) => boolean): InterfaceA; +>filter : (callback: (newValue: T, oldValue: T) => boolean) => InterfaceA +>callback : (newValue: T, oldValue: T) => boolean +>newValue : T +>oldValue : T + + map(callback: (value: T) => D): InterfaceA; +>map : (callback: (value: T) => D) => InterfaceA +>callback : (value: T) => D +>value : T + + await>(): InterfaceA; +>await : >() => InterfaceA + + awaitLatest>(): InterfaceA; +>awaitLatest : >() => InterfaceA + + awaitOrdered>(): InterfaceA; +>awaitOrdered : >() => InterfaceA + + awaitOrdered2>(): InterfaceA; +>awaitOrdered2 : >() => InterfaceA + + awaitOrdered3>(): InterfaceA; +>awaitOrdered3 : >() => InterfaceA + + awaitOrdered4>(): InterfaceA; +>awaitOrdered4 : >() => InterfaceA + + awaitOrdered5>(): InterfaceA; +>awaitOrdered5 : >() => InterfaceA + + awaitOrdered6>(): InterfaceA; +>awaitOrdered6 : >() => InterfaceA + + awaitOrdered7>(): InterfaceA; +>awaitOrdered7 : >() => InterfaceA + + awaitOrdered8>(): InterfaceA; +>awaitOrdered8 : >() => InterfaceA + + awaitOrdered9>(): InterfaceA; +>awaitOrdered9 : >() => InterfaceA +} + +export interface InterfaceB extends InterfaceA { + map(callback: (value: T) => D): InterfaceB; +>map : (callback: (value: T) => D) => InterfaceB +>callback : (value: T) => D +>value : T + + await>(): InterfaceB; +>await : >() => InterfaceB + + awaitLatest>(): InterfaceB; +>awaitLatest : >() => InterfaceB + + awaitOrdered>(): InterfaceB; +>awaitOrdered : >() => InterfaceB + + awaitOrdered2>(): InterfaceB; +>awaitOrdered2 : >() => InterfaceB + + awaitOrdered3>(): InterfaceB; +>awaitOrdered3 : >() => InterfaceB + + awaitOrdered4>(): InterfaceB; +>awaitOrdered4 : >() => InterfaceB + + awaitOrdered5>(): InterfaceB; +>awaitOrdered5 : >() => InterfaceB + + awaitOrdered6>(): InterfaceB; +>awaitOrdered6 : >() => InterfaceB + + awaitOrdered7>(): InterfaceB; +>awaitOrdered7 : >() => InterfaceB + + awaitOrdered8>(): InterfaceB; +>awaitOrdered8 : >() => InterfaceB + + awaitOrdered9>(): InterfaceB; +>awaitOrdered9 : >() => InterfaceB +} + +export class A implements InterfaceB { +>A : A + + public filter(callback: (newValue: T, oldValue: T) => boolean): B { +>filter : (callback: (newValue: T, oldValue: T) => boolean) => B +>callback : (newValue: T, oldValue: T) => boolean +>newValue : T +>oldValue : T + + return undefined as any; +>undefined as any : any +>undefined : undefined + } + + public map(callback: (value: T) => D): B { +>map : (callback: (value: T) => D) => B +>callback : (value: T) => D +>value : T + + return undefined as any; +>undefined as any : any +>undefined : undefined + } + + public await>(): B { +>await : >() => B + + return undefined as any; +>undefined as any : any +>undefined : undefined + } + + public awaitOrdered>(): B { +>awaitOrdered : >() => B + + return undefined as any; +>undefined as any : any +>undefined : undefined + } + + public awaitOrdered2>(): B { +>awaitOrdered2 : >() => B + + return undefined as any; +>undefined as any : any +>undefined : undefined + } + + public awaitOrdered3>(): B { +>awaitOrdered3 : >() => B + + return undefined as any; +>undefined as any : any +>undefined : undefined + } + + public awaitOrdered4>(): B { +>awaitOrdered4 : >() => B + + return undefined as any; +>undefined as any : any +>undefined : undefined + } + + public awaitOrdered5>(): B { +>awaitOrdered5 : >() => B + + return undefined as any; +>undefined as any : any +>undefined : undefined + } + + public awaitOrdered6>(): B { +>awaitOrdered6 : >() => B + + return undefined as any; +>undefined as any : any +>undefined : undefined + } + + public awaitOrdered7>(): B { +>awaitOrdered7 : >() => B + + return undefined as any; +>undefined as any : any +>undefined : undefined + } + + public awaitOrdered8>(): B { +>awaitOrdered8 : >() => B + + return undefined as any; +>undefined as any : any +>undefined : undefined + } + + public awaitOrdered9>(): B { +>awaitOrdered9 : >() => B + + return undefined as any; +>undefined as any : any +>undefined : undefined + } + + public awaitLatest>(): B { +>awaitLatest : >() => B + + return undefined as any; +>undefined as any : any +>undefined : undefined + } +} + +export class B extends A { } +>B : B +>A : A + diff --git a/tests/cases/compiler/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts b/tests/cases/compiler/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts new file mode 100644 index 0000000000000..c1744880e9212 --- /dev/null +++ b/tests/cases/compiler/performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts @@ -0,0 +1,89 @@ +// @strict: true +export declare type ThenArg = T extends any ? any : T extends PromiseLike ? U : T; + +export interface InterfaceA { + filter(callback: (newValue: T, oldValue: T) => boolean): InterfaceA; + map(callback: (value: T) => D): InterfaceA; + await>(): InterfaceA; + awaitLatest>(): InterfaceA; + awaitOrdered>(): InterfaceA; + awaitOrdered2>(): InterfaceA; + awaitOrdered3>(): InterfaceA; + awaitOrdered4>(): InterfaceA; + awaitOrdered5>(): InterfaceA; + awaitOrdered6>(): InterfaceA; + awaitOrdered7>(): InterfaceA; + awaitOrdered8>(): InterfaceA; + awaitOrdered9>(): InterfaceA; +} + +export interface InterfaceB extends InterfaceA { + map(callback: (value: T) => D): InterfaceB; + await>(): InterfaceB; + awaitLatest>(): InterfaceB; + awaitOrdered>(): InterfaceB; + awaitOrdered2>(): InterfaceB; + awaitOrdered3>(): InterfaceB; + awaitOrdered4>(): InterfaceB; + awaitOrdered5>(): InterfaceB; + awaitOrdered6>(): InterfaceB; + awaitOrdered7>(): InterfaceB; + awaitOrdered8>(): InterfaceB; + awaitOrdered9>(): InterfaceB; +} + +export class A implements InterfaceB { + public filter(callback: (newValue: T, oldValue: T) => boolean): B { + return undefined as any; + } + + public map(callback: (value: T) => D): B { + return undefined as any; + } + + public await>(): B { + return undefined as any; + } + + public awaitOrdered>(): B { + return undefined as any; + } + + public awaitOrdered2>(): B { + return undefined as any; + } + + public awaitOrdered3>(): B { + return undefined as any; + } + + public awaitOrdered4>(): B { + return undefined as any; + } + + public awaitOrdered5>(): B { + return undefined as any; + } + + public awaitOrdered6>(): B { + return undefined as any; + } + + public awaitOrdered7>(): B { + return undefined as any; + } + + public awaitOrdered8>(): B { + return undefined as any; + } + + public awaitOrdered9>(): B { + return undefined as any; + } + + public awaitLatest>(): B { + return undefined as any; + } +} + +export class B extends A { } \ No newline at end of file From e7547a1321f5dabd8597e36177747987372935ad Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 9 Feb 2021 15:48:27 -0800 Subject: [PATCH 2/2] Do the same, but with only string manipulations --- src/compiler/checker.ts | 79 +++++------------------------------------ 1 file changed, 9 insertions(+), 70 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index caf670b11cafc..c7fa702199aa3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17699,9 +17699,16 @@ namespace ts { targetStack = []; } else { + // generate a key where all type parameter id positions are replaced with unconstrained type parameter ids + // this isn't perfect - nested type references passed as type arguments will muck up the indexes and thus + // prevent finding matches- but it should hit up the common cases + const broadestEquivalentId = id.split(",").map(i => i.replace(/-\d+/g, (_match, offset: number) => { + const index = length(id.slice(0, offset).match(/[-=]/g) || undefined); + return `=${index}`; + })).join(","); for (let i = 0; i < maybeCount; i++) { // If source and target are already being compared, consider them related with assumptions - if (id === maybeKeys[i]) { + if (id === maybeKeys[i] || broadestEquivalentId === maybeKeys[i]) { return Ternary.Maybe; } } @@ -17773,13 +17780,6 @@ namespace ts { return result; } - function getInstanceOfAliasOrReferenceWithMarker(input: Type, typeArguments: readonly Type[]) { - const s = input.aliasSymbol ? getTypeAliasInstantiation(input.aliasSymbol, typeArguments) : createTypeReference((input).target, typeArguments); - if (s.aliasSymbol) s.aliasTypeArgumentsContainsMarker = true; - else (s).objectFlags |= ObjectFlags.MarkerType; - return s; - } - function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { if (intersectionState & IntersectionState.PropertyCheck) { return propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, IntersectionState.None); @@ -17868,67 +17868,6 @@ namespace ts { } } - // If a more _general_ version of the source and target are being compared, consider them related with assumptions - // eg, if { x: Q } and { x: Q, y: A } are being compared and we're about to look at { x: Q' } and { x: Q', y: A } where Q' - // is some specialization or subtype of Q - // This is difficult to detect generally, so we scan for prior comparisons of the same instantiated type, and match up matching - // type arguments into sets to create a canonicalization based on those matches - if (relation !== identityRelation && ((source.aliasSymbol && !source.aliasTypeArgumentsContainsMarker && source.aliasTypeArguments) || (getObjectFlags(source) & ObjectFlags.Reference && !!getTypeArguments(source).length && !(getObjectFlags(source) & ObjectFlags.MarkerType))) && - ((target.aliasSymbol && !target.aliasTypeArgumentsContainsMarker && target.aliasTypeArguments) || (getObjectFlags(target) & ObjectFlags.Reference && !!getTypeArguments(target).length && !(getObjectFlags(target) & ObjectFlags.MarkerType)))) { - if (source.aliasSymbol || target.aliasSymbol || (source).target !== (target).target) { // ensure like symbols are just handled by standard variance analysis - const sourceTypeArguments = source.aliasTypeArguments || getTypeArguments(source); - const sourceHasMarker = some(sourceTypeArguments, a => a === markerOtherType); - const targetTypeArguments = target.aliasTypeArguments || getTypeArguments(target); - const targetHasMarker = some(targetTypeArguments, a => a === markerOtherType); - // We're using `markerOtherType` as an existential, so we can't use it again if it's already in use, - // as we'd get spurious equivalencies - we'd need to use a second existential type, and once we're doing - // that we lose a lot of the benefit of canonicalizing back to a single-existential comparison, since then - // we'd need to manufacture new type identities for every new existential we make - // The above checks don't catch all cases this can occur, as they can only detect when the containing type - // was flagged during construction as containing a marker; however if a marker enters a type through instantiation - // we need to catch that here. - // We only do this when there's a handful of possible ways to match the type parameters up, as otherwise we manufacture - // an inordinate quantity of types just to calculate their IDs! - if (!sourceHasMarker && !targetHasMarker && sourceTypeArguments.length * targetTypeArguments.length < 10) { - const originalKey = getRelationKey(source, target, intersectionState, relation); - for (let i = 0; i < sourceTypeArguments.length; i++) { - for (let j = 0; j < targetTypeArguments.length; j++) { - if ((!(sourceTypeArguments[i].flags & TypeFlags.TypeParameter) && !isTypeAny(sourceTypeArguments[i]) && sourceTypeArguments[i] === targetTypeArguments[j]) || - // Similarly, if we're comparing X to Z, X is assignable to Z trivially if X is assignable to Z - (!(sourceTypeArguments[i].flags & TypeFlags.TypeParameter) && isTypeAny(targetTypeArguments[j])) || - // Again, but for `X` vs `Z` - (isTypeAny(sourceTypeArguments[i]) && !(targetTypeArguments[j].flags & TypeFlags.TypeParameter)) || - // Likewise, if we're comparing X to Z and are already comparing X to Z, we can assume it to be true - !!(sourceTypeArguments[i].flags & TypeFlags.TypeParameter) && sourceTypeArguments[i] === targetTypeArguments[j]) { - const sourceClone = sourceTypeArguments.slice(); - sourceClone[i] = markerOtherType; - const s = getInstanceOfAliasOrReferenceWithMarker(source, sourceClone); - const targetClone = targetTypeArguments.slice(); - targetClone[j] = markerOtherType; - const t = getInstanceOfAliasOrReferenceWithMarker(target, targetClone); - // If the marker-instantiated form looks "the same" as the type we already have (eg, - // because we replace unconstrained generics with unconstrained generics), skip the check - // since we'll otherwise deliver a spurious `Maybe` result from the key _just_ set upon - // entry into `recursiveTypeRelatedTo` - const existentialKey = getRelationKey(s, t, intersectionState, relation); - if (existentialKey !== originalKey) { - // We don't actually trigger the comparison, since we'd rather not do an extra comparison - // if we haven't already started that more general comparison; instead we just look for the - // key in the maybeKeys stack - for (let i = 0; i < maybeCount; i++) { - // If source and target are already being compared, consider them related with assumptions - if (existentialKey === maybeKeys[i]) { - return Ternary.Maybe; - } - } - } - } - } - } - } - } - } - // For a generic type T and a type U that is assignable to T, [...U] is assignable to T, U is assignable to readonly [...T], // and U is assignable to [...T] when U is constrained to a mutable array or tuple type. if (isSingleElementGenericTupleType(source) && !source.target.readonly && (result = isRelatedTo(getTypeArguments(source)[0], target)) || @@ -19209,7 +19148,7 @@ namespace ts { } function isTypeReferenceWithGenericArguments(type: Type): boolean { - return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t)); + return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => !!(t.flags & TypeFlags.TypeParameter) || isTypeReferenceWithGenericArguments(t)); } /**