Skip to content

Commit fa22d3a

Browse files
committed
Merge branch 'main' into fix-52345-3
2 parents fbc0ccc + 01de788 commit fa22d3a

File tree

91 files changed

+2248
-366
lines changed

Some content is hidden

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

91 files changed

+2248
-366
lines changed

package-lock.json

Lines changed: 282 additions & 282 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/compiler/checker.ts

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13573,7 +13573,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1357313573
}
1357413574

1357513575
function getConstraintFromIndexedAccess(type: IndexedAccessType) {
13576-
if (isMappedTypeGenericIndexedAccess(type)) {
13576+
if (isMappedTypeGenericIndexedAccess(type) || isGenericMappedType(type.objectType)) {
1357713577
// For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic,
1357813578
// we substitute an instantiation of E where P is replaced with X.
1357913579
return substituteIndexedMappedType(type.objectType as MappedType, type.indexType);
@@ -16276,6 +16276,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1627616276
i--;
1627716277
const source = types[i];
1627816278
if (hasEmptyObject || source.flags & TypeFlags.StructuredOrInstantiable) {
16279+
// A type parameter with a union constraint may be a subtype of some union, but not a subtype of the
16280+
// individual constituents of that union. For example, `T extends A | B` is a subtype of `A | B`, but not
16281+
// a subtype of just `A` or just `B`. When we encounter such a type parameter, we therefore check if the
16282+
// type parameter is a subtype of a union of all the other types.
16283+
if (source.flags & TypeFlags.TypeParameter && getBaseConstraintOrType(source).flags & TypeFlags.Union) {
16284+
if (isTypeRelatedTo(source, getUnionType(map(types, t => t === source ? neverType : t)), strictSubtypeRelation)) {
16285+
orderedRemoveItemAt(types, i);
16286+
}
16287+
continue;
16288+
}
1627916289
// Find the first property with a unit type, if any. When constituents have a property by the same name
1628016290
// but of a different unit type, we can quickly disqualify them from subtype checks. This helps subtype
1628116291
// reduction of large discriminated union types.
@@ -18177,7 +18187,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1817718187
const declarations = concatenate(leftProp.declarations, rightProp.declarations);
1817818188
const flags = SymbolFlags.Property | (leftProp.flags & SymbolFlags.Optional);
1817918189
const result = createSymbol(flags, leftProp.escapedName);
18180-
result.links.type = getUnionType([getTypeOfSymbol(leftProp), removeMissingOrUndefinedType(rightType)], UnionReduction.Subtype);
18190+
// Optimization: avoid calculating the union type if spreading into the exact same type.
18191+
// This is common, e.g. spreading one options bag into another where the bags have the
18192+
// same type, or have properties which overlap. If the unions are large, it may turn out
18193+
// to be expensive to perform subtype reduction.
18194+
const leftType = getTypeOfSymbol(leftProp);
18195+
const leftTypeWithoutUndefined = removeMissingOrUndefinedType(leftType);
18196+
const rightTypeWithoutUndefined = removeMissingOrUndefinedType(rightType);
18197+
result.links.type = leftTypeWithoutUndefined === rightTypeWithoutUndefined ? leftType : getUnionType([leftType, rightTypeWithoutUndefined], UnionReduction.Subtype);
1818118198
result.links.leftSpread = leftProp;
1818218199
result.links.rightSpread = rightProp;
1818318200
result.declarations = declarations;
@@ -19813,6 +19830,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1981319830
const sourceHasMoreParameters = !hasEffectiveRestParameter(target) &&
1981419831
(checkMode & SignatureCheckMode.StrictArity ? hasEffectiveRestParameter(source) || getParameterCount(source) > targetCount : getMinArgumentCount(source) > targetCount);
1981519832
if (sourceHasMoreParameters) {
19833+
if (reportErrors && !(checkMode & SignatureCheckMode.StrictArity)) {
19834+
// the second condition should be redundant, because there is no error reporting when comparing signatures by strict arity
19835+
// since it is only done for subtype reduction
19836+
errorReporter!(Diagnostics.Target_signature_provides_too_few_arguments_Expected_0_or_more_but_got_1, getMinArgumentCount(source), targetCount);
19837+
}
1981619838
return Ternary.False;
1981719839
}
1981819840

@@ -21569,6 +21591,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2156921591
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, RecursionFlags.Source, reportErrors && constraint !== unknownType && !(targetFlags & sourceFlags & TypeFlags.TypeParameter), /*headMessage*/ undefined, intersectionState)) {
2157021592
return result;
2157121593
}
21594+
if (sourceFlags & TypeFlags.IndexedAccess) {
21595+
const indexType = (source as IndexedAccessType).indexType;
21596+
if (indexType.flags & TypeFlags.Index) {
21597+
const unresolvedIndexConstraint = getBaseConstraintOfType((indexType as IndexType).type);
21598+
const indexConstraint = unresolvedIndexConstraint && unresolvedIndexConstraint !== noConstraintType ? getIndexType(unresolvedIndexConstraint) : keyofConstraintType;
21599+
const constraint = getIndexedAccessType((source as IndexedAccessType).objectType, indexConstraint);
21600+
if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) {
21601+
return result;
21602+
}
21603+
}
21604+
}
2157221605
if (isMappedTypeGenericIndexedAccess(source)) {
2157321606
// For an indexed access type { [P in K]: E}[X], above we have already explored an instantiation of E with X
2157421607
// substituted for P. We also want to explore type { [P in K]: E }[C], where C is the constraint of X.
@@ -22897,7 +22930,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2289722930
return type.symbol;
2289822931
}
2289922932
if (isTupleType(type)) {
22900-
return type;
22933+
return type.target;
2290122934
}
2290222935
}
2290322936
if (type.flags & TypeFlags.TypeParameter) {
@@ -24259,8 +24292,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2425924292
let inferencePriority: number = InferencePriority.MaxValue;
2426024293
let allowComplexConstraintInference = true;
2426124294
let visited: Map<string, number>;
24262-
let sourceStack: object[];
24263-
let targetStack: object[];
24295+
let sourceStack: Type[];
24296+
let targetStack: Type[];
2426424297
let expandingFlags = ExpandingFlags.None;
2426524298
inferFromTypes(originalSource, originalTarget);
2426624299

@@ -24516,20 +24549,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2451624549
// We stop inferring and report a circularity if we encounter duplicate recursion identities on both
2451724550
// the source side and the target side.
2451824551
const saveExpandingFlags = expandingFlags;
24519-
const sourceIdentity = getRecursionIdentity(source);
24520-
const targetIdentity = getRecursionIdentity(target);
24521-
if (contains(sourceStack, sourceIdentity)) expandingFlags |= ExpandingFlags.Source;
24522-
if (contains(targetStack, targetIdentity)) expandingFlags |= ExpandingFlags.Target;
24552+
(sourceStack ??= []).push(source);
24553+
(targetStack ??= []).push(target);
24554+
if (isDeeplyNestedType(source, sourceStack, sourceStack.length, 2)) expandingFlags |= ExpandingFlags.Source;
24555+
if (isDeeplyNestedType(target, targetStack, targetStack.length, 2)) expandingFlags |= ExpandingFlags.Target;
2452324556
if (expandingFlags !== ExpandingFlags.Both) {
24524-
(sourceStack || (sourceStack = [])).push(sourceIdentity);
24525-
(targetStack || (targetStack = [])).push(targetIdentity);
2452624557
action(source, target);
24527-
targetStack.pop();
24528-
sourceStack.pop();
2452924558
}
2453024559
else {
2453124560
inferencePriority = InferencePriority.Circularity;
2453224561
}
24562+
targetStack.pop();
24563+
sourceStack.pop();
2453324564
expandingFlags = saveExpandingFlags;
2453424565
visited.set(key, inferencePriority);
2453524566
inferencePriority = Math.min(inferencePriority, saveInferencePriority);

src/compiler/commandLineParser.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ import {
4141
filterMutate,
4242
find,
4343
findIndex,
44-
firstDefined,
4544
firstOrUndefinedIterator,
4645
flatten,
4746
forEach,
4847
forEachEntry,
48+
forEachTsConfigPropArray,
4949
getBaseFileName,
5050
getDirectoryPath,
5151
getFileMatcherPatterns,
@@ -59,7 +59,6 @@ import {
5959
getSupportedExtensions,
6060
getSupportedExtensionsWithJsonIfResolveJsonModule,
6161
getTextOfPropertyName,
62-
getTsConfigPropArray,
6362
getTsConfigPropArrayElementValue,
6463
hasExtension,
6564
hasProperty,
@@ -2886,7 +2885,7 @@ function parseJsonConfigFileContentWorker(
28862885
if (sourceFile) {
28872886
const fileName = configFileName || "tsconfig.json";
28882887
const diagnosticMessage = Diagnostics.The_files_list_in_config_file_0_is_empty;
2889-
const nodeValue = firstDefined(getTsConfigPropArray(sourceFile, "files"), property => property.initializer);
2888+
const nodeValue = forEachTsConfigPropArray(sourceFile, "files", property => property.initializer);
28902889
const error = createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, nodeValue, diagnosticMessage, fileName);
28912890
errors.push(error);
28922891
}

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3619,6 +3619,10 @@
36193619
"category": "Error",
36203620
"code": 2848
36213621
},
3622+
"Target signature provides too few arguments. Expected {0} or more, but got {1}.": {
3623+
"category": "Error",
3624+
"code": 2849
3625+
},
36223626

36233627
"Import declaration '{0}' is using private name '{1}'.": {
36243628
"category": "Error",

src/compiler/program.ts

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ import {
9393
filter,
9494
find,
9595
findIndex,
96-
firstDefined,
9796
firstDefinedIterator,
9897
flatMap,
9998
flatten,
@@ -104,7 +103,9 @@ import {
104103
forEachEmittedFile,
105104
forEachEntry,
106105
forEachKey,
106+
forEachPropertyAssignment,
107107
forEachResolvedProjectReference as ts_forEachResolvedProjectReference,
108+
forEachTsConfigPropArray,
108109
FunctionLikeDeclaration,
109110
getAllowJSCompilerOption,
110111
getAutomaticTypeDirectiveNames,
@@ -138,7 +139,6 @@ import {
138139
getPathFromPathComponents,
139140
getPositionOfLineAndCharacter,
140141
getPropertyArrayElementValue,
141-
getPropertyAssignment,
142142
getResolvedModule,
143143
getResolveJsonModule,
144144
getRootLength,
@@ -152,7 +152,6 @@ import {
152152
getTransformers,
153153
getTsBuildInfoEmitOutputFilePath,
154154
getTsConfigObjectLiteralExpression,
155-
getTsConfigPropArray,
156155
getTsConfigPropArrayElementValue,
157156
HasChangedAutomaticTypeDirectiveNames,
158157
hasChangesInResolutions,
@@ -263,6 +262,7 @@ import {
263262
ProjectReference,
264263
ProjectReferenceFile,
265264
projectReferenceIsEqualTo,
265+
PropertyAssignment,
266266
PropertyDeclaration,
267267
ReferencedFile,
268268
removeFileExtension,
@@ -4535,7 +4535,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
45354535
);
45364536
if (!referenceInfo) return undefined;
45374537
const { sourceFile, index } = referenceInfo;
4538-
const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile as TsConfigSourceFile, "references"),
4538+
const referencesSyntax = forEachTsConfigPropArray(sourceFile as TsConfigSourceFile, "references",
45394539
property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
45404540
return referencesSyntax && referencesSyntax.elements.length > index ?
45414541
createDiagnosticForNodeInSourceFile(
@@ -4610,52 +4610,47 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
46104610

46114611
function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, ...args: DiagnosticArguments) {
46124612
let needCompilerDiagnostic = true;
4613-
const pathsSyntax = getOptionPathsSyntax();
4614-
for (const pathProp of pathsSyntax) {
4613+
forEachOptionPathsSyntax(pathProp => {
46154614
if (isObjectLiteralExpression(pathProp.initializer)) {
4616-
for (const keyProps of getPropertyAssignment(pathProp.initializer, key)) {
4615+
forEachPropertyAssignment(pathProp.initializer, key, keyProps => {
46174616
const initializer = keyProps.initializer;
46184617
if (isArrayLiteralExpression(initializer) && initializer.elements.length > valueIndex) {
46194618
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, initializer.elements[valueIndex], message, ...args));
46204619
needCompilerDiagnostic = false;
46214620
}
4622-
}
4621+
});
46234622
}
4624-
}
4625-
4623+
});
46264624
if (needCompilerDiagnostic) {
46274625
programDiagnostics.add(createCompilerDiagnostic(message, ...args));
46284626
}
46294627
}
46304628

46314629
function createDiagnosticForOptionPaths(onKey: boolean, key: string, message: DiagnosticMessage, ...args: DiagnosticArguments) {
46324630
let needCompilerDiagnostic = true;
4633-
const pathsSyntax = getOptionPathsSyntax();
4634-
for (const pathProp of pathsSyntax) {
4631+
forEachOptionPathsSyntax(pathProp => {
46354632
if (isObjectLiteralExpression(pathProp.initializer) &&
46364633
createOptionDiagnosticInObjectLiteralSyntax(
46374634
pathProp.initializer, onKey, key, /*key2*/ undefined,
46384635
message, ...args)) {
46394636
needCompilerDiagnostic = false;
46404637
}
4641-
}
4638+
});
46424639
if (needCompilerDiagnostic) {
46434640
programDiagnostics.add(createCompilerDiagnostic(message, ...args));
46444641
}
46454642
}
46464643

4647-
function getOptionsSyntaxByName(name: string) {
4648-
const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
4649-
return compilerOptionsObjectLiteralSyntax && getPropertyAssignment(compilerOptionsObjectLiteralSyntax, name);
4644+
function forEachOptionsSyntaxByName<T>(name: string, callback: (prop: PropertyAssignment) => T | undefined): T | undefined {
4645+
return forEachPropertyAssignment(getCompilerOptionsObjectLiteralSyntax(), name, callback);
46504646
}
46514647

4652-
function getOptionPathsSyntax() {
4653-
return getOptionsSyntaxByName("paths") || emptyArray;
4648+
function forEachOptionPathsSyntax<T>(callback: (prop: PropertyAssignment) => T | undefined) {
4649+
return forEachOptionsSyntaxByName("paths", callback);
46544650
}
46554651

46564652
function getOptionsSyntaxByValue(name: string, value: string) {
4657-
const syntaxByName = getOptionsSyntaxByName(name);
4658-
return syntaxByName && firstDefined(syntaxByName, property => isStringLiteral(property.initializer) && property.initializer.text === value ? property.initializer : undefined);
4653+
return forEachOptionsSyntaxByName(name, property => isStringLiteral(property.initializer) && property.initializer.text === value ? property.initializer : undefined);
46594654
}
46604655

46614656
function getOptionsSyntaxByArrayElementValue(name: string, value: string) {
@@ -4673,7 +4668,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
46734668
}
46744669

46754670
function createDiagnosticForReference(sourceFile: JsonSourceFile | undefined, index: number, message: DiagnosticMessage, ...args: DiagnosticArguments) {
4676-
const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile || options.configFile, "references"),
4671+
const referencesSyntax = forEachTsConfigPropArray(sourceFile || options.configFile, "references",
46774672
property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
46784673
if (referencesSyntax && referencesSyntax.elements.length > index) {
46794674
programDiagnostics.add(createDiagnosticForNodeInSourceFile(sourceFile || options.configFile!, referencesSyntax.elements[index], message, ...args));
@@ -4703,16 +4698,11 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
47034698

47044699
function getCompilerOptionsObjectLiteralSyntax() {
47054700
if (_compilerOptionsObjectLiteralSyntax === undefined) {
4706-
_compilerOptionsObjectLiteralSyntax = false;
4707-
const jsonObjectLiteral = getTsConfigObjectLiteralExpression(options.configFile);
4708-
if (jsonObjectLiteral) {
4709-
for (const prop of getPropertyAssignment(jsonObjectLiteral, "compilerOptions")) {
4710-
if (isObjectLiteralExpression(prop.initializer)) {
4711-
_compilerOptionsObjectLiteralSyntax = prop.initializer;
4712-
break;
4713-
}
4714-
}
4715-
}
4701+
_compilerOptionsObjectLiteralSyntax = forEachPropertyAssignment(
4702+
getTsConfigObjectLiteralExpression(options.configFile),
4703+
"compilerOptions",
4704+
prop => isObjectLiteralExpression(prop.initializer) ? prop.initializer : undefined
4705+
) || false;
47164706
}
47174707
return _compilerOptionsObjectLiteralSyntax || undefined;
47184708
}
@@ -4721,17 +4711,18 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
47214711
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean;
47224712
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): boolean;
47234713
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): boolean {
4724-
const props = getPropertyAssignment(objectLiteral, key1, key2);
4725-
for (const prop of props) {
4714+
let needsCompilerDiagnostic = false;
4715+
forEachPropertyAssignment(objectLiteral, key1, prop => {
47264716
// eslint-disable-next-line local/no-in-operator
47274717
if ("messageText" in message) {
47284718
programDiagnostics.add(createDiagnosticForNodeFromMessageChain(options.configFile!, onKey ? prop.name : prop.initializer, message));
47294719
}
47304720
else {
47314721
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, ...args));
47324722
}
4733-
}
4734-
return !!props.length;
4723+
needsCompilerDiagnostic = true;
4724+
}, key2);
4725+
return needsCompilerDiagnostic;
47354726
}
47364727

47374728
/**

0 commit comments

Comments
 (0)