Skip to content

Commit

Permalink
Merge branch 'release-5.5' into cherry-pick/59070/release-5.5
Browse files Browse the repository at this point in the history
  • Loading branch information
sheetalkamat committed Jul 17, 2024
2 parents de1c3de + 8794318 commit 9eec534
Show file tree
Hide file tree
Showing 319 changed files with 6,318 additions and 2,430 deletions.
58 changes: 42 additions & 16 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2193,6 +2193,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
/** Key is "/path/to/a.ts|/path/to/b.ts". */
var amalgamatedDuplicates: Map<string, DuplicateInfoForFiles> | undefined;
var reverseMappedCache = new Map<string, Type | undefined>();
var reverseHomomorphicMappedCache = new Map<string, Type | undefined>();
var ambientModulesCache: Symbol[] | undefined;
/**
* List of every ambient module with a "*" wildcard.
Expand Down Expand Up @@ -7003,20 +7004,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function shouldUsePlaceholderForProperty(propertySymbol: Symbol, context: NodeBuilderContext) {
// Use placeholders for reverse mapped types we've either already descended into, or which
// are nested reverse mappings within a mapping over a non-anonymous type. The later is a restriction mostly just to
// Use placeholders for reverse mapped types we've either
// (1) already descended into, or
// (2) are nested reverse mappings within a mapping over a non-anonymous type, or
// (3) are deeply nested properties that originate from the same mapped type.
// Condition (2) is a restriction mostly just to
// reduce the blowup in printback size from doing, eg, a deep reverse mapping over `Window`.
// Since anonymous types usually come from expressions, this allows us to preserve the output
// for deep mappings which likely come from expressions, while truncating those parts which
// come from mappings over library functions.
// Condition (3) limits printing of possibly infinitely deep reverse mapped types.
const depth = 3;
return !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped)
&& (
contains(context.reverseMappedStack, propertySymbol as ReverseMappedSymbol)
|| (
context.reverseMappedStack?.[0]
&& !(getObjectFlags(last(context.reverseMappedStack).links.propertyType) & ObjectFlags.Anonymous)
)
|| isDeeplyNestedReverseMappedTypeProperty()
);
function isDeeplyNestedReverseMappedTypeProperty() {
if ((context.reverseMappedStack?.length ?? 0) < depth) {
return false;
}
for (let i = 0; i < depth; i++) {
const prop = context.reverseMappedStack![context.reverseMappedStack!.length - 1 - i];
if (prop.links.mappedType.symbol !== (propertySymbol as ReverseMappedSymbol).links.mappedType.symbol) {
return false;
}
}
return true;
}
}

function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) {
Expand Down Expand Up @@ -8291,11 +8310,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const typePredicate = getTypePredicateOfSignature(signature);
const type = getReturnTypeOfSignature(signature);
if (context.enclosingDeclaration && (!isErrorType(type) || (context.flags & NodeBuilderFlags.AllowUnresolvedNames)) && signature.declaration && !nodeIsSynthesized(signature.declaration)) {
const annotation = signature.declaration && getNonlocalEffectiveReturnTypeAnnotationNode(signature.declaration);
// Default constructor signatures inherited from base classes return the derived class but have the base class declaration
// 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
if (annotation && getTypeFromTypeNode(context, annotation) === type) {
const result = tryReuseExistingTypeNodeHelper(context, annotation);
const annotation = getNonlocalEffectiveReturnTypeAnnotationNode(signature.declaration);
if (annotation) {
const result = tryReuseExistingTypeNode(context, annotation, type, context.enclosingDeclaration);
if (result) {
return result;
}
Expand Down Expand Up @@ -8805,7 +8822,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
);
}
if (isNamedDeclaration(node) && node.name.kind === SyntaxKind.ComputedPropertyName && !isLateBindableName(node.name)) {
if (!(context.flags & NodeBuilderFlags.AllowUnresolvedNames && hasDynamicName(node) && isEntityNameExpression(node.name.expression) && checkComputedPropertyName(node.name).flags & TypeFlags.Any)) {
if (!hasDynamicName(node)) {
return visitEachChild(node, visitExistingNodeTreeSymbols);
}
if (!(context.flags & NodeBuilderFlags.AllowUnresolvedNames && isEntityNameExpression(node.name.expression) && checkComputedPropertyName(node.name).flags & TypeFlags.Any)) {
return undefined;
}
}
Expand Down Expand Up @@ -8949,7 +8969,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (result) {
if (result.pos !== -1 || result.end !== -1) {
if (result === nodes) {
result = factory.createNodeArray(nodes, nodes.hasTrailingComma);
result = factory.createNodeArray(nodes.slice(), nodes.hasTrailingComma);
}
setTextRangePosEnd(result, -1, -1);
}
Expand Down Expand Up @@ -15923,7 +15943,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function createSignatureTypeMapper(signature: Signature, typeArguments: readonly Type[] | undefined): TypeMapper {
return createTypeMapper(signature.typeParameters!, typeArguments);
return createTypeMapper(sameMap(signature.typeParameters!, tp => tp.mapper ? instantiateType(tp, tp.mapper) : tp), typeArguments);
}

function getErasedSignature(signature: Signature): Signature {
Expand Down Expand Up @@ -25604,11 +25624,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
*/
function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
const cacheKey = source.id + "," + target.id + "," + constraint.id;
if (reverseMappedCache.has(cacheKey)) {
return reverseMappedCache.get(cacheKey);
if (reverseHomomorphicMappedCache.has(cacheKey)) {
return reverseHomomorphicMappedCache.get(cacheKey);
}
const type = createReverseMappedType(source, target, constraint);
reverseMappedCache.set(cacheKey, type);
reverseHomomorphicMappedCache.set(cacheKey, type);
return type;
}

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

checkJsxPreconditions(node);

markLinkedReferences(node, ReferenceHint.Jsx);
markJsxAliasReferenced(node);

if (isNodeOpeningLikeElement) {
const jsxOpeningLikeNode = node;
Expand Down Expand Up @@ -49219,11 +49239,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
forEachNodeRecursively(node, checkIdentifiers);
}

function isExpressionNodeOrShorthandPropertyAssignmentName(node: Identifier) {
// TODO(jakebailey): Just use isExpressionNode once that considers these identifiers to be expressions.
return isExpressionNode(node)
|| isShorthandPropertyAssignment(node.parent) && (node.parent.objectAssignmentInitializer ?? node.parent.name) === node;
}

function checkSingleIdentifier(node: Node) {
const nodeLinks = getNodeLinks(node);
nodeLinks.calculatedFlags |= NodeCheckFlags.ConstructorReference | NodeCheckFlags.CapturedBlockScopedBinding | NodeCheckFlags.BlockScopedBindingInLoop;
if (isIdentifier(node) && isExpressionNode(node) && !(isPropertyAccessExpression(node.parent) && node.parent.name === node)) {
const s = getSymbolAtLocation(node, /*ignoreErrors*/ true);
if (isIdentifier(node) && isExpressionNodeOrShorthandPropertyAssignmentName(node) && !(isPropertyAccessExpression(node.parent) && node.parent.name === node)) {
const s = getResolvedSymbol(node);
if (s && s !== unknownSymbol) {
checkIdentifierCalculateNodeCheckFlags(node, s);
}
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
type: "boolean",
affectsEmit: true,
affectsBuildInfo: true,
affectsSourceFile: true,
category: Diagnostics.Emit,
description: Diagnostics.Allow_importing_helper_functions_from_tslib_once_per_project_instead_of_including_them_per_file,
defaultValueDescription: false,
Expand Down Expand Up @@ -1270,6 +1271,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
affectsEmit: true,
affectsBuildInfo: true,
affectsModuleResolution: true,
affectsSourceFile: true,
category: Diagnostics.Language_and_Environment,
description: Diagnostics.Specify_module_specifier_used_to_import_the_JSX_factory_functions_when_using_jsx_Colon_react_jsx_Asterisk,
defaultValueDescription: "react",
Expand Down
52 changes: 44 additions & 8 deletions src/compiler/factory/nodeChildren.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,61 @@
import {
Debug,
emptyArray,
isNodeKind,
Node,
SourceFileLike,
SyntaxKind,
SyntaxList,
} from "../_namespaces/ts.js";

const nodeChildren = new WeakMap<Node, readonly Node[] | undefined>();
const sourceFileToNodeChildren = new WeakMap<SourceFileLike, WeakMap<Node, readonly Node[] | undefined>>();

/** @internal */
export function getNodeChildren(node: Node): readonly Node[] | undefined {
if (!isNodeKind(node.kind)) return emptyArray;
export function getNodeChildren(node: Node, sourceFile: SourceFileLike): readonly Node[] | undefined {
const kind = node.kind;
if (!isNodeKind(kind)) {
return emptyArray;
}
if (kind === SyntaxKind.SyntaxList) {
return (node as SyntaxList)._children;
}

return nodeChildren.get(node);
return sourceFileToNodeChildren.get(sourceFile)?.get(node);
}

/** @internal */
export function setNodeChildren(node: Node, children: readonly Node[]): readonly Node[] {
nodeChildren.set(node, children);
export function setNodeChildren(node: Node, sourceFile: SourceFileLike, children: readonly Node[]): readonly Node[] {
if (node.kind === SyntaxKind.SyntaxList) {
// SyntaxList children are always eagerly created in the process of
// creating their parent's `children` list. We shouldn't need to set them here.
Debug.fail("Should not need to re-set the children of a SyntaxList.");
}

let map = sourceFileToNodeChildren.get(sourceFile);
if (map === undefined) {
map = new WeakMap();
sourceFileToNodeChildren.set(sourceFile, map);
}
map.set(node, children);
return children;
}

/** @internal */
export function unsetNodeChildren(node: Node) {
nodeChildren.delete(node);
export function unsetNodeChildren(node: Node, origSourceFile: SourceFileLike) {
if (node.kind === SyntaxKind.SyntaxList) {
// Syntax lists are synthesized and we store their children directly on them.
// They are a special case where we expect incremental parsing to toss them away entirely
// if a change intersects with their containing parents.
Debug.fail("Did not expect to unset the children of a SyntaxList.");
}
sourceFileToNodeChildren.get(origSourceFile)?.delete(node);
}

/** @internal */
export function transferSourceFileChildren(sourceFile: SourceFileLike, targetSourceFile: SourceFileLike) {
const map = sourceFileToNodeChildren.get(sourceFile);
if (map !== undefined) {
sourceFileToNodeChildren.delete(sourceFile);
sourceFileToNodeChildren.set(targetSourceFile, map);
}
}
3 changes: 1 addition & 2 deletions src/compiler/factory/nodeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,6 @@ import {
setEmitFlags,
setIdentifierAutoGenerate,
setIdentifierTypeArguments,
setNodeChildren,
setParent,
setTextRange,
ShorthandPropertyAssignment,
Expand Down Expand Up @@ -6211,7 +6210,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
// @api
function createSyntaxList(children: readonly Node[]) {
const node = createBaseNode<SyntaxList>(SyntaxKind.SyntaxList);
setNodeChildren(node, children);
node._children = children;
return node;
}

Expand Down
18 changes: 10 additions & 8 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ import {
tokenIsIdentifierOrKeywordOrGreaterThan,
tokenToString,
tracing,
transferSourceFileChildren,
TransformFlags,
TryStatement,
TupleTypeNode,
Expand Down Expand Up @@ -2637,7 +2638,7 @@ namespace Parser {
function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier {
if (isIdentifier) {
identifierCount++;
const pos = getNodePos();
const pos = scanner.hasLeadingAsterisks() ? scanner.getTokenStart() : getNodePos();
// Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker
const originalKeywordKind = token();
const text = internIdentifier(scanner.getTokenValue());
Expand Down Expand Up @@ -9949,6 +9950,7 @@ namespace IncrementalParser {
aggressiveChecks,
);
result.impliedNodeFormat = sourceFile.impliedNodeFormat;
transferSourceFileChildren(sourceFile, result);
return result;
}

Expand Down Expand Up @@ -10001,9 +10003,9 @@ namespace IncrementalParser {
}
}

function moveElementEntirelyPastChangeRange(element: Node, isArray: false, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
function moveElementEntirelyPastChangeRange(element: NodeArray<Node>, isArray: true, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
function moveElementEntirelyPastChangeRange(element: Node | NodeArray<Node>, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
function moveElementEntirelyPastChangeRange(element: Node, origSourceFile: SourceFile, isArray: false, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
function moveElementEntirelyPastChangeRange(element: NodeArray<Node>, origSourceFile: SourceFile, isArray: true, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
function moveElementEntirelyPastChangeRange(element: Node | NodeArray<Node>, origSourceFile: SourceFile, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
if (isArray) {
visitArray(element as NodeArray<Node>);
}
Expand All @@ -10020,7 +10022,7 @@ namespace IncrementalParser {

// Ditch any existing LS children we may have created. This way we can avoid
// moving them forward.
unsetNodeChildren(node);
unsetNodeChildren(node, origSourceFile);

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

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

Expand All @@ -10177,7 +10179,7 @@ namespace IncrementalParser {
const fullEnd = child.end;
if (fullEnd >= changeStart) {
markAsIntersectingIncrementalChange(child);
unsetNodeChildren(child);
unsetNodeChildren(child, sourceFile);

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

Expand Down
13 changes: 8 additions & 5 deletions src/compiler/performanceCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@ function tryGetPerformance() {
if (isNodeLikeSystem()) {
try {
// By default, only write native events when generating a cpu profile or using the v8 profiler.
const { performance } = require("perf_hooks") as typeof import("perf_hooks");
return {
shouldWriteNativeEvents: false,
performance,
};
// Some environments may polyfill this module with an empty object; verify the object has the expected shape.
const { performance } = require("perf_hooks") as Partial<typeof import("perf_hooks")>;
if (performance) {
return {
shouldWriteNativeEvents: false,
performance,
};
}
}
catch {
// ignore errors
Expand Down
10 changes: 9 additions & 1 deletion src/compiler/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ export interface Scanner {
resetTokenState(pos: number): void;
/** @internal */
setSkipJsDocLeadingAsterisks(skip: boolean): void;
/** @internal */
hasLeadingAsterisks(): boolean;
// Invokes the provided callback then unconditionally restores the scanner to the state it
// was in immediately prior to invoking the callback. The result of invoking the callback
// is returned from this function.
Expand Down Expand Up @@ -1042,6 +1044,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean

var commentDirectives: CommentDirective[] | undefined;
var skipJsDocLeadingAsterisks = 0;
var asteriskSeen = false;

var scriptKind = ScriptKind.Unknown;
var jsDocParsingMode = JSDocParsingMode.ParseAll;
Expand Down Expand Up @@ -1096,6 +1099,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
resetTokenState,
setTextPos: resetTokenState,
setSkipJsDocLeadingAsterisks,
hasLeadingAsterisks,
tryScan,
lookAhead,
scanRange,
Expand Down Expand Up @@ -1877,7 +1881,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
function scan(): SyntaxKind {
fullStartPos = pos;
tokenFlags = TokenFlags.None;
let asteriskSeen = false;
asteriskSeen = false;
while (true) {
tokenStart = pos;
if (pos >= end) {
Expand Down Expand Up @@ -4004,6 +4008,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
function setSkipJsDocLeadingAsterisks(skip: boolean) {
skipJsDocLeadingAsterisks += skip ? 1 : -1;
}

function hasLeadingAsterisks() {
return asteriskSeen;
}
}

function codePointAt(s: string, i: number): number {
Expand Down
Loading

0 comments on commit 9eec534

Please sign in to comment.