Skip to content

Commit d6d6a4a

Browse files
author
Andy Hanson
committed
Merge branch 'goto_definition_super', remote-tracking branch 'origin' into constructor_references
3 parents 0dc976d + 5f16a48 + 3eadbf6 commit d6d6a4a

File tree

127 files changed

+914
-1318
lines changed

Some content is hidden

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

127 files changed

+914
-1318
lines changed

src/compiler/checker.ts

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3346,7 +3346,13 @@ namespace ts {
33463346
// Otherwise, fall back to 'any'.
33473347
else {
33483348
if (compilerOptions.noImplicitAny) {
3349-
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbolToString(symbol));
3349+
if (setter) {
3350+
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
3351+
}
3352+
else {
3353+
Debug.assert(!!getter, "there must existed getter as we are current checking either setter or getter in this function");
3354+
error(getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
3355+
}
33503356
}
33513357
type = anyType;
33523358
}
@@ -11960,18 +11966,12 @@ namespace ts {
1196011966
// Function interface, since they have none by default. This is a bit of a leap of faith
1196111967
// that the user will not add any.
1196211968
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
11963-
1196411969
const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
11965-
// TS 1.0 spec: 4.12
11966-
// If FuncExpr is of type Any, or of an object type that has no call or construct signatures
11967-
// but is a subtype of the Function interface, the call is an untyped function call. In an
11968-
// untyped function call no TypeArgs are permitted, Args can be any argument list, no contextual
11970+
11971+
// TS 1.0 Spec: 4.12
11972+
// In an untyped function call no TypeArgs are permitted, Args can be any argument list, no contextual
1196911973
// types are provided for the argument expressions, and the result is always of type Any.
11970-
// We exclude union types because we may have a union of function types that happen to have
11971-
// no common signatures.
11972-
if (isTypeAny(funcType) ||
11973-
(isTypeAny(apparentType) && funcType.flags & TypeFlags.TypeParameter) ||
11974-
(!callSignatures.length && !constructSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) {
11974+
if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, constructSignatures.length)) {
1197511975
// The unknownType indicates that an error already occurred (and was reported). No
1197611976
// need to report another error in this case.
1197711977
if (funcType !== unknownType && node.typeArguments) {
@@ -11994,6 +11994,29 @@ namespace ts {
1199411994
return resolveCall(node, callSignatures, candidatesOutArray);
1199511995
}
1199611996

11997+
/**
11998+
* TS 1.0 spec: 4.12
11999+
* If FuncExpr is of type Any, or of an object type that has no call or construct signatures
12000+
* but is a subtype of the Function interface, the call is an untyped function call.
12001+
*/
12002+
function isUntypedFunctionCall(funcType: Type, apparentFuncType: Type, numCallSignatures: number, numConstructSignatures: number) {
12003+
if (isTypeAny(funcType)) {
12004+
return true;
12005+
}
12006+
if (isTypeAny(apparentFuncType) && funcType.flags & TypeFlags.TypeParameter) {
12007+
return true;
12008+
}
12009+
if (!numCallSignatures && !numConstructSignatures) {
12010+
// We exclude union types because we may have a union of function types that happen to have
12011+
// no common signatures.
12012+
if (funcType.flags & TypeFlags.Union) {
12013+
return false;
12014+
}
12015+
return isTypeAssignableTo(funcType, globalFunctionType);
12016+
}
12017+
return false;
12018+
}
12019+
1199712020
function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[]): Signature {
1199812021
if (node.arguments && languageVersion < ScriptTarget.ES5) {
1199912022
const spreadIndex = getSpreadArgumentIndex(node.arguments);
@@ -12119,8 +12142,9 @@ namespace ts {
1211912142
}
1212012143

1212112144
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
12145+
const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
1212212146

12123-
if (isTypeAny(tagType) || (!callSignatures.length && !(tagType.flags & TypeFlags.Union) && isTypeAssignableTo(tagType, globalFunctionType))) {
12147+
if (isUntypedFunctionCall(tagType, apparentType, callSignatures.length, constructSignatures.length)) {
1212412148
return resolveUntypedCall(node);
1212512149
}
1212612150

@@ -12165,7 +12189,8 @@ namespace ts {
1216512189
}
1216612190

1216712191
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
12168-
if (funcType === anyType || (!callSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) {
12192+
const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
12193+
if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, constructSignatures.length)) {
1216912194
return resolveUntypedCall(node);
1217012195
}
1217112196

@@ -18763,7 +18788,13 @@ namespace ts {
1876318788
(augmentations || (augmentations = [])).push(file.moduleAugmentations);
1876418789
}
1876518790
if (file.symbol && file.symbol.globalExports) {
18766-
mergeSymbolTable(globals, file.symbol.globalExports);
18791+
// Merge in UMD exports with first-in-wins semantics (see #9771)
18792+
const source = file.symbol.globalExports;
18793+
for (const id in source) {
18794+
if (!(id in globals)) {
18795+
globals[id] = source[id];
18796+
}
18797+
}
1876718798
}
1876818799
});
1876918800

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
@@ -6587,7 +6587,7 @@ const _super = (function (geti, seti) {
65876587
// import { x, y } from "foo"
65886588
// import d, * as x from "foo"
65896589
// import d, { x, y } from "foo"
6590-
const isNakedImport = SyntaxKind.ImportDeclaration && !(<ImportDeclaration>node).importClause;
6590+
const isNakedImport = node.kind === SyntaxKind.ImportDeclaration && !(<ImportDeclaration>node).importClause;
65916591
if (!isNakedImport) {
65926592
write(varOrConst);
65936593
write(getGeneratedNameForNode(<ImportDeclaration>node));

src/compiler/parser.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2339,6 +2339,7 @@ namespace ts {
23392339
token() === SyntaxKind.LessThanToken ||
23402340
token() === SyntaxKind.QuestionToken ||
23412341
token() === SyntaxKind.ColonToken ||
2342+
token() === SyntaxKind.CommaToken ||
23422343
canParseSemicolon();
23432344
}
23442345
return false;

src/compiler/utilities.ts

Lines changed: 12 additions & 0 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;

src/harness/fourslash.ts

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,24 @@ namespace FourSlash {
206206

207207
private inputFiles = ts.createMap<string>(); // Map between inputFile's fileName and its content for easily looking up when resolving references
208208

209+
private static getDisplayPartsJson(displayParts: ts.SymbolDisplayPart[]) {
210+
let result = "";
211+
ts.forEach(displayParts, part => {
212+
if (result) {
213+
result += ",\n ";
214+
}
215+
else {
216+
result = "[\n ";
217+
}
218+
result += JSON.stringify(part);
219+
});
220+
if (result) {
221+
result += "\n]";
222+
}
223+
224+
return result;
225+
}
226+
209227
// Add input file which has matched file name with the given reference-file path.
210228
// This is necessary when resolveReference flag is specified
211229
private addMatchedInputFile(referenceFilePath: string, extensions: string[]) {
@@ -777,6 +795,20 @@ namespace FourSlash {
777795
ts.forEachProperty(this.rangesByText(), ranges => this.verifyRangesReferenceEachOther(ranges));
778796
}
779797

798+
public verifyDisplayPartsOfReferencedSymbol(expected: ts.SymbolDisplayPart[]) {
799+
const referencedSymbols = this.findReferencesAtCaret();
800+
801+
if (referencedSymbols.length === 0) {
802+
this.raiseError("No referenced symbols found at current caret position");
803+
}
804+
else if (referencedSymbols.length > 1) {
805+
this.raiseError("More than one referenced symbol found");
806+
}
807+
808+
assert.equal(TestState.getDisplayPartsJson(referencedSymbols[0].definition.displayParts),
809+
TestState.getDisplayPartsJson(expected), this.messageAtLastKnownMarker("referenced symbol definition display parts"));
810+
}
811+
780812
private verifyReferencesWorker(references: ts.ReferenceEntry[], fileName: string, start: number, end: number, isWriteAccess?: boolean, isDefinition?: boolean) {
781813
for (let i = 0; i < references.length; i++) {
782814
const reference = references[i];
@@ -811,6 +843,10 @@ namespace FourSlash {
811843
return this.languageService.getReferencesAtPosition(this.activeFile.fileName, this.currentCaretPosition);
812844
}
813845

846+
private findReferencesAtCaret() {
847+
return this.languageService.findReferences(this.activeFile.fileName, this.currentCaretPosition);
848+
}
849+
814850
public getSyntacticDiagnostics(expected: string) {
815851
const diagnostics = this.languageService.getSyntacticDiagnostics(this.activeFile.fileName);
816852
this.testDiagnostics(expected, diagnostics);
@@ -856,30 +892,12 @@ namespace FourSlash {
856892
displayParts: ts.SymbolDisplayPart[],
857893
documentation: ts.SymbolDisplayPart[]) {
858894

859-
function getDisplayPartsJson(displayParts: ts.SymbolDisplayPart[]) {
860-
let result = "";
861-
ts.forEach(displayParts, part => {
862-
if (result) {
863-
result += ",\n ";
864-
}
865-
else {
866-
result = "[\n ";
867-
}
868-
result += JSON.stringify(part);
869-
});
870-
if (result) {
871-
result += "\n]";
872-
}
873-
874-
return result;
875-
}
876-
877895
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition);
878896
assert.equal(actualQuickInfo.kind, kind, this.messageAtLastKnownMarker("QuickInfo kind"));
879897
assert.equal(actualQuickInfo.kindModifiers, kindModifiers, this.messageAtLastKnownMarker("QuickInfo kindModifiers"));
880898
assert.equal(JSON.stringify(actualQuickInfo.textSpan), JSON.stringify(textSpan), this.messageAtLastKnownMarker("QuickInfo textSpan"));
881-
assert.equal(getDisplayPartsJson(actualQuickInfo.displayParts), getDisplayPartsJson(displayParts), this.messageAtLastKnownMarker("QuickInfo displayParts"));
882-
assert.equal(getDisplayPartsJson(actualQuickInfo.documentation), getDisplayPartsJson(documentation), this.messageAtLastKnownMarker("QuickInfo documentation"));
899+
assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.displayParts), TestState.getDisplayPartsJson(displayParts), this.messageAtLastKnownMarker("QuickInfo displayParts"));
900+
assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.documentation), TestState.getDisplayPartsJson(documentation), this.messageAtLastKnownMarker("QuickInfo documentation"));
883901
}
884902

885903
public verifyRenameLocations(findInStrings: boolean, findInComments: boolean, ranges?: Range[]) {
@@ -1546,7 +1564,7 @@ namespace FourSlash {
15461564
public goToDefinition(definitionIndex: number) {
15471565
const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
15481566
if (!definitions || !definitions.length) {
1549-
this.raiseError("goToDefinition failed - expected to at least one definition location but got 0");
1567+
this.raiseError("goToDefinition failed - expected to find at least one definition location but got 0");
15501568
}
15511569

15521570
if (definitionIndex >= definitions.length) {
@@ -1561,7 +1579,7 @@ namespace FourSlash {
15611579
public goToTypeDefinition(definitionIndex: number) {
15621580
const definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
15631581
if (!definitions || !definitions.length) {
1564-
this.raiseError("goToTypeDefinition failed - expected to at least one definition location but got 0");
1582+
this.raiseError("goToTypeDefinition failed - expected to find at least one definition location but got 0");
15651583
}
15661584

15671585
if (definitionIndex >= definitions.length) {
@@ -1582,7 +1600,7 @@ namespace FourSlash {
15821600
this.raiseError(`goToDefinition - expected to 0 definition locations but got ${definitions.length}`);
15831601
}
15841602
else if (!foundDefinitions && !negative) {
1585-
this.raiseError("goToDefinition - expected to at least one definition location but got 0");
1603+
this.raiseError("goToDefinition - expected to find at least one definition location but got 0");
15861604
}
15871605
}
15881606

@@ -2947,6 +2965,10 @@ namespace FourSlashInterface {
29472965
this.state.verifyRangesReferenceEachOther(ranges);
29482966
}
29492967

2968+
public findReferencesDefinitionDisplayPartsAtCaretAre(expected: ts.SymbolDisplayPart[]) {
2969+
this.state.verifyDisplayPartsOfReferencedSymbol(expected);
2970+
}
2971+
29502972
public rangesWithSameTextReferenceEachOther() {
29512973
this.state.verifyRangesWithSameTextReferenceEachOther();
29522974
}

src/harness/harness.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,23 +1370,31 @@ namespace Harness {
13701370

13711371
// Produce baselines. The first gives the types for all expressions.
13721372
// The second gives symbols for all identifiers.
1373-
let e1: Error, e2: Error;
1373+
let typesError: Error, symbolsError: Error;
13741374
try {
13751375
checkBaseLines(/*isSymbolBaseLine*/ false);
13761376
}
13771377
catch (e) {
1378-
e1 = e;
1378+
typesError = e;
13791379
}
13801380

13811381
try {
13821382
checkBaseLines(/*isSymbolBaseLine*/ true);
13831383
}
13841384
catch (e) {
1385-
e2 = e;
1385+
symbolsError = e;
13861386
}
13871387

1388-
if (e1 || e2) {
1389-
throw e1 || e2;
1388+
if (typesError && symbolsError) {
1389+
throw new Error(typesError.message + ts.sys.newLine + symbolsError.message);
1390+
}
1391+
1392+
if (typesError) {
1393+
throw typesError;
1394+
}
1395+
1396+
if (symbolsError) {
1397+
throw symbolsError;
13901398
}
13911399

13921400
return;
@@ -1396,7 +1404,12 @@ namespace Harness {
13961404

13971405
const fullExtension = isSymbolBaseLine ? ".symbols" : ".types";
13981406

1399-
Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, fullExtension), () => fullBaseLine, opts);
1407+
// When calling this function from rwc-runner, the baselinePath will have no extension.
1408+
// As rwc test- file is stored in json which ".json" will get stripped off.
1409+
// When calling this function from compiler-runner, the baselinePath will then has either ".ts" or ".tsx" extension
1410+
const outputFileName = ts.endsWith(baselinePath, ".ts") || ts.endsWith(baselinePath, ".tsx") ?
1411+
baselinePath.replace(/\.tsx?/, fullExtension) : baselinePath.concat(fullExtension);
1412+
Harness.Baseline.runBaseline(outputFileName, () => fullBaseLine, opts);
14001413
}
14011414

14021415
function generateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): string {

src/harness/rwcRunner.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ namespace RWC {
223223
});
224224

225225
it("has the expected types", () => {
226-
Harness.Compiler.doTypeAndSymbolBaseline(`${baseName}.types`, compilerResult, inputFiles
226+
// We don't need to pass the extension here because "doTypeAndSymbolBaseline" will append appropriate extension of ".types" or ".symbols"
227+
Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles
227228
.concat(otherFiles)
228229
.filter(file => !!compilerResult.program.getSourceFile(file.unitName))
229230
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts);

0 commit comments

Comments
 (0)