Skip to content

Commit a26d310

Browse files
committed
Merge remote-tracking branch 'origin/master' into import_completions_pr
2 parents 8728b98 + 4a643e5 commit a26d310

File tree

119 files changed

+7090
-1574
lines changed

Some content is hidden

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

119 files changed

+7090
-1574
lines changed

Jakefile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ var servicesSources = [
102102
"services.ts",
103103
"shims.ts",
104104
"signatureHelp.ts",
105+
"types.ts",
105106
"utilities.ts",
106107
"formatting/formatting.ts",
107108
"formatting/formattingContext.ts",

src/compiler/checker.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ namespace ts {
146146

147147
const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
148148
const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
149+
const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
149150

150151
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
151152

@@ -5381,7 +5382,7 @@ namespace ts {
53815382
while (i > 0) {
53825383
i--;
53835384
if (isSubtypeOfAny(types[i], types)) {
5384-
types.splice(i, 1);
5385+
orderedRemoveItemAt(types, i);
53855386
}
53865387
}
53875388
}
@@ -8761,7 +8762,7 @@ namespace ts {
87618762
// The location isn't a reference to the given symbol, meaning we're being asked
87628763
// a hypothetical question of what type the symbol would have if there was a reference
87638764
// to it at the given location. Since we have no control flow information for the
8764-
// hypotherical reference (control flow information is created and attached by the
8765+
// hypothetical reference (control flow information is created and attached by the
87658766
// binder), we simply return the declared type of the symbol.
87668767
return getTypeOfSymbol(symbol);
87678768
}
@@ -12232,10 +12233,10 @@ namespace ts {
1223212233
// or that a different candidatesOutArray was passed in. Therefore, we need to redo the work
1223312234
// to correctly fill the candidatesOutArray.
1223412235
const cached = links.resolvedSignature;
12235-
if (cached && cached !== anySignature && !candidatesOutArray) {
12236+
if (cached && cached !== resolvingSignature && !candidatesOutArray) {
1223612237
return cached;
1223712238
}
12238-
links.resolvedSignature = anySignature;
12239+
links.resolvedSignature = resolvingSignature;
1223912240
const result = resolveSignature(node, candidatesOutArray);
1224012241
// If signature resolution originated in control flow type analysis (for example to compute the
1224112242
// assigned type in a flow assignment) we don't cache the result as it may be based on temporary
@@ -12247,7 +12248,7 @@ namespace ts {
1224712248
function getResolvedOrAnySignature(node: CallLikeExpression) {
1224812249
// If we're already in the process of resolving the given signature, don't resolve again as
1224912250
// that could cause infinite recursion. Instead, return anySignature.
12250-
return getNodeLinks(node).resolvedSignature === anySignature ? anySignature : getResolvedSignature(node);
12251+
return getNodeLinks(node).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(node);
1225112252
}
1225212253

1225312254
function getInferredClassType(symbol: Symbol) {

src/compiler/core.ts

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,36 @@ namespace ts {
566566
return result;
567567
}
568568

569+
/**
570+
* Adds the value to an array of values associated with the key, and returns the array.
571+
* Creates the array if it does not already exist.
572+
*/
573+
export function multiMapAdd<V>(map: Map<V[]>, key: string, value: V): V[] {
574+
const values = map[key];
575+
if (values) {
576+
values.push(value);
577+
return values;
578+
}
579+
else {
580+
return map[key] = [value];
581+
}
582+
}
583+
584+
/**
585+
* Removes a value from an array of values associated with the key.
586+
* Does not preserve the order of those values.
587+
* Does nothing if `key` is not in `map`, or `value` is not in `map[key]`.
588+
*/
589+
export function multiMapRemove<V>(map: Map<V[]>, key: string, value: V): void {
590+
const values = map[key];
591+
if (values) {
592+
unorderedRemoveItem(values, value);
593+
if (!values.length) {
594+
delete map[key];
595+
}
596+
}
597+
}
598+
569599
/**
570600
* Tests whether a value is an array.
571601
*/
@@ -1500,20 +1530,39 @@ namespace ts {
15001530
}
15011531
}
15021532

1503-
export function copyListRemovingItem<T>(item: T, list: T[]) {
1504-
const copiedList: T[] = [];
1505-
for (const e of list) {
1506-
if (e !== item) {
1507-
copiedList.push(e);
1533+
/** Remove an item from an array, moving everything to its right one space left. */
1534+
export function orderedRemoveItemAt<T>(array: T[], index: number): void {
1535+
// This seems to be faster than either `array.splice(i, 1)` or `array.copyWithin(i, i+ 1)`.
1536+
for (let i = index; i < array.length - 1; i++) {
1537+
array[i] = array[i + 1];
1538+
}
1539+
array.pop();
1540+
}
1541+
1542+
export function unorderedRemoveItemAt<T>(array: T[], index: number): void {
1543+
// Fill in the "hole" left at `index`.
1544+
array[index] = array[array.length - 1];
1545+
array.pop();
1546+
}
1547+
1548+
/** Remove the *first* occurrence of `item` from the array. */
1549+
export function unorderedRemoveItem<T>(array: T[], item: T): void {
1550+
unorderedRemoveFirstItemWhere(array, element => element === item);
1551+
}
1552+
1553+
/** Remove the *first* element satisfying `predicate`. */
1554+
function unorderedRemoveFirstItemWhere<T>(array: T[], predicate: (element: T) => boolean): void {
1555+
for (let i = 0; i < array.length; i++) {
1556+
if (predicate(array[i])) {
1557+
unorderedRemoveItemAt(array, i);
1558+
break;
15081559
}
15091560
}
1510-
return copiedList;
15111561
}
15121562

1513-
export function createGetCanonicalFileName(useCaseSensitivefileNames: boolean): (fileName: string) => string {
1514-
return useCaseSensitivefileNames
1563+
export function createGetCanonicalFileName(useCaseSensitiveFileNames: boolean): (fileName: string) => string {
1564+
return useCaseSensitiveFileNames
15151565
? ((fileName) => fileName)
15161566
: ((fileName) => fileName.toLowerCase());
15171567
}
1518-
15191568
}

src/compiler/emitter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6851,7 +6851,7 @@ const _super = (function (geti, seti) {
68516851
// export { x, y }
68526852
for (const specifier of (<ExportDeclaration>node).exportClause.elements) {
68536853
const name = (specifier.propertyName || specifier.name).text;
6854-
(exportSpecifiers[name] || (exportSpecifiers[name] = [])).push(specifier);
6854+
multiMapAdd(exportSpecifiers, name, specifier);
68556855
}
68566856
}
68576857
break;

src/compiler/program.ts

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ namespace ts {
88

99
const emptyArray: any[] = [];
1010

11-
const defaultTypeRoots = ["node_modules/@types"];
12-
1311
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string {
1412
while (true) {
1513
const fileName = combinePaths(searchPath, configName);
@@ -168,21 +166,50 @@ namespace ts {
168166

169167
const typeReferenceExtensions = [".d.ts"];
170168

171-
export function getEffectiveTypeRoots(options: CompilerOptions, currentDirectory: string) {
169+
export function getEffectiveTypeRoots(options: CompilerOptions, host: { directoryExists?: (directoryName: string) => boolean, getCurrentDirectory?: () => string }): string[] | undefined {
172170
if (options.typeRoots) {
173171
return options.typeRoots;
174172
}
175173

174+
let currentDirectory: string;
176175
if (options.configFilePath) {
177176
currentDirectory = getDirectoryPath(options.configFilePath);
178177
}
178+
else if (host.getCurrentDirectory) {
179+
currentDirectory = host.getCurrentDirectory();
180+
}
179181

180-
if (!currentDirectory) {
181-
return undefined;
182+
return currentDirectory && getDefaultTypeRoots(currentDirectory, host);
183+
}
184+
185+
/**
186+
* Returns the path to every node_modules/@types directory from some ancestor directory.
187+
* Returns undefined if there are none.
188+
*/
189+
function getDefaultTypeRoots(currentDirectory: string, host: { directoryExists?: (directoryName: string) => boolean }): string[] | undefined {
190+
if (!host.directoryExists) {
191+
return [combinePaths(currentDirectory, nodeModulesAtTypes)];
192+
// And if it doesn't exist, tough.
193+
}
194+
195+
let typeRoots: string[];
196+
197+
while (true) {
198+
const atTypes = combinePaths(currentDirectory, nodeModulesAtTypes);
199+
if (host.directoryExists(atTypes)) {
200+
(typeRoots || (typeRoots = [])).push(atTypes);
201+
}
202+
203+
const parent = getDirectoryPath(currentDirectory);
204+
if (parent === currentDirectory) {
205+
break;
206+
}
207+
currentDirectory = parent;
182208
}
183209

184-
return map(defaultTypeRoots, d => combinePaths(currentDirectory, d));
210+
return typeRoots;
185211
}
212+
const nodeModulesAtTypes = combinePaths("node_modules", "@types");
186213

187214
/**
188215
* @param {string | undefined} containingFile - file that contains type reference directive, can be undefined if containing file is unknown.

src/compiler/sys.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ namespace ts {
267267
}
268268

269269
function addFileWatcherCallback(filePath: string, callback: FileWatcherCallback): void {
270-
(fileWatcherCallbacks[filePath] || (fileWatcherCallbacks[filePath] = [])).push(callback);
270+
multiMapAdd(fileWatcherCallbacks, filePath, callback);
271271
}
272272

273273
function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
@@ -283,16 +283,7 @@ namespace ts {
283283
}
284284

285285
function removeFileWatcherCallback(filePath: string, callback: FileWatcherCallback) {
286-
const callbacks = fileWatcherCallbacks[filePath];
287-
if (callbacks) {
288-
const newCallbacks = copyListRemovingItem(callback, callbacks);
289-
if (newCallbacks.length === 0) {
290-
delete fileWatcherCallbacks[filePath];
291-
}
292-
else {
293-
fileWatcherCallbacks[filePath] = newCallbacks;
294-
}
295-
}
286+
multiMapRemove(fileWatcherCallbacks, filePath, callback);
296287
}
297288

298289
function fileEventHandler(eventName: string, relativeFileName: string, baseDirPath: string) {

src/compiler/tsc.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -489,10 +489,7 @@ namespace ts {
489489
sourceFile.fileWatcher.close();
490490
sourceFile.fileWatcher = undefined;
491491
if (removed) {
492-
const index = rootFileNames.indexOf(sourceFile.fileName);
493-
if (index >= 0) {
494-
rootFileNames.splice(index, 1);
495-
}
492+
unorderedRemoveItem(rootFileNames, sourceFile.fileName);
496493
}
497494
startTimerForRecompilation();
498495
}

src/compiler/utilities.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,18 @@ namespace ts {
10351035
return undefined;
10361036
}
10371037

1038+
export function isCallLikeExpression(node: Node): node is CallLikeExpression {
1039+
switch (node.kind) {
1040+
case SyntaxKind.CallExpression:
1041+
case SyntaxKind.NewExpression:
1042+
case SyntaxKind.TaggedTemplateExpression:
1043+
case SyntaxKind.Decorator:
1044+
return true;
1045+
default:
1046+
return false;
1047+
}
1048+
}
1049+
10381050
export function getInvokedExpression(node: CallLikeExpression): Expression {
10391051
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
10401052
return (<TaggedTemplateExpression>node).tag;
@@ -2659,10 +2671,17 @@ namespace ts {
26592671
return token >= SyntaxKind.FirstAssignment && token <= SyntaxKind.LastAssignment;
26602672
}
26612673

2662-
export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): boolean {
2663-
return node.kind === SyntaxKind.ExpressionWithTypeArguments &&
2674+
/** Get `C` given `N` if `N` is in the position `class C extends N` where `N` is an ExpressionWithTypeArguments. */
2675+
export function tryGetClassExtendingExpressionWithTypeArguments(node: Node): ClassLikeDeclaration | undefined {
2676+
if (node.kind === SyntaxKind.ExpressionWithTypeArguments &&
26642677
(<HeritageClause>node.parent).token === SyntaxKind.ExtendsKeyword &&
2665-
isClassLike(node.parent.parent);
2678+
isClassLike(node.parent.parent)) {
2679+
return node.parent.parent;
2680+
}
2681+
}
2682+
2683+
export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): boolean {
2684+
return tryGetClassExtendingExpressionWithTypeArguments(node) !== undefined;
26662685
}
26672686

26682687
export function isEntityNameExpression(node: Expression): node is EntityNameExpression {

0 commit comments

Comments
 (0)