Skip to content

Commit 9eec534

Browse files
committed
Merge branch 'release-5.5' into cherry-pick/59070/release-5.5
2 parents de1c3de + 8794318 commit 9eec534

File tree

319 files changed

+6318
-2430
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

319 files changed

+6318
-2430
lines changed

src/compiler/checker.ts

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21932193
/** Key is "/path/to/a.ts|/path/to/b.ts". */
21942194
var amalgamatedDuplicates: Map<string, DuplicateInfoForFiles> | undefined;
21952195
var reverseMappedCache = new Map<string, Type | undefined>();
2196+
var reverseHomomorphicMappedCache = new Map<string, Type | undefined>();
21962197
var ambientModulesCache: Symbol[] | undefined;
21972198
/**
21982199
* List of every ambient module with a "*" wildcard.
@@ -7003,20 +7004,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
70037004
}
70047005

70057006
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
70087012
// reduce the blowup in printback size from doing, eg, a deep reverse mapping over `Window`.
70097013
// Since anonymous types usually come from expressions, this allows us to preserve the output
70107014
// for deep mappings which likely come from expressions, while truncating those parts which
70117015
// come from mappings over library functions.
7016+
// Condition (3) limits printing of possibly infinitely deep reverse mapped types.
7017+
const depth = 3;
70127018
return !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped)
70137019
&& (
70147020
contains(context.reverseMappedStack, propertySymbol as ReverseMappedSymbol)
70157021
|| (
70167022
context.reverseMappedStack?.[0]
70177023
&& !(getObjectFlags(last(context.reverseMappedStack).links.propertyType) & ObjectFlags.Anonymous)
70187024
)
7025+
|| isDeeplyNestedReverseMappedTypeProperty()
70197026
);
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+
}
70207039
}
70217040

70227041
function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) {
@@ -8291,11 +8310,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
82918310
const typePredicate = getTypePredicateOfSignature(signature);
82928311
const type = getReturnTypeOfSignature(signature);
82938312
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);
82998316
if (result) {
83008317
return result;
83018318
}
@@ -8805,7 +8822,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
88058822
);
88068823
}
88078824
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)) {
88098829
return undefined;
88108830
}
88118831
}
@@ -8949,7 +8969,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
89498969
if (result) {
89508970
if (result.pos !== -1 || result.end !== -1) {
89518971
if (result === nodes) {
8952-
result = factory.createNodeArray(nodes, nodes.hasTrailingComma);
8972+
result = factory.createNodeArray(nodes.slice(), nodes.hasTrailingComma);
89538973
}
89548974
setTextRangePosEnd(result, -1, -1);
89558975
}
@@ -15923,7 +15943,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1592315943
}
1592415944

1592515945
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);
1592715947
}
1592815948

1592915949
function getErasedSignature(signature: Signature): Signature {
@@ -25604,11 +25624,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2560425624
*/
2560525625
function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
2560625626
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);
2560925629
}
2561025630
const type = createReverseMappedType(source, target, constraint);
25611-
reverseMappedCache.set(cacheKey, type);
25631+
reverseHomomorphicMappedCache.set(cacheKey, type);
2561225632
return type;
2561325633
}
2561425634

@@ -33316,7 +33336,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3331633336

3331733337
checkJsxPreconditions(node);
3331833338

33319-
markLinkedReferences(node, ReferenceHint.Jsx);
33339+
markJsxAliasReferenced(node);
3332033340

3332133341
if (isNodeOpeningLikeElement) {
3332233342
const jsxOpeningLikeNode = node;
@@ -49219,11 +49239,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4921949239
forEachNodeRecursively(node, checkIdentifiers);
4922049240
}
4922149241

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+
4922249248
function checkSingleIdentifier(node: Node) {
4922349249
const nodeLinks = getNodeLinks(node);
4922449250
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);
4922749253
if (s && s !== unknownSymbol) {
4922849254
checkIdentifierCalculateNodeCheckFlags(node, s);
4922949255
}

src/compiler/commandLineParser.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
800800
type: "boolean",
801801
affectsEmit: true,
802802
affectsBuildInfo: true,
803+
affectsSourceFile: true,
803804
category: Diagnostics.Emit,
804805
description: Diagnostics.Allow_importing_helper_functions_from_tslib_once_per_project_instead_of_including_them_per_file,
805806
defaultValueDescription: false,
@@ -1270,6 +1271,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
12701271
affectsEmit: true,
12711272
affectsBuildInfo: true,
12721273
affectsModuleResolution: true,
1274+
affectsSourceFile: true,
12731275
category: Diagnostics.Language_and_Environment,
12741276
description: Diagnostics.Specify_module_specifier_used_to_import_the_JSX_factory_functions_when_using_jsx_Colon_react_jsx_Asterisk,
12751277
defaultValueDescription: "react",

src/compiler/factory/nodeChildren.ts

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,61 @@
11
import {
2+
Debug,
23
emptyArray,
34
isNodeKind,
45
Node,
6+
SourceFileLike,
7+
SyntaxKind,
8+
SyntaxList,
59
} from "../_namespaces/ts.js";
610

7-
const nodeChildren = new WeakMap<Node, readonly Node[] | undefined>();
11+
const sourceFileToNodeChildren = new WeakMap<SourceFileLike, WeakMap<Node, readonly Node[] | undefined>>();
812

913
/** @internal */
10-
export function getNodeChildren(node: Node): readonly Node[] | undefined {
11-
if (!isNodeKind(node.kind)) return emptyArray;
14+
export function getNodeChildren(node: Node, sourceFile: SourceFileLike): readonly Node[] | undefined {
15+
const kind = node.kind;
16+
if (!isNodeKind(kind)) {
17+
return emptyArray;
18+
}
19+
if (kind === SyntaxKind.SyntaxList) {
20+
return (node as SyntaxList)._children;
21+
}
1222

13-
return nodeChildren.get(node);
23+
return sourceFileToNodeChildren.get(sourceFile)?.get(node);
1424
}
1525

1626
/** @internal */
17-
export function setNodeChildren(node: Node, children: readonly Node[]): readonly Node[] {
18-
nodeChildren.set(node, children);
27+
export function setNodeChildren(node: Node, sourceFile: SourceFileLike, children: readonly Node[]): readonly Node[] {
28+
if (node.kind === SyntaxKind.SyntaxList) {
29+
// SyntaxList children are always eagerly created in the process of
30+
// creating their parent's `children` list. We shouldn't need to set them here.
31+
Debug.fail("Should not need to re-set the children of a SyntaxList.");
32+
}
33+
34+
let map = sourceFileToNodeChildren.get(sourceFile);
35+
if (map === undefined) {
36+
map = new WeakMap();
37+
sourceFileToNodeChildren.set(sourceFile, map);
38+
}
39+
map.set(node, children);
1940
return children;
2041
}
2142

2243
/** @internal */
23-
export function unsetNodeChildren(node: Node) {
24-
nodeChildren.delete(node);
44+
export function unsetNodeChildren(node: Node, origSourceFile: SourceFileLike) {
45+
if (node.kind === SyntaxKind.SyntaxList) {
46+
// Syntax lists are synthesized and we store their children directly on them.
47+
// They are a special case where we expect incremental parsing to toss them away entirely
48+
// if a change intersects with their containing parents.
49+
Debug.fail("Did not expect to unset the children of a SyntaxList.");
50+
}
51+
sourceFileToNodeChildren.get(origSourceFile)?.delete(node);
52+
}
53+
54+
/** @internal */
55+
export function transferSourceFileChildren(sourceFile: SourceFileLike, targetSourceFile: SourceFileLike) {
56+
const map = sourceFileToNodeChildren.get(sourceFile);
57+
if (map !== undefined) {
58+
sourceFileToNodeChildren.delete(sourceFile);
59+
sourceFileToNodeChildren.set(targetSourceFile, map);
60+
}
2561
}

src/compiler/factory/nodeFactory.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,6 @@ import {
387387
setEmitFlags,
388388
setIdentifierAutoGenerate,
389389
setIdentifierTypeArguments,
390-
setNodeChildren,
391390
setParent,
392391
setTextRange,
393392
ShorthandPropertyAssignment,
@@ -6211,7 +6210,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
62116210
// @api
62126211
function createSyntaxList(children: readonly Node[]) {
62136212
const node = createBaseNode<SyntaxList>(SyntaxKind.SyntaxList);
6214-
setNodeChildren(node, children);
6213+
node._children = children;
62156214
return node;
62166215
}
62176216

src/compiler/parser.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ import {
369369
tokenIsIdentifierOrKeywordOrGreaterThan,
370370
tokenToString,
371371
tracing,
372+
transferSourceFileChildren,
372373
TransformFlags,
373374
TryStatement,
374375
TupleTypeNode,
@@ -2637,7 +2638,7 @@ namespace Parser {
26372638
function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier {
26382639
if (isIdentifier) {
26392640
identifierCount++;
2640-
const pos = getNodePos();
2641+
const pos = scanner.hasLeadingAsterisks() ? scanner.getTokenStart() : getNodePos();
26412642
// Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker
26422643
const originalKeywordKind = token();
26432644
const text = internIdentifier(scanner.getTokenValue());
@@ -9949,6 +9950,7 @@ namespace IncrementalParser {
99499950
aggressiveChecks,
99509951
);
99519952
result.impliedNodeFormat = sourceFile.impliedNodeFormat;
9953+
transferSourceFileChildren(sourceFile, result);
99529954
return result;
99539955
}
99549956

@@ -10001,9 +10003,9 @@ namespace IncrementalParser {
1000110003
}
1000210004
}
1000310005

10004-
function moveElementEntirelyPastChangeRange(element: Node, isArray: false, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
10005-
function moveElementEntirelyPastChangeRange(element: NodeArray<Node>, isArray: true, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
10006-
function moveElementEntirelyPastChangeRange(element: Node | NodeArray<Node>, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
10006+
function moveElementEntirelyPastChangeRange(element: Node, origSourceFile: SourceFile, isArray: false, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
10007+
function moveElementEntirelyPastChangeRange(element: NodeArray<Node>, origSourceFile: SourceFile, isArray: true, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
10008+
function moveElementEntirelyPastChangeRange(element: Node | NodeArray<Node>, origSourceFile: SourceFile, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
1000710009
if (isArray) {
1000810010
visitArray(element as NodeArray<Node>);
1000910011
}
@@ -10020,7 +10022,7 @@ namespace IncrementalParser {
1002010022

1002110023
// Ditch any existing LS children we may have created. This way we can avoid
1002210024
// moving them forward.
10023-
unsetNodeChildren(node);
10025+
unsetNodeChildren(node, origSourceFile);
1002410026

1002510027
setTextRangePosEnd(node, node.pos + delta, node.end + delta);
1002610028

@@ -10167,7 +10169,7 @@ namespace IncrementalParser {
1016710169
if (child.pos > changeRangeOldEnd) {
1016810170
// Node is entirely past the change range. We need to move both its pos and
1016910171
// end, forward or backward appropriately.
10170-
moveElementEntirelyPastChangeRange(child, /*isArray*/ false, delta, oldText, newText, aggressiveChecks);
10172+
moveElementEntirelyPastChangeRange(child, sourceFile, /*isArray*/ false, delta, oldText, newText, aggressiveChecks);
1017110173
return;
1017210174
}
1017310175

@@ -10177,7 +10179,7 @@ namespace IncrementalParser {
1017710179
const fullEnd = child.end;
1017810180
if (fullEnd >= changeStart) {
1017910181
markAsIntersectingIncrementalChange(child);
10180-
unsetNodeChildren(child);
10182+
unsetNodeChildren(child, sourceFile);
1018110183

1018210184
// Adjust the pos or end (or both) of the intersecting element accordingly.
1018310185
adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
@@ -10200,7 +10202,7 @@ namespace IncrementalParser {
1020010202
if (array.pos > changeRangeOldEnd) {
1020110203
// Array is entirely after the change range. We need to move it, and move any of
1020210204
// its children.
10203-
moveElementEntirelyPastChangeRange(array, /*isArray*/ true, delta, oldText, newText, aggressiveChecks);
10205+
moveElementEntirelyPastChangeRange(array, sourceFile, /*isArray*/ true, delta, oldText, newText, aggressiveChecks);
1020410206
return;
1020510207
}
1020610208

src/compiler/performanceCore.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,14 @@ function tryGetPerformance() {
3131
if (isNodeLikeSystem()) {
3232
try {
3333
// By default, only write native events when generating a cpu profile or using the v8 profiler.
34-
const { performance } = require("perf_hooks") as typeof import("perf_hooks");
35-
return {
36-
shouldWriteNativeEvents: false,
37-
performance,
38-
};
34+
// Some environments may polyfill this module with an empty object; verify the object has the expected shape.
35+
const { performance } = require("perf_hooks") as Partial<typeof import("perf_hooks")>;
36+
if (performance) {
37+
return {
38+
shouldWriteNativeEvents: false,
39+
performance,
40+
};
41+
}
3942
}
4043
catch {
4144
// ignore errors

src/compiler/scanner.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ export interface Scanner {
112112
resetTokenState(pos: number): void;
113113
/** @internal */
114114
setSkipJsDocLeadingAsterisks(skip: boolean): void;
115+
/** @internal */
116+
hasLeadingAsterisks(): boolean;
115117
// Invokes the provided callback then unconditionally restores the scanner to the state it
116118
// was in immediately prior to invoking the callback. The result of invoking the callback
117119
// is returned from this function.
@@ -1042,6 +1044,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
10421044

10431045
var commentDirectives: CommentDirective[] | undefined;
10441046
var skipJsDocLeadingAsterisks = 0;
1047+
var asteriskSeen = false;
10451048

10461049
var scriptKind = ScriptKind.Unknown;
10471050
var jsDocParsingMode = JSDocParsingMode.ParseAll;
@@ -1096,6 +1099,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
10961099
resetTokenState,
10971100
setTextPos: resetTokenState,
10981101
setSkipJsDocLeadingAsterisks,
1102+
hasLeadingAsterisks,
10991103
tryScan,
11001104
lookAhead,
11011105
scanRange,
@@ -1877,7 +1881,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
18771881
function scan(): SyntaxKind {
18781882
fullStartPos = pos;
18791883
tokenFlags = TokenFlags.None;
1880-
let asteriskSeen = false;
1884+
asteriskSeen = false;
18811885
while (true) {
18821886
tokenStart = pos;
18831887
if (pos >= end) {
@@ -4004,6 +4008,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
40044008
function setSkipJsDocLeadingAsterisks(skip: boolean) {
40054009
skipJsDocLeadingAsterisks += skip ? 1 : -1;
40064010
}
4011+
4012+
function hasLeadingAsterisks() {
4013+
return asteriskSeen;
4014+
}
40074015
}
40084016

40094017
function codePointAt(s: string, i: number): number {

0 commit comments

Comments
 (0)