Skip to content

Commit 66e1c92

Browse files
author
Paul van Brenk
committed
Merge branch 'master' into pvb/codeaction/api
2 parents f931e60 + 707d61d commit 66e1c92

46 files changed

Lines changed: 589 additions & 88 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.

src/compiler/checker.ts

Lines changed: 38 additions & 13 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

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/harness/fourslash.ts

Lines changed: 42 additions & 20 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[]) {
@@ -776,6 +794,20 @@ namespace FourSlash {
776794
ts.forEachProperty(this.rangesByText(), ranges => this.verifyRangesReferenceEachOther(ranges));
777795
}
778796

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

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

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

884902
public verifyRenameLocations(findInStrings: boolean, findInComments: boolean, ranges?: Range[]) {
@@ -2988,6 +3006,10 @@ namespace FourSlashInterface {
29883006
this.state.verifyRangesReferenceEachOther(ranges);
29893007
}
29903008

3009+
public findReferencesDefinitionDisplayPartsAtCaretAre(expected: ts.SymbolDisplayPart[]) {
3010+
this.state.verifyDisplayPartsOfReferencedSymbol(expected);
3011+
}
3012+
29913013
public rangesWithSameTextReferenceEachOther() {
29923014
this.state.verifyRangesWithSameTextReferenceEachOther();
29933015
}

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);

src/services/services.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,8 +1388,12 @@ namespace ts {
13881388
containerName: string;
13891389
}
13901390

1391+
export interface ReferencedSymbolDefinitionInfo extends DefinitionInfo {
1392+
displayParts: SymbolDisplayPart[];
1393+
}
1394+
13911395
export interface ReferencedSymbol {
1392-
definition: DefinitionInfo;
1396+
definition: ReferencedSymbolDefinitionInfo;
13931397
references: ReferenceEntry[];
13941398
}
13951399

@@ -6127,7 +6131,7 @@ namespace ts {
61276131

61286132
return result;
61296133

6130-
function getDefinition(symbol: Symbol): DefinitionInfo {
6134+
function getDefinition(symbol: Symbol): ReferencedSymbolDefinitionInfo {
61316135
const info = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, node.getSourceFile(), getContainerNode(node), node);
61326136
const name = map(info.displayParts, p => p.text).join("");
61336137
const declarations = symbol.declarations;
@@ -6141,7 +6145,8 @@ namespace ts {
61416145
name,
61426146
kind: info.symbolKind,
61436147
fileName: declarations[0].getSourceFile().fileName,
6144-
textSpan: createTextSpan(declarations[0].getStart(), 0)
6148+
textSpan: createTextSpan(declarations[0].getStart(), 0),
6149+
displayParts: info.displayParts
61456150
};
61466151
}
61476152

@@ -6336,13 +6341,14 @@ namespace ts {
63366341
}
63376342
});
63386343

6339-
const definition: DefinitionInfo = {
6344+
const definition: ReferencedSymbolDefinitionInfo = {
63406345
containerKind: "",
63416346
containerName: "",
63426347
fileName: targetLabel.getSourceFile().fileName,
63436348
kind: ScriptElementKind.label,
63446349
name: labelName,
6345-
textSpan: createTextSpanFromBounds(targetLabel.getStart(), targetLabel.getEnd())
6350+
textSpan: createTextSpanFromBounds(targetLabel.getStart(), targetLabel.getEnd()),
6351+
displayParts: [displayPart(labelName, SymbolDisplayPartKind.text)]
63466352
};
63476353

63486354
return [{ definition, references }];
@@ -6582,14 +6588,20 @@ namespace ts {
65826588
getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, references);
65836589
}
65846590

6591+
const thisOrSuperSymbol = typeChecker.getSymbolAtLocation(thisOrSuperKeyword);
6592+
6593+
const displayParts = thisOrSuperSymbol && getSymbolDisplayPartsDocumentationAndSymbolKind(
6594+
thisOrSuperSymbol, thisOrSuperKeyword.getSourceFile(), getContainerNode(thisOrSuperKeyword), thisOrSuperKeyword).displayParts;
6595+
65856596
return [{
65866597
definition: {
65876598
containerKind: "",
65886599
containerName: "",
65896600
fileName: node.getSourceFile().fileName,
65906601
kind: ScriptElementKind.variableElement,
65916602
name: "this",
6592-
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd())
6603+
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()),
6604+
displayParts
65936605
},
65946606
references: references
65956607
}];
@@ -6660,7 +6672,8 @@ namespace ts {
66606672
fileName: node.getSourceFile().fileName,
66616673
kind: ScriptElementKind.variableElement,
66626674
name: type.text,
6663-
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd())
6675+
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()),
6676+
displayParts: [displayPart(getTextOfNode(node), SymbolDisplayPartKind.stringLiteral)]
66646677
},
66656678
references: references
66666679
}];

0 commit comments

Comments
 (0)