Skip to content

Commit b06b0d8

Browse files
author
Andy Hanson
committed
Merge branch 'master' into services_settings
2 parents ca0beaf + eb4dba7 commit b06b0d8

File tree

59 files changed

+2097
-1270
lines changed

Some content is hidden

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

59 files changed

+2097
-1270
lines changed

.circleci/config.yml

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,10 @@
1-
defaultFilters: &defaultFilters
2-
filters:
3-
branches:
4-
only:
5-
- master
6-
- release-2.5
7-
- release-2.6
8-
- release-2.7
91
workflows:
102
version: 2
113
main:
124
jobs:
13-
- node9:
14-
<<: *defaultFilters
15-
- node8:
16-
<<: *defaultFilters
17-
- node6:
18-
<<: *defaultFilters
5+
- node9
6+
- node8
7+
- node6
198
nightly:
209
triggers:
2110
- schedule:
@@ -25,24 +14,20 @@ workflows:
2514
only: master
2615
jobs:
2716
- node9:
28-
<<: *defaultFilters
2917
context: nightlies
3018
- node8:
31-
<<: *defaultFilters
3219
context: nightlies
3320
- node6:
34-
<<: *defaultFilters
3521
context: nightlies
3622

3723
base: &base
3824
environment:
3925
- workerCount: 4
4026
- timeout: 400000
4127
steps:
42-
- checkout:
43-
post:
44-
- git submodule update --init --recursive
28+
- checkout
4529
- run: |
30+
git submodule update --init --recursive
4631
npm uninstall typescript --no-save
4732
npm uninstall tslint --no-save
4833
npm install

src/compiler/checker.ts

Lines changed: 51 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ namespace ts {
422422

423423
let deferredNodes: Node[];
424424
let deferredUnusedIdentifierNodes: Node[];
425+
const seenDeferredUnusedIdentifiers = createMap<true>(); // For assertion that we don't defer the same identifier twice
425426

426427
let flowLoopStart = 0;
427428
let flowLoopCount = 0;
@@ -2051,6 +2052,7 @@ namespace ts {
20512052
}
20522053
if (namespace.valueDeclaration &&
20532054
isVariableDeclaration(namespace.valueDeclaration) &&
2055+
namespace.valueDeclaration.initializer &&
20542056
isCommonJsRequire(namespace.valueDeclaration.initializer)) {
20552057
const moduleName = (namespace.valueDeclaration.initializer as CallExpression).arguments[0] as StringLiteral;
20562058
const moduleSym = resolveExternalModuleName(moduleName, moduleName);
@@ -4165,7 +4167,10 @@ namespace ts {
41654167
return getTypeForBindingElement(<BindingElement>declaration);
41664168
}
41674169

4168-
const isOptional = !isBindingElement(declaration) && !isVariableDeclaration(declaration) && !!declaration.questionToken && includeOptionality;
4170+
const isOptional = includeOptionality && (
4171+
isInJavaScriptFile(declaration) && isParameter(declaration) && getJSDocParameterTags(declaration).some(tag => tag.isBracketed)
4172+
|| !isBindingElement(declaration) && !isVariableDeclaration(declaration) && !!declaration.questionToken);
4173+
41694174
// Use type from type annotation if one is present
41704175
const declaredType = tryGetTypeFromEffectiveTypeNode(declaration);
41714176
if (declaredType) {
@@ -6569,23 +6574,10 @@ namespace ts {
65696574
}
65706575

65716576
function isJSDocOptionalParameter(node: ParameterDeclaration) {
6572-
if (isInJavaScriptFile(node)) {
6573-
if (node.type && node.type.kind === SyntaxKind.JSDocOptionalType) {
6574-
return true;
6575-
}
6576-
const paramTags = getJSDocParameterTags(node);
6577-
if (paramTags) {
6578-
for (const paramTag of paramTags) {
6579-
if (paramTag.isBracketed) {
6580-
return true;
6581-
}
6582-
6583-
if (paramTag.typeExpression) {
6584-
return paramTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType;
6585-
}
6586-
}
6587-
}
6588-
}
6577+
return isInJavaScriptFile(node) && (
6578+
node.type && node.type.kind === SyntaxKind.JSDocOptionalType
6579+
|| getJSDocParameterTags(node).some(({ isBracketed, typeExpression }) =>
6580+
isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType));
65896581
}
65906582

65916583
function tryFindAmbientModule(moduleName: string, withAugmentations: boolean) {
@@ -6761,17 +6753,20 @@ namespace ts {
67616753
return links.resolvedSignature;
67626754
}
67636755

6756+
/**
6757+
* A JS function gets a synthetic rest parameter if it references `arguments` AND:
6758+
* 1. It has no parameters but at least one `@param` with a type that starts with `...`
6759+
* OR
6760+
* 2. It has at least one parameter, and the last parameter has a matching `@param` with a type that starts with `...`
6761+
*/
67646762
function maybeAddJsSyntheticRestParameter(declaration: SignatureDeclaration, parameters: Symbol[]): boolean {
6765-
// JS functions get a free rest parameter if:
6766-
// a) The last parameter has `...` preceding its type
6767-
// b) It references `arguments` somewhere
6763+
if (!containsArgumentsReference(declaration)) {
6764+
return false;
6765+
}
67686766
const lastParam = lastOrUndefined(declaration.parameters);
6769-
const lastParamTags = lastParam && getJSDocParameterTags(lastParam);
6767+
const lastParamTags = lastParam ? getJSDocParameterTags(lastParam) : getJSDocTags(declaration).filter(isJSDocParameterTag);
67706768
const lastParamVariadicType = firstDefined(lastParamTags, p =>
67716769
p.typeExpression && isJSDocVariadicType(p.typeExpression.type) ? p.typeExpression.type : undefined);
6772-
if (!lastParamVariadicType && !containsArgumentsReference(declaration)) {
6773-
return false;
6774-
}
67756770

67766771
const syntheticArgsSymbol = createSymbol(SymbolFlags.Variable, "args" as __String);
67776772
syntheticArgsSymbol.type = lastParamVariadicType ? createArrayType(getTypeFromTypeNode(lastParamVariadicType.type)) : anyArrayType;
@@ -8668,9 +8663,10 @@ namespace ts {
86688663
return getTypeFromIntersectionTypeNode(<IntersectionTypeNode>node);
86698664
case SyntaxKind.JSDocNullableType:
86708665
return getTypeFromJSDocNullableTypeNode(<JSDocNullableType>node);
8666+
case SyntaxKind.JSDocOptionalType:
8667+
return addOptionality(getTypeFromTypeNode((node as JSDocOptionalType).type));
86718668
case SyntaxKind.ParenthesizedType:
86728669
case SyntaxKind.JSDocNonNullableType:
8673-
case SyntaxKind.JSDocOptionalType:
86748670
case SyntaxKind.JSDocTypeExpression:
86758671
return getTypeFromTypeNode((<ParenthesizedTypeNode | JSDocTypeReferencingNode | JSDocTypeExpression>node).type);
86768672
case SyntaxKind.JSDocVariadicType:
@@ -18673,7 +18669,6 @@ namespace ts {
1867318669

1867418670
// The identityMapper object is used to indicate that function expressions are wildcards
1867518671
if (checkMode === CheckMode.SkipContextSensitive && isContextSensitive(node)) {
18676-
checkNodeDeferred(node);
1867718672
return anyFunctionType;
1867818673
}
1867918674

@@ -21448,9 +21443,24 @@ namespace ts {
2144821443
function checkJSDocParameterTag(node: JSDocParameterTag) {
2144921444
checkSourceElement(node.typeExpression);
2145021445
if (!getParameterSymbolFromJSDoc(node)) {
21451-
error(node.name,
21452-
Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name,
21453-
idText(node.name.kind === SyntaxKind.QualifiedName ? node.name.right : node.name));
21446+
const decl = getHostSignatureFromJSDoc(node);
21447+
// don't issue an error for invalid hosts -- just functions --
21448+
// and give a better error message when the host function mentions `arguments`
21449+
// but the tag doesn't have an array type
21450+
if (decl) {
21451+
if (!containsArgumentsReference(decl)) {
21452+
error(node.name,
21453+
Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name,
21454+
idText(node.name.kind === SyntaxKind.QualifiedName ? node.name.right : node.name));
21455+
}
21456+
else if (findLast(getJSDocTags(decl), isJSDocParameterTag) === node &&
21457+
node.typeExpression && node.typeExpression.type &&
21458+
!isArrayType(getTypeFromTypeNode(node.typeExpression.type))) {
21459+
error(node.name,
21460+
Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name_It_would_match_arguments_if_it_had_an_array_type,
21461+
idText(node.name.kind === SyntaxKind.QualifiedName ? node.name.right : node.name));
21462+
}
21463+
}
2145421464
}
2145521465
}
2145621466

@@ -21461,7 +21471,7 @@ namespace ts {
2146121471
return;
2146221472
}
2146321473

21464-
const augmentsTags = getAllJSDocTagsOfKind(classLike, SyntaxKind.JSDocAugmentsTag);
21474+
const augmentsTags = getJSDocTags(classLike).filter(isJSDocAugmentsTag);
2146521475
Debug.assert(augmentsTags.length > 0);
2146621476
if (augmentsTags.length > 1) {
2146721477
error(augmentsTags[1], Diagnostics.Class_declarations_cannot_have_more_than_one_augments_or_extends_tag);
@@ -21563,6 +21573,8 @@ namespace ts {
2156321573

2156421574
function registerForUnusedIdentifiersCheck(node: Node) {
2156521575
if (deferredUnusedIdentifierNodes) {
21576+
// TODO: GH#22580
21577+
// Debug.assert(addToSeen(seenDeferredUnusedIdentifiers, getNodeId(node)), "Deferring unused identifier check twice");
2156621578
deferredUnusedIdentifierNodes.push(node);
2156721579
}
2156821580
}
@@ -24477,18 +24489,19 @@ namespace ts {
2447724489
const paramTag = parent.parent;
2447824490
if (isJSDocTypeExpression(parent) && isJSDocParameterTag(paramTag)) {
2447924491
// Else we will add a diagnostic, see `checkJSDocVariadicType`.
24480-
const param = getParameterSymbolFromJSDoc(paramTag);
24481-
if (param) {
24482-
const host = getHostSignatureFromJSDoc(paramTag);
24492+
const host = getHostSignatureFromJSDoc(paramTag);
24493+
if (host) {
2448324494
/*
24484-
Only return an array type if the corresponding parameter is marked as a rest parameter.
24495+
Only return an array type if the corresponding parameter is marked as a rest parameter, or if there are no parameters.
2448524496
So in the following situation we will not create an array type:
2448624497
/** @param {...number} a * /
2448724498
function f(a) {}
2448824499
Because `a` will just be of type `number | undefined`. A synthetic `...args` will also be added, which *will* get an array type.
2448924500
*/
24490-
const lastParamDeclaration = host && last(host.parameters);
24491-
if (lastParamDeclaration.symbol === param && isRestParameter(lastParamDeclaration)) {
24501+
const lastParamDeclaration = lastOrUndefined(host.parameters);
24502+
const symbol = getParameterSymbolFromJSDoc(paramTag);
24503+
if (!lastParamDeclaration ||
24504+
symbol && lastParamDeclaration.symbol === symbol && isRestParameter(lastParamDeclaration)) {
2449224505
return createArrayType(type);
2449324506
}
2449424507
}
@@ -24572,6 +24585,7 @@ namespace ts {
2457224585
}
2457324586

2457424587
deferredNodes = undefined;
24588+
seenDeferredUnusedIdentifiers.clear();
2457524589
deferredUnusedIdentifierNodes = undefined;
2457624590

2457724591
if (isExternalOrCommonJsModule(node)) {

src/compiler/core.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,7 @@ namespace ts {
10771077
* Returns the first element of an array if non-empty, `undefined` otherwise.
10781078
*/
10791079
export function firstOrUndefined<T>(array: ReadonlyArray<T>): T | undefined {
1080-
return elementAt(array, 0);
1080+
return array.length === 0 ? undefined : array[0];
10811081
}
10821082

10831083
export function first<T>(array: ReadonlyArray<T>): T {
@@ -1089,7 +1089,7 @@ namespace ts {
10891089
* Returns the last element of an array if non-empty, `undefined` otherwise.
10901090
*/
10911091
export function lastOrUndefined<T>(array: ReadonlyArray<T>): T | undefined {
1092-
return elementAt(array, -1);
1092+
return array.length === 0 ? undefined : array[array.length - 1];
10931093
}
10941094

10951095
export function last<T>(array: ReadonlyArray<T>): T {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3720,6 +3720,10 @@
37203720
"category": "Error",
37213721
"code": 8028
37223722
},
3723+
"JSDoc '@param' tag has name '{0}', but there is no parameter with that name. It would match 'arguments' if it had an array type.": {
3724+
"category": "Error",
3725+
"code": 8029
3726+
},
37233727
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
37243728
"category": "Error",
37253729
"code": 9002

src/compiler/factory.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ namespace ts {
2424
* Make `elements` into a `NodeArray<T>`. If `elements` is `undefined`, returns an empty `NodeArray<T>`.
2525
*/
2626
export function createNodeArray<T extends Node>(elements?: ReadonlyArray<T>, hasTrailingComma?: boolean): NodeArray<T> {
27-
if (elements) {
27+
if (!elements || elements === emptyArray) {
28+
elements = [];
29+
}
30+
else {
2831
if (isNodeArray(elements)) {
2932
return elements;
3033
}
3134
}
32-
else {
33-
elements = [];
34-
}
3535

3636
const array = <NodeArray<T>>elements;
3737
array.pos = -1;

src/compiler/parser.ts

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4119,17 +4119,32 @@ namespace ts {
41194119
return finishNode(node);
41204120
}
41214121

4122-
function parseJsxChild(): JsxChild {
4123-
switch (token()) {
4122+
function parseJsxChild(openingTag: JsxOpeningElement | JsxOpeningFragment, token: JsxTokenSyntaxKind): JsxChild | undefined {
4123+
switch (token) {
4124+
case SyntaxKind.EndOfFileToken:
4125+
// If we hit EOF, issue the error at the tag that lacks the closing element
4126+
// rather than at the end of the file (which is useless)
4127+
if (isJsxOpeningFragment(openingTag)) {
4128+
parseErrorAtPosition(openingTag.pos, openingTag.end - openingTag.pos, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag);
4129+
}
4130+
else {
4131+
const openingTagName = openingTag.tagName;
4132+
parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName));
4133+
}
4134+
return undefined;
4135+
case SyntaxKind.LessThanSlashToken:
4136+
case SyntaxKind.ConflictMarkerTrivia:
4137+
return undefined;
41244138
case SyntaxKind.JsxText:
41254139
case SyntaxKind.JsxTextAllWhiteSpaces:
41264140
return parseJsxText();
41274141
case SyntaxKind.OpenBraceToken:
4128-
return parseJsxExpression(/*inExpressionContext*/ false)!;
4142+
return parseJsxExpression(/*inExpressionContext*/ false);
41294143
case SyntaxKind.LessThanToken:
41304144
return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false);
4145+
default:
4146+
return Debug.assertNever(token);
41314147
}
4132-
Debug.fail("Unknown JSX child kind " + token());
41334148
}
41344149

41354150
function parseJsxChildren(openingTag: JsxOpeningElement | JsxOpeningFragment): NodeArray<JsxChild> {
@@ -4139,34 +4154,12 @@ namespace ts {
41394154
parsingContext |= 1 << ParsingContext.JsxChildren;
41404155

41414156
while (true) {
4142-
currentToken = scanner.reScanJsxToken();
4143-
if (token() === SyntaxKind.LessThanSlashToken) {
4144-
// Closing tag
4145-
break;
4146-
}
4147-
else if (token() === SyntaxKind.EndOfFileToken) {
4148-
// If we hit EOF, issue the error at the tag that lacks the closing element
4149-
// rather than at the end of the file (which is useless)
4150-
if (isJsxOpeningFragment(openingTag)) {
4151-
parseErrorAtPosition(openingTag.pos, openingTag.end - openingTag.pos, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag);
4152-
}
4153-
else {
4154-
const openingTagName = openingTag.tagName;
4155-
parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName));
4156-
}
4157-
break;
4158-
}
4159-
else if (token() === SyntaxKind.ConflictMarkerTrivia) {
4160-
break;
4161-
}
4162-
const child = parseJsxChild();
4163-
if (child) {
4164-
list.push(child);
4165-
}
4157+
const child = parseJsxChild(openingTag, currentToken = scanner.reScanJsxToken());
4158+
if (!child) break;
4159+
list.push(child);
41664160
}
41674161

41684162
parsingContext = saveParsingContext;
4169-
41704163
return createNodeArray(list, listPos);
41714164
}
41724165

src/compiler/scanner.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ namespace ts {
3333
reScanTemplateToken(): SyntaxKind;
3434
scanJsxIdentifier(): SyntaxKind;
3535
scanJsxAttributeValue(): SyntaxKind;
36-
reScanJsxToken(): SyntaxKind;
37-
scanJsxToken(): SyntaxKind;
36+
reScanJsxToken(): JsxTokenSyntaxKind;
37+
scanJsxToken(): JsxTokenSyntaxKind;
3838
scanJSDocToken(): JsDocSyntaxKind;
3939
scan(): SyntaxKind;
4040
getText(): string;
@@ -1836,12 +1836,12 @@ namespace ts {
18361836
return token = scanTemplateAndSetTokenValue();
18371837
}
18381838

1839-
function reScanJsxToken(): SyntaxKind {
1839+
function reScanJsxToken(): JsxTokenSyntaxKind {
18401840
pos = tokenPos = startPos;
18411841
return token = scanJsxToken();
18421842
}
18431843

1844-
function scanJsxToken(): SyntaxKind {
1844+
function scanJsxToken(): JsxTokenSyntaxKind {
18451845
startPos = tokenPos = pos;
18461846

18471847
if (pos >= end) {

0 commit comments

Comments
 (0)