Skip to content

Commit 23e3b4e

Browse files
committed
Merge branch 'master' into perf-test-refkey
2 parents 11d9a60 + 454b428 commit 23e3b4e

30 files changed

+889
-42
lines changed

src/compiler/checker.ts

+56-13
Original file line numberDiff line numberDiff line change
@@ -9943,13 +9943,13 @@ namespace ts {
99439943
return type.flags & TypeFlags.Union ? getIntersectionType(map((<IntersectionType>type).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) :
99449944
type.flags & TypeFlags.Intersection ? getUnionType(map((<IntersectionType>type).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) :
99459945
maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type, stringsOnly) :
9946-
getObjectFlags(type) & ObjectFlags.Mapped ? filterType(getConstraintTypeFromMappedType(<MappedType>type), t => !(noIndexSignatures && t.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number))) :
9946+
getObjectFlags(type) & ObjectFlags.Mapped ? filterType(getConstraintTypeFromMappedType(<MappedType>type), t => !(noIndexSignatures && t.flags & (TypeFlags.Any | TypeFlags.String))) :
99479947
type === wildcardType ? wildcardType :
99489948
type.flags & TypeFlags.Unknown ? neverType :
99499949
type.flags & (TypeFlags.Any | TypeFlags.Never) ? keyofConstraintType :
99509950
stringsOnly ? !noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromProperties(type, TypeFlags.StringLiteral) :
99519951
!noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? getUnionType([stringType, numberType, getLiteralTypeFromProperties(type, TypeFlags.UniqueESSymbol)]) :
9952-
!noIndexSignatures && getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromProperties(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) :
9952+
getNonEnumNumberIndexInfo(type) ? getUnionType([numberType, getLiteralTypeFromProperties(type, TypeFlags.StringLiteral | TypeFlags.UniqueESSymbol)]) :
99539953
getLiteralTypeFromProperties(type, TypeFlags.StringOrNumberLiteralOrUnique);
99549954
}
99559955

@@ -10067,10 +10067,10 @@ namespace ts {
1006710067
if (objectType.flags & (TypeFlags.Any | TypeFlags.Never)) {
1006810068
return objectType;
1006910069
}
10070-
const indexInfo = isTypeAssignableToKind(indexType, TypeFlags.NumberLike) && getIndexInfoOfType(objectType, IndexKind.Number) ||
10071-
getIndexInfoOfType(objectType, IndexKind.String);
10070+
const stringIndexInfo = getIndexInfoOfType(objectType, IndexKind.String);
10071+
const indexInfo = isTypeAssignableToKind(indexType, TypeFlags.NumberLike) && getIndexInfoOfType(objectType, IndexKind.Number) || stringIndexInfo;
1007210072
if (indexInfo) {
10073-
if (accessFlags & AccessFlags.NoIndexSignatures) {
10073+
if (accessFlags & AccessFlags.NoIndexSignatures && indexInfo === stringIndexInfo) {
1007410074
if (accessExpression) {
1007510075
error(accessExpression, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(originalObjectType));
1007610076
}
@@ -14228,6 +14228,32 @@ namespace ts {
1422814228
return strictNullChecks ? getGlobalNonNullableTypeInstantiation(type) : type;
1422914229
}
1423014230

14231+
14232+
/**
14233+
* Is source potentially coercible to target type under `==`.
14234+
* Assumes that `source` is a constituent of a union, hence
14235+
* the boolean literal flag on the LHS, but not on the RHS.
14236+
*
14237+
* This does not fully replicate the semantics of `==`. The
14238+
* intention is to catch cases that are clearly not right.
14239+
*
14240+
* Comparing (string | number) to number should not remove the
14241+
* string element.
14242+
*
14243+
* Comparing (string | number) to 1 will remove the string
14244+
* element, though this is not sound. This is a pragmatic
14245+
* choice.
14246+
*
14247+
* @see narrowTypeByEquality
14248+
*
14249+
* @param source
14250+
* @param target
14251+
*/
14252+
function isCoercibleUnderDoubleEquals(source: Type, target: Type): boolean {
14253+
return ((source.flags & (TypeFlags.Number | TypeFlags.String | TypeFlags.BooleanLiteral)) !== 0)
14254+
&& ((target.flags & (TypeFlags.Number | TypeFlags.String | TypeFlags.Boolean)) !== 0);
14255+
}
14256+
1423114257
/**
1423214258
* Return true if type was inferred from an object literal, written as an object type literal, or is the shape of a module
1423314259
* with no call or construct signatures.
@@ -16598,7 +16624,10 @@ namespace ts {
1659816624
return type;
1659916625
}
1660016626
if (assumeTrue) {
16601-
const narrowedType = filterType(type, t => areTypesComparable(t, valueType));
16627+
const filterFn: (t: Type) => boolean = operator === SyntaxKind.EqualsEqualsToken ?
16628+
(t => areTypesComparable(t, valueType) || isCoercibleUnderDoubleEquals(t, valueType)) :
16629+
t => areTypesComparable(t, valueType);
16630+
const narrowedType = filterType(type, filterFn);
1660216631
return narrowedType.flags & TypeFlags.Never ? type : replacePrimitivesWithLiterals(narrowedType, valueType);
1660316632
}
1660416633
if (isUnitType(valueType)) {
@@ -26461,14 +26490,28 @@ namespace ts {
2646126490
}
2646226491
// For a binding pattern, validate the initializer and exit
2646326492
if (isBindingPattern(node.name)) {
26464-
// Don't validate for-in initializer as it is already an error
26465-
if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
26466-
const initializerType = checkExpressionCached(node.initializer);
26467-
if (strictNullChecks && node.name.elements.length === 0) {
26468-
checkNonNullNonVoidType(initializerType, node);
26493+
const needCheckInitializer = node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement;
26494+
const needCheckWidenedType = node.name.elements.length === 0;
26495+
if (needCheckInitializer || needCheckWidenedType) {
26496+
// Don't validate for-in initializer as it is already an error
26497+
const widenedType = getWidenedTypeForVariableLikeDeclaration(node);
26498+
if (needCheckInitializer) {
26499+
const initializerType = checkExpressionCached(node.initializer!);
26500+
if (strictNullChecks && needCheckWidenedType) {
26501+
checkNonNullNonVoidType(initializerType, node);
26502+
}
26503+
else {
26504+
checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer);
26505+
}
2646926506
}
26470-
else {
26471-
checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer);
26507+
// check the binding pattern with empty elements
26508+
if (needCheckWidenedType) {
26509+
if (isArrayBindingPattern(node.name)) {
26510+
checkIteratedTypeOrElementType(widenedType, node, /* allowStringInput */ false, /* allowAsyncIterables */ false);
26511+
}
26512+
else if (strictNullChecks) {
26513+
checkNonNullNonVoidType(widenedType, node);
26514+
}
2647226515
}
2647326516
}
2647426517
return;

src/compiler/moduleNameResolver.ts

+24-8
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ namespace ts {
421421
*/
422422
export interface ModuleResolutionCache extends NonRelativeModuleNameResolutionCache {
423423
getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference): Map<ResolvedModuleWithFailedLookupLocations>;
424+
/*@internal*/ directoryToModuleNameMap: CacheWithRedirects<Map<ResolvedModuleWithFailedLookupLocations>>;
424425
}
425426

426427
/**
@@ -429,49 +430,64 @@ namespace ts {
429430
*/
430431
export interface NonRelativeModuleNameResolutionCache {
431432
getOrCreateCacheForModuleName(nonRelativeModuleName: string, redirectedReference?: ResolvedProjectReference): PerModuleNameCache;
433+
/*@internal*/ moduleNameToDirectoryMap: CacheWithRedirects<PerModuleNameCache>;
432434
}
433435

434436
export interface PerModuleNameCache {
435437
get(directory: string): ResolvedModuleWithFailedLookupLocations | undefined;
436438
set(directory: string, result: ResolvedModuleWithFailedLookupLocations): void;
437439
}
438440

439-
export function createModuleResolutionCache(currentDirectory: string, getCanonicalFileName: (s: string) => string): ModuleResolutionCache {
441+
export function createModuleResolutionCache(currentDirectory: string, getCanonicalFileName: (s: string) => string, options?: CompilerOptions): ModuleResolutionCache {
440442
return createModuleResolutionCacheWithMaps(
441-
createCacheWithRedirects(),
442-
createCacheWithRedirects(),
443+
createCacheWithRedirects(options),
444+
createCacheWithRedirects(options),
443445
currentDirectory,
444446
getCanonicalFileName
445447
);
446448
}
447449

450+
448451
/*@internal*/
449452
export interface CacheWithRedirects<T> {
450453
ownMap: Map<T>;
451454
redirectsMap: Map<Map<T>>;
452455
getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map<T>;
453456
clear(): void;
457+
setOwnOptions(newOptions: CompilerOptions): void;
458+
setOwnMap(newOwnMap: Map<T>): void;
454459
}
455460

456461
/*@internal*/
457-
export function createCacheWithRedirects<T>(): CacheWithRedirects<T> {
458-
const ownMap: Map<T> = createMap();
462+
export function createCacheWithRedirects<T>(options?: CompilerOptions): CacheWithRedirects<T> {
463+
let ownMap: Map<T> = createMap();
459464
const redirectsMap: Map<Map<T>> = createMap();
460465
return {
461466
ownMap,
462467
redirectsMap,
463468
getOrCreateMapOfCacheRedirects,
464-
clear
469+
clear,
470+
setOwnOptions,
471+
setOwnMap
465472
};
466473

474+
function setOwnOptions(newOptions: CompilerOptions) {
475+
options = newOptions;
476+
}
477+
478+
function setOwnMap(newOwnMap: Map<T>) {
479+
ownMap = newOwnMap;
480+
}
481+
467482
function getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined) {
468483
if (!redirectedReference) {
469484
return ownMap;
470485
}
471486
const path = redirectedReference.sourceFile.path;
472487
let redirects = redirectsMap.get(path);
473488
if (!redirects) {
474-
redirects = createMap();
489+
// Reuse map if redirected reference map uses same resolution
490+
redirects = !options || optionsHaveModuleResolutionChanges(options, redirectedReference.commandLine.options) ? createMap() : ownMap;
475491
redirectsMap.set(path, redirects);
476492
}
477493
return redirects;
@@ -490,7 +506,7 @@ namespace ts {
490506
currentDirectory: string,
491507
getCanonicalFileName: GetCanonicalFileName): ModuleResolutionCache {
492508

493-
return { getOrCreateCacheForDirectory, getOrCreateCacheForModuleName };
509+
return { getOrCreateCacheForDirectory, getOrCreateCacheForModuleName, directoryToModuleNameMap, moduleNameToDirectoryMap };
494510

495511
function getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference) {
496512
const path = toPath(directoryName, currentDirectory, getCanonicalFileName);

src/compiler/program.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,8 @@ namespace ts {
528528
}
529529
}
530530

531-
function loadWithLocalCache<T>(names: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, loader: (name: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => T): T[] {
531+
/* @internal */
532+
export function loadWithLocalCache<T>(names: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, loader: (name: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => T): T[] {
532533
if (names.length === 0) {
533534
return [];
534535
}
@@ -773,7 +774,7 @@ namespace ts {
773774
});
774775
}
775776
else {
776-
moduleResolutionCache = createModuleResolutionCache(currentDirectory, x => host.getCanonicalFileName(x));
777+
moduleResolutionCache = createModuleResolutionCache(currentDirectory, x => host.getCanonicalFileName(x), options);
777778
const loader = (moduleName: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => resolveModuleName(moduleName, containingFile, options, host, moduleResolutionCache, redirectedReference).resolvedModule!; // TODO: GH#18217
778779
resolveModuleNamesWorker = (moduleNames, containingFile, _reusedNames, redirectedReference) => loadWithLocalCache<ResolvedModuleFull>(Debug.assertEachDefined(moduleNames), containingFile, redirectedReference, loader);
779780
}

src/compiler/tsbuild.ts

+37
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,10 @@ namespace ts {
400400
const compilerHost = createCompilerHostFromProgramHost(host, () => projectCompilerOptions);
401401
setGetSourceFileAsHashVersioned(compilerHost, host);
402402

403+
compilerHost.resolveModuleNames = maybeBind(host, host.resolveModuleNames);
404+
compilerHost.resolveTypeReferenceDirectives = maybeBind(host, host.resolveTypeReferenceDirectives);
405+
let moduleResolutionCache = !compilerHost.resolveModuleNames ? createModuleResolutionCache(currentDirectory, getCanonicalFileName) : undefined;
406+
403407
const buildInfoChecked = createFileMap<true>(toPath);
404408

405409
// Watch state
@@ -1097,6 +1101,30 @@ namespace ts {
10971101

10981102
// TODO: handle resolve module name to cache result in project reference redirect
10991103
projectCompilerOptions = configFile.options;
1104+
// Update module resolution cache if needed
1105+
if (moduleResolutionCache) {
1106+
const projPath = toPath(proj);
1107+
if (moduleResolutionCache.directoryToModuleNameMap.redirectsMap.size === 0) {
1108+
// The own map will be for projectCompilerOptions
1109+
Debug.assert(moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.size === 0);
1110+
moduleResolutionCache.directoryToModuleNameMap.redirectsMap.set(projPath, moduleResolutionCache.directoryToModuleNameMap.ownMap);
1111+
moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.set(projPath, moduleResolutionCache.moduleNameToDirectoryMap.ownMap);
1112+
}
1113+
else {
1114+
// Set correct own map
1115+
Debug.assert(moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.size > 0);
1116+
1117+
const ref: ResolvedProjectReference = {
1118+
sourceFile: projectCompilerOptions.configFile!,
1119+
commandLine: configFile
1120+
};
1121+
moduleResolutionCache.directoryToModuleNameMap.setOwnMap(moduleResolutionCache.directoryToModuleNameMap.getOrCreateMapOfCacheRedirects(ref));
1122+
moduleResolutionCache.moduleNameToDirectoryMap.setOwnMap(moduleResolutionCache.moduleNameToDirectoryMap.getOrCreateMapOfCacheRedirects(ref));
1123+
}
1124+
moduleResolutionCache.directoryToModuleNameMap.setOwnOptions(projectCompilerOptions);
1125+
moduleResolutionCache.moduleNameToDirectoryMap.setOwnOptions(projectCompilerOptions);
1126+
}
1127+
11001128
const program = host.createProgram(
11011129
configFile.fileNames,
11021130
configFile.options,
@@ -1368,6 +1396,13 @@ namespace ts {
13681396
readFileWithCache = newReadFileWithCache;
13691397
compilerHost.getSourceFile = getSourceFileWithCache!;
13701398

1399+
const originalResolveModuleNames = compilerHost.resolveModuleNames;
1400+
if (!compilerHost.resolveModuleNames) {
1401+
const loader = (moduleName: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => resolveModuleName(moduleName, containingFile, projectCompilerOptions, compilerHost, moduleResolutionCache, redirectedReference).resolvedModule!;
1402+
compilerHost.resolveModuleNames = (moduleNames, containingFile, _reusedNames, redirectedReference) =>
1403+
loadWithLocalCache<ResolvedModuleFull>(Debug.assertEachDefined(moduleNames), containingFile, redirectedReference, loader);
1404+
}
1405+
13711406
const graph = getGlobalDependencyGraph();
13721407
reportBuildQueue(graph);
13731408
let anyFailed = false;
@@ -1428,6 +1463,8 @@ namespace ts {
14281463
host.writeFile = originalWriteFile;
14291464
compilerHost.getSourceFile = savedGetSourceFile;
14301465
readFileWithCache = savedReadFileWithCache;
1466+
compilerHost.resolveModuleNames = originalResolveModuleNames;
1467+
moduleResolutionCache = undefined;
14311468
return anyFailed ? ExitStatus.DiagnosticsPresent_OutputsSkipped : ExitStatus.Success;
14321469
}
14331470

src/compiler/utilities.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,12 @@ namespace ts {
101101
}
102102

103103
export function changesAffectModuleResolution(oldOptions: CompilerOptions, newOptions: CompilerOptions): boolean {
104-
return oldOptions.configFilePath !== newOptions.configFilePath || moduleResolutionOptionDeclarations.some(o =>
104+
return oldOptions.configFilePath !== newOptions.configFilePath ||
105+
optionsHaveModuleResolutionChanges(oldOptions, newOptions);
106+
}
107+
108+
export function optionsHaveModuleResolutionChanges(oldOptions: CompilerOptions, newOptions: CompilerOptions) {
109+
return moduleResolutionOptionDeclarations.some(o =>
105110
!isJsonEqual(getCompilerOptionValue(oldOptions, o), getCompilerOptionValue(newOptions, o)));
106111
}
107112

src/lib/es5.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ declare function encodeURI(uri: string): string;
6060
* Encodes a text string as a valid component of a Uniform Resource Identifier (URI).
6161
* @param uriComponent A value representing an encoded URI component.
6262
*/
63-
declare function encodeURIComponent(uriComponent: string): string;
63+
declare function encodeURIComponent(uriComponent: string | number | boolean): string;
6464

6565
/**
6666
* Computes a new string in which certain characters have been replaced by a hexadecimal escape sequence.

tests/baselines/reference/1.0lib-noErrors.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ declare function encodeURI(uri: string): string;
7878
* Encodes a text string as a valid component of a Uniform Resource Identifier (URI).
7979
* @param uriComponent A value representing an encoded URI component.
8080
*/
81-
declare function encodeURIComponent(uriComponent: string): string;
81+
declare function encodeURIComponent(uriComponent: string | number | boolean): string;
8282

8383
interface PropertyDescriptor {
8484
configurable?: boolean;
@@ -1141,7 +1141,7 @@ declare var Array: {
11411141
<T>(...items: T[]): T[];
11421142
isArray(arg: any): boolean;
11431143
prototype: Array<any>;
1144-
}
1144+
}
11451145

11461146
//// [1.0lib-noErrors.js]
11471147
/* *****************************************************************************

0 commit comments

Comments
 (0)