Skip to content

Commit 3cca4b9

Browse files
committed
Merge branch 'release-2.4' of https://github.com/Microsoft/TypeScript into release-2.4
2 parents 34700c6 + 5e36756 commit 3cca4b9

28 files changed

+329
-169
lines changed

src/compiler/checker.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4826,12 +4826,9 @@ namespace ts {
48264826
}
48274827

48284828
function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: TypeNode[], location: Node): Signature[] {
4829-
let signatures = getConstructorsForTypeArguments(type, typeArgumentNodes, location);
4830-
if (typeArgumentNodes) {
4831-
const typeArguments = map(typeArgumentNodes, getTypeFromTypeNode);
4832-
signatures = map(signatures, sig => getSignatureInstantiation(sig, typeArguments));
4833-
}
4834-
return signatures;
4829+
const signatures = getConstructorsForTypeArguments(type, typeArgumentNodes, location);
4830+
const typeArguments = map(typeArgumentNodes, getTypeFromTypeNode);
4831+
return sameMap(signatures, sig => some(sig.typeParameters) ? getSignatureInstantiation(sig, typeArguments) : sig);
48354832
}
48364833

48374834
/**
@@ -20927,7 +20924,7 @@ namespace ts {
2092720924
const staticBaseType = getApparentType(baseConstructorType);
2092820925
checkBaseTypeAccessibility(staticBaseType, baseTypeNode);
2092920926
checkSourceElement(baseTypeNode.expression);
20930-
if (baseTypeNode.typeArguments) {
20927+
if (some(baseTypeNode.typeArguments)) {
2093120928
forEach(baseTypeNode.typeArguments, checkSourceElement);
2093220929
for (const constructor of getConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode)) {
2093320930
if (!checkTypeArgumentConstraints(constructor.typeParameters, baseTypeNode.typeArguments)) {
@@ -23910,6 +23907,11 @@ namespace ts {
2391023907
const sourceFile = getSourceFileOfNode(node);
2391123908
return grammarErrorAtPos(sourceFile, types.pos, 0, Diagnostics._0_list_cannot_be_empty, listType);
2391223909
}
23910+
return forEach(types, checkGrammarExpressionWithTypeArguments);
23911+
}
23912+
23913+
function checkGrammarExpressionWithTypeArguments(node: ExpressionWithTypeArguments) {
23914+
return checkGrammarTypeArguments(node, node.typeArguments);
2391323915
}
2391423916

2391523917
function checkGrammarClassDeclarationHeritageClauses(node: ClassLikeDeclaration) {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3625,6 +3625,10 @@
36253625
"category": "Message",
36263626
"code": 90024
36273627
},
3628+
"Prefix '{0}' with an underscore.": {
3629+
"category": "Message",
3630+
"code": 90025
3631+
},
36283632

36293633
"Convert function to an ES2015 class": {
36303634
"category": "Message",

src/harness/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
"../services/codefixes/fixConstructorForDerivedNeedSuperCall.ts",
8181
"../services/codefixes/helpers.ts",
8282
"../services/codefixes/importFixes.ts",
83-
"../services/codefixes/unusedIdentifierFixes.ts",
83+
"../services/codefixes/fixUnusedIdentifier.ts",
8484
"../services/codefixes/disableJsDiagnostics.ts",
8585

8686
"harness.ts",

src/services/codefixes/unusedIdentifierFixes.ts renamed to src/services/codefixes/fixUnusedIdentifier.ts

Lines changed: 58 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ namespace ts.codefix {
1818

1919
switch (token.kind) {
2020
case ts.SyntaxKind.Identifier:
21-
return deleteIdentifier();
21+
return deleteIdentifierOrPrefixWithUnderscore(<Identifier>token);
2222

2323
case SyntaxKind.PropertyDeclaration:
2424
case SyntaxKind.NamespaceImport:
25-
return deleteNode(token.parent);
25+
return [deleteNode(token.parent)];
2626

2727
default:
28-
return deleteDefault();
28+
return [deleteDefault()];
2929
}
3030

3131
function deleteDefault() {
@@ -40,126 +40,132 @@ namespace ts.codefix {
4040
}
4141
}
4242

43-
function deleteIdentifier(): CodeAction[] | undefined {
44-
switch (token.parent.kind) {
43+
function prefixIdentifierWithUnderscore(identifier: Identifier): CodeAction {
44+
const startPosition = identifier.getStart(sourceFile, /*includeJsDocComment*/ false);
45+
return {
46+
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Prefix_0_with_an_underscore), { 0: token.getText() }),
47+
changes: [{
48+
fileName: sourceFile.path,
49+
textChanges: [{
50+
span: { start: startPosition, length: 0 },
51+
newText: "_"
52+
}]
53+
}]
54+
};
55+
}
56+
57+
function deleteIdentifierOrPrefixWithUnderscore(identifier: Identifier): CodeAction[] | undefined {
58+
const parent = identifier.parent;
59+
switch (parent.kind) {
4560
case ts.SyntaxKind.VariableDeclaration:
46-
return deleteVariableDeclaration(<ts.VariableDeclaration>token.parent);
61+
return deleteVariableDeclarationOrPrefixWithUnderscore(identifier, <ts.VariableDeclaration>parent);
4762

4863
case SyntaxKind.TypeParameter:
49-
const typeParameters = (<DeclarationWithTypeParameters>token.parent.parent).typeParameters;
64+
const typeParameters = (<DeclarationWithTypeParameters>parent.parent).typeParameters;
5065
if (typeParameters.length === 1) {
5166
const previousToken = getTokenAtPosition(sourceFile, typeParameters.pos - 1, /*includeJsDocComment*/ false);
52-
if (!previousToken || previousToken.kind !== SyntaxKind.LessThanToken) {
53-
return deleteRange(typeParameters);
54-
}
5567
const nextToken = getTokenAtPosition(sourceFile, typeParameters.end, /*includeJsDocComment*/ false);
56-
if (!nextToken || nextToken.kind !== SyntaxKind.GreaterThanToken) {
57-
return deleteRange(typeParameters);
58-
}
59-
return deleteNodeRange(previousToken, nextToken);
68+
Debug.assert(previousToken.kind === SyntaxKind.LessThanToken);
69+
Debug.assert(nextToken.kind === SyntaxKind.GreaterThanToken);
70+
71+
return [deleteNodeRange(previousToken, nextToken)];
6072
}
6173
else {
62-
return deleteNodeInList(token.parent);
74+
return [deleteNodeInList(parent)];
6375
}
6476

6577
case ts.SyntaxKind.Parameter:
66-
const functionDeclaration = <FunctionDeclaration>token.parent.parent;
67-
if (functionDeclaration.parameters.length === 1) {
68-
return deleteNode(token.parent);
69-
}
70-
else {
71-
return deleteNodeInList(token.parent);
72-
}
78+
const functionDeclaration = <FunctionDeclaration>parent.parent;
79+
return [functionDeclaration.parameters.length === 1 ? deleteNode(parent) : deleteNodeInList(parent),
80+
prefixIdentifierWithUnderscore(identifier)];
7381

7482
// handle case where 'import a = A;'
7583
case SyntaxKind.ImportEqualsDeclaration:
76-
const importEquals = getAncestor(token, SyntaxKind.ImportEqualsDeclaration);
77-
return deleteNode(importEquals);
84+
const importEquals = getAncestor(identifier, SyntaxKind.ImportEqualsDeclaration);
85+
return [deleteNode(importEquals)];
7886

7987
case SyntaxKind.ImportSpecifier:
80-
const namedImports = <NamedImports>token.parent.parent;
88+
const namedImports = <NamedImports>parent.parent;
8189
if (namedImports.elements.length === 1) {
8290
// Only 1 import and it is unused. So the entire declaration should be removed.
83-
const importSpec = getAncestor(token, SyntaxKind.ImportDeclaration);
84-
return deleteNode(importSpec);
91+
const importSpec = getAncestor(identifier, SyntaxKind.ImportDeclaration);
92+
return [deleteNode(importSpec)];
8593
}
8694
else {
8795
// delete import specifier
88-
return deleteNodeInList(token.parent);
96+
return [deleteNodeInList(parent)];
8997
}
9098

9199
// handle case where "import d, * as ns from './file'"
92100
// or "'import {a, b as ns} from './file'"
93101
case SyntaxKind.ImportClause: // this covers both 'import |d|' and 'import |d,| *'
94-
const importClause = <ImportClause>token.parent;
102+
const importClause = <ImportClause>parent;
95103
if (!importClause.namedBindings) { // |import d from './file'| or |import * as ns from './file'|
96104
const importDecl = getAncestor(importClause, SyntaxKind.ImportDeclaration);
97-
return deleteNode(importDecl);
105+
return [deleteNode(importDecl)];
98106
}
99107
else {
100108
// import |d,| * as ns from './file'
101109
const start = importClause.name.getStart(sourceFile);
102110
const nextToken = getTokenAtPosition(sourceFile, importClause.name.end, /*includeJsDocComment*/ false);
103111
if (nextToken && nextToken.kind === SyntaxKind.CommaToken) {
104112
// shift first non-whitespace position after comma to the start position of the node
105-
return deleteRange({ pos: start, end: skipTrivia(sourceFile.text, nextToken.end, /*stopAfterLineBreaks*/ false, /*stopAtComments*/ true) });
113+
return [deleteRange({ pos: start, end: skipTrivia(sourceFile.text, nextToken.end, /*stopAfterLineBreaks*/ false, /*stopAtComments*/ true) })];
106114
}
107115
else {
108-
return deleteNode(importClause.name);
116+
return [deleteNode(importClause.name)];
109117
}
110118
}
111119

112120
case SyntaxKind.NamespaceImport:
113-
const namespaceImport = <NamespaceImport>token.parent;
114-
if (namespaceImport.name === token && !(<ImportClause>namespaceImport.parent).name) {
121+
const namespaceImport = <NamespaceImport>parent;
122+
if (namespaceImport.name === identifier && !(<ImportClause>namespaceImport.parent).name) {
115123
const importDecl = getAncestor(namespaceImport, SyntaxKind.ImportDeclaration);
116-
return deleteNode(importDecl);
124+
return [deleteNode(importDecl)];
117125
}
118126
else {
119127
const previousToken = getTokenAtPosition(sourceFile, namespaceImport.pos - 1, /*includeJsDocComment*/ false);
120128
if (previousToken && previousToken.kind === SyntaxKind.CommaToken) {
121129
const startPosition = textChanges.getAdjustedStartPosition(sourceFile, previousToken, {}, textChanges.Position.FullStart);
122-
return deleteRange({ pos: startPosition, end: namespaceImport.end });
130+
return [deleteRange({ pos: startPosition, end: namespaceImport.end })];
123131
}
124-
return deleteRange(namespaceImport);
132+
return [deleteRange(namespaceImport)];
125133
}
126134

127135
default:
128-
return deleteDefault();
136+
return [deleteDefault()];
129137
}
130138
}
131139

132140
// token.parent is a variableDeclaration
133-
function deleteVariableDeclaration(varDecl: ts.VariableDeclaration): CodeAction[] | undefined {
141+
function deleteVariableDeclarationOrPrefixWithUnderscore(identifier: Identifier, varDecl: ts.VariableDeclaration): CodeAction[] | undefined {
134142
switch (varDecl.parent.parent.kind) {
135143
case SyntaxKind.ForStatement:
136144
const forStatement = <ForStatement>varDecl.parent.parent;
137145
const forInitializer = <VariableDeclarationList>forStatement.initializer;
138-
if (forInitializer.declarations.length === 1) {
139-
return deleteNode(forInitializer);
140-
}
141-
else {
142-
return deleteNodeInList(varDecl);
143-
}
146+
return [forInitializer.declarations.length === 1 ? deleteNode(forInitializer) : deleteNodeInList(varDecl)];
144147

145148
case SyntaxKind.ForOfStatement:
146149
const forOfStatement = <ForOfStatement>varDecl.parent.parent;
147150
Debug.assert(forOfStatement.initializer.kind === SyntaxKind.VariableDeclarationList);
148151
const forOfInitializer = <VariableDeclarationList>forOfStatement.initializer;
149-
return replaceNode(forOfInitializer.declarations[0], createObjectLiteral());
152+
return [
153+
replaceNode(forOfInitializer.declarations[0], createObjectLiteral()),
154+
prefixIdentifierWithUnderscore(identifier)
155+
];
150156

151157
case SyntaxKind.ForInStatement:
152158
// There is no valid fix in the case of:
153159
// for .. in
154-
return undefined;
160+
return [prefixIdentifierWithUnderscore(identifier)];
155161

156162
default:
157163
const variableStatement = <VariableStatement>varDecl.parent.parent;
158164
if (variableStatement.declarationList.declarations.length === 1) {
159-
return deleteNode(variableStatement);
165+
return [deleteNode(variableStatement)];
160166
}
161167
else {
162-
return deleteNodeInList(varDecl);
168+
return [deleteNodeInList(varDecl)];
163169
}
164170
}
165171
}
@@ -184,11 +190,11 @@ namespace ts.codefix {
184190
return makeChange(textChanges.ChangeTracker.fromCodeFixContext(context).replaceNode(sourceFile, n, newNode));
185191
}
186192

187-
function makeChange(changeTracker: textChanges.ChangeTracker) {
188-
return [{
193+
function makeChange(changeTracker: textChanges.ChangeTracker): CodeAction {
194+
return {
189195
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_declaration_for_Colon_0), { 0: token.getText() }),
190196
changes: changeTracker.getChanges()
191-
}];
197+
};
192198
}
193199
}
194200
});

src/services/codefixes/fixes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/// <reference path="fixConstructorForDerivedNeedSuperCall.ts" />
77
/// <reference path="fixExtendsInterfaceBecomesImplements.ts" />
88
/// <reference path="fixForgottenThisPropertyAccess.ts" />
9-
/// <reference path='unusedIdentifierFixes.ts' />
9+
/// <reference path='fixUnusedIdentifier.ts' />
1010
/// <reference path='importFixes.ts' />
1111
/// <reference path='disableJsDiagnostics.ts' />
1212
/// <reference path='helpers.ts' />

tests/baselines/reference/genericDefaults.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,15 @@ const Derived02c01 = new Derived02(1);
458458
const Derived02c02 = new Derived02<number>();
459459
const Derived02c03 = new Derived02<number>(1);
460460

461+
// https://github.com/Microsoft/TypeScript/issues/16211
462+
interface Base02 {}
463+
interface Base02Constructor { new <T = A>(a: T): Base02 & T; }
464+
declare const Base02: Base02Constructor;
465+
declare class Derived03 extends Base02 {}
466+
const Derived03c00 = new Derived03(ab);
467+
const Derived03c01 = Derived03c00.a;
468+
type DerivedProps = keyof Derived03;
469+
461470
type t00<T = number> = { a: T; }
462471
const t00c00 = (<t00>x).a;
463472
const t00c01 = (<t00<number>>x).a;
@@ -478,8 +487,7 @@ const t03c00 = (<t03<number>>x).a;
478487
const t03c01 = (<t03<1>>x).a;
479488
const t03c02 = (<t03<number, number>>x).a;
480489
const t03c03 = (<t03<1, 1>>x).a;
481-
const t03c04 = (<t03<number, 1>>x).a;
482-
490+
const t03c04 = (<t03<number, 1>>x).a;
483491

484492
//// [genericDefaults.js]
485493
// no inference
@@ -834,6 +842,8 @@ var Derived02c00 = new Derived02();
834842
var Derived02c01 = new Derived02(1);
835843
var Derived02c02 = new Derived02();
836844
var Derived02c03 = new Derived02(1);
845+
var Derived03c00 = new Derived03(ab);
846+
var Derived03c01 = Derived03c00.a;
837847
var t00c00 = x.a;
838848
var t00c01 = x.a;
839849
var t01c00 = x.a;
@@ -977,6 +987,17 @@ declare const Derived02c00: Derived02<string>;
977987
declare const Derived02c01: Derived02<number>;
978988
declare const Derived02c02: Derived02<number>;
979989
declare const Derived02c03: Derived02<number>;
990+
interface Base02 {
991+
}
992+
interface Base02Constructor {
993+
new <T = A>(a: T): Base02 & T;
994+
}
995+
declare const Base02: Base02Constructor;
996+
declare class Derived03 extends Base02 {
997+
}
998+
declare const Derived03c00: Derived03;
999+
declare const Derived03c01: number;
1000+
declare type DerivedProps = keyof Derived03;
9801001
declare type t00<T = number> = {
9811002
a: T;
9821003
};

0 commit comments

Comments
 (0)