@@ -2193,6 +2193,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2193
2193
/** Key is "/path/to/a.ts|/path/to/b.ts". */
2194
2194
var amalgamatedDuplicates: Map<string, DuplicateInfoForFiles> | undefined;
2195
2195
var reverseMappedCache = new Map<string, Type | undefined>();
2196
+ var reverseHomomorphicMappedCache = new Map<string, Type | undefined>();
2196
2197
var ambientModulesCache: Symbol[] | undefined;
2197
2198
/**
2198
2199
* List of every ambient module with a "*" wildcard.
@@ -7003,20 +7004,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
7003
7004
}
7004
7005
7005
7006
function shouldUsePlaceholderForProperty(propertySymbol: Symbol, context: NodeBuilderContext) {
7006
- // Use placeholders for reverse mapped types we've either already descended into, or which
7007
- // are nested reverse mappings within a mapping over a non-anonymous type. The later is a restriction mostly just to
7007
+ // Use placeholders for reverse mapped types we've either
7008
+ // (1) already descended into, or
7009
+ // (2) are nested reverse mappings within a mapping over a non-anonymous type, or
7010
+ // (3) are deeply nested properties that originate from the same mapped type.
7011
+ // Condition (2) is a restriction mostly just to
7008
7012
// reduce the blowup in printback size from doing, eg, a deep reverse mapping over `Window`.
7009
7013
// Since anonymous types usually come from expressions, this allows us to preserve the output
7010
7014
// for deep mappings which likely come from expressions, while truncating those parts which
7011
7015
// come from mappings over library functions.
7016
+ // Condition (3) limits printing of possibly infinitely deep reverse mapped types.
7017
+ const depth = 3;
7012
7018
return !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped)
7013
7019
&& (
7014
7020
contains(context.reverseMappedStack, propertySymbol as ReverseMappedSymbol)
7015
7021
|| (
7016
7022
context.reverseMappedStack?.[0]
7017
7023
&& !(getObjectFlags(last(context.reverseMappedStack).links.propertyType) & ObjectFlags.Anonymous)
7018
7024
)
7025
+ || isDeeplyNestedReverseMappedTypeProperty()
7019
7026
);
7027
+ function isDeeplyNestedReverseMappedTypeProperty() {
7028
+ if ((context.reverseMappedStack?.length ?? 0) < depth) {
7029
+ return false;
7030
+ }
7031
+ for (let i = 0; i < depth; i++) {
7032
+ const prop = context.reverseMappedStack![context.reverseMappedStack!.length - 1 - i];
7033
+ if (prop.links.mappedType.symbol !== (propertySymbol as ReverseMappedSymbol).links.mappedType.symbol) {
7034
+ return false;
7035
+ }
7036
+ }
7037
+ return true;
7038
+ }
7020
7039
}
7021
7040
7022
7041
function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) {
@@ -8291,11 +8310,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8291
8310
const typePredicate = getTypePredicateOfSignature(signature);
8292
8311
const type = getReturnTypeOfSignature(signature);
8293
8312
if (context.enclosingDeclaration && (!isErrorType(type) || (context.flags & NodeBuilderFlags.AllowUnresolvedNames)) && signature.declaration && !nodeIsSynthesized(signature.declaration)) {
8294
- const annotation = signature.declaration && getNonlocalEffectiveReturnTypeAnnotationNode(signature.declaration);
8295
- // Default constructor signatures inherited from base classes return the derived class but have the base class declaration
8296
- // To ensure we don't serialize the wrong type we check that that return type of the signature corresponds to the declaration return type signature
8297
- if (annotation && getTypeFromTypeNode(context, annotation) === type) {
8298
- const result = tryReuseExistingTypeNodeHelper(context, annotation);
8313
+ const annotation = getNonlocalEffectiveReturnTypeAnnotationNode(signature.declaration);
8314
+ if (annotation) {
8315
+ const result = tryReuseExistingTypeNode(context, annotation, type, context.enclosingDeclaration);
8299
8316
if (result) {
8300
8317
return result;
8301
8318
}
@@ -8805,7 +8822,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8805
8822
);
8806
8823
}
8807
8824
if (isNamedDeclaration(node) && node.name.kind === SyntaxKind.ComputedPropertyName && !isLateBindableName(node.name)) {
8808
- if (!(context.flags & NodeBuilderFlags.AllowUnresolvedNames && hasDynamicName(node) && isEntityNameExpression(node.name.expression) && checkComputedPropertyName(node.name).flags & TypeFlags.Any)) {
8825
+ if (!hasDynamicName(node)) {
8826
+ return visitEachChild(node, visitExistingNodeTreeSymbols);
8827
+ }
8828
+ if (!(context.flags & NodeBuilderFlags.AllowUnresolvedNames && isEntityNameExpression(node.name.expression) && checkComputedPropertyName(node.name).flags & TypeFlags.Any)) {
8809
8829
return undefined;
8810
8830
}
8811
8831
}
@@ -8949,7 +8969,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8949
8969
if (result) {
8950
8970
if (result.pos !== -1 || result.end !== -1) {
8951
8971
if (result === nodes) {
8952
- result = factory.createNodeArray(nodes, nodes.hasTrailingComma);
8972
+ result = factory.createNodeArray(nodes.slice() , nodes.hasTrailingComma);
8953
8973
}
8954
8974
setTextRangePosEnd(result, -1, -1);
8955
8975
}
@@ -15923,7 +15943,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
15923
15943
}
15924
15944
15925
15945
function createSignatureTypeMapper(signature: Signature, typeArguments: readonly Type[] | undefined): TypeMapper {
15926
- return createTypeMapper(signature.typeParameters!, typeArguments);
15946
+ return createTypeMapper(sameMap( signature.typeParameters!, tp => tp.mapper ? instantiateType(tp, tp.mapper) : tp) , typeArguments);
15927
15947
}
15928
15948
15929
15949
function getErasedSignature(signature: Signature): Signature {
@@ -25604,11 +25624,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
25604
25624
*/
25605
25625
function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
25606
25626
const cacheKey = source.id + "," + target.id + "," + constraint.id;
25607
- if (reverseMappedCache .has(cacheKey)) {
25608
- return reverseMappedCache .get(cacheKey);
25627
+ if (reverseHomomorphicMappedCache .has(cacheKey)) {
25628
+ return reverseHomomorphicMappedCache .get(cacheKey);
25609
25629
}
25610
25630
const type = createReverseMappedType(source, target, constraint);
25611
- reverseMappedCache .set(cacheKey, type);
25631
+ reverseHomomorphicMappedCache .set(cacheKey, type);
25612
25632
return type;
25613
25633
}
25614
25634
@@ -33316,7 +33336,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
33316
33336
33317
33337
checkJsxPreconditions(node);
33318
33338
33319
- markLinkedReferences (node, ReferenceHint.Jsx );
33339
+ markJsxAliasReferenced (node);
33320
33340
33321
33341
if (isNodeOpeningLikeElement) {
33322
33342
const jsxOpeningLikeNode = node;
@@ -49219,11 +49239,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
49219
49239
forEachNodeRecursively(node, checkIdentifiers);
49220
49240
}
49221
49241
49242
+ function isExpressionNodeOrShorthandPropertyAssignmentName(node: Identifier) {
49243
+ // TODO(jakebailey): Just use isExpressionNode once that considers these identifiers to be expressions.
49244
+ return isExpressionNode(node)
49245
+ || isShorthandPropertyAssignment(node.parent) && (node.parent.objectAssignmentInitializer ?? node.parent.name) === node;
49246
+ }
49247
+
49222
49248
function checkSingleIdentifier(node: Node) {
49223
49249
const nodeLinks = getNodeLinks(node);
49224
49250
nodeLinks.calculatedFlags |= NodeCheckFlags.ConstructorReference | NodeCheckFlags.CapturedBlockScopedBinding | NodeCheckFlags.BlockScopedBindingInLoop;
49225
- if (isIdentifier(node) && isExpressionNode (node) && !(isPropertyAccessExpression(node.parent) && node.parent.name === node)) {
49226
- const s = getSymbolAtLocation (node, /*ignoreErrors*/ true );
49251
+ if (isIdentifier(node) && isExpressionNodeOrShorthandPropertyAssignmentName (node) && !(isPropertyAccessExpression(node.parent) && node.parent.name === node)) {
49252
+ const s = getResolvedSymbol (node);
49227
49253
if (s && s !== unknownSymbol) {
49228
49254
checkIdentifierCalculateNodeCheckFlags(node, s);
49229
49255
}
0 commit comments