Skip to content

Commit 5e9b706

Browse files
authored
Merge branch 'main' into fix/enum-computed-keys
2 parents 91424d8 + 7f6a846 commit 5e9b706

File tree

2,189 files changed

+5693
-4385
lines changed

Some content is hidden

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

2,189 files changed

+5693
-4385
lines changed

src/compiler/checker.ts

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15344,6 +15344,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1534415344
undefined;
1534515345
}
1534615346
if (t.flags & TypeFlags.Index) {
15347+
if (isGenericMappedType((t as IndexType).type)) {
15348+
const mappedType = (t as IndexType).type as MappedType;
15349+
if (getNameTypeFromMappedType(mappedType) && !isMappedTypeWithKeyofConstraintDeclaration(mappedType)) {
15350+
return getBaseConstraint(getIndexTypeForMappedType(mappedType, IndexFlags.None));
15351+
}
15352+
}
1534715353
return stringNumberSymbolType;
1534815354
}
1534915355
if (t.flags & TypeFlags.TemplateLiteral) {
@@ -18836,7 +18842,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1883618842
// a circular definition. For this reason, we only eagerly manifest the keys if the constraint is non-generic.
1883718843
if (isGenericIndexType(constraintType)) {
1883818844
if (isMappedTypeWithKeyofConstraintDeclaration(type)) {
18839-
// We have a generic index and a homomorphic mapping (but a distributive key remapping) - we need to defer
18845+
// We have a generic index and a homomorphic mapping and a key remapping - we need to defer
1884018846
// the whole `keyof whatever` for later since it's not safe to resolve the shape of modifier type.
1884118847
return getIndexTypeForGenericType(type, indexFlags);
1884218848
}
@@ -18866,25 +18872,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1886618872
}
1886718873
}
1886818874

18869-
// Ordinarily we reduce a keyof M, where M is a mapped type { [P in K as N<P>]: X }, to simply N<K>. This however presumes
18870-
// that N distributes over union types, i.e. that N<A | B | C> is equivalent to N<A> | N<B> | N<C>. Specifically, we only
18871-
// want to perform the reduction when the name type of a mapped type is distributive with respect to the type variable
18872-
// introduced by the 'in' clause of the mapped type. Note that non-generic types are considered to be distributive because
18873-
// they're the same type regardless of what's being distributed over.
18874-
function hasDistributiveNameType(mappedType: MappedType) {
18875-
const typeVariable = getTypeParameterFromMappedType(mappedType);
18876-
return isDistributive(getNameTypeFromMappedType(mappedType) || typeVariable);
18877-
function isDistributive(type: Type): boolean {
18878-
return type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Primitive | TypeFlags.Never | TypeFlags.TypeParameter | TypeFlags.Object | TypeFlags.NonPrimitive) ? true :
18879-
type.flags & TypeFlags.Conditional ? (type as ConditionalType).root.isDistributive && (type as ConditionalType).checkType === typeVariable :
18880-
type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) ? every((type as UnionOrIntersectionType | TemplateLiteralType).types, isDistributive) :
18881-
type.flags & TypeFlags.IndexedAccess ? isDistributive((type as IndexedAccessType).objectType) && isDistributive((type as IndexedAccessType).indexType) :
18882-
type.flags & TypeFlags.Substitution ? isDistributive((type as SubstitutionType).baseType) && isDistributive((type as SubstitutionType).constraint) :
18883-
type.flags & TypeFlags.StringMapping ? isDistributive((type as StringMappingType).type) :
18884-
false;
18885-
}
18886-
}
18887-
1888818875
function getLiteralTypeFromPropertyName(name: PropertyName | JsxAttributeName) {
1888918876
if (isPrivateIdentifier(name)) {
1889018877
return neverType;
@@ -18936,7 +18923,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1893618923
function shouldDeferIndexType(type: Type, indexFlags = IndexFlags.None) {
1893718924
return !!(type.flags & TypeFlags.InstantiableNonPrimitive ||
1893818925
isGenericTupleType(type) ||
18939-
isGenericMappedType(type) && (!hasDistributiveNameType(type) || getMappedTypeNameTypeKind(type) === MappedTypeNameTypeKind.Remapping) ||
18926+
isGenericMappedType(type) && getNameTypeFromMappedType(type) ||
1894018927
type.flags & TypeFlags.Union && !(indexFlags & IndexFlags.NoReducibleCheck) && isGenericReducibleType(type) ||
1894118928
type.flags & TypeFlags.Intersection && maybeTypeOfKind(type, TypeFlags.Instantiable) && some((type as IntersectionType).types, isEmptyAnonymousObjectType));
1894218929
}
@@ -19457,6 +19444,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1945719444
function getSimplifiedType(type: Type, writing: boolean): Type {
1945819445
return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing) :
1945919446
type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type as ConditionalType, writing) :
19447+
type.flags & TypeFlags.Index ? getSimplifiedIndexType(type as IndexType) :
1946019448
type;
1946119449
}
1946219450

@@ -19556,6 +19544,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1955619544
return type;
1955719545
}
1955819546

19547+
function getSimplifiedIndexType(type: IndexType) {
19548+
if (isGenericMappedType(type.type) && getNameTypeFromMappedType(type.type) && !isMappedTypeWithKeyofConstraintDeclaration(type.type)) {
19549+
return getIndexTypeForMappedType(type.type, IndexFlags.None);
19550+
}
19551+
return type;
19552+
}
19553+
1955919554
/**
1956019555
* Invokes union simplification logic to determine if an intersection is considered empty as a union constituent
1956119556
*/
@@ -42851,12 +42846,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4285142846
// Check if the index type is assignable to 'keyof T' for the object type.
4285242847
const objectType = (type as IndexedAccessType).objectType;
4285342848
const indexType = (type as IndexedAccessType).indexType;
42854-
// skip index type deferral on remapping mapped types
42855-
const objectIndexType = isGenericMappedType(objectType) && getMappedTypeNameTypeKind(objectType) === MappedTypeNameTypeKind.Remapping
42856-
? getIndexTypeForMappedType(objectType, IndexFlags.None)
42857-
: getIndexType(objectType, IndexFlags.None);
4285842849
const hasNumberIndexInfo = !!getIndexInfoOfType(objectType, numberType);
42859-
if (everyType(indexType, t => isTypeAssignableTo(t, objectIndexType) || hasNumberIndexInfo && isApplicableIndexType(t, numberType))) {
42850+
if (everyType(indexType, t => isTypeAssignableTo(t, getIndexType(objectType, IndexFlags.None)) || hasNumberIndexInfo && isApplicableIndexType(t, numberType))) {
4286042851
if (
4286142852
accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) &&
4286242853
getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.IncludeReadonly

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4480,6 +4480,10 @@
44804480
"category": "Error",
44814481
"code": 5010
44824482
},
4483+
"The common source directory of '{0}' is '{1}'. The 'rootDir' setting must be explicitly set to this or another path to adjust your output's file layout.": {
4484+
"category": "Error",
4485+
"code": 5011
4486+
},
44834487
"Cannot read file '{0}': {1}.": {
44844488
"category": "Error",
44854489
"code": 5012

src/compiler/emitter.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ export function getCommonSourceDirectory(
646646
commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, currentDirectory);
647647
checkSourceFilesBelongToPath?.(options.rootDir);
648648
}
649-
else if (options.composite && options.configFilePath) {
649+
else if (options.configFilePath) {
650650
// Project compilations never infer their root from the input source paths
651651
commonSourceDirectory = getDirectoryPath(normalizeSlashes(options.configFilePath));
652652
checkSourceFilesBelongToPath?.(commonSourceDirectory);
@@ -664,6 +664,23 @@ export function getCommonSourceDirectory(
664664
return commonSourceDirectory;
665665
}
666666

667+
/** @internal */
668+
export function getComputedCommonSourceDirectory(
669+
emittedFiles: readonly string[],
670+
currentDirectory: string,
671+
getCanonicalFileName: GetCanonicalFileName,
672+
): string {
673+
let commonSourceDirectory = computeCommonSourceDirectoryOfFilenames(emittedFiles, currentDirectory, getCanonicalFileName);
674+
675+
if (commonSourceDirectory && commonSourceDirectory[commonSourceDirectory.length - 1] !== directorySeparator) {
676+
// Make sure directory path ends with directory separator so this string can directly
677+
// used to replace with "" to get the relative path of the source file and the relative path doesn't
678+
// start with / making it rooted path
679+
commonSourceDirectory += directorySeparator;
680+
}
681+
return commonSourceDirectory;
682+
}
683+
667684
/** @internal */
668685
export function getCommonSourceDirectoryOfConfig({ options, fileNames }: ParsedCommandLine, ignoreCase: boolean): string {
669686
return getCommonSourceDirectory(

src/compiler/moduleNameResolver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2889,7 +2889,7 @@ function getLoadModuleFromTargetExportOrImport(extensions: Extensions, state: Mo
28892889
const commonSourceDirGuesses: string[] = [];
28902890
// A `rootDir` compiler option strongly indicates the root location
28912891
// A `composite` project is using project references and has it's common src dir set to `.`, so it shouldn't need to check any other locations
2892-
if (state.compilerOptions.rootDir || (state.compilerOptions.composite && state.compilerOptions.configFilePath)) {
2892+
if (state.compilerOptions.rootDir || state.compilerOptions.configFilePath) {
28932893
const commonDir = toAbsolutePath(getCommonSourceDirectory(state.compilerOptions, () => [], state.host.getCurrentDirectory?.() || "", getCanonicalFileName));
28942894
commonSourceDirGuesses.push(commonDir);
28952895
}

src/compiler/program.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ import {
109109
GetCanonicalFileName,
110110
getCommonSourceDirectory as ts_getCommonSourceDirectory,
111111
getCommonSourceDirectoryOfConfig,
112+
getComputedCommonSourceDirectory,
112113
getDeclarationDiagnostics as ts_getDeclarationDiagnostics,
113114
getDefaultLibFileName,
114115
getDirectoryPath,
@@ -132,6 +133,7 @@ import {
132133
getPackageScopeForPath,
133134
getPathFromPathComponents,
134135
getPositionOfLineAndCharacter,
136+
getRelativePathFromFile,
135137
getResolvedModuleFromResolution,
136138
getResolvedTypeReferenceDirectiveFromResolution,
137139
getResolveJsonModule,
@@ -4254,6 +4256,35 @@ export function createProgram(_rootNamesOrOptions: readonly string[] | CreatePro
42544256
}
42554257
}
42564258

4259+
if (
4260+
!options.noEmit &&
4261+
!options.composite &&
4262+
!options.rootDir &&
4263+
options.configFilePath &&
4264+
(options.outDir || // there is --outDir specified
4265+
(getEmitDeclarations(options) && options.declarationDir) || // there is --declarationDir specified
4266+
options.outFile)
4267+
) {
4268+
// Check if rootDir inferred changed and issue diagnostic
4269+
const dir = getCommonSourceDirectory();
4270+
const emittedFiles = mapDefined(files, file => !file.isDeclarationFile && sourceFileMayBeEmitted(file, program) ? file.fileName : undefined);
4271+
const dir59 = getComputedCommonSourceDirectory(emittedFiles, currentDirectory, getCanonicalFileName);
4272+
if (dir59 !== "" && getCanonicalFileName(dir) !== getCanonicalFileName(dir59)) {
4273+
// change in layout
4274+
createDiagnosticForOption(
4275+
/*onKey*/ true,
4276+
options.outFile ? "outFile" : options.outDir ? "outDir" : "declarationDir",
4277+
!options.outFile && options.outDir ? "declarationDir" : undefined,
4278+
chainDiagnosticMessages(
4279+
chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Visit_https_Colon_Slash_Slashaka_ms_Slashts6_for_migration_information),
4280+
Diagnostics.The_common_source_directory_of_0_is_1_The_rootDir_setting_must_be_explicitly_set_to_this_or_another_path_to_adjust_your_output_s_file_layout,
4281+
getBaseFileName(options.configFilePath),
4282+
getRelativePathFromFile(options.configFilePath, dir59, getCanonicalFileName),
4283+
),
4284+
);
4285+
}
4286+
}
4287+
42574288
if (options.checkJs && !getAllowJSCompilerOption(options)) {
42584289
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "checkJs", "allowJs");
42594290
}

src/compiler/resolutionCache.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,9 @@ export interface ResolutionCacheHost extends MinimalResolutionCacheHost {
199199
fileIsOpen(filePath: Path): boolean;
200200
onDiscoveredSymlink?(): void;
201201

202+
skipWatchingFailedLookups?(path: Path): boolean | undefined;
203+
skipWatchingTypeRoots?(): boolean | undefined;
204+
202205
// For incremental testing
203206
beforeResolveSingleModuleNameWithoutWatching?(
204207
moduleResolutionCache: ModuleResolutionCache,
@@ -895,7 +898,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
895898
resolutionHost.onDiscoveredSymlink();
896899
}
897900
resolutionsInFile.set(name, mode, resolution);
898-
if (resolution !== existingResolution) {
901+
if (resolution !== existingResolution && !resolutionHost.skipWatchingFailedLookups?.(path)) {
899902
watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution, path, getResolutionWithResolvedFileName, deferWatchingNonRelativeResolution);
900903
if (existingResolution) {
901904
stopWatchFailedLookupLocationOfResolution(existingResolution, path, getResolutionWithResolvedFileName);
@@ -947,7 +950,9 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
947950
// Stop watching and remove the unused name
948951
resolutionsInFile.forEach((resolution, name, mode) => {
949952
if (!seenNamesInFile.has(name, mode)) {
950-
stopWatchFailedLookupLocationOfResolution(resolution, path, getResolutionWithResolvedFileName);
953+
if (!resolutionHost.skipWatchingFailedLookups?.(path)) {
954+
stopWatchFailedLookupLocationOfResolution(resolution, path, getResolutionWithResolvedFileName);
955+
}
951956
resolutionsInFile.delete(name, mode);
952957
}
953958
});
@@ -1434,13 +1439,15 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
14341439
// Deleted file, stop watching failed lookups for all the resolutions in the file
14351440
const resolutions = cache.get(filePath);
14361441
if (resolutions) {
1437-
resolutions.forEach(resolution =>
1438-
stopWatchFailedLookupLocationOfResolution(
1439-
resolution,
1440-
filePath,
1441-
getResolutionWithResolvedFileName,
1442-
)
1443-
);
1442+
if (!resolutionHost.skipWatchingFailedLookups?.(filePath)) {
1443+
resolutions.forEach(resolution =>
1444+
stopWatchFailedLookupLocationOfResolution(
1445+
resolution,
1446+
filePath,
1447+
getResolutionWithResolvedFileName,
1448+
)
1449+
);
1450+
}
14441451
cache.delete(filePath);
14451452
}
14461453
}
@@ -1667,6 +1674,12 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
16671674
return;
16681675
}
16691676

1677+
// if this is inferred project with non watchable root or current directory that is lib location, skip watching type roots
1678+
if (!isRootWatchable || resolutionHost.skipWatchingTypeRoots?.()) {
1679+
closeTypeRootsWatch();
1680+
return;
1681+
}
1682+
16701683
// we need to assume the directories exist to ensure that we can get all the type root directories that get included
16711684
// But filter directories that are at root level to say directory doesnt exist, so that we arent watching them
16721685
const typeRoots = getEffectiveTypeRoots(options, { getCurrentDirectory });

src/compiler/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6394,7 +6394,7 @@ export const enum TypeFlags {
63946394
/** @internal */
63956395
ObjectFlagsType = Any | Nullable | Never | Object | Union | Intersection,
63966396
/** @internal */
6397-
Simplifiable = IndexedAccess | Conditional,
6397+
Simplifiable = IndexedAccess | Conditional | Index,
63986398
/** @internal */
63996399
Singleton = Any | Unknown | String | Number | Boolean | BigInt | ESSymbol | Void | Undefined | Null | Never | NonPrimitive,
64006400
// 'Narrowable' types are types where narrowing actually narrows.

src/compiler/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6640,7 +6640,7 @@ export function sourceFileMayBeEmitted(sourceFile: SourceFile, host: SourceFileM
66406640
// Json file is not emitted if outDir is not specified
66416641
if (!options.outDir) return false;
66426642
// Otherwise if rootDir or composite config file, we know common sourceDir and can check if file would be emitted in same location
6643-
if (options.rootDir || (options.composite && options.configFilePath)) {
6643+
if (options.rootDir || options.configFilePath) {
66446644
const commonDir = getNormalizedAbsolutePath(getCommonSourceDirectory(options, () => [], host.getCurrentDirectory(), host.getCanonicalFileName), host.getCurrentDirectory());
66456645
const outputPath = getSourceFilePathInNewDirWorker(sourceFile.fileName, options.outDir, host.getCurrentDirectory(), commonDir, host.getCanonicalFileName);
66466646
if (comparePaths(sourceFile.fileName, outputPath, host.getCurrentDirectory(), !host.useCaseSensitiveFileNames()) === Comparison.EqualTo) return false;

0 commit comments

Comments
 (0)