Skip to content

Commit e5e4888

Browse files
committed
Merge branch 'master' into getJSDocParameterTags_defined
2 parents 0e7e3b1 + 60501c8 commit e5e4888

8 files changed

+159
-33
lines changed

src/compiler/checker.ts

Lines changed: 16 additions & 3 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;
@@ -4166,7 +4167,17 @@ namespace ts {
41664167
return getTypeForBindingElement(<BindingElement>declaration);
41674168
}
41684169

4169-
const isOptional = !isBindingElement(declaration) && !isVariableDeclaration(declaration) && !!declaration.questionToken && includeOptionality;
4170+
let isOptional = false;
4171+
if (includeOptionality) {
4172+
if (isInJavaScriptFile(declaration) && isParameter(declaration)) {
4173+
const parameterTags = getJSDocParameterTags(declaration);
4174+
isOptional = !!(parameterTags && parameterTags.length > 0 && find(parameterTags, tag => tag.isBracketed));
4175+
}
4176+
if (!isBindingElement(declaration) && !isVariableDeclaration(declaration) && !!declaration.questionToken) {
4177+
isOptional = true;
4178+
}
4179+
}
4180+
41704181
// Use type from type annotation if one is present
41714182
const declaredType = tryGetTypeFromEffectiveTypeNode(declaration);
41724183
if (declaredType) {
@@ -8656,9 +8667,10 @@ namespace ts {
86568667
return getTypeFromIntersectionTypeNode(<IntersectionTypeNode>node);
86578668
case SyntaxKind.JSDocNullableType:
86588669
return getTypeFromJSDocNullableTypeNode(<JSDocNullableType>node);
8670+
case SyntaxKind.JSDocOptionalType:
8671+
return addOptionality(getTypeFromTypeNode((node as JSDocOptionalType).type));
86598672
case SyntaxKind.ParenthesizedType:
86608673
case SyntaxKind.JSDocNonNullableType:
8661-
case SyntaxKind.JSDocOptionalType:
86628674
case SyntaxKind.JSDocTypeExpression:
86638675
return getTypeFromTypeNode((<ParenthesizedTypeNode | JSDocTypeReferencingNode | JSDocTypeExpression>node).type);
86648676
case SyntaxKind.JSDocVariadicType:
@@ -18661,7 +18673,6 @@ namespace ts {
1866118673

1866218674
// The identityMapper object is used to indicate that function expressions are wildcards
1866318675
if (checkMode === CheckMode.SkipContextSensitive && isContextSensitive(node)) {
18664-
checkNodeDeferred(node);
1866518676
return anyFunctionType;
1866618677
}
1866718678

@@ -21551,6 +21562,7 @@ namespace ts {
2155121562

2155221563
function registerForUnusedIdentifiersCheck(node: Node) {
2155321564
if (deferredUnusedIdentifierNodes) {
21565+
Debug.assert(addToSeen(seenDeferredUnusedIdentifiers, getNodeId(node)), "Deferring unused identifier check twice");
2155421566
deferredUnusedIdentifierNodes.push(node);
2155521567
}
2155621568
}
@@ -24560,6 +24572,7 @@ namespace ts {
2456024572
}
2456124573

2456224574
deferredNodes = undefined;
24575+
seenDeferredUnusedIdentifiers.clear();
2456324576
deferredUnusedIdentifierNodes = undefined;
2456424577

2456524578
if (isExternalOrCommonJsModule(node)) {

src/compiler/utilities.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3839,6 +3839,16 @@ namespace ts {
38393839
export function showModuleSpecifier({ moduleSpecifier }: ImportDeclaration): string {
38403840
return isStringLiteral(moduleSpecifier) ? moduleSpecifier.text : getTextOfNode(moduleSpecifier);
38413841
}
3842+
3843+
/** Add a value to a set, and return true if it wasn't already present. */
3844+
export function addToSeen(seen: Map<true>, key: string | number): boolean {
3845+
key = String(key);
3846+
if (seen.has(key)) {
3847+
return false;
3848+
}
3849+
seen.set(key, true);
3850+
return true;
3851+
}
38423852
}
38433853

38443854
namespace ts {

src/harness/virtualFileSystemWithWatch.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,12 +276,14 @@ interface Array<T> {}`
276276
DynamicPolling = "RecursiveDirectoryUsingDynamicPriorityPolling"
277277
}
278278

279+
const timeIncrements = 1000;
279280
export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, ModuleResolutionHost {
280281
args: string[] = [];
281282

282283
private readonly output: string[] = [];
283284

284285
private fs: Map<FSEntry> = createMap<FSEntry>();
286+
private time = timeIncrements;
285287
getCanonicalFileName: (s: string) => string;
286288
private toPath: (f: string) => Path;
287289
private timeoutCallbacks = new Callbacks();
@@ -355,6 +357,11 @@ interface Array<T> {}`
355357
return s;
356358
}
357359

360+
private now() {
361+
this.time += timeIncrements;
362+
return new Date(this.time);
363+
}
364+
358365
reloadFS(fileOrFolderList: ReadonlyArray<FileOrFolder>, options?: Partial<ReloadWatchInvokeOptions>) {
359366
const mapNewLeaves = createMap<true>();
360367
const isNewFs = this.fs.size === 0;
@@ -381,8 +388,8 @@ interface Array<T> {}`
381388
}
382389
else {
383390
currentEntry.content = fileOrDirectory.content;
384-
currentEntry.modifiedTime = new Date();
385-
this.fs.get(getDirectoryPath(currentEntry.path)).modifiedTime = new Date();
391+
currentEntry.modifiedTime = this.now();
392+
this.fs.get(getDirectoryPath(currentEntry.path)).modifiedTime = this.now();
386393
if (options && options.invokeDirectoryWatcherInsteadOfFileChanged) {
387394
this.invokeDirectoryWatcher(getDirectoryPath(currentEntry.fullPath), currentEntry.fullPath);
388395
}
@@ -406,7 +413,7 @@ interface Array<T> {}`
406413
}
407414
else {
408415
// Folder update: Nothing to do.
409-
currentEntry.modifiedTime = new Date();
416+
currentEntry.modifiedTime = this.now();
410417
}
411418
}
412419
}
@@ -505,7 +512,7 @@ interface Array<T> {}`
505512

506513
private addFileOrFolderInFolder(folder: Folder, fileOrDirectory: File | Folder | SymLink, ignoreWatch?: boolean) {
507514
insertSorted(folder.entries, fileOrDirectory, (a, b) => compareStringsCaseSensitive(getBaseFileName(a.path), getBaseFileName(b.path)));
508-
folder.modifiedTime = new Date();
515+
folder.modifiedTime = this.now();
509516
this.fs.set(fileOrDirectory.path, fileOrDirectory);
510517

511518
if (ignoreWatch) {
@@ -520,7 +527,7 @@ interface Array<T> {}`
520527
const baseFolder = this.fs.get(basePath) as Folder;
521528
if (basePath !== fileOrDirectory.path) {
522529
Debug.assert(!!baseFolder);
523-
baseFolder.modifiedTime = new Date();
530+
baseFolder.modifiedTime = this.now();
524531
filterMutate(baseFolder.entries, entry => entry !== fileOrDirectory);
525532
}
526533
this.fs.delete(fileOrDirectory.path);
@@ -587,7 +594,7 @@ interface Array<T> {}`
587594
return {
588595
path: this.toPath(fullPath),
589596
fullPath,
590-
modifiedTime: new Date()
597+
modifiedTime: this.now()
591598
};
592599
}
593600

src/services/utilities.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,16 +1205,6 @@ namespace ts {
12051205
};
12061206
}
12071207

1208-
/** Add a value to a set, and return true if it wasn't already present. */
1209-
export function addToSeen(seen: Map<true>, key: string | number): boolean {
1210-
key = String(key);
1211-
if (seen.has(key)) {
1212-
return false;
1213-
}
1214-
seen.set(key, true);
1215-
return true;
1216-
}
1217-
12181208
export function getSnapshotText(snap: IScriptSnapshot): string {
12191209
return snap.getText(0, snap.getLength());
12201210
}

tests/baselines/reference/jsdocParamTagTypeLiteral.types

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@ normal(12);
2323
* @param {string} [opts1.w="hi"] doc5
2424
*/
2525
function foo1(opts1) {
26-
>foo1 : (opts1: { x: string; y?: string; z?: string; w?: string; }) => void
27-
>opts1 : { x: string; y?: string; z?: string; w?: string; }
26+
>foo1 : (opts1: { x: string; y?: string | undefined; z?: string; w?: string; }) => void
27+
>opts1 : { x: string; y?: string | undefined; z?: string; w?: string; }
2828

2929
opts1.x;
3030
>opts1.x : string
31-
>opts1 : { x: string; y?: string; z?: string; w?: string; }
31+
>opts1 : { x: string; y?: string | undefined; z?: string; w?: string; }
3232
>x : string
3333
}
3434

3535
foo1({x: 'abc'});
3636
>foo1({x: 'abc'}) : void
37-
>foo1 : (opts1: { x: string; y?: string; z?: string; w?: string; }) => void
37+
>foo1 : (opts1: { x: string; y?: string | undefined; z?: string; w?: string; }) => void
3838
>{x: 'abc'} : { x: string; }
3939
>x : string
4040
>'abc' : "abc"
@@ -45,20 +45,20 @@ foo1({x: 'abc'});
4545
* @param {string=} opts2[].anotherY
4646
*/
4747
function foo2(/** @param opts2 bad idea theatre! */opts2) {
48-
>foo2 : (opts2: { anotherX: string; anotherY?: string; }[]) => void
49-
>opts2 : { anotherX: string; anotherY?: string; }[]
48+
>foo2 : (opts2: { anotherX: string; anotherY?: string | undefined; }[]) => void
49+
>opts2 : { anotherX: string; anotherY?: string | undefined; }[]
5050

5151
opts2[0].anotherX;
5252
>opts2[0].anotherX : string
53-
>opts2[0] : { anotherX: string; anotherY?: string; }
54-
>opts2 : { anotherX: string; anotherY?: string; }[]
53+
>opts2[0] : { anotherX: string; anotherY?: string | undefined; }
54+
>opts2 : { anotherX: string; anotherY?: string | undefined; }[]
5555
>0 : 0
5656
>anotherX : string
5757
}
5858

5959
foo2([{anotherX: "world"}]);
6060
>foo2([{anotherX: "world"}]) : void
61-
>foo2 : (opts2: { anotherX: string; anotherY?: string; }[]) => void
61+
>foo2 : (opts2: { anotherX: string; anotherY?: string | undefined; }[]) => void
6262
>[{anotherX: "world"}] : { anotherX: string; }[]
6363
>{anotherX: "world"} : { anotherX: string; }
6464
>anotherX : string
@@ -92,20 +92,20 @@ foo3({x: 'abc'});
9292
* @param {string} [opts4[].w="hi"]
9393
*/
9494
function foo4(opts4) {
95-
>foo4 : (opts4: { x: string; y?: string; z?: string; w?: string; }[]) => void
96-
>opts4 : { x: string; y?: string; z?: string; w?: string; }[]
95+
>foo4 : (opts4: { x: string; y?: string | undefined; z?: string; w?: string; }[]) => void
96+
>opts4 : { x: string; y?: string | undefined; z?: string; w?: string; }[]
9797

9898
opts4[0].x;
9999
>opts4[0].x : string
100-
>opts4[0] : { x: string; y?: string; z?: string; w?: string; }
101-
>opts4 : { x: string; y?: string; z?: string; w?: string; }[]
100+
>opts4[0] : { x: string; y?: string | undefined; z?: string; w?: string; }
101+
>opts4 : { x: string; y?: string | undefined; z?: string; w?: string; }[]
102102
>0 : 0
103103
>x : string
104104
}
105105

106106
foo4([{ x: 'hi' }]);
107107
>foo4([{ x: 'hi' }]) : void
108-
>foo4 : (opts4: { x: string; y?: string; z?: string; w?: string; }[]) => void
108+
>foo4 : (opts4: { x: string; y?: string | undefined; z?: string; w?: string; }[]) => void
109109
>[{ x: 'hi' }] : { x: string; }[]
110110
>{ x: 'hi' } : { x: string; }
111111
>x : string
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
=== tests/cases/conformance/jsdoc/a.js ===
2+
/**
3+
* @param {number} [p]
4+
* @param {number=} q
5+
* @param {number} [r=101]
6+
*/
7+
function f(p, q, r) {
8+
>f : Symbol(f, Decl(a.js, 0, 0))
9+
>p : Symbol(p, Decl(a.js, 5, 11))
10+
>q : Symbol(q, Decl(a.js, 5, 13))
11+
>r : Symbol(r, Decl(a.js, 5, 16))
12+
13+
p = undefined
14+
>p : Symbol(p, Decl(a.js, 5, 11))
15+
>undefined : Symbol(undefined)
16+
17+
q = undefined
18+
>q : Symbol(q, Decl(a.js, 5, 13))
19+
>undefined : Symbol(undefined)
20+
21+
// note that, unlike TS, JSDOC [r=101] retains | undefined because
22+
// there's no code emitted to get rid of it.
23+
r = undefined
24+
>r : Symbol(r, Decl(a.js, 5, 16))
25+
>undefined : Symbol(undefined)
26+
}
27+
f()
28+
>f : Symbol(f, Decl(a.js, 0, 0))
29+
30+
f(undefined, undefined, undefined)
31+
>f : Symbol(f, Decl(a.js, 0, 0))
32+
>undefined : Symbol(undefined)
33+
>undefined : Symbol(undefined)
34+
>undefined : Symbol(undefined)
35+
36+
f(1, 2, 3)
37+
>f : Symbol(f, Decl(a.js, 0, 0))
38+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
=== tests/cases/conformance/jsdoc/a.js ===
2+
/**
3+
* @param {number} [p]
4+
* @param {number=} q
5+
* @param {number} [r=101]
6+
*/
7+
function f(p, q, r) {
8+
>f : (p?: number | undefined, q?: number | undefined, r?: number | undefined) => void
9+
>p : number | undefined
10+
>q : number | undefined
11+
>r : number | undefined
12+
13+
p = undefined
14+
>p = undefined : undefined
15+
>p : number | undefined
16+
>undefined : undefined
17+
18+
q = undefined
19+
>q = undefined : undefined
20+
>q : number | undefined
21+
>undefined : undefined
22+
23+
// note that, unlike TS, JSDOC [r=101] retains | undefined because
24+
// there's no code emitted to get rid of it.
25+
r = undefined
26+
>r = undefined : undefined
27+
>r : number | undefined
28+
>undefined : undefined
29+
}
30+
f()
31+
>f() : void
32+
>f : (p?: number | undefined, q?: number | undefined, r?: number | undefined) => void
33+
34+
f(undefined, undefined, undefined)
35+
>f(undefined, undefined, undefined) : void
36+
>f : (p?: number | undefined, q?: number | undefined, r?: number | undefined) => void
37+
>undefined : undefined
38+
>undefined : undefined
39+
>undefined : undefined
40+
41+
f(1, 2, 3)
42+
>f(1, 2, 3) : void
43+
>f : (p?: number | undefined, q?: number | undefined, r?: number | undefined) => void
44+
>1 : 1
45+
>2 : 2
46+
>3 : 3
47+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// @noEmit: true
2+
// @allowJs: true
3+
// @checkJs: true
4+
// @strict: true
5+
// @Filename: a.js
6+
7+
/**
8+
* @param {number} [p]
9+
* @param {number=} q
10+
* @param {number} [r=101]
11+
*/
12+
function f(p, q, r) {
13+
p = undefined
14+
q = undefined
15+
// note that, unlike TS, JSDOC [r=101] retains | undefined because
16+
// there's no code emitted to get rid of it.
17+
r = undefined
18+
}
19+
f()
20+
f(undefined, undefined, undefined)
21+
f(1, 2, 3)

0 commit comments

Comments
 (0)