Skip to content

Commit 3ccc58c

Browse files
committed
Merge remote-tracking branch 'origin/master' into go_to_implementation_pr
2 parents b0eff90 + 43e1915 commit 3ccc58c

253 files changed

Lines changed: 9076 additions & 2908 deletions

File tree

Some content is hidden

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

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: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
/* @internal */
44
namespace ts {
5+
const ambientModuleSymbolRegex = /^".+"$/;
6+
57
let nextSymbolId = 1;
68
let nextNodeId = 1;
79
let nextMergeId = 1;
@@ -100,6 +102,7 @@ namespace ts {
100102
getAliasedSymbol: resolveAlias,
101103
getEmitResolver,
102104
getExportsOfModule: getExportsOfModuleAsArray,
105+
getAmbientModules,
103106

104107
getJsxElementAttributesType,
105108
getJsxIntrinsicTagNames,
@@ -143,6 +146,7 @@ namespace ts {
143146

144147
const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
145148
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);
146150

147151
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
148152

@@ -3346,7 +3350,13 @@ namespace ts {
33463350
// Otherwise, fall back to 'any'.
33473351
else {
33483352
if (compilerOptions.noImplicitAny) {
3349-
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbolToString(symbol));
3353+
if (setter) {
3354+
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
3355+
}
3356+
else {
3357+
Debug.assert(!!getter, "there must existed getter as we are current checking either setter or getter in this function");
3358+
error(getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
3359+
}
33503360
}
33513361
type = anyType;
33523362
}
@@ -5372,7 +5382,7 @@ namespace ts {
53725382
while (i > 0) {
53735383
i--;
53745384
if (isSubtypeOfAny(types[i], types)) {
5375-
types.splice(i, 1);
5385+
orderedRemoveItemAt(types, i);
53765386
}
53775387
}
53785388
}
@@ -8752,7 +8762,7 @@ namespace ts {
87528762
// The location isn't a reference to the given symbol, meaning we're being asked
87538763
// a hypothetical question of what type the symbol would have if there was a reference
87548764
// to it at the given location. Since we have no control flow information for the
8755-
// hypotherical reference (control flow information is created and attached by the
8765+
// hypothetical reference (control flow information is created and attached by the
87568766
// binder), we simply return the declared type of the symbol.
87578767
return getTypeOfSymbol(symbol);
87588768
}
@@ -12223,10 +12233,10 @@ namespace ts {
1222312233
// or that a different candidatesOutArray was passed in. Therefore, we need to redo the work
1222412234
// to correctly fill the candidatesOutArray.
1222512235
const cached = links.resolvedSignature;
12226-
if (cached && cached !== anySignature && !candidatesOutArray) {
12236+
if (cached && cached !== resolvingSignature && !candidatesOutArray) {
1222712237
return cached;
1222812238
}
12229-
links.resolvedSignature = anySignature;
12239+
links.resolvedSignature = resolvingSignature;
1223012240
const result = resolveSignature(node, candidatesOutArray);
1223112241
// If signature resolution originated in control flow type analysis (for example to compute the
1223212242
// assigned type in a flow assignment) we don't cache the result as it may be based on temporary
@@ -12238,7 +12248,7 @@ namespace ts {
1223812248
function getResolvedOrAnySignature(node: CallLikeExpression) {
1223912249
// If we're already in the process of resolving the given signature, don't resolve again as
1224012250
// that could cause infinite recursion. Instead, return anySignature.
12241-
return getNodeLinks(node).resolvedSignature === anySignature ? anySignature : getResolvedSignature(node);
12251+
return getNodeLinks(node).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(node);
1224212252
}
1224312253

1224412254
function getInferredClassType(symbol: Symbol) {
@@ -20013,5 +20023,15 @@ namespace ts {
2001320023
return true;
2001420024
}
2001520025
}
20026+
20027+
function getAmbientModules(): Symbol[] {
20028+
const result: Symbol[] = [];
20029+
for (const sym in globals) {
20030+
if (ambientModuleSymbolRegex.test(sym)) {
20031+
result.push(globals[sym]);
20032+
}
20033+
}
20034+
return result;
20035+
}
2001620036
}
2001720037
}

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/diagnosticMessages.json

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2871,11 +2871,7 @@
28712871
"Element implicitly has an 'any' type because index expression is not of type 'number'.": {
28722872
"category": "Error",
28732873
"code": 7015
2874-
},
2875-
"Property '{0}' implicitly has type 'any', because its 'set' accessor lacks a type annotation.": {
2876-
"category": "Error",
2877-
"code": 7016
2878-
},
2874+
},
28792875
"Index signature of object type implicitly has an 'any' type.": {
28802876
"category": "Error",
28812877
"code": 7017
@@ -2932,6 +2928,14 @@
29322928
"category": "Error",
29332929
"code": 7031
29342930
},
2931+
"Property '{0}' implicitly has type 'any', because its set accessor lacks a parameter type annotation.": {
2932+
"category": "Error",
2933+
"code": 7032
2934+
},
2935+
"Property '{0}' implicitly has type 'any', because its get accessor lacks a return type annotation.": {
2936+
"category": "Error",
2937+
"code": 7033
2938+
},
29352939
"You cannot rename this element.": {
29362940
"category": "Error",
29372941
"code": 8000

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: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@ namespace ts {
88

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

11-
const defaultTypeRoots = ["node_modules/@types"];
12-
13-
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean): string {
11+
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string {
1412
while (true) {
15-
const fileName = combinePaths(searchPath, "tsconfig.json");
13+
const fileName = combinePaths(searchPath, configName);
1614
if (fileExists(fileName)) {
1715
return fileName;
1816
}
@@ -168,7 +166,7 @@ namespace ts {
168166

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

171-
function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost) {
169+
export function getEffectiveTypeRoots(options: CompilerOptions, host: { directoryExists?: (directoryName: string) => boolean, getCurrentDirectory?: () => string }): string[] | undefined {
172170
if (options.typeRoots) {
173171
return options.typeRoots;
174172
}
@@ -181,11 +179,37 @@ namespace ts {
181179
currentDirectory = host.getCurrentDirectory();
182180
}
183181

184-
if (!currentDirectory) {
185-
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.
186193
}
187-
return map(defaultTypeRoots, d => combinePaths(currentDirectory, d));
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;
208+
}
209+
210+
return typeRoots;
188211
}
212+
const nodeModulesAtTypes = combinePaths("node_modules", "@types");
189213

190214
/**
191215
* @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/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1889,6 +1889,7 @@ namespace ts {
18891889
getJsxElementAttributesType(elementNode: JsxOpeningLikeElement): Type;
18901890
getJsxIntrinsicTagNames(): Symbol[];
18911891
isOptionalParameter(node: ParameterDeclaration): boolean;
1892+
getAmbientModules(): Symbol[];
18921893

18931894
// Should not be called directly. Should only be accessed through the Program instance.
18941895
/* @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];

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)